I'm currently trying to work out a Makefile that I could use for multiple projects without the need to change it for every single project. However I recently began programming in C and making Makefiles
This is my current project structure.
project
| src
| gd.c, gd.h, geom.c(only file with main function)
| obj // *.o files should be created here
| bin // executable should be created here
| Makefile
This is what I have build so far, but am not sure at all how to specify the subdirectories for the compiled/linked files.
1 TARGET = projectname
2 LIBS = -lm
3 CC = gcc
4 CFLAGS = -std=c11 -Wall
5 LD = gcc
6 LDFLAGS = -Wall
7
8 SRCDIR = src
9 OBJDIR = obj
10 EXEDIR = bin
11
12 SOURCES =
13 HEADERS =
14 OBJECTS =
15
16 $(EXEDIR)/$(TARGET): $(OBJECTS)
17 $(LD) $(OBJECTS) $(LDFLAGS) -o $# $(LIBS)
18
19 $(OBJECTS): $(SOURCES) $(HEADERS)
20 $(CC) $(CFLAGS) -c $< -o $#
21
22 .PHONY: clean
23 clean:
24 rm -f *.o
25
26 .PHONY: remove
27 remove: clean
28 rm -f $(EXEDIR)/$(TARGET)
My Question would be:
How can I create these files and put them in their respective subdirectory with my layout or something similar to it?
Is it possible to create the necessary folders(obj and bin) when using the make command and if so how can I do it?
If I understand well, you want to know - in your layout - how to set SOURCES, HEADERS and OBJECTS values that will make your Makefile work.
For this you can use regular expressions:
SOURCES = $(wildcard $(SRCDIR)/*.c)
OBJECTS = $(patsubst $(SRCDIR)/%.c,$(OBJDIR)/%.o,$(SOURCES))
HEADERS = $(patsubst %.c,%.h,$(SOURCES))
wildcard documentation here
patsubst documentation here
This is a simple answer, if you want to create a fully reusable Makefile you will have to deal with sources subfolders for example.
The rule to create the objects is strange (maybe it works). I think it is better if you use a rule to create one object with one source at a time, something like:
$(OBJDIR)/%.o: $(SRCDIR)/%.c
$(CC) $(CFLAGS) -c $< -o $#
In this case the SOURCES variable become useless.
Moreover the HEADERS variable is useless I think, because in the compilation process you don't give to gcc the headers but the headers folder with gcc ... -I<headers folder>
And your clean should be rm -f $(OBJDIR)/*.o to delete the object files in the obj folder
Edit
I forgot the second question, you can use the shell commands to create the folder just before the file creation:
$(OBJDIR)/%.o: $(SRCDIR)/%.c
#mkdir $(OBJDIR)
$(CC) $(CFLAGS) -c $< -o $#
Related
I have a question about Makefiles with subdirectories:
I have a program with the structure
---src
|
|-> main.c
|-> morestuff.c
|-> [...]
|-> builtins -> builtin.c
-> builtin2.c
---obj
---inc
Now what I want to do is: I want to run make such that I create object files in my object directory (order structure not necessarily needed) and that I (obviously) create an executable.
I am able to do that without the subdirectories, but my pattern rules break, once I try to include the subdirectories...
My current approach (without subdirectories) looks something like this:
NAME = minishell
SRC_DIR = src/
OBJ_DIR = obj/
INC_DIR = inc/
LIBFT_DIR = libft/
LIBFT_EXEC = libft.a
CC = gcc
CFLAGS = -Wall -Werror -Wextra -g
# place all source files here
SRC = $(SRC_DIR)main.c \
$(SRC_DIR)builtin1.c \
$(SRC_DIR)builtin2.c \
[...]
# takes all named source files and converts them to .o files in the /obj directory
OBJ = $(SRC:$(SRC_DIR)%.c=$(OBJ_DIR)%.o)
# prevents rules from being considered as files
.PHONY: all clean fclean re
all: $(NAME)
# creates subdirectory /obj
$(OBJ_DIR):
#mkdir $#
#echo "Creating object directory..."
# makes sure to make a /obj dir before compiling .o files
$(OBJ): | $(OBJ_DIR)
$(OBJ): $(OBJ_DIR)%.o: $(SRC_DIR)%.c
$(CC) $(CFLAGS) -c $< -o $#
# compiles all object files and builds executable file 'minishell' -> ADJUST READLINE FOR LINUX!
$(NAME): $(OBJ)
#echo "Compiling libft..."
$(MAKE) -C libft
#echo "Compiling $(NAME)..."
$(CC) $(CFLAGS) $^ $(LIBFT_DIR)$(LIBFT_EXEC) -L $(HOME)/goinfre/.brew/opt/readline/lib/ -lreadline -o $#
#echo "SUCCESSFULLY CREATED MINISHELL!"
So how can I scale that up to handle subdirectories?
I know I could make Makefiles in subdirectories, but this is not worth the effort since there aren't a lot of files in there...
Instead of just creating the object directory before compiling, you should create the object file directory tree prior to compiling each file:
$(OBJ_DIR)%.o: $(SRC_DIR)%.c
#mkdir -p $(dir $#)
$(CC) $(CFLAGS) -c $< -o $#
$(dir $#) is a GNU make extension. You can use #mkdir -p `dirname $#` for portability to other make flavors.
I have a client/server application in C. The server has its own folder dserver, the same for the client dclient. Using both of them some files containing utility functions, I created another directory at the same level of the previously ones, named common.
My idea is to create each Makefile in each subfolder (one in dserver, one in dclient and another in common) and then one Makefile in the main directory which will run the other Makefiles which looks like:
all:
+$(MAKE) -C common
+$(MAKE) -C dserver
+$(MAKE) -C dclient
The first problem is that the common/Makefile should not create an executable but only create the object files that will be needed to create the executable for the client and for the server. In my case it is:
CXX = gcc
SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR=$(SOURCEDIR)/obj
OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
$(CXX) $(WARNING) -MMD -MP -c $< -o $#
$(OBJDIR):
mkdir -p $(OBJDIR)
My problem is that it is creating the object directory specified by OBJDIR but not the object files *.o: how should it be?
Secondly in the client and server Makefiles I should both include path to the files in common and then referencing the object files in the resulting from the compilation of common to build the executables. So taking for example the dserver/Makefile I added the line INC_PATH = -I../common/ and referencing it in the compilation as $(CXX) $(WARNING) -MMD -MP -c $(INC_PATH) $< -o $#. However in the code I had to do #include "../common/utilities.h".
Is there a way to include the path in the Makefile so that in the code it allows to do just: #include "utilities.h"?
And also, supposing that common has its own object directory containing the object files needed both by the client and server, how build, for example the server executable referencing the object files both in the common directory and the ones specific and contained in the server directory?
The dserver/Makefile is something like (and the dclient/Makefile has the same structure):
CXX = gcc
INC_PATH = -I../common/
SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR=./obj
OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: server
clean:
$(RM) $(OBJECTS) $(DEPENDS) server
# Linking the executable from the object files
# $^ # "src.c src.h" (all prerequisites)
../server: $(OBJECTS)
$(CXX) $(WARNING) $(INC_PATH) $^ -o $#
#$(CXX) $(WARNING) $(CXXFLAGS) $(INC_PATH) $^ -o $# $(LIBS)
-include $(DEPENDS)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
$(CXX) $(WARNING) -MMD -MP -c $(INC_PATH) $< -o $#
You don't specify any rules for building the objects in your "common" Makefile - this is the only rule you have.
$(OBJDIR):
mkdir -p $(OBJDIR)
You want to put a rule before that to all get it to build the objects, maybe something along the lines of:
all: $(OBJDIR) $(OBJECTS)
It has to go before the original rule as if you don't specify what is being built, make will do the first rule it finds.
Including header files from "common" in your other directories should be working just fine by using -I../common/.
Using the objects from "common" should just be a case of adding them to the list of objects ie:
COMMON_OBJECTS=../common/obj/utilities.o
../server: $(OBJECTS) $(COMMON_OBJECTS)
Or having them built into a library so you don't need to know what object files there are.
Also it's worth noting that $(CXX) is the variable used to store the C++ compiler - for building with the C compiler you want to be using $(CC) and $(CFLAGS).
Trying to compile a friend's code - but he has included no Makefile, I build my own and am perplexed by an issue I've run into.
I think it's best I post the full contents of the Makefile below... I tried to keep it short!
CFLAGS = -Wall -pedantic
LFLAGS =
CC = gcc
RM = /bin/rm -rf
AR = ar rc
RANLIB = ranlib
LIBRARY = const.a read.a descr.a
LIB_SRC = read.c futex.c testy.c
LIB_OBJ = $(patsubst %.c,%.o,$(LIB_SRC))
# pattern rule for object files
%.o: %.c
$(CC) -c $(CFLAGS) $< -o $#
all: $(LIBRARY)
$(LIBRARY): $(LIB_OBJ)
$(AR) $(LIBRARY) $(LIB_OBJ)
$(RANLIB) $(LIBRARY)
clean:
$(RM) $(LIBRARY) $(LIB_OBJ)
.PHONY: depend
depend:
$(CFLAGS) -- $(LIB_SRC) 2>/dev/null
All of the files, const.h, read.h, and descr.h are in the directory in which I call make. Likewise for read.c, futex.c, and testy.c.
The files are entangled in various ways - if I need to show exactly the nature of these entanglements, I will do so.
I 'make' and the compiler alledges:
ar: read.a: No such file or directory
Is it not the case that read.a is supposed to be being produced? Of course it isn't there yet.
I've stared a while now and I feel like this must be something simple I am missing.
This command:
$(AR) $(LIBRARY) $(LIB_OBJ)
expands to this:
ar rc const.a read.a descr.a read.o futex.o testy.o
So when Make tries to build const.a, it tells ar to combine several files into const.a, starting with read.a, and ar complains that there's no such file. (Whether ar could do anything useful with read.a if it did exist is immaterial.)
It's not clear how you want Make to build those libraries, but this might be a step in the right direction:
$(LIBRARY): $(LIB_OBJ)
$(AR) $# $(LIB_OBJ)
$(RANLIB) $#
The automatic variable $# expands to the name of the target. You can use another one for the list of prerequisites ($(LIB_OBJ)), but let's try one new thing at a time.
I have a root directory and a child directory. I am planning to put the functions in child directory under libfunc.o
This libfunc.o should be merged along with other object files in top directory. But I am getting error:
$make all
cd folder; make libfunc.o
make[1]: Entering directory `/home/Work/test_makefile/folder'
cc -c -o func2.o func2.c
cc -c -o func3.o func3.c
func3.c: In function ‘set’:
func3.c:3:25: warning: initialization makes pointer from integer without a cast [enabled by default]
ld -r -o libfunc.o func2.o func3.o
make[1]: Leaving directory `/home/Work/test_makefile/folder'
arm-linux-gnueabi-gcc -c -o hellofun.o hellofun.c -I. -I./include
arm-linux-gnueabi-gcc -c -o hellomake.o hellomake.c -I. -I./include
arm-linux-gnueabi-gcc hellofun.o hellomake.o folder/libfunc.o -o hm
folder/libfunc.o: file not recognized: File format not recognized
collect2: ld returned 1 exit status
make: *** [hm] Error 1
Makefiles: toplevel
1 CC=arm-linux-gnueabi-gcc
2 LD=arm-linux-gnueabi-ld
3 AR=arm-linux-gnueabi-ar
4 CFLAGS=-I. -I./include
5 SOURCES=hellofun.c hellomake.c
6 OBJECTS=$(SOURCES:.c=.o)
7 SUBDIR_OBJS=folder/libfunc.o
8 TARGET=hm
9 DEPS = hellomake.h
10
11 %.o: %.c $(DEPS) $(SUBDIR_OBJS)
12 $(CC) -c -o $# $< $(CFLAGS)
13
14 folder/libfunc.o:
15 cd folder; $(MAKE) libfunc.o
16
17 clean:
18 rm -rf *.o hellomake folder/*.o
19
20 all: $(SOURCES) $(TARGET)
21
22 $(TARGET): $(OBJECTS)
23 $(CC) $(OBJECTS) $(SUBDIR_OBJS) -o $#
24
Makefile : Child
1 SOURCES=$(wildcard *.c)
2 OBJECTS=$(SOURCES:.c=.o)
3 TARGET=libfunc.o
4 %.o: %.c
5 $(CC) -c -o $# $< $(CFLAGS)
6
7 clean:
8 rm -rf *.o
9
10
11 $(TARGET): $(OBJECTS)
12 $(if $(strip $(OBJECTS)),\
13 $(LD) $(LDFLAGS) -r -o $# $(OBJECTS),\
14 rm -f $#; $(AR) rcs $# )
~
~
~
There's more than one error here. First, when asking questions please always provide the complete error message. The no rule to make target error will print out which target it's trying to make; that's critical information for helping you.
Second, you reference a variable SUBDIR_OBJS, but that's never defined. Plus you list that as a prerequisite for building other object files in the %.o : %.c rule: it's virtually never correct to list object files as prerequisites of other object files.
The top-level makefile does not run make in the folder directory, so no commands in that directory will be run automatically. You'll have to go there and run make yourself by hand.
Also in config.mk you create a variable merge_object but in folder/Makefile you refer to a variable merge_objects, which is not the same variable.
I missed export CC in root makefile
I would suggest put on the -Wall option in your compiler options, so that you can have a better debug view of your compiling process.
The output ld -r -o libfunc.o func2.o func3.o seems suspicious to me. Looks like The system used default linker rather than your cross-compile linker, which is arm-linux-gnueabi-ld. That might be a reason for the file not recognized.
As the error was file format not recognized, maybe you can check file libfunc.o output?
If you are having with LD, why not skip it and try other methods, like just gcc -o hm with all object files, or use ar to package the objects in subfolder.
A few months ago, I came up with the following generic Makefile for school assignments:
# ------------------------------------------------
# Generic Makefile
#
# Author: yanick.rochon#gmail.com
# Date : 2010-11-05
#
# Changelog :
# 0.01 - first version
# ------------------------------------------------
# project name (generate executable with this name)
TARGET = projectname
CC = gcc -std=c99 -c
# compiling flags here
CFLAGS = -Wall -I.
LINKER = gcc -o
# linking flags here
LFLAGS = -Wall
SOURCES := $(wildcard *.c)
INCLUDES := $(wildcard *.h)
OBJECTS := $(SOURCES:.c=*.o)
rm = rm -f
$(TARGET): obj
#$(LINKER) $(TARGET) $(LFLAGS) $(OBJECTS)
#echo "Linking complete!"
obj: $(SOURCES) $(INCLUDES)
#$(CC) $(CFLAGS) $(SOURCES)
#echo "Compilation complete!"
clean:
#$(rm) $(TARGET) $(OBJECTS)
#echo "Cleanup complete!"
This will basically compile every .c and .h file to generate .o files and the executable projectname all in the same folder.
Now, I'd like to push this a little. How can I write a Makefile to compile a C project with the following directory structure?
./
./Makefile
./src/*.c;*.h
./obj/*.o
./bin/<executable>
In other words, I'd like to have a Makefile that compiles C sources from ./src/ into ./obj/ and then link everything to create the executable in ./bin/.
I've tried to read different Makefiles, but I simply can't make them work for the project structure above; instead, the project fails to compile with all sorts of errors. Sure, I could use full blown IDE (Monodevelop, Anjuta, etc.), but I honestly prefer to stick with gEdit and the good ol' terminal.
Is there a guru who can give me a working solution, or clear information about how this can be done? Thank you!
** UPDATE (v4) **
The final solution :
# ------------------------------------------------
# Generic Makefile
#
# Author: yanick.rochon#gmail.com
# Date : 2011-08-10
#
# Changelog :
# 2010-11-05 - first version
# 2011-08-10 - added structure : sources, objects, binaries
# thanks to http://stackoverflow.com/users/128940/beta
# 2017-04-24 - changed order of linker params
# ------------------------------------------------
# project name (generate executable with this name)
TARGET = projectname
CC = gcc
# compiling flags here
CFLAGS = -std=c99 -Wall -I.
LINKER = gcc
# linking flags here
LFLAGS = -Wall -I. -lm
# change these to proper directories where each file should be
SRCDIR = src
OBJDIR = obj
BINDIR = bin
SOURCES := $(wildcard $(SRCDIR)/*.c)
INCLUDES := $(wildcard $(SRCDIR)/*.h)
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
rm = rm -f
$(BINDIR)/$(TARGET): $(OBJECTS)
#$(LINKER) $(OBJECTS) $(LFLAGS) -o $#
#echo "Linking complete!"
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
#$(CC) $(CFLAGS) -c $< -o $#
#echo "Compiled "$<" successfully!"
.PHONY: clean
clean:
#$(rm) $(OBJECTS)
#echo "Cleanup complete!"
.PHONY: remove
remove: clean
#$(rm) $(BINDIR)/$(TARGET)
#echo "Executable removed!"
First, your $(OBJECTS) rule is problematic, because:
it's kind of indiscriminate, making all sources prerequisites of every object,
it often uses the wrong source (as you discovered with file1.o and file2.o)
it tries to build executables instead of stopping at objects, and
the name of the target (foo.o) is not what the rule will actually produce (obj/foo.o).
I suggest the following:
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
$(CC) $(CFLAGS) -c $< -o $#
#echo "Compiled "$<" successfully!"
The $(TARGET) rule has the same problem that the target name does not actually describe what the rule builds. For that reason, if you type make several times, Make will rebuild the target each time, even though there is no reason to. A small change fixes that:
$(BINDIR)/$(TARGET): $(OBJECTS)
$(LINKER) $# $(LFLAGS) $(OBJECTS)
#echo "Linking complete!"
Once that's all in order, you might consider more sophisticated dependency handling; if you modify one of the header files, this makefile will not know which objects/executables must be rebuilt. But that can wait for another day.
EDIT:
Sorry, I omitted part of the $(OBJECTS) rule above; I've corrected it. (I wish I could use "strike" inside a code sample.)
You can add the -I flag to the compiler flags (CFLAGS) to indicate where the compiler should look for source files , and the -o flag to indicate where the binary should be left:
CFLAGS = -Wall -I./src
TARGETPATH = ./bin
$(TARGET): obj
#$(LINKER) $(TARGETPATH)/$(TARGET) $(LFLAGS) $(OBJECTS)
#echo "Linking complete!"
In order to drop the object files into the obj directory, use the -o option when compiling. Also, look at the $# and $< automatic variables.
For example, consider this simple Makefile
CFLAGS= -g -Wall -O3
OBJDIR= ./obj
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o )
all:$(OBJS)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $(OBJDIR)/$#
Update>
By looking at your makefile, I realize you are using the -o flag. Good. Continue using it, but add a target directory variable to indicate where the output file should be written.
I have stopped writing makefiles these days, if your intention is to learn go ahead, else you have good makefile generator that comes with eclipse CDT. If you want some maintainability / multiple project support with in your build tree, have a look at the following -
https://github.com/dmoulding/boilermake I found this pretty good..!