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

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

Related

Makefile Skipping a rule even though the filetype exists

I have a makefile with these rules.
all: $(TARGET)
OBJECTS = file.o
%.o: %.c
$(COMPILER) -c $(FLAGS) &< -o C_$(basename $#).o
%.o: %.s
$(COMPILER) -c $(FLAGS) &< -o S_$(basename $#).o
... The Linker is then called with *.o to link all the object files
I have the same filename file.c and file.s in a src directory. But make is only running the first rule for the object file. Why does it only compile once? And how can I get make to compile both file.c and file.s if they exist in my src folder?
I don't want to have to create a different object file name for a different extension. That would be silly.
Is there a way for me to compile the filename with the both .s and .c extension?
I feel like make can easily do this and I am missing something.
Thank you for the help. If I'm not clear please tell me and I will try to explain it more in depth.
You misunderstand how Make works.
There may be many ways to build a target; Make will use one of them, not all. Anyway, your makefile violates one of Mad Scientist's rules, in that your pattern rules do not build what they claim to build:
%.o: %.c
$(COMPILER) -c $(FLAGS) &< -o C_$(basename $#).o
%.o: %.s
$(COMPILER) -c $(FLAGS) &< -o S_$(basename $#).o
The first doesn't build foo.o, it builds C_foo.o; the second doesn't build foo.o, it builds S_foo.o. I don't know how your linking rule works, but if it depends on foo.o, you're in for trouble.
Try this:
C_%.o: %.c
$(COMPILER) -c $(FLAGS) &< -o $#
S_%.o: %.s
$(COMPILER) -c $(FLAGS) &< -o $#
Then give your linking rule whatever prerequisites you think it should have. If you want it to use both C_foo.o and S_foo.o (which doesn't sound like a good idea), then put both of them in the prerequisite list.

Single make rule for multiple output files in different directories

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)

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.

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.

Makefile string substitution in dependency not working

I have a folder structure where all my source files are in ./src/, and all my object files are in ./obj/ (with the same internal directory structure, mirrored using path substitutions). I've created the following makefile:
$(EXECUTABLE): $(OBJECTS)
#echo Linking $(EXECUTABLE)...
$(CXX) $(LDLIBS) $(OBJECTS) -o $(EXECUTABLE)
%.o: $(subst o,cpp,$(subst obj/,src/,$#))
#echo Building $#...
$(CXX) $(CPPFLAGS) -c $(subst o,cpp,$(subst obj/,src/,$#)) -o $#
Which doesn't work! Make keeps claiming that the object files are up to date, even when the source file is actually older than the object file. On the other hand, if I do this:
obj/main.o: src/main.cpp
#echo Building $#...
$(CXX) $(CPPFLAGS) -c src/main.cpp -o $#
For every source file, it works perfectly. I checked, and the two subst give the same result (obj/main.o becomes src/main.cpp as expected). Yet Make doesn't accept the dependency for some reason.
This is giving me a lot of grief, can somebody explain where I am going wrong? I don't understand what is going on, I thought my substitution would work the same since it gives the same output. Am I not allowed to use subst, or $# in the dependencies or something?
You can't use $# in the prerequisites, only in the commands.
But you can do this:
$(OBJECTS): obj/%.o : src/%.cpp
#echo Building $# from $<...
$(CXX) $(CPPFLAGS) -c $< -o $#

Resources