Makefile static rule syntax explaination - makefile

This is a snippet of the makefile code example of static rule :
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $#
what does this means like:
target : %.o : %.c
does this means that target : %.o and %.o : %.c explaining that all the dependency of the target would be generated by %.o rule and the recipe is applied on that and all the dependencies of %.o would be generated by %.c rule and recipe is applied?
Please somebody clarify it:
1.What are the static rule in makefile explain the syntax?
2.Does the recipe is applies on both the %.o and %.c rules?
3.Is it concatenation of target : $(all).o and $(all).o : $(all).c where all contains all the file names without any extension?

Your snippet:
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $#
expands to (after expanding variables):
all: foo.o bar.o
foo.o bar.o: %.o: %.c
$(CC) -c $(CFLAGS) $< -o $#
This is a shorthand for writing:
foo.o: foo.c
$(CC) -c $(CFLAGS) $< -o $#
bar.o: bar.c
$(CC) -c $(CFLAGS) $< -o $#
So, in short, for each target in the target list apply the pattern and create a static rule for the result.

Related

How to write a general pattern in makefile

I have multiple programs which share the same structure of compilation.
test_variance : test_variance.o
$(CPP) -o test_variance.exe $(CFLAGS) test_variance.o $(LIBDIR) $(LIBS)
test_variance_incremental: test_variance_incremental.o
$(CPP) -o test_variance_incremental.exe $(CFLAGS) test_variance_incremental.o $(LIBDIR) $(LIBS)
test_hyper: test_hyper.o
$(CPP) -o test_hyper.exe $(CFLAGS) test_hyper.o $(LIBDIR) $(LIBS)
test_hyper.o: test_hyper.cpp
$(CPP) $(CFLAGS) $(INCLUDES) -c test_hyper.cpp
test_variance_incremental.o: test_variance_incremental.cpp
$(CPP) $(CFLAGS) $(INCLUDES) -c test_variance_incremental.cpp
test_variance.o : test_variance.cpp
$(CPP) $(CFLAGS) $(INCLUDES) -c test_variance.cpp
So for compling .o, I can use the pattern
%.o: %.cpp
$(CPP) $(CFLAGS) $(INCLUDES) -c $<
I wonder if there is a general pattern for compling the executive. I've tried
TARGETS = test_variance test_variance_incremental test_hyper
$(TARGETS): $#.o
$(CPP) -o $#.exe $^ $(CFLAGS) $(LIBDIR) $(LIBS)
But Make tells me there is no input files and I think my usage of $# is wrong. Any advice?
You should use CC and CFLAGS for compiling C code, and CXX and CXXFLAGS for compiling C++ code. CPP (in make) is used for running the C preprocessor (only). The standard variable to hold libraries is LDLIBS.
If you use these variables then you don't even need to define your own rules at all: there are built-in rules in make that already know how to compile and link C++ programs. All you need is this:
TARGETS = test_variance test_variance_incremental test_hyper
all: $(TARGETS)
Anyway, if you want to write it explicitly you can write:
TARGETS = test_variance test_variance_incremental test_hyper
all: $(TARGETS)
% : %.o
$(CXX) -o $# $^ $(CXXFLAGS) $(LDFLAGS) $(LDLIBS)
(you should definitely not name the target test_variance, but then have your link line build test_variance.exe: the target name and the file that the recipe builds must always be the same).

Makefile multiple sources ouputs variable expansion

suppose CC variable is a compiling command and we don't need any additional flags. Simple part of makefile compiling main.c and next.c to main.o and next.o:
all: main.o next.o
%.o : %.c
$(CC) $< -o $#
Now suppose I would like to have output files in variable:
all: $(OBJ)
OBJ = main.o next.o
%.o : %.c
$(CC) $< -o $#
Of course it won't work. I understand why but I can't find solution. Can you help me?

How to replace parent directory in Makefile

I've the following situation:
SOURCES=home/main.cpp modelChecking/Configuracao.cpp modelChecking/Estado.cpp modelChecking/Formula.cpp modelChecking/ModelChecking.cpp lib/VisitTree.cpp
SUFIX=$(SOURCES:.cpp=.o)
OBJECTS=$(SUFIX)
all: refiner
refiner: $(OBJECTS)
$(CC) $^ -o refiner
home/main.o: home/main.cpp
$(CC) $(CFLAGS) $< -o $#
modelChecking/Configuracao.o: modelChecking/Configuracao.cpp
$(CC) $(CFLAGS) $< -o $#
modelChecking/Estado.o: modelChecking/Estado.cpp
$(CC) $(CFLAGS) $< -o $#
...
...and so on.
As you can see, I have different directories to compile my executable.
Now, I want to put every file .o in the bin/ folder and the variable OBJECT must replace the every parent directory, and I tried different ways:
OBJECTS=$(SUFIX:%/ = bin/)
OBJECTS=$(subst %/,bin/,$(SUFIX))
OBJECTS=$(patsubst %/,bin/,$(SUFIX))
When I use something like this $(subst home/,bin/,$(SUFIX)) it works, because I type the substring "home/", but I need of a regular expression to replace all directories.
And I'll need to change the target too, perhaps the code below will works:
%.o: %.cpp
$(CC) $(CFLAGS) $< -o $#
... But I prefer every target separate
You are looking for SUFIX=$(addprefix bin/,$(notdir $(SOURCES:.cpp=.o)))
The Makefile will look like:
SOURCES=home/main.cpp modelChecking/Configuracao.cpp
SUFIX=$(addprefix bin/,$(notdir $(SOURCES:.cpp=.o)))
OBJECTS=$(SUFIX)
all: refiner
refiner: $(OBJECTS)
$(CC) $^ -o refiner
bin/main.o: home/main.cpp
$(CC) $(CFLAGS) -c $< -o $#
bin/Configuracao.o: modelChecking/Configuracao.cpp
$(CC) $(CFLAGS) -c $< -o $#
However I suggest to use SUBDIRS instead. Create to Makefiles
Makefile
SUBDIRS = bin
.PHONY: subdirs $(SUBDIRS)
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $#
bin/Makefile
SOURCES=../home/main.cpp ../modelChecking/Configuracao.cpp
SUFIX=$(addprefix bin/,$(notdir $(SOURCES:.cpp=.o)))
OBJECTS=$(SUFIX)
all: refiner
refiner: $(OBJECTS)
$(CC) $^ -o refiner
main.o: ../home/main.cpp
$(CC) $(CFLAGS) -c $< -o $#
Configuracao.o: ../modelChecking/Configuracao.cpp
$(CC) $(CFLAGS) -c $< -o $#
This way you will not have to worry about object prefix.

Makefile generic binaries compilations

I have a set of source files that share the same Makefile rule pattern:
bin1: bin1.o libfoo.a
$(LDENV) $(CC) $(CFLAGS) $(LDFLAGS) -o $# $^
bin2: bin2.o libfoo.a
$(LDENV) $(CC) $(CFLAGS) $(LDFLAGS) -o $# $^
bin3: bin3.o libfoo.a
$(LDENV) $(CC) $(CFLAGS) $(LDFLAGS) -o $# $^
...
Now, how may I refactor this to avoid repeating the same rule over and over? This is easy if a file extension is added to the binaries:
%.out: %.o libfoo.a
$(LDENV) $(CC) $(CFLAGS) $(LDFLAGS) -o $# $^
But is it possible to do the same without using one?
You can use Static Pattern Rules:
bin1 bin2 bin3: %: %.o libfoo.a
$(LDENV) $(CC) $(CFLAGS) $(LDFLAGS) -o $# $^
This way this is cleaner and you are sure that the % only match bin1, bin2 and bin3 targets (I think this is want you want).

Out-of-tree build makefile without automake?

Consider the following dead-simple Makefile:
foo: foo.c
$(CC) $(CFLAGS) -o $# $<
And the following directory structure for ~/foo:
Makefile
foo.c
How can I adjust the Makefile such that I can do something like:
/tmp$ make -f ~/foo/Makefile
cc -o foo /home/me/foo/foo.c
I have tried to use $(srcdir), but that seems automake-specific. Is there any other similar variable?
This will do it:
foo: /home/me/foo/foo.c
$(CC) $(CFLAGS) -o $# $<
Or this:
foo: foo.c
$(CC) $(CFLAGS) -o $# $<
vpath %.c /home/me/foo
Or, if you don't want to hard-code the path into the makefile:
foo: foo.c
$(CC) $(CFLAGS) -o $# $<
vpath %.c $(dir $(lastword $(MAKEFILE_LIST)))

Resources