I can write pattern rules like that to compile .cfiles to .ofiles.
%.o:%.c
$(CC) -c $< $(CFLAGS) -o $#
But it seems that this method will only work when all the c file are in the same directory.
If my project's struct is like this
|-folder1
|----a.c
|----b.c
|-folder2
|----c.c
|----d.c
|Makefile
I have to change my Makefile to this
%.o:folder1/%.c
$(CC) -c $< $(CFLAGS) -o $#
%.o:folder2/%.c
$(CC) -c $< $(CFLAGS) -o $#
If i have a lot of folders, I think repeating code like this is not the correct way to solve the problem.
Anyone has better solutions?
Related
Lets say I have one directory with c files (.) and I want the object files to end up in two different directories: debug and release. Now I want to make the rule for this. This will end up being something like this:
$(DEBUGDIR)%.o : %.c
$(CC) $(CFLAGS) -c $< -o $#
$(RELEASEDIR)%.o : %.c
$(CC) $(CFLAGS) -c $< -o $#
These are two rules which are exactly the same. Since all possible differences between those rules are contained in CFLAGS there is no reason to even have two rules: I want to maintain only one. I tried this:
$(DEBUGDIR)%.o $(RELEASEDIR)%.o : %.c
$(CC) $(CFLAGS) -c $< -o $#
But now it will not compile the o-files for RELEASE when it already compiled for DEBUG. How can I merge these two rules into one?
You can't do it. Pattern rules with multiple targets define a recipe that creates multiple output files when run one time.
For this I'd just write the rule twice. Alternatively you can put the recipe into a variable and use it twice:
COMPILE = $(CC) $(CFLAGS) -c $< -o $#
$(DEBUGDIR)%.o : %.c
$(COMPILE)
$(RELEASEDIR)%.o : %.c
$(COMPILE)
I'm trying to understand deeply how makefiles work.
For example, I've the following one:
CC = gcc
CFLAGS = -I.
DEPS = int_array.h
OBJS = int_array.o test_int_array.o
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
clean:
rm -rf *.o test_int_array *.dSYM
The part that I really don't understand fully is :
...
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
...
I know that the option -c basically indicates just to run the preprocessor, compiling and assembling steps (i.e. without producing executables, I guess).
-o means to write the output to the specified file. Which file in this case?
I understood that $# (and $^ for right) is apparently referring to a "left" side, but which one? Is it referring, in the first case, to the left side of :, that is %.o?
What does $< mean?
Could you please explain step by step how the make tool would interpret those two statements?
I think I understood this part more or less:
...
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
...
which should mean produce an executable called "test_int_array" (which basically is indicated by these options -o $# from the $(OBJS) files on the right (stated using the option $^).
Is $(CFLAGS) needed in both cases? Does the order matter?
In the example:
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
$# is the filename of the target for this rule: test_int_array.
$^ is the names of all prerequisites.
This would be whatever is contained in OBJS, so: int_array.o test_int_array.o
In the example:
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
$< is the name of the first prerequisite: %.c
$# is the filename of the target for this rule: %.o
$(CFLAGS) is not needed for linking, since it only includes the flag -I. Also the CFLAGS indicates that the flags are used for compiling only, hence C FLAGS.
In a Makefile, each rule follows this format:
resulting_file : source_files
steps to get resulting_file from source_files
What is called respectively lefthand and righthand in a rule is the resulting_file and the source_files.
%.ext : %.ext2
is a pattern rule. It allows your Makefile to automatically create any .ext file it needs if it can find a file at the same path with .ext2.
%.c : %.o
is a pattern rule to obtain your .o files (int_array.o test_int_array.o) from their equivalent .c files (int_array.c test_int_array.c)
This is invoked when you specify that $(OBJS) is needed to build the test_int_array file.
Pattern rules automatically use certain variables, such as $(CFLAGS) so you do not need to manually add it in that rule. You can find a full list of implicitly used variables in pattern rules here: https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC96
You can find out about $#, $< and $^ and similar here: https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC101
$#: the entire lefthand
$<: the first file in the righthand
$^: the entire righthand list of files, space separated.
Condition 0:
Say, I have several source codes, a.c, b.c, ..., z.c, and I want a rule to have each of them compiled. Here is a solution:
%.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
Condition 1:
Then I introduce a header c.h used in c.c, and another header e.h used in c.c and e.c, and things become complex:
%.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
c.o: c.c c.h e.h
$(CC) -c -o $# $(CFLAGS) $<
e.o: e.c e.h
$(CC) -c -o $# $(CFLAGS) $<
My question:
Based on the solution of condition 1, is there something like add_dependency in make to simplify the solution and obtain something like the following one?
%.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
add_dependency(c.o, c.h e.h)
add_dependency(e.o, e.h)
Or, what do you think is a better solution to condition 1?
EDITED:
Thanks for the kind notice #ctheo :)
Yes I did have a look at autotools and understood that shall satisfy all my needs. However what I'm dealing with is an existing project and its Makefile contains other directives dealing with codes in C++, and I think for now I'd better just modify a few lines instead of port the whole Makefile to autotools, unless I couldn't find a satisfying solution without introducing autotools. :)
At first I did not expected to exist a solution for this. It seemed to me that it was covered by autotools. However, after some search, I found this section of GNU/make manual.
It states that :
One file can be the target of several rules. All the prerequisites mentioned in all the rules are merged into one list of prerequisites for the target.
So there is a solution for your query
c.o: c.h e.h
e.o: e.h
%.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
Thanks for insisting. I learned something today :)
In addition, the .o files in your example all depend on a .h file with the same stem, so you can generalise that part of your rules too:
c.o: e.h
%.o: %.c %.h
$(CC) -c -o $# $(CFLAGS) $<
This way, your “normal” situations are covered entirely by the rule that triggers compilation and your “unusual” situations stand out because those are the only additional rules.
I want to compile my program both to linux and windows using g++ and mingw respectively. The only difference between the compilations is the compiler to use and output file name.
A single make command should produce both output files. What is the best way to achieve this with as little duplications in the makefile as possible?
How about this:
linux-name: CC:=g++
windows-name: CC:=mingw
linux-name windows-name:
$(CC) whatever -o $#
EDIT:
What I wrote above is only the new part of the makefile; I assumed that the rest of the makefile was implied. To be more explicit:
all: linux-name windows-name
linux-name: CC:=g++
windows-name: CC:=mingw
linux-name windows-name: foo.o bar.o baz.o SomethingElse
$(CC) $(CCFLAGS) whatever $^ -o $#
%.o: %.cc
$(CC) $(CFLAGS) -I$(INC_DIR) whatever -c $< -o $#
SomethingElse:
build somehow
I am having trouble with my makefile, i have been reading somme tutoriels on how to make a more re-usable makefile but i am facing this error, and i have been searching for a while now, especially on the GNU make manual and here.
Here is my makefile :
SRC_DIR=./src
BUILD_DIR=./build
OBJS= $(BUILD_DIR)/main.o $(BUILD_DIR)/hamming.o
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c $(SRC_DIR)/%.h
$(CC) -c $< $(CFLAGS) -o $#
$(BUILD_DIR)/main: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
I am having the error :
make: No rule to make target build/main.o', needed bybuild/main'. Stop.
It seems to me that the objects in the variable OBJS are not associated with the %.o pattern rule, but i don't know why.
In my working directory there is : my makefile and the two directories 'src' and 'build'.
Thank you.
I'll go out on a limb and guess that there is no src/main.h. If that's the case, you could fix things this way:
$(BUILD_DIR)/hamming.o: $(BUILD_DIR)/%.o : $(SRC_DIR)/%.h
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) -c $< $(CFLAGS) -o $#
EDIT:
Now I'm puzzled. Please try this (it is crude, but if it works we can refine it):
SRC_DIR=./src
BUILD_DIR=./build
OBJS= $(BUILD_DIR)/main.o $(BUILD_DIR)/hamming.o
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c $(SRC_DIR)/%.h
$(CC) -c $< $(CFLAGS) -o $#
$(BUILD_DIR)/main.o: $(SRC_DIR)/main.c
$(CC) -c $< $(CFLAGS) -o $#
$(BUILD_DIR)/main: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
Here is a little documentation I put together for NMake a while back I hope it helps. Are you sure there are only tabs before the commands. You can't have spaces that is the number one error I have seen in the past.