makefile rule to build multiple targets without intermediate file - gnu-make

I am stumped coming up with a makefile rule to have several executables where each depends on its respective source file. There is a library common to all and each program has a single source file: a.c compiled and linked with the library produces executable a, etc.
LIB_C_FILES = f1.c f2.c f3.c
LIB_H_FILES = f1.h f2.h f3.h
TARGETS = a b c
CFLAGS = -g -O0 -DDEBUG
.PHONY : all clean
.c.o:
g++ -c $(CFLAGS) -o $# $<
all: $(TARGETS)
${TARGETS} : lib.a ${#:%=%.c}
g++ $(CFLAGS) ${#:=.c} -o $# lib.a
lib.a: ${LIB_C_FILES:.c=.o} $(LIB_H_FILES)
ar r $# $?
The library portion works fine. And when an executable does not exist, it also works fine. But when one of the standalone source files is modified it says make: Nothing to be done for 'all'.
I don't understand the proper way to make target a depend on source a.c individually in a list. What am I missing?

Just for completeness: you can do what you want with plain old static pattern rules, so long as you can match all of ${TARGETS} with make's (noddy) pattern matching.
${TARGETS}: %: %.C lib.a
g++ ${CFLAGS} $< -o $# lib.a
lib.a: ...
ar ...
A tad more readable, and perhaps more compatible than .SECONDEXPANSION?

First, I assume fio.a was a typo (you probably meant lib.a).
Second, I think the tricky part is your ${#:%=%.c} prerequisite. AFAIK, $# can't be used this way.
I think you can get the behavior you're looking for using .SECONDEXPANSION though.
Try:
.SECONDEXPANSION:
${TARGETS} : lib.a $$(patsubst %,%.c,$$#)
There may be an old-style substitution way to do this, but I find the patsubst line to be more readable than ${#:%=%.c}.
(I should add that this applies to Gnu make 3.82. YMMV with older versions of Gnu make, or [heaven forbid] non-Gnu versions of make).

Related

make: *** No rule to make target '%.o', needed by 'Program.exe'. Stop

i have my source files inside the src folder and when i run make (windows) i get the following error
make: *** No rule to make target '%.o', needed by 'Program.exe'. Stop.
VPATH := src
Program.exe : %.o
g++.exe -o bin/program.exe $<
%.o : %.cpp
echo $<
g++ -c -ILibraries/include -LLibraries/lib $< -lgdi32
The % in make is not a wildcard that matches files. Just as well, because when make starts there won't be any .o files to match.
The % in make is a pattern match and it only works in pattern rules: pattern rules must have a % in the target (like the second rule you have, %.o : %.c). If you don't have a % in the target, then make just thinks that the % in the prerequisite list is a normal character like an a or b or whatever. Make doesn't know how to create a file named, literally, %.o because there is no matching %.cpp file.
Also it's always wrong in make to create a file that is not equal to $#. Here your target is Program.exe but your recipe creates a file bin/program.exe: those are not the same thing so it's wrong.
Also $< is only the FIRST prerequisite: when you want to link lots of files together you want to use $^ which is all the prerequisites.
You need to list all the object files you want to create:
bin/program.exe: src/foo.o src/bar.o src/baz.o
g++.exe -o $# $^
If you want to automatically generate all the object files then, assuming you want to compile all the source files, you can do something like:
OBJS := $(patsubst %.cpp,%.o,$(wildcard src/*.cpp))
bin/program.exe: $(OBJS)
g++.exe -o $# $^
You don't need to set VPATH in this situation; it doesn't help.

How to define a rule with a recursive recipe in GNU make?

I want to call make files in subfolders from one top make file.
An example of my top make file that works looks like this, where buildPath is a parameter in to the make script:
.PHONY: testSystem
testSystem:
$(MAKE) all -C $(buildPath)/Test1Build
$(MAKE) all -C $(buildPath)/Test2Build
$(MAKE) all -C $(buildPath)/Test3Build
The problem with this solution is that I have to list all subfolders; Test1Build, Test2Build, Test3Build etc.
Is there a way (with make) to define this rule in such a way that the subfolders in the receipt are recursively found without having to list them all?
...or can I solve this problem in a totally different way?
All subfolders begins with Test and ends with Build as a pattern.
It's not hard at all. One simple way:
testSystem:
for d in $(buildPath)/*/.; do \
$(MAKE) all -C $$d; \
done
However, that has many problems. Much more reliable and robust will be this:
subdirs := $(wildcard $(buildPath)/*/.)
testSystem: $(subdirs)
$(subdirs):
$(MAKE) -C $# all
.PHONY: testSystem $(subdirs)
One caveat: if you use parallel make (-j) then you may run into problems with the second solution if the results of the subdirectories depend on each other. If they do then you'll have to declare these dependency relationships in your makefile:
$(buildPath)/foo/. : $(buildPath)/bar/.
etc.

Error in calling one make target from another

$make --- Will have normal build
$make CAdvisor
Above will do following steps:
1) Update variable CC, now it should become "cadvise -pdb mypdb +wlint +wall aCC"
2) Run all with updated CC option
CC = aCC
CFLAGS = -c #-Wall
LDFLAGS =
SOURCES = foo.cc
OBJECTS = $(SOURCES:.cc=.o)
EXECUTABLE = observer
RM=rm -rf
CADVISE_OPTS= -pdb mypdb +wlint
CADVISE= /opt/cadvise/bin/cadvise
.PHONY : CAdvisor update_cc clean all
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cc.o:
$(CC) $(CFLAGS) $< -o $#
clean:
$(RM) $(EXECUTABLE) $(OBJECTS)
update_cc: CC := ${$(CADVISE) $(CADVISE_OPTS) $(CC)}
CAdvisor: update_cc all;
#echo DEBD $(CC)
Now above code is giving me error:
**$ make CAdvisor
Make: Don't know how to make CC. Stop.
$**
How to fix this error
Any better option?
Linkes:link_how to call target from another
Thanks
Sorry, but that's not how target-specific variables work. Target-specific variables are scoped to their target and any prerequisite built as a result of building that target. It's not the case that the target-specific setting changes the value of the global variable for the rest of the recipes expanded by make.
In your example, all is not a prerequisite of update_cc, it's a sibling. So, target-specific variables that are set for update_cc have no impact on the all target.
Second, using ${$(CADVISE) $(CADVISE_OPTS) $(CC)} is definitely not right: the inside will be expanded first then because the entire thing is enclosed in ${...} it will be treated as a variable name, and that variable (which clearly doesn't exist) will be looked up, resulting in an empty string.
I don't know why you have added the extra target update_cc at all; why not just set the target-specific variable on the CAdvisor target?
CAdvisor: CC := $(CADVISE) $(CADVISE_OPTS) $(CC)
CAdvisor: all
#echo DEBD $(CC)

No rule to make target in Maefile

I'm learning to write makefiles. I made my own simple one just to try and test, but every time I run make, i get:
make: *** No rule to make target `/%.cpp', needed by `obj'. Stop.
I googled. I'm pretty sure I typed everything correctly, and my folders are set up the way they should be. Here is the makefile:
CC = g++
LD = g++
NAME = app
OBJ_DIR = obj
SRC_DIR = src
CC_FLAGS = -std=c++0x
all: $(NAME)
$(NAME): $(OBJ_DIR)/%.o
$(LD) $(OBJ_DIR)/%.o -o $#
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CC) $< -o $# $(CC_FLAGS)
clean:
rm $(NAME) $(OBJ_DIR) -rf
What is the problem?
The line:
$(NAME): $(OBJ_DIR)/%.o
is not correct. This is not a pattern rule (because the target doesn't contain a pattern character, %) and so it's interpreted as an explicit rule, saying that app depends on the actual file named obj/%.o which doesn't exist, and make doesn't know how to build it (because there's no file src/%.cpp).
You need to change this to:
$(NAME): $(OBJ_DIR)/foo.o ...
or whatever object files you have.

makefiles implicit and explicit rule

I have a rule
*.o: *.c
gcc <certain compiler switches>
I would like to build a few *.c files with different compiler switches than the standard rule.
I believe I simply add before the first rule
foo.o : foo.c
foobar.o : foobar.c
gcc <other compiler switches>
Does the explicit rule of foo and foobar override the *.o : *.c rule?
There are lots of problems with your makefile. *.o: *.c uses shell wildcards and is almost certainly not what you want. You are probably wanting to write a pattern rules using make wildcards—%.o: %.c. I don't like these much (pattern rules that is). I always like to be very explicit in my makefiles. Something like:
SRCS := foo.c foobar.c
OBJS := ${SRCS:%.c=%.o}
${OBJS}: %.o: %.c
gcc ${OPTS-${#D}} $< -o $#
Now you can define OPTS-foo and OPTS-foobar as you see fit.

Resources