Variable dependent target in makefile - makefile

I have a small project for testing and I want to link different implementations of a solution to test.
So, I create makefile that looks like this
CC=g++
FLAGS=-Wall -O2
CFLAGS=-c $(FLAGS)
I_PATH=implementation1.cpp
all: instance
instance: instance.cpp .implementation.o
$(CC) $(FLAGS) instance.cpp .implementation.o -o $#
.implementation.o: $(I_PATH)
$(CC) $(CFLAGS) $(I_PATH) -o $#
clean:
-rm .implementation*
-rm instance
Here, I_PATH is a path to solution implementation. And I want to test different solution passing different implementation via command line arguments: make I_PATH=implementation2.cpp.
But, because of all my implementations compiled to the same object file .implementation.o, make can't understand that something changes and doesn't rebuild project.
Of course, I can call make clean before run make for a specific implementation. But this increase build time (I can run tests for one implementation many times) and not very comfortable.
I can fix this makefile to something like this:
CC=g++
FLAGS=-Wall -O2
CFLAGS=-c $(FLAGS)
I_PATH=implementation1.cpp
C_PATH := $(shell echo -n $(I_PATH) | md5sum | awk '{print ".implementation_" substr($$1, 0, 10) ".o";}')
all: force instance
force_relink:
touch -c $(C_PATH)
instance: instance.cpp $(C_PATH)
$(CC) $(FLAGS) instance.cpp $(C_PATH) -o $#
$(C_PATH): $(I_PATH)
$(CC) $(CFLAGS) $< -o $#
clean:
-rm .implementation*
-rm instance
Here I create I_PATH dependent object file(take hash of path to implementation) and in addition force re-linking instance.cpp with object file every time make runs.
But maybe there is some mechanism in make to fix this behavior? Or I can achieve the same goal with different approaches?

Wouldn't it make more sense to give each compiled .o file a distinct name, and simply link to the compiled .o file you want?
instance: instance.cpp $(IMPL_O)
$(CC) $(FLAGS) $^ -o $# # propably no need to override default rule
Use make IMPL_O=implementation2.o to generate the example in your question.
This way, the name of each file truly reveals its identity, and you don't have to keep track of anything explicitly.
(Obviously, you could refactor the .o extension into the Makefile itself so you can just say IMPL=implementation2 or whatever.)

Related

Makefile Syntax unclear

This is my first Makefile, and I am can't figure out some of the syntax used. The questions are marked below.
$(BUILD_DIR)/%.o: %.c $(BUILD_DIR)
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $#
What is the usage of "$(BUILD_DIR)" in the dependency?
What is the meaning of "$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $#" in the role?
As with most computer languages the syntax of make cannot be clear if you don't know it. If you are using GNU make the GNU make manual is your friend. In the following explanations I will assume that BUILD_DIR = build and that one of the source files is bar/foo.c.
$(BUILD_DIR) in the list of prerequisites (dependencies) tells make that the build directory (in which object files are supposed to go) must exist before the recipe is executed; logical. There must be another rule somewhere to create the directory if it does not exist yet. Something like:
$(BUILD_DIR):
mkdir -p $#
But unless you forgot to copy an important character, this dependency is terribly sub-optimal. As the last modification time of a directory changes each time its content changes (files or sub-directories added or removed), it will force the re-compilation of all source files every time the directory changes, which is not what you want. A better dependency would be order-only:
$(BUILD_DIR)/%.o: %.c | $(BUILD_DIR)
that tells make to consider only the existence of $(BUILD_DIR), not its last modification time, when deciding to re-build or not.
$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $# is just a combination of make automatic variables and functions.
$< and $# expand as the first prerequisite (bar/foo.c) and the target (build/bar/foo.o) respectively.
$(<:.c=.lst) replaces .c by .lst in $<: bar/foo.lst.
$(notdir $(<:.c=.lst)) removes the directory part: foo.lst.
All in all, for a bar/foo.c source file, and with BUILD_DIR = build, the pattern rule would be equivalent to:
build/bar/foo.o: bar/foo.c | build
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=build/foo.lst bar/foo.c -o build/bar/foo.o
Note that there are two different situations to consider:
All your source files are in the same directory as the Makefile (no bar/foo.c, just foo.c). Then you can simplify your recipe:
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(<:.c=.lst) $< -o $#
because the $(notdir...) is useless.
Your source files can be in sub-directories (bar/foo.c). Then you need the $(notdir...) in your recipe. But be warned that if you have two source files with the same base name (bar/foo.c and baz/foo.c) you will have a name conflict for $(BUILD_DIR)/foo.lst and your Makefile will not work as expected. Moreover, the order-only prerequisite of the rule should be equivalent to build/bar (or build/baz), not just build. And there should be a rule to create it if needed. If it is your case I suggest to change your pattern rule for:
$(BUILD_DIR)/%.o: %.c
mkdir -p $(dir $#)
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $#
There are other solutions (secondary expansion...) but there are a bit too complicated for this already too long answer.

Makefile decoupled dependencies

With the following makefile snippet:
main: main.o f1.o f2.o
$(CC) $(CFLAGS) -o program main.o f1.o f2.o
main.o: main.cc
$(CC) $(CFLAGS) -c main.cc
f1.o: f1.cc
$(CC) $(CFLAGS) -c f1.cc
f2.o: f2.cc
$(CC) $(CFLAGS) -c f2.cc
If I just change one file, only that file get recompiled when I rerun make, as desired. However, I'm having a hard time generalizing this without having to list each file individually. When I try something like:
$(OBJECTS): $(SOURCES)
$(CC) $(CFLAGS) -o $# -c $(patsubst %.o,%.cc,$#)
It builds each object file individually, but each object file depends on ALL my sources, so a change in any one file causing a full recompile. What's a good way to accomplish this?
Basically,
you do have to list each .o file's dependencies individually.
For example, each .o is likely to depend on a different bunch of headers.
Taking your f1.o, you need something like:
f1.o: include/i.h
f1.o: another.h dir/and-another.h
f1.o: f1.cc
$(CC) $(CFLAGS) -c f1.cc
(you can have as many dependency lines for a target as you like).
Maintaining that list is a nightmare.
Broken dependency lists render your Makefile worse than useless—you might as well use a batch file.
All is not lost!
If you are tidy,
you can get the compiler to do it automatically,
and pretty much for free.
Makes your Makefile tidier to boot.
Win Win.
As Ismail Badawi commented, pattern rules provide a nice solution. They are a type of implicit rule for make. Basically, implicit rules are automatic recipes based off the file extension. For example, make knows how to convert .c files into .o files implicitly. By default make will run the following recipe for .c files (see the rule catalogue):
$(CC) $(CPPFLAGS) $(CFLAGS) -c
You can modify the process either by setting the variables CC, CPPFLAGS, and CFLAGS, or by defining a pattern rule:
%.o: %.c
$(CC) $(CFLAGS) -c $<
The "$<" above matches the name of the first prerequisite, which will be the .c file in this example. See Beta's comment and automatic variables.

Wildcard in make dependency list

Hey I'm trying to build some files at the same time with different suffixes. Somehow it seems imposible to do this in one line. My makefile looks as follows:
ARCH=ar
ARCHFLAGS=r
F90=gfortran
F90FLAGS=-O2 -Wall
LDFLAGS=-llapack -lblas
SRCF=/Users/pm/bin/src
OBJF=/Users/pm/bin/objs
MODF=/Users/pm/bin/mods
LIBF=/Users/pm/bin/include
SOURCES=a.f b.f90 c.f90
OBJECTS=$(addprefix $(OBJF)/,$(addsuffix .o,$(basename $(SOURCES))))
MODULES=$(addprefix $(MODF)/,*.mod)
TARGET=lib_pm_math_lib.a
$(LIBF)/$(TARGET): $(OBJECTS)
$(ARCH) $(ARCHFLAGS) $# $(OBJECTS) $(MODULES)
obmod.clean :
rm $(OBJECTS) $(MODULES)
clean :
rm $(OBJECTS) $(MODULES) $(LIBF)/$(TARGET)
$(OBJECTS): $(OBJF)/%.o : $(addprefix $(SRCF)/,$(join %.,$(suffix $(SOURCES))))
$(F90) $(F90FLAGS) $(LDFLAGS) -c $< -o$# -J$(MODF)
#$(OBJECTS): $(OBJF)/%.o : $(subst .x, ,$(addprefix $(SRCF)/,$(addsuffix .x$(suffix $(SOURCES)),%)))
# $(F90) $(F90FLAGS) $(LDFLAGS) -c $< -o$# -J$(MODF)
#$(OBJECTS): $(OBJF)/%.o : $(SRCF)/%.f90
# $(F90) $(F90FLAGS) $(LDFLAGS) -c $< -o $# -J$(MODF)
As you can see, I already managed to define my OBJECTS. But I'm not able to creat a construct that does the same for the building part of the object. Of course my first try was to use the join without the extra dot, but this results in only the suffix, for whatever reasons. Substituting the two dots with one dot does this as well. So I'm lost. The lines that I commanded out are another interesting try, and a working version for only .f90 suffixes. Actually I was hoping for something like the following to be working:
$(OBJECTS): $(OBJF)/%.o : $(SRCF)/%.*
$(F90) $(F90FLAGS) $(LDFLAGS) -c $< -o $# -J$(MODF)
I hope it's not too messy. I posted the whole file since I bet you guy's see other problems which I didn't even think of so far. Thanks in advance!
If I'm understanding you correctly, you're wanting a suffix-based wildcard rule that you can run on multiple file suffixes. You can only have one wildcard per recipe, so there's no way to do it directly. You'll need separate rules for each suffix.
The easy solution is to copy-paste one rule and change the suffix. This can become unmanageable when you start to have a lot of suffixes. Another option is to create a rule template and use that to dynamically generate your rules for you:
# Template for build rules
# Pass a file extension for an argument
define build_rule
$(OBJF)/%.o: $(SRCF)/%.$(1)
$(F90) $(F90FLAGS) $(LDFLAGS) -c $$< -o$$# -J$(MODF)
endef
# Generate rules for each selected file extension
FILE_EXTS = f f90
$(foreach ext,$(FILE_EXTS),$(eval $(call build_rule,$(ext))))
This will dynamically generate a rule that differs only by the file extension used on the input file. To support a new file extension, simply add it to the FILE_EXTS list.
Note that when make initially parses the recipe template (inside call), it will expand variables. You have to double-up the $ in the template for anything that you don't want make to expand until the recipe is actually executed (like $# or $<).
You shouldn't need to do anything special to ensure that only the objects in the OBJECTS list are compiled. Since your default make target only lists $(OBJECTS) as a dependency, the files in $(OBJECTS) will be the only ones that get built.
In this case I'd probably just use two rules:
$(OBJF)/%.o: $(SRCF)/%.f
$(F90) $(F90FLAGS) $(LDFLAGS) -c $< -o$# -J$(MODF)
$(OBJF)/%.o: $(SRCF)/%.f90
$(F90) $(F90FLAGS) $(LDFLAGS) -c $< -o$# -J$(MODF)
You could combine them into one, but it's not really worth the effort.

Makefile separate directories

It really takes a long time to read the make and gcc manual. Since I just need some basic function of them, I want to learn them quickly.
The project directory is like the following.
CWD
|----Source----1.cpp
|----Header----1.h
|----Object----1.o
|----Makefile
There are three directories and one Makefile in Current Working Directories, and "1.cpp" includes "1.h". I want to use Makefile which is in the CWD to compile the project such that the object output is in Object directory.
This is simplified version of the problem I have now. Since it is relatively hard to begin from scratch, could anyone help me to write a Makefile for this simple problem? And I will try to learn from it and solve my own problem. Or could anyone suggests which parts of make and gcc I need to learn to solve this problem.
Thanks in advance.
This will be enough to compile the source and produce the object:
Object/1.o: Source/1.cpp Header/1.h
$(CXX) -c Source/1.cpp -IHeader -o Object/1.o
If you want to build an executable, maybe called "one", add another rule above that:
one: Object/1.o
$(CXX) Object/1.o -o one
Object/1.o: Source/1.cpp Header/1.h
$(CXX) -c Source/1.cpp -IHeader -o Object/1.o
To clean things up a little, use automatic variables:
one: Object/1.o
$(CXX) $^ -o $#
Object/1.o: Source/1.cpp Header/1.h
$(CXX) -c $< -IHeader -o $#
And if you want to make the second rule more general, so that it can handle more objects you can turn the second rule into a pattern rule and separate the header dependency of 1.o:
one: Object/1.o
$(CXX) $^ -o $#
Object/1.o: Header/1.h
Object/%.o: Source/%.cpp
$(CXX) -c $< -IHeader -o $#
And of course there is a lot more you can do, when you're ready.

How to add different rules for specific files?

I have a certain problem with my Makefile.
With this command, I can compile all my *.c files to *.o which works well:
$(OBJ) : %.o : %.c $(LDSCRIPT) Makefile
$(CC) $(ARM9_INCLUDES) -c $(CFLAGS) $< -o $#
But now I'm wondering, what if I want to run -O3 optimization on just ONE particular file, and have -O0 on the rest?
Is there any command to add a different rule for a specific file?
What I'm doing right now is compiling each C file with its own rules, which is very annoying because I have around 30 files which makes the Makefile huge, and every time I change something in one file it compiles EVERYTHING again.
particular_file.o : CFLAGS+=-O3
(assuming GNU make) see target-specific variable values in GNU Make manual
(and the immediately following pattern-specific variable values, maybe).
Also note, that commands are used from the most specific rule for given file, so you can have in case target-specific variable value is not sufficient:
particular_file.o : particular_file.c
completely_special_compiler -o $# $<
%.o : %.c
$(CC) $(CFLAGS) -o $# $<
It's possible to make the solution a bit more extensible.
Suppose you need to compile one set of files in one way and the other set of files in another way, rather than having only one exception, and you could identify patterns in those two sets of files, e.g. one set starts with "a", and the other set starts with "b", you can do something like this:
a%.o : a%.c
completely_special_compiler -o $# $<
b%.o : b%.c
$(CC) $(CFLAGS) -o $# $<
For more explanation, see Static Patterns.

Resources