Right way to use VPATH/vpath? - makefile

I am trying to use my Makefile (Make for Windows) by adding source paths to vpath/VPATH. This seems trivial but for some reason I am unable to get it to work
My directory structure is like this:
├── Makefile
├── out\
└── src\
└── hello.cpp
My Makefile is:
TGT=out
OBJ=hello.o
VPATH=src
# vpath %.cpp src
all: $(TGT)\app.exe
$(TGT)\app : $(TGT)\$(OBJ)
g++ $^ -o $#
$(TGT)\%.o : %.cpp
g++ -Wall -Wextra -Werror -c $<
changing to vpath didn't help me. I seem to have something fundamentally wrong here. The error I see is:
make: *** No rule to make target `out\hello.o', needed by `out\app'. Stop.
EDIT: debug output from make -d
Considering target file `all'.
File `all' does not exist.
No implicit rule found for `all'.
Considering target file `out\app'.
File `out\app' does not exist.
Considering target file `out\hello.o'.
File `out\hello.o' does not exist.
Looking for an implicit rule for `out\hello.o'.
Trying pattern rule with stem `hello'.
Looking for a rule with intermediate file `out\hello.cpp'.
Avoiding implicit rule recursion.
Trying pattern rule with stem `hello.cpp'.
No implicit rule found for `out\hello.o'.
Finished prerequisites of target file `out\hello.o'.
Must remake target `out\hello.o'.

As MadScientist points out you should avoid backslashes as they have odd results like this, had you used forward slashes throughout your Makefile you wouldn't have had this issue, that said it is possible to work around them.
There are a few things wrong here:
You haven't posted the same Makefile you're using again, the first rule after all should have $(TGT)\app.exe as a target.
A backslash before % in a pattern rule will turn it into a literal %, escape the backslash
You forgot to tell gcc where to output the object file
Once you've fixed all of this you should find vpath works as expected, the complete fixed Makefile is
TGT=out
OBJ=hello.o
vpath %.cpp src
all: $(TGT)\app.exe
$(TGT)\app.exe : $(TGT)\$(OBJ)
g++ $^ -o $#
$(TGT)\\%.o : %.cpp
g++ -Wall -Wextra -Werror -c $< -o $#

Related

Makefile: Pattern rule that can ignore directories

I am trying to have a Makefile rule that can generate an object file from a source file in a directory that is specified explicitly.
exe: foo.o bar.o
foo.o: path/to/foo.c
%.o: %.c
echo Making $# from $<
This example will find it needs to make "exe", then search to make "foo.o". The "foo.o" search will try pattern rules with stem "foo" and fail to use the rule because "foo.c" doesn't exist. I want to find a way to have it see that "foo.o" can be compiled from "path/to/foo.c" using the pattern rule.
In my case it doesn't make sense for me to have the rule be "%.o: path/to/%.c" because the path should be specified for each target that needs the source to be located in another directory.
The pattern rule works for "bar.o" being made from "bar.c" within the same directory and I want to keep that working.
The solution I am going with for now is:
define c-to-o-command
echo Making $# from $<
endef
exe: foo.o bar.o
foo.o: path/to/foo.c
$(c-to-o-command)
%.o: %.c
$(c-to-o-command)
This has a drawback that the command for the pattern rule is not visible in the Makefile at the same place. It also will need to be expanded for other pattern rules that may need to have this "out of path" dependency.

How to write Make rules for *.h files as dependencies

I'm trying to understand how to handle header file dependencies in Make rules. Let me give you a specific example.
I'm building application called myap using GNU Make. It consists of various *.h and *.c files.
Directory inc/ contains defs.h and util.h header files.
Directory src/ contains main.c, cmd.c and win.c files.
Directory obj/ contains all generated object files.
I have multiple applications that need different build options. So I don't want to rely on any implicit rules and would like to specify my own rules for all object files, etc.
I would like to specify the following rules:
Object files depend on specific *.h and *.c files. If any of them change, all object files must be regenerated. However, even though *.h files are part of the prerequisites list, I don't want to pass them to the compiler. I only want to compile *.c files.
Executable myapp depends on specific *.o files. If any of them change, executable file must be regenerated.
So far, the following Makefile with a static pattern rule seems to work correctly:
myapp_inc := inc/defs.h inc/util.h
myapp_src := src/main.c src/cmd.c src/win.c
myapp_obj := $(patsubst src/%.c,obj/%.o,$(myapp_src))
myapp_bin := obj/myapp
.PHONY: all
all:
# Create obj/main.o obj/cmd.o and obj/win.o from various *.c files
# If any *.h files in $(myapp_inc) list change, all objects are regenerated.
# If any *.c files in $(myapp_src) list change, all objects are regenerated.
$(myapp_obj): obj/%.o: src/%.c $(myapp_inc) $(myapp_src)
gcc -c -o $# $<
# Create obj/myapp from various *.o files
# If any *.o files in $(myapp_obj) list change, executable is regenerated.
$(myapp_bin): $(myapp_obj)
gcc -o $# $^
all: $(myapp_bin)
.PHONY: clean
clean:
rm -f obj/*
I don't quite understand how Make rules should be written correctly in order to handle such use case. Is the above static pattern rule, the only way that works correctly?
Specifically, I have tried the following combinations, as given in various simple examples on the Internet, and they all failed for various reasons.
This rule causes $< to always pass the name of the first prerequisite, which doesn't work with multiple *.c files:
$(myapp_obj): $(myapp_src) $(myapp_inc)
gcc -c -o $# $<
$ make
gcc -c -o obj/main.o src/main.c
gcc -c -o obj/cmd.o src/main.c
gcc -c -o obj/win.o src/main.c
gcc -o obj/myapp obj/main.o obj/cmd.o obj/win.o
/bin/ld: obj/cmd.o: in function `main':
main.c:(.text+0x0): multiple definition of `main'; obj/main.o:main.c:(.text+0x0): first defined here
/bin/ld: obj/win.o: in function `main':
main.c:(.text+0x0): multiple definition of `main'; obj/main.o:main.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
make: *** [Makefile:18: obj/myapp] Error 1
This rule causes $^ to always pass the names of all prerequisites, which fails:
$(myapp_obj): $(myapp_src) $(myapp_inc)
gcc -c -o $# $^
$ make
gcc -c -o obj/main.o src/main.c src/cmd.c src/win.c inc/defs.h inc/util.h
gcc: fatal error: cannot specify ‘-o’ with ‘-c’, ‘-S’ or ‘-E’ with multiple files
compilation terminated.
make: *** [Makefile:13: obj/main.o] Error 1
Now I understand the difference between $< and $^ variables, but a lot of documentation is not clear on how they should be used when dealing with a list of multiple *.c and *.h files as prerequisites.
What are the recommended usage pattern for this?
Why is it that when using $< only *.c files get passed to the recipe, but not *.h files? Is Make doing some internal filtering? Is this documented anywhere? Is it possible to modify this behavior for custom suffixes?
Is the above static pattern rule, the only way to make objects depend on *.h and *.c files, but exclude *.h files during compilation?
I don't understand the goal of trying to avoid implicit rules. But in any event, it doesn't matter to the recipe you write whether the rule was implicit or explicit: the same automatic variables are set either way. The $< automatic variable is always the first prerequisite, so if you write your rules such that the first prerequisite is the appropriate .c file then you can always use $< in your recipe to mean the .c file and no other files. All the following will work:
%.o : %.c $(headers)
gcc -c -o $# $<
foo.o: foo.c $(headers)
gcc -c -o $# $<
foo.o : %.o : %.c $(headers)
gcc -c -o $# $<
%.o : %.c
gcc -c -o $# $<
$(srcs) : $(headers)
and others.
Does this mean that all of the prerequisites apply, but only those that match the pattern get passed to the recipe?
I don't understand the question, really. The value of variables and the expansion of the recipe happens only AFTER make has decided to run the rule and is not really related (except for some special automatic variables like $?). Once make has decided that the target is out of date and the recipe needs to be run, it will assign the appropriate automatic variables, expand the recipe, then pass the recipe to the shell to be run.
The automatic variables are assigned as described in the manual: $# is the target, $< is the first prerequisite, $^ is all the prerequisites, etc.
ETA
You still haven't really explained why you don't want to use static pattern rules. They are a perfectly fine and reasonable way to do things.
If you explain what you don't like about static pattern rules, or what you wish you could do differently, then we can probably suggest alternatives that meet those requirements.
Specifically, I have tried the following combinations, as given in various simple examples on the Internet,
$(myapp_obj): $(myapp_src) $(myapp_inc)
Wherever you found this as a recommended example on the Internet, you should immediately delete from any bookmarks as that site doesn't know anything about make.
We see this paradigm at least once a week on SO. I've never really understand why people think it will work: I guess they think make is much more "magical" than it is. Consider, what does the above expand to? Suppose myapp_obj contained foo.o bar.o biz.o and myapp_src contained foo.c bar.c biz.c and myapp_inc contained foo.h bar.h, then make sees:
foo.o bar.o biz.o: foo.c bar.c biz.c foo.h bar.h
I suppose some people think make will intuit that the ".o" files should somehow match up with the ".c" files and will generate a bunch of rules that make that true. That's not what make does. The above line is exactly identical to writing this:
foo.o: foo.c bar.c biz.c foo.h bar.h
bar.o: foo.c bar.c biz.c foo.h bar.h
biz.o: foo.c bar.c biz.c foo.h bar.h
That is, if you have multiple targets make creates one copy of the rule for each target, with the same prerequisites and recipe.
This is obviously not what you want, and that's why none of the examples that try to do things this way can ever work properly.
Why is it that when using $< only *.c files get passed to the recipe, but not *.h files? Is Make doing some internal filtering? Is this documented anywhere? Is it possible to modify this behavior for custom suffixes?
None of that is the case. As I described above, the $< expands to the first prerequisite. That's all. It doesn't matter whether the first prerequisite is a .c file, a .h file, or some other file; whatever it is, $< will be that value. If you write your rule as:
foo.o : foo.c foo.h ; $(CC) -c -o $# $<
then your compiler will be invoked with foo.c. If you write your rule as:
foo.o : foo.h foo.c ; $(CC) -c -o $# $<
then your compiler will be invoked with foo.h. There's no magic here.

How to make makefile to use pattern rule?

Having this simple makefile:
VPATH = include
CC := gcc
CFLAGS := -I include -Wall -pedantic
%: %.o include.o
$(CC) -o $# $^
%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
When I trigger it with the name of a program (the same name as is source with .c extension), I would expect to trigger the first rule (since I provided just a name without extension) and the the second one, because for the first rule, there is %.o prerequisite, which is exactly the second rule.
Having these file in pwd:
client.c include makefile server6.c server.c
Now If I make make server:
It does
gcc -I include -Wall -pedantic server.c -o server
In other words, The second rule is not triggered. there is no step with makeing object files, even though the object file is in the first rule as prerequisite. So how is that possible? The make is simply ignoring the prerequisite and trying to make just with the first rule. How to fix that?
That's because make has a built-in rule for %: %.c and make will always choose a pattern rule that can directly create the target over a pattern rule that requires another pattern rule:
Note however, that a rule whose prerequisites actually exist or are mentioned always takes priority over a rule with prerequisites that must be made by chaining other implicit rules.
You can run make -r to remove all the built-in rules, or else remove it yourself by adding:
% : %.c
to your makefile.
You can see all built-in rules by running make -p -f/dev/null

What is the semantics of '%' in Makefile?

Googling doesn't help much in understand how the % variable is being used in the Makefile snippet below.
_OBJ = a.o b.o c.o
OBJ = $(patsubst %,$(OBJDIR)/%,$(_OBJ))
$(OBJDIR)/%.o: $(SRCDIR)/%.c $(INC)
$(CC) -c -o $# $< $(CFLAGS)
Can anybody please help me out? Does it mean that if there are five .c files present under $(SRCDIR), that many *.o rules are being populated behind the scene?
That is an "implicit rule". The % makes the word $(OBJDIR)/%.o a pattern. It tells make that if it's trying to build a target and the name of the target matches that pattern (where the % can substitute for one or more characters--any characters), AND that a file that matches the pattern $(SRCDIR)/%.c (where the % here has the same value as in the target) either already exists or can be built, then make can use this recipe to build that target.
So, if make wants to build a file foo/bar.o and the variable OBJDIR has the value foo, then this pattern foo/%.o will match that file with the % matching bar (this is called the stem in the GNU make documentation).
Then if SRCDIR has the value blah and make can find (or create) a file named blah/bar.c, then this implicit rule can be used to build the target foo/bar.o by running this recipe ($(CC) -c -o $# $< $(CFLAGS)).

What are double-colon rules in a Makefile for?

Section 4.13 of the GNU Make manual describes the so-called double-colon rules:
Double-colon rules are rules written with ‘::’ instead of ‘:’ after the target names. They are handled differently from ordinary rules when the same target appears in more than one rule.
When a target appears in multiple rules, all the rules must be the same type: all ordinary, or all double-colon. If they are double-colon, each of them is independent of the others. Each double-colon rule's commands are executed if the target is older than any prerequisites of that rule. If there are no prerequisites for that rule, its commands are always executed (even if the target already exists). This can result in executing none, any, or all of the double-colon rules.
Double-colon rules with the same target are in fact completely separate from one another. Each double-colon rule is processed individually, just as rules with different targets are processed.
The double-colon rules for a target are executed in the order they appear in the makefile. However, the cases where double-colon rules really make sense are those where the order of executing the commands would not matter.
Double-colon rules are somewhat obscure and not often very useful; they provide a mechanism for cases in which the method used to update a target differs depending on which prerequisite files caused the update, and such cases are rare.
Each double-colon rule should specify commands; if it does not, an implicit rule will be used if one applies. See section Using Implicit Rules.
I kinda grok the meaning of each sentence of this section individually, but it's still not clear to me what double-colon rules are for. As for being rare, I have not yet seen any open-source project whose Makefile did not begin with
all::
Therefore: What's the intended purpose of double-colon rules in Makefiles?
Each :: rule is processed independently, so it can be simpler. For example, the single rule:
libxxx.a : sub1.o sub2.o
ar rv libxxx.a sub1.o
ar rv libxxx.a sub2.o
can be replaced with two simpler rules:
libxxx.a :: sub1.o
ar rv libxxx.a sub1.o
libxxx.a :: sub2.o
ar rv libxxx.a sub2.o
Utilities like AutoMake have an easier time spitting out many simple rules than a few complex ones.
A great answer with more examples was posted, then taken down, then found here:
https://web.archive.org/web/20180122002430/http://owen.sj.ca.us/~rk/howto/slides/make/slides/makecolon.html
Thanks to R.K. Owen for writing it, and Edward Minnix for finding it again!
There are 3 situations where the double colon are useful:
Alternate between the compile rules based on which prerequisite is newer than the target. The following example is based on "Example 19-3. Double-colon rules" from http://books.gigatux.nl/mirror/cinanutshell/0596006977/cinanut-CHP-19-SECT-3.html
Sample .c file:
c#desk:~/test/circle$ cat circle.c
#include <stdio.h>
int main (void)
{
printf("Example.\n");
return 0;
}
Makefile used:
c#desk:~/test/circle$ cat Makefile
# A makefile for "circle" to demonstrate double-colon rules.
CC = gcc
RM = rm -f
CFLAGS = -Wall -std=c99
DBGFLAGS = -ggdb -pg
DEBUGFILE = ./debug
SRC = circle.c
circle :: $(SRC)
$(CC) $(CFLAGS) -o $# -lm $^
circle :: $(DEBUGFILE)
$(CC) $(CFLAGS) $(DBGFLAGS) -o $# -lm $(SRC)
.PHONY : clean
clean :
$(RM) circle
Outcome:
c#desk:~/test/circle$ make circle
gcc -Wall -std=c99 -o circle -lm circle.c
make: *** No rule to make target 'debug', needed by 'circle'. Stop.
c#desk:~/test/circle$ make circle
gcc -Wall -std=c99 -o circle -lm circle.c
gcc -Wall -std=c99 -ggdb -pg -o circle -lm circle.c
c#desk:~/test/circle$ vim circle.c
c#desk:~/test/circle$ make circle
gcc -Wall -std=c99 -o circle -lm circle.c
c#desk:~/test/circle$ vim debug
c#desk:~/test/circle$ make circle
gcc -Wall -std=c99 -ggdb -pg -o circle -lm circle.c
Make a pattern rule terminal.
The following example explains this situation: the a.config file is obtained from a.cfg, which in turn is obtained from a.cfg1 (a.cfg being the intermediate file).
c#desk:~/test/circle1$ ls
a.cfg1 log.txt Makefile
c#desk:~/test/circle1$ cat Makefile
CP=/bin/cp
%.config:: %.cfg
#echo "$# from $<"
#$(CP) $< $#
%.cfg: %.cfg1
#echo "$# from $<"
#$(CP) $< $#
clean:
-$(RM) *.config
Outcome (as the %.config rule is terminal, make inhibits the creation of the intermediate a.cfg file from a.cfg1):
c#desk:~/test/circle1$ make a.conf
make: *** No rule to make target 'a.conf'. Stop.
Without the double colon for the %.config, the outcome is:
c#desk:~/test/circle1$ make a.config
a.cfg from a.cfg1
a.config from a.cfg
rm a.cfg
Make a rule that executes always (useful for clean rules). The rule must not have prerequisites!
c#desk:~/test/circle3$ cat Makefile
CP=/bin/cp
a.config::
#echo "Always" >> $#
a.config::
#echo "Always!" >> $#
clean:
-$(RM) *.config
Outcome:
c#desk:~/test/circle3$ make a.config
c#desk:~/test/circle3$ cat a.config
Always
Always!
c#desk:~/test/circle3$ make a.config
c#desk:~/test/circle3$ cat a.config
Always
Always!
Always
Always!
They are handy for non-recursive makefiles and targets like clean. That is, an individual .mk file can add its own commands to the clean target already defined elsewhere.
Documentation gives an answer:
Double-colon rules are somewhat obscure and not often very useful; they provide a mechanism for cases in which the method used to update a target differs depending on which prerequisite files caused the update, and such cases are rare.
Just as the documentation says, double-colon rules are rarely very useful. They are a nice, little way of not naming the individual targets of a composite phony target (like all::), but not really necessary in this role. I can only form one contrived example where they are necessary:
Suppose you have a logfile L that is concatenated from several other logfiles L1, L2, .... You formulate a number of double-colon rules like:
L :: L1
cat $< >> $# && rm $<
L :: L2
cat $< >> $# && rm $<
Nowadays in GNU make, you would of course use $^ for this kind of magic, but it is listed as an inspired feature on GNU make's feature tab.
I'll contribute a simple example to hopefully make the usage clear:
Experiment with the following makefile:
a.faux:: dep1.fake
$(info run a dep1.fake)
touch a.faux
a.faux:: dep2.fake
$(info run a dep2.fake)
touch a.faux
dep1.fake:
touch dep1.fake
dep2.fake:
touch dep2.fake
Run make a.faux, it will causes dep1.fake and dep2.fake to run. Delete dep1.fake and run make a.faux again, only dep1.fake will run.

Resources