Makefile: add prefix to nothing - bash

In Bash, brace expansion just works:
$ echo client_win{,_throttle,_freq}.exe
client_win.exe client_win_throttle.exe client_win_freq.exe
In Makefile:
$(addsuffix .exe,client_win $(addprefix client_win, _throttle _freq )):client_win.c def.h
client_win.exe:
$(CC_W) -o $# $< -lws2_32
client_win_throttle.exe:
$(CC_W_REL) -DTHROTTLE -o $# $< -lws2_32
client_win_freq.exe:
$(CC_W_REL) -DFREQ -o $# $< -lws2_32
Is it possible to have client_win itself absorbed into $(addprefix client_win,...)?
Something like this?
$(addprefix client_win, NOTHING _throttle _freq )

This is not easy because make, unlike the shell, has no concept of "existing but zero length string". Make will expand something and look at the resulting string and if it contains no characters it's as if it didn't exist at all.
You could do something like this:
$(patsubst %,client_%.exe, win win_throttle win_freq)
To remove the "empty" option by adding more to it.
Or you can just write the "empty" one out:
client-win.exe $(patsubst %,client_win_%.exe, throttle freq)

Related

How do I write a prerequisite to loop through two lists of files together?

This is an example illustrating the output I would like:
LIST1 := hello.o world.o
LIST2 := hello.c world.c
# Make the first object
# hello.o: hello.c
$(word 1, $(LIST1)): $(word 1, $(LIST2))
cc -c $^ -o $#
# Make the second object
# world.o: world.c
$(word 2, $(LIST1)): $(word 2, $(LIST2))
cc -c $^ -o $#
Is there a way to summarise the target: prerequisite text so that it loops through two entire lists?
I have tried using foreach functions with word functions but I don't get the output. I get non-numeric arguments to word and other invalid expressions.
You actually can do it, but it's really ugly (and would be hard to maintain), I'm showing the answer, but I am definitely not suggesting using it... If you can use pattern rules as #MadScientist suggests, that would be best. If not (say the names differ, you can do something like):
LIST1 := hello.o bob.o
hello.o : hello.c
bob.o : sally.c
$(LIST1):
cc -c $< -o $#
Which allows you to specify custom prereqs for each target. If you really need two lists, the technical answer to your question would be as follows:
LIST1 := hello.o bob.o
LIST2 := hello.c sally.c
all:
define recursive_def
$(firstword $(1)) : $(firstword $(2))
cc -c $$^ -o $$#
$(if $(wordlist 2,3,$1),$(call recursive_def,$(wordlist 2,$(words $(1)),$1),$(wordlist 2,$(words $(2)),$(2))))
endef
$(info -v---v-)
$(info $(call recursive_def,$(LIST1),$(LIST2)))
$(info -^---^-)
$(eval $(call recursive_def,$(LIST1),$(LIST2)))
The short answer is "no". Why don't you just write a pattern rule?
all: $(LIST1)
%.o : %.c
cc -c $^ -o $#
? In fact you don't even need to write a pattern rule at all: make already has a default rule that can build object files from C source files.
ETA
If you have source files in different directories, you have two choices. The best choice is to have one pattern rule and create all your objects in a subdirectory structure that mimics your source directories. So, like this:
SRCS := foo.c bar/bar.c bar/biz/baz.c
OBJS := $(patsubst %.c,obj/%.o,$(SRCS))
all: $(OBJS)
obj/%.o : %.c
#mkdir -p $(#D)
$(COMPILE.c) -o $# $<
If you really don't want to do that and you want to put all the object files into the same directory (a bad idea because if you have two source files with the same name in different source directories, your build will fail) you can use VPATH:
SRCS := foo.c bar/bar.c bar/biz/baz.c
OBJS := $(patsubst %.c,obj/%.o,$(notdir $(SRCS)))
VPATH := $(sort $(dir $(SRCS)))
all: $(OBJS)
obj/%.o : %.c
#mkdir -p $(#D)
$(COMPILE.c) -o $# $<

Makefile - prereq-patterns % in $(wildcard)

I want to add rules of .cc files to a static mode rule. And I try to use $(wildcard ) to enable the prereq-pattern which exists in folder in order to avoid a No rule to make target ... error. But % in $(wildcard ) isn't transformed to the file basename. $(wildcard %.cpp) and $(wildcard %.cc) turn to be nothing.
I want to know how to solve this and make .cc, .cpp in one static mode rule.
# before
# CXX_SOURCE_FILE = $(wildcard *.cpp)
CXX_SOURCE_FILE = $(wildcard *.cpp) $(wildcard *.cc)
C++ = g++
CXX_FLAGS = -g -Wall
c++ : $(basename $(CXX_SOURCE_FILE))
# before
# $(basename $(CXX_SOURCE_FILE)) : % : %.cpp
# $(C++) $< -o $# $(CXX_FLAGS)
$(basename $(CXX_SOURCE_FILE)) : % : $(wildcard %.cpp) $(wildcard %.cc)
$(C++) $< -o $# $(CXX_FLAGS)
You cannot use wildcard like this because it will be evaluated during the parsing, before static pattern rules are considered. Unless you have source files that are literally %.cpp or %.cc your prerequisite list will be empty when the time comes to consider the rules.
A simple solution consists in separating your two sets of source files (CPP_SOURCE_FILE and CC_SOURCE_FILE) and use two different static pattern rules:
CPP_SOURCE_FILE = $(wildcard *.cpp)
CC_SOURCE_FILE = $(wildcard *.cc)
$(basename $(CPP_SOURCE_FILE)): %: %.cpp
$(C++) $< -o $# $(CXX_FLAGS)
$(basename $(CC_SOURCE_FILE)): %: %.cc
$(C++) $< -o $# $(CXX_FLAGS)
There are other solutions but they are more complicated. If you use GNU make you can either use the foreach-eval-call construct or the secondary expansion.
Example with foreach-eval-call:
# $1: executable
define MY_rule
$1: $$(wildcard $1.cpp) $$(wildcard $1.cc)
$$(C++) $$< -o $$# $$(CXX_FLAGS)
endef
$(foreach e,$(basename $(CXX_SOURCE_FILE)),$(eval $(call MY_rule,$e)))
For executable foo this will call MY_rule with parameter foo, pass the result to eval that will expand it and instantiate it as a new rule. $(call MY_rule,foo) expands as:
foo: $$(wildcard foo.cpp) $$(wildcard foo.cc)
$$(C++) $$< -o $$# $$(CXX_FLAGS)
eval expands it as:
foo: $(wildcard foo.cpp) $(wildcard foo.cc)
$(C++) $< -o $# $(CXX_FLAGS)
This is exactly what you wanted for this executable. Note the need of $$ to escape the first expansion by eval.
Example with secondary expansion:
.SECONDEXPANSION:
$(basename $(CXX_SOURCE_FILE)): $$(wildcard $$#.cpp) $$(wildcard $$#.cc)
$(C++) $< -o $# $(CXX_FLAGS)
After the first expansion, during the parsing of the Makefile, this becomes:
foo bar baz: $(wildcard $#.cpp) $(wildcard $#.cc)
$(C++) $< -o $# $(CXX_FLAGS)
Note that if you were trying to use this rule in your Makefile, instead of your static pattern rule, this would not work for the very same reason: when the Makefile is parsed and the prerequisites are expanded the automatic variables are not yet set. So, unless you have files named .cpp or .cc your liste of prerequisites would also be empty.
But every rule after .SECONDEXPANSION: has its prerequisites expanded a second time. And the second time, different from the first, the automatic variables are set, including $#. The final result is equivalent to the 3 following rules:
foo: $(wildcard foo.cpp) $(wildcard foo.cc)
$(C++) $< -o $# $(CXX_FLAGS)
bar: $(wildcard bar.cpp) $(wildcard bar.cc)
$(C++) $< -o $# $(CXX_FLAGS)
baz: $(wildcard baz.cpp) $(wildcard baz.cc)
$(C++) $< -o $# $(CXX_FLAGS)
From the GNU make manual:
the true power of this feature only becomes apparent when you discover that secondary expansions always take place within the scope of the automatic variables for that target. This means that you can use variables such as $#, $*, etc. during the second expansion and they will have their expected values, just as in the recipe. All you have to do is defer the expansion by escaping the $.
Note: here again the $$ are essential to escape the first expansion.

A make rule for verbosity

Typically we have this in a Makefile
%.o:%.c
$(cc) $(flags) -o $# -c $<
When the amount of flags is huge, I feel better to write this instead
%.o:%.c
$(info $(cc): $< --> $#)
#$(cc) $(flags) -o $# -c $<
However it can be useful to sometime see everything. So I defined a variable for that:
at=#
%.o:%.c
$(info $(cc): $< --> $#)
$(at)$(cc) $(flags) -o $# -c $<
My question is how to properly, easily set or unset $(at) from the command line. I see two solutions:
$ make verbose all
$ make verbose=1 all
With the first solution I would do this
ifeq (,$(filter verbose,$(MAKECMDGOALS)))
at=#
dummy:=$(filter-out verbose,$(MAKECMDGOALS)))
endif
With the second I might do this
ifeq (,$(filter 1,$(verbose)))
at=#
endif
Is both solutions acceptable or can I do better?
I generally set up my makefiles like this:
Recipe lines that I know I will never want to see the commands reported begin with # (typically this is just any echo statements or other similar meta-statements).
All other recipe lines do NOT prefix with #.
I add the .SILENT: psuedo-target to make the output silent by default.
I prefix (or suffix) the .SILENT: psuedo-target with a variable reference, like $V.
So, something like this:
%.o: %.c
#echo '$(cc): $< --> $#'
$(cc) $(flags) -o $# -c $<
$V.SILENT:
Now by default V is not set, so the last line expands to the .SILENT special target and no recipe commands are shown. If I run make V=1 (or any other value) then the target expands to 1.SILENT: which is nothing special to make and so is essentially ignored, and all my commands that are NOT prefixed with # are printed.

Makefile target matching

I'm having troubles with my Makefile :-(
I have a mix of assembly and C sourcecode that I need to link together. I need different build-instructions for those two types. Since both the assembler and C compiler output *.o files, I cannot use the general %.o:%.c construction often found in example Makefiles
This what I'm trying now:
Get a list of all C files and their resulting output files:
C_SRCFILES := $(shell find $(SRCDIRS) -type -f -name "*.c")
C_OBJFILES := $(patsub %.c,%.o,$(C_SRCFILES))
Get a list of all asm files and their resulting output files:
A_SRCFILES := $(shell find $(SRCDIRS) -type -f -name "*.asm")
A_OBJFILES := $(patsub %.asm,%.o,$(A_SRCFILES))
When I echo those vars to the screen, they seem to be correct, but how I do define my targets now?
I tried something like this
$(A_OBJFILES): ($A_SRCFILES)
$(AS) $(AFLAGS) -o $# $*
$(C_OBJFILES): ($C_SRCFILES)
$(CC) $(CFLAGS) -c -o $# $*
all: $(A_OBJFILES) $(C_OBJFILES)
$(LD) $(LDFLAGS) $(A_OBJFILES) $(C_OBJFILES) -o $(TARGET_OUTPUT)
but ofcourse, this doesn't work...
Any suggestions?
First problem: a misplaced parenthesis or two.
$(A_OBJFILES): ($A_SRCFILES)
Notice that you have the $ inside the ( in ($A_SRCFILES). Make expands $A, which is nothing, and things go downhill. I think you meant $(A_SRCFILES), and the same thing in the other rule.
Second problem: I don't know the syntax of the assembler, but the syntax of the compiler command is wrong:
$(CC) $(CFLAGS) -c -o $# $*
The variable $* is nothing if we're not in a pattern rule, which we're not (yet). And anyway, if we were in a pattern rule and you were trying to build foo.o, this command would look for the source file foo, and there's no such file. Do it this way:
$(CC) $(CFLAGS) -c -o $# $<
Third problem: each object file depends on all source files (in each rule). Try this instead:
$(A_OBJFILES): %.o : %.asm
...
$(C_OBJFILES): %.o : %.c
...
(Now it's a pattern rule.)
Fourth problem: a lot of redundancy in the last rule. Change it to this:
all: $(A_OBJFILES) $(C_OBJFILES)
$(LD) $(LDFLAGS) $^ -o $(TARGET_OUTPUT)
or better still:
all: $(TARGET_OUTPUT)
$(TARGET_OUTPUT): $(A_OBJFILES) $(C_OBJFILES)
$(LD) $(LDFLAGS) $^ -o $#
Since both the assembler and C compiler output *.o files, I cannot use the general %.o:%.c construction often found in example Makefiles
Sure you can:
%.o : %.c
# commands to make .o from a corresponding .c
%.o : %.asm
# commands to make .o from a corresponding .asm

In gnu make, can the prerequisites in a static pattern rule have different suffixes

Our make file compiles .c source files with a static pattern rule like this:
OBJECTS = foo.o bar.o baz.o
$(OBJECTS): %.o: %.c
$(CC) $< $(C_OPTIONS) -c -o $#
I need to change one of the .c files to an Objective-C .m file. Invoking the compiler is the same for both source types, so I'd like to use the same rule and just tweak it to be more flexible. I'd rather not change the OPTIONS variable because it's also used for the linking step, etc.
Is there a way to make the rule above more flexible to accommodate both .c and .m files?
Thanks
We can add this either-or behavior to the list of things Make should be able to do easily, but isn't. Here's a way to do it, using "eval" to create a seperate rule for each object.
define RULE_template
$(1): $(wildcard $(basename $(1)).[cm])
endef
OBJECTS = foo.o bar.o baz.o
$(foreach obj,$(OBJECTS),$(eval $(call RULE_template,$(obj))))
$(OBJECTS):
$(CC) $&lt $(C_OPTIONS) -c -o $#
Note that this depends on the source files already existing before you run Make (foo.c or foo.m, but not both). If you're generating those sources in the same step, this won't work.
Here's a less clever, more robust method.
CPP_OBJECTS = foo.o bar.o
OBJECTIVE_OBJECTS = baz.o
OBJECTS = $(CPP_OBJECTS) $(OBJECTIVE_OBJECTS)
$(CPP_OBJECTS): %.o: %.c
$(OBJECTIVE_OBJECTS): %.o: %.m
$(OBJECTS):
$(CC) $&lt $(C_OPTIONS) -c -o $#
EDIT: corrected OBJECTS assignment, thanks to Jonathan Leffler.
Not really just copy to
$(OBJECTS): %.o: %.m
$(CC) $< $(C_OPTIONS) -c -o $#
The call to the same compiler is just a happy occasion. Normally you do not compile objective-c code with $(CC). That just feels strange.
But since you go in a harsh way, I won't post do-it-right solution, where you separate objective-C targets from C targets into two different $(OBJECTS)-like variables and make two rules (which you should really do). Too boring. Instead, take a hack!
OBJC_FILES:=$(subst $(wildcard *.m))
real_name = `(test -h $(1) && readlink $(1) ) || echo $(1)`
$(OBJECTS): %.o: %.c
$(GCC) $< $(C_OPTIONS) -c -o $(call real_name,$#)
$(OBJC_FILES): %.c: %.m
ln -s $< $#
And God help those who maintains it!
Btw, this obviously won't work if your m-files are generated.

Resources