Generic target/rule to build all source files from a list, outputting objects to one directory - makefile

I am trying to make one generic target in my makefile that will builds sources from mixed directories and output the object files to on single directory.
We have a source structure that is mixed in various directories (like said above, below is just an example)
SRCS = ../a/b/source1.c \
b/source2.c \
../c/source3.c
But I would like all of the object files to output to the directory ./objs (same directory level as 'b')
To do this I was trying the following
OBJS = $(addprefix objs/, $(notdir $(SRCS:.c=.o)))
$(OBJS): %.o : $(filter %/$(basename $(notdir %)).c, $(SRCS))
echo "dependencies: $^" # shows up empty
$(CC) $(filter %/$(basename $(notdir $#)).c, $(SRCS)) -o $# # This works and finds the proper source file
$(CC) $^, $(SRCS)) -o $# # I would like to use this, but as I said the dependencies show up blank
There is a weird problem with this however, and I don't understand where the problem is.
In the dependency it doesn't match anything, but in the recipe it does match properly.
Now the weird part (for me atleast). If I try and test out by hard coding one of the paths then it match for ALL files in that path
$(OBJS): %.o : $(filter ../a/b/$(basename $(notdir %)).c, $(SRCS)) # matches for all files in "../a/b" directory
But using SECONDEXPANSION and hardcoding the directory it works
.SECONDEXPANSION:
$(OBJS): %.o : $$(filter ../a/b/$$(basename $$(notdir %)).c, $(SRCS))
And also not using SECONDEXPANSION and hardcoding the source file name works
$(OBJS): %.o : $(filter %source1.c, $(SRCS)) # Hardcoding source1.c works for source1.c
But it seems like I can't combine to two do what I want for some reason. I have tried secondexpansion stuff (thoguht I'm not really sure why I would need it in this case) and could never get anything working that way either.
I am trying to avoid manually declaring targets for each file individually i.e.
objs/source1.o : ../a/b/source1.c
Because our real world example has tons of files and it would be nice to have less to maintain. I feel like I am very close to getting it.
I am using Cygwin with GNU Make 4.0.

After googling a few more times I finally came across the fix here:
http://lists.gnu.org/archive/html/help-make/2010-09/msg00062.html
I still don't know exactly why I needed to use the SECONDEXPANSION ($$-ness) at all but in practice it doesn't work without it. But basically I needed to create a variable for the '%' sign. Doing the following works for me.
SRCS = ../a/b/source1.c \
b/source2.c \
../c/source3.c
OBJS = $(addprefix objs/, $(notdir $(SRCS:.c=.o)))
.SECONDEXPANSION:
PERCENT = %
$(OBJS): %.o : $$(filter $$(PERCENT)/$$(notdir %).c, $(SRCS))
$(CC) $< -o $#
This now builds source1.c, source2.c, and source3.c and outputs the object files into the objs/ directory.
What I didn't mention in my question but I knew all along was that this will only work if you have unique file names for all source files. But we are okay with that limitation (obviously).

Related

Why is makefile exhibiting non-deterministic behaviour?

I have a makefile that is trying to do the following: identify all files under the current directory (all sub-directories included) with .c and .s extensions, for each one compile a non-linked object file and put it into a directory. All C files end up in objects/c, all assembly files end up in objects/ass.
The makefile always works as expected on the first execution (all commands are called in the right order) and no errors are produced.
However if I call make again, half of the time i get "nothing to be done for 'all'.". Which is what you would expect, since no files have been modified. But the other half of the time, make is selecting a random assembly file and compiling that file. That is to say,if I keep doing "make" I sometimes compile file1.s sometimes file2.s. and it keeps randomly swapping between the assembly files add infinitum (it never reaches a "nothing to be done") state.
How is make exhibitting non deterministic behaviour?
This is the smallest makefile I could make that reproduces the error:
SRC_C = $(wildcard *.c) $(wildcard **/*.c)
SRC_ASS = $(wildcard *.s) $(wildcard **/*.s)
OBJECTS_C = $(addprefix $(OBJECT_DIR)c/, $(notdir $(SRC_C:.c=.o)))
OBJECTS_ASS = $(addprefix $(OBJECT_DIR)ass/, $(notdir $(SRC_ASS:.s=.o)))
OBJECTS = $(OBJECTS_C) $(OBJECTS_ASS)
OBJECT_DIR = objects/
all: $(OBJECTS)
%/:
mkdir $#
$(OBJECTS_C): $(OBJECT_DIR) $(OBJECT_DIR)c/
arm-none-eabi-gcc -O0 -march=armv8-a $(wildcard */$(#F:.o=.c)) -nostartfiles -c -o $#
$(OBJECTS_ASS): $(OBJECT_DIR) $(OBJECT_DIR)ass/
arm-none-eabi-as -march=armv8-a $(wildcard */$(#F:.o=.s)) -c -o $#
.PHONY: clean
clean:
rm -rf $(OBJECT_DIR)
You have many errors here.
The biggest is a conceptual one: By flattening all your object files into one directory, there's no way to express proper dependencies using pattern rules, so your object files do not really depend on their respective source files. I'd say: just don't do that! Having object directories is fine, but they should mirror the directory structure of the source tree.
Further errors:
directly depending on directories. This will not work as expected, directories should always be order-only dependencies, as already stated in the comments
Make doesn't support recursive wildcards -- if you really need that, you could write your own function or, assuming you're always building on *nix, just call find instead
Pattern rules for creating directories are not the best idea either -- I'd suggest to collect all needed directories in a variable and loop over that.
Stylistic improvements:
Assign variables that don't need deferred evaluation with :=
Assign variables influencing the build process with ?=, so the user can override them at the command line
Use "standard" variables like CC, AS, CROSS_COMPILE
declare all phony targets in .PHONY.
Your Makefile with these changes applied would look like this:
OBJECT_DIR ?= objects
C_OBJECT_DIR ?= $(OBJECT_DIR)/c
AS_OBJECT_DIR ?= $(OBJECT_DIR)/ass
SRC_C:= $(shell find -name \*.c)
SRC_ASS:= $(shell find -name \*.s)
OBJECTS_C:= $(addprefix $(C_OBJECT_DIR)/, $(SRC_C:.c=.o))
OBJECTS_ASS:= $(addprefix $(AS_OBJECT_DIR)/, $(SRC_ASS:.s=.o))
OBJECTS:= $(OBJECTS_C) $(OBJECTS_ASS)
OUTDIRS:= $(sort $(dir $(OBJECTS)))
CROSS_COMPILE ?= arm-none-eabi-
CC ?= gcc
AS ?= as
CFLAGS ?= -O0 -march=armv8-a -nostartfiles
ASFLAGS ?= -march=armv8-a
all: $(OBJECTS)
$(OUTDIRS):
$(foreach _dir,$#,mkdir -p $(_dir);)
$(C_OBJECT_DIR)/%.o: %.c | $(OUTDIRS)
$(CROSS_COMPILE)$(CC) -c -o $# $(CFLAGS) $<
$(AS_OBJECT_DIR)/%.o: %.s | $(OUTDIRS)
$(CROSS_COMPILE)$(AS) -c -o $# $(ASFLAGS) $<
clean:
rm -rf $(OBJECT_DIR)
.PHONY: all clean
Note there is one important thing missing: automatic dependencies. With this Makefile, each object file depends on its respective source file, but completely misses any headers included. For anything other than a simple toy, you should add that, google for "gnu make gcc automatic dependencies" or something similar (not the scope of this question).

Makefile. Special chars

I have a question to this expression:
%.out: %.cpp Makefile
g++ $< -o $# -std=c++0x
What does it mean? I know, that it is defined target for *.o files but what does it mean %.cpp Makefile and $< and $#?
And:
What is differenece between:
all: $(patsubst %.cpp, %.o, $(wildcard *.cpp))
and:
all:
$(patsubst %.cpp, %.o, $(wildcard *.cpp))
The second doesn't works.
For the first part of your question:
%.out: %.cpp Makefile
g++ $< -o $# -std=c++0x
This is a pattern rule, and means: "for all files with a .cpp extension, compile (if needed) a corresponding .out file using the command g++ $< -o $# -std=c++0x
In this line, $< is the prerequisite (the .cpp file) , $# is the name of the target (the .out file). See here.
The rule also adds the makefile itself as a prerequisite, which means that all the files will be rebuild (even if they are already compiled) when you issue a make target command, if you make changes to the makefile.
For the second part of the question, your are mixing two things. A make rule is made of three parts:
target: dependencies
commands
The second one you show cannot work because there is no command. The line just produces a bunch of filenames, that your shell cannot understand.
The first one adds to the list of dependencies all the object files, whose names are deduced from all the .ccp files. But you are missing a command, so nothing should happen (unless you didn't give us the whole rule ?)
Edit: ouch, missed something, this rule actually should work fine, as make will evaluate all the prerequisite targets, thus call the pattern rule described above. I got confused by the fact that this structure is usually written like this:
targetname: $(OUTFILES)
#echo "- Done target $#"
with the variable defined above as:
OUTFILES = $(patsubst %.cpp, %.o, $(wildcard *.cpp))
or even as:
INFILES = $(wildcard *.cpp)
OUTFILES = $(patsubst %.cpp, %.o, $(INFILES))
I suggest you find a good make tutorial, or read the manual, you seem to have lots of concepts to learn...

Passing target name in dependencies which can be formatted in a makefile

What I would like to do is to get the target name in the dependency and be able to format it.
For example if the target is Objs/foo.o I would like to make the dependency to Sources1/foo.c, I tried doing this
$(filter %.o,$(OBJS)): $(filter %/$(patsubst %.o,%,$(notdir $#)).cpp, $(SRCS))
but none of them works. Where OBJS is a list of object files ex. Objs/foo.o Objs/moo.o etc..
Any help would be greatly appreciated. And SRCS is a list of different directories were sources can be located. Example Sources1/ and Sources2/ where I need to search in both those directories to find where the source is.
Using the vpath directive could take care of your issue. Here's an example:
OBJS:=Objs/foo.o Objs/bar.o
all: $(OBJS)
# This tells make to search for %.c files in Sources1 and Sources2.
vpath %.c Sources1 Sources2
$(filter %.o,$(OBJS)): Objs/%.o : %.c
#echo $# $^
When I run it here with foo.c in Sources1 and bar.c in Sources2, I get the following output:
Objs/foo.o Sources1/foo.c
Objs/bar.o Sources2/bar.c

Makefile Dynamic Rules w/ No GNU-make Pattern

I have a set of .cpp files that I want to compile. These .cpp files are in a hierarchical directory structure. I want the corresponding .o files to all end up in one build folder.
Here's how I get GNU make to enumerate the files:
SRCS = \
$(wildcard $(CODE)/**/*.cpp) \
$(wildcard $(CODE)/AlgebraLibraries/**/*.cpp) \
$(wildcard $(CODE)/Calculator/Environments/**/*.cpp)
BARE_SRCS = $(notdir $(SRCS))
BARE_OBJS = $(BARE_SRCS:.cpp=.o)
OBJS = $(addprefix $(BUILD)/, $(BARE_OBJS))
Having done this, I have no idea how to create the rules that will create the .o files from the .cpp files. Intuitively, what I want to do is the following pseudocode:
for i=0, N do # <-- a for-loop!
$(OBJS)[i]: $(SRCS)[i] # <-- the rule!
$(CPP) -c $(SRCS)[i] -o $(OBJS)[i] # <-- the recipe
end
Of course, this is not valid GNU make code, but I trust you understand what it is here that I'm trying to do. The following will not work.
%.o: %.cpp
$(CPP) -c $< -o $#
This doesn't work, because GNU make is matching up the % signs, assuming that the .o files live along-side the .cpp files.
The alternative to all of this, which I know will work, but will be extremely tedious, is to enumerate all of the rules by-hand as explicit rules. There has to be a better way!
I've been researching GNU make's ability to generate rules, but there appears to be no way to do it without the built-in logic. It would be really nice if I could utilize some flow-control statements to generate the rules that I want to make. Is this asking too much of GNU-make?
In any case, is there a way to do what it is I'm trying to do with GNU make? If so, how?
This looks like a job for... several advanced Make tricks:
all: $(OBJS)
define ruletemp
$(patsubst %.cpp, $(BUILD)/%.o, $(notdir $(1))): $(1)
$$(CPP) -c $$< -o $$#
endef
$(foreach src,$(SRCS),$(eval $(call ruletemp, $(src))))
If $(BUILD) is constant, you can always just do:
$(BUILD)/%.o: %.cpp
$(CPP) -c $< -o $#

A Concise Makefile

I am doing some Makefile refactoring and trying to figure out the most concise way to implement a Makefile that does the following:
Has one variable that has all the source files listed (can be both C and C++ files)
All object files are generated in OBJ_DIR
The object directory is created if it does not exist
Here is what I have so far:
...
OBJ_DIR = obj/
BIN_DIR = bin/
PROGRAM = program
SRCS = test1.cpp test2.c
OBJS = $(addprefix $(OBJ_DIR), \
$(patsubst %.cpp, %.o, \
$(patsubst %.c, %.o, $(SRCS))))
$(BIN_DIR)$(PROGRAM) : $(OBJS)
$(CREATE_OUT_DIR)
$(LINK)
$(OBJ_DIR)%.o : %.c
$(CREATE_OBJ_DIR)
$(CCOMPILE)
$(OBJ_DIR)%.o : %.cpp
$(CREATE_OBJ_DIR)
$(CPPCOMPILE)
...
I'd like to eliminate the call to $(CREATE_OBJ_DIR) for every .o compile. Anyone know how to do this? I tried adding this, but then it would not build the object files:
$(OBJS): | $(OBJ_DIR)
$(OBJ_DIR):
$(CREATE_OBJ_DIR)
You already seem to have solved your first point: Have them all in one variable (I shouldn't think you actually need to to separate them into TEMP1 and TEMP2 like you have, just have different build rules)
For the second point, you can tell the compiler where to output the object files (for g++ its like this:
g++ -c MySourceFile.cpp -o obj/MySourceFile.o
The make rule for this would look like:
obj/%.o: %.cpp
g++ -c $*.cpp -o obj/$*.o
And your third point is also easily solved, as you can have a build rule for it (Just put the directory name in the dependency list for the target, before all of the objects are listed), and the build rule would look like this
obj:
mkdir obj
Edit: or following your code examples:
$(BIN_DIR)$(PROGRAM) : $(BIN_DIR) $(OBJS)
$(LINK)
$(BIN_DIR):
$(CREATE_OUT_DIR)
As for your 3rd point: This question has been asked here before. Unfortunately there is no really good answer for this, and you need to find the least ugly hack from the answer. Personally, I vote for the marker file solution.
This is what I do:
$(OBJ_LOC)/%.o: $(SRC_LOC)/%.c
#[ -d $(OBJ_LOC) ] || mkdir -p $(OBJ_LOC)
g++ ...
But, I am looking at these other answers with great interest.

Resources