Single make rule for multiple output files in different directories - makefile

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)

Related

How can I make a Makefile file target depend on a different path?

I apologize for the ambiguous title, I couldn't think of a simple way to phrase it due to my lack of knowledge in GNU make.
I'm writing a simple Makefile for a small project, and I'm trying to enable it to generate individual objects by using their base name (without path) as the target:
$(BASE_OBJS) : %.o : $(SRC_DIR)/%.c $(OBJDIR) $(INCLUDES)
#echo $(CC): [$(notdir $<)] '->' [$(notdir $#)]
#$(CC) -c $< $(CFLAGS) -o $(OBJDIR)/$#
The problem is that the 'make' app obviously expects the target object to be present in the current folder, but it's actually found in the $(OBJDIR) subfolder. The causes those targets to unnecessarily rebuild.
Alternatively, this rule does check for the object's existence in the right place:
$(OBJS) : $(OBJDIR)/%.o: $(SRC_DIR)/%.c $(INCLUDES)
#echo $(CC): [$(notdir $<)] '->' [$(notdir $#)]
#$(CC) -c $< $(CFLAGS) -o $#
But it can't be used for running things like 'make main.o', as $(OBJS) includes the full path of the objects, so it only allows things like 'make output/main.o'.
If it's a duplicate then I'm sorry, I was looking for a while and couldn't find a similar question.
For reference, these are the variable definitions:
BASE_SRC=$(notdir $(SOURCES))
BASE_OBJS = $(BASE_SRC:%.c=%.o)
OBJS = $(BASE_OBJS:%.o=$(OBJDIR)/%.o)
Your main set of targets and prerequisites must use the full path, because that's how make works. So you must have something like:
$(OBJS) : $(OBJDIR)/%.o: $(SRC_DIR)/%.c $(INCLUDES)
#echo $(CC): [$(notdir $<)] '->' [$(notdir $#)]
#$(CC) -c $< $(CFLAGS) -o $#
Now if in addition you want to be able to run a simple make foo.o, then to do that you should define extra "alias" targets for the real targets. These rules only exist for the short-hand, they don't actually do anything. Something like:
$(BASE_OBJS) : %.o : $(OBJDIR)/%.o

Rename .o files using Makefile and gcc

I have several lines in Makefile that are compiling and producing .o and .d files. I want two sets of .o .d to be produced, something like:
name.d
name_hello.d
name.o
name_hello.o
Already found how to change names of .d using "$(#:.o=_hello.d)" but have no success changing .o Perhaps i need to play with $# but have no idea how to do it.
Here is Make file code:
$(OBJECT_DIRECTORY)/%.o: %.c
# Build header dependencies
$(CC) $(CFLAGS) $(INCLUDEPATHS) -M $< -MF "$(#:.o=.d)" -MT $#
$(CC) $(CFLAGS) $(INCLUDEPATHS) -M $< -MF "$(#:.o=_hello.d)" -MT $#
# Do the actual compilation
$(CC) $(CFLAGS) $(INCLUDEPATHS) -c -o $# $<
$(CC) $(CFLAGS) $(INCLUDEPATHS) -c -o $# $< - this line i want to change
I use arm-none-eabi-gcc.exe for ARMs and make.exe
Update
Seems that using separate target is preffered solution than changing names. So, i did separate target for it. But it is never used. In other place of the Makefile there is next line of code that tells compiler what .o files to use:
C_OBJECTS = $(addprefix $(OBJECT_DIRECTORY)/, $(C_SOURCE_FILENAMES:.c=.o) )
I suppose that i need to change it to something like:
C_OBJECTS_hello = $(addprefix $(OBJECT_DIRECTORY)/, $(C_SOURCE_FILENAMES:.c=*_hello.o) )
Please tell how to modify C_OBJECTS in order to make compiler use *_hello.o files
Update 2
This is how C_OBJECTS used, i suppose some kind of a filter in C_OBJECTS tells CC ( arm-none-eabi-gcc.exe ) to use certain .o files. And since *_hello.o files are not used in the filter they are also not produced in their target.
## Link C and assembler objects to an .out file
$(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out: $(BUILD_DIRECTORIES) $(C_OBJECTS) $(ASSEMBLER_OBJECTS) $(LIBRARIES)
$(CC) $(LDFLAGS) $(C_OBJECTS) $(ASSEMBLER_OBJECTS) $(LIBRARIES) -o $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out
I know that this is written in make help and i am reading it, but still not able to find an answer
Update 3
Here is how i modified 'C_OBJECTS' , and seems this works:
C_OBJECTS_hello = $(addprefix $(OBJECT_DIRECTORY)/, $(C_SOURCE_FILENAMES:.c=_hello.o) )
You indeed would use a replacement. The $# variable expands all the %.o matches. That's why you had a $(#:.o=.d) replacement; you needed a .d file for each %.o match.
In this case, you can indeed use a $(#:.o=_hello.o) replacement. Note that this is NOT a dependency of the %.c input; it is a secondary output.
The alternative is to add a second output $(OBJECT_DIRECTORY)/%.o $(OBJECT_DIRECTORY)/%_hello.o: %.c. In this case, you wouldn't use $# but use $* which is the matched %. So your two dependency files would be $(OBJECT_DIRECTORY)/$*.d and $(OBJECT_DIRECTORY)/$*_hello.d
Your makefile rule produces more files than make is aware of. $(OBJECT_DIRECTORY)/%.o: %.c says it builds one .o from .c, whereas you would like it to build 4 files.
You need to make make aware what files its rules produces, so that it can build a complete dependency graph:
$(OBJECT_DIRECTORY)/%.o $(OBJECT_DIRECTORY)/%.d: %.c # Compile and build dependencies.
$(CC) -c -o $# $(CFLAGS) $(INCLUDEPATHS) -MD -MP $<
$(OBJECT_DIRECTORY)/%_hello.o $(OBJECT_DIRECTORY)/%_hello.d: %.c # Compile and build dependencies.
$(CC) -c -o $# $(CFLAGS) $(INCLUDEPATHS) -MD -MP $<
Note that these rules do not explicitly name the .d output file, letting the compiler determine it by replacing .o with .d.
Now that you have two rules instead of one make can parallelize their execution when -j flag is used.
Note that you should not need explicit rules for auto-generated dependencies for the reasons stated in https://stackoverflow.com/a/7358961/412080.

Understanding deeply using a specific case how makefiles are interpreted

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.

Add dependencies to existing make targets

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.

Passing target name to a dependency in makefile

If I have the following rule in a makefile:
$(OBJ)/%.o: $(SRC)/%.c
$(CC) -c -o $# $< $(CFLAGS)
Every file matching the prefix ./obj/ and sufix .o will have its stem passed to %, so I can provide some dependencies based on its name.
But, suppose I have this kind of rule, which I specify one by one the targets I want:
OBJECTS=abc.o bca.o cba.o
$(OBJECTS): $(SRC)/%.c
$(CC) -c -o $# $< $(CFLAGS)
How do I make the % stem actually work for the current target name make is executing? Just using % doesn't work, neither $#.
Note that I'm trying to write the actual target name to its own dependency. For example, when make is executing the rule for abc.o, it would include $(SRC)/abc.c and just it (something like $(patsubst %.o, $(SRC)/%.c, MAGIC_TARGET_NAME_VARIABLE)).
You can just replace this rule:
$(OBJECTS): $(SRC)/%.c
with:
$(OBJECTS) : %.o : $(SRC)/%.c
You will need to add the $(OBJ) to the -o part of the recipe if you still want them built there:
$(OBJECTS) : %.o : $(SRC)/%.c
$(CC) -c -o $(OBJ)/$# $< $(CFLAGS)
I’m not completely clear on what you’re asking, but I think this accomplishes what you’re trying to do:
OBJECTS=abc.o bca.o cba.o
.PHONY: all
all: $(OBJECTS:%=obj/%)
$(OBJ)/%.o: $(SRC)/%.c
echo $(CC) -c -o $# $< $(CFLAGS)
All .o files are built; each .o file is built using only the .c file corresponding to it; and if you want to refer to the list of all object files or source files in the command for compiling a .o file, then you can reference ${OBJECTS} directly.
If this isn’t what you’re trying to do, you’ll be able to get a better answer by listing the input files you have, the output files you want to make, the input dependencies of each output file, and what compilation command you want to execute for each output file.

Resources