Splitting $^ in a Makefile - makefile

I have the following rules in my Makefile:
appfile appfile.symbols:
build-the-app
distribute: appfile appfile.symbols
push -flag1 appfile -flag2 appfile.symbols
I would like to exchange push -flag1 appfile -flag2 appfile.symbols to instead use the dependencies retrieved from $^ like push -flag1 $^1 -flag2 $^2
Is there any way of splitting $^ in order to achieve this?
Thanks.

The first prerequisite is in $<. You can use the word function in GNU make to get others (or for all of them if you prefer):
distribute: appfile appfile.symbols
push -flag1 $< -flag2 $(word 2,$^)

When dependencies have a certain pattern, you can use filter and filter-out; e.g.
distribute: ...
push -flag1 $(filter-out %.symbols,$^) -flag2 $(filter %.symbols,$^)

Related

GNU make: several targets in one pattern rule

With explicit targets I can combine several rules like
foo.o bar.o: $(SOURCES)
cc $< -o $#
This is equivalent of
foo.o: $(SOURCES)
cc $< -o $#
bar.o: $(SOURCES)
cc $< -o $#
But I want to use pattern rules.
I have several troff documents (man, README) and I want to generate .html and .ascii files.
Naive approach is
GROFF := groff
DOCS := man README
DOC_FILES = $(foreach doc,$(DOCS),$(doc).html $(doc).ascii)
CALL_GROFF = $(GROFF) -T$(subst $*.,,$#) -mman $< > $#
%.html %.ascii: %.doc
$(CALL_GROFF)
.DEFAULT: all
all: $(DOC_FILES)
.PHONY: clean
clean:
rm $(DOC_FILES)
But it doesn't work, because make believes that all files are created with one command (much like & in modern make: https://www.gnu.org/software/make/manual/html_node/Multiple-Targets.html)
Obviously I can do
GROFF := groff
DOCS := man README
DOC_FILES = $(foreach doc,$(DOCS),$(doc).html $(doc).ascii)
CALL_GROFF = $(GROFF) -T$(subst $*.,,$#) -mman $< > $#
%.ascii: %.doc
$(CALL_GROFF)
%.html: %.doc
$(CALL_GROFF)
.DEFAULT: all
all: $(DOC_FILES)
.PHONY: clean
clean:
rm $(DOC_FILES)
But it is a kind of copy-paste.
Could it be solved with GNU make?
This is exactly how this works; it's a long-standing feature. From the documentation:
Pattern rules may have more than one target; however, every target must contain a % character. Pattern rules are always treated as grouped targets (see Multiple Targets in a Rule) regardless of whether they use the : or &: separator.
As example states, it was meant to deal with programs that generate more than one output in one invocation, like bison. You can either update your recipe to generate both files in one shot, or keep the rules separated as you do now.

Makefile Dynamic Rules w/ No GNU-make Pattern

I have a set of .cpp files that I want to compile. These .cpp files are in a hierarchical directory structure. I want the corresponding .o files to all end up in one build folder.
Here's how I get GNU make to enumerate the files:
SRCS = \
$(wildcard $(CODE)/**/*.cpp) \
$(wildcard $(CODE)/AlgebraLibraries/**/*.cpp) \
$(wildcard $(CODE)/Calculator/Environments/**/*.cpp)
BARE_SRCS = $(notdir $(SRCS))
BARE_OBJS = $(BARE_SRCS:.cpp=.o)
OBJS = $(addprefix $(BUILD)/, $(BARE_OBJS))
Having done this, I have no idea how to create the rules that will create the .o files from the .cpp files. Intuitively, what I want to do is the following pseudocode:
for i=0, N do # <-- a for-loop!
$(OBJS)[i]: $(SRCS)[i] # <-- the rule!
$(CPP) -c $(SRCS)[i] -o $(OBJS)[i] # <-- the recipe
end
Of course, this is not valid GNU make code, but I trust you understand what it is here that I'm trying to do. The following will not work.
%.o: %.cpp
$(CPP) -c $< -o $#
This doesn't work, because GNU make is matching up the % signs, assuming that the .o files live along-side the .cpp files.
The alternative to all of this, which I know will work, but will be extremely tedious, is to enumerate all of the rules by-hand as explicit rules. There has to be a better way!
I've been researching GNU make's ability to generate rules, but there appears to be no way to do it without the built-in logic. It would be really nice if I could utilize some flow-control statements to generate the rules that I want to make. Is this asking too much of GNU-make?
In any case, is there a way to do what it is I'm trying to do with GNU make? If so, how?
This looks like a job for... several advanced Make tricks:
all: $(OBJS)
define ruletemp
$(patsubst %.cpp, $(BUILD)/%.o, $(notdir $(1))): $(1)
$$(CPP) -c $$< -o $$#
endef
$(foreach src,$(SRCS),$(eval $(call ruletemp, $(src))))
If $(BUILD) is constant, you can always just do:
$(BUILD)/%.o: %.cpp
$(CPP) -c $< -o $#

Makefile trick to get dependencies of a rule

Is there any trick in GNU Makefiles to get all dependencies of a rule?
Example:
rule1: dep1_1 dep1_2 dep1_3
rule2: dep2_1 dep2_2 rule1
dump_deps:
echo "Dependencies of rule1: $(call do_the_trick, $(rule1))"
echo "Dependencies of rule2: $(call do_the_trick, $(rule2))"
install: $(prefix install-,$(call do_the_trick, $(rule1)))
I'd like to be able to call make dump_deps and see:
dep1_1 dep1_2 dep1_3
dep2_1 dep2_2 dep1_1 dep1_2 dep1_3
Or automatically install dependencies with make install and things like.
Is it possible?
EDIT:
I changed the example to show better that I want something automatic, and not having to hardcode dependency lists myself.
You can't show the transitive dependencies, only the direct ones, however, you can take the output generated below and feed it into the programs dot (part of graphviz) to make sense of the these transitive relationships.
Edit: I guess you could also post-process the results in other ways to just list the deps, but I think pretty pictures are better; feel free to downvote if you disagree ;)
Here's a sample makefile (watch for missing tabs when c&p!):
# Makefile that demonstrates how to dump dependencies.
# The macros we use for compiling stuff.
CC_OBJ=$(CC) -o $# -c $(CFLAGS) $<
CC_BIN=$(CC) -o $# $(CFLAGS) $(LDFLAGS) $^
# If we get "DUMP_DEPS=1 DUMP_DOT=1" on the command line, then instead of
# make-style dependencies, we'll output 'dot' syntax.
# Note: normally, DUMP_DOT_TAIL is undefined, so it doesn't generate any noise.
ifeq ($(DUMP_DOT),1)
DUMP_DOT_HEAD=digraph dependencies {
DUMP_DOT_TAIL=#echo "}"
$(info $(DUMP_DOT_HEAD))
list_dep=#for f in $^; do echo " \"$#\" -> \"$$f\";"; done
else
list_dep=#echo "$#: $^"
endif
# If we get "DUMP_DEPS=1" on the command line, then
# instead of building the code, just print the dependencies.
ifeq ($(DUMP_DEPS),1)
CC_OBJ=$(list_dep)
CC_BIN=$(list_dep)
endif
# An implicit rule that builds *.c -> *.o.
%.o:%.c
$(CC_OBJ)
# Variables for stuff we wanna build.
target=hello
objects=main.o
objects+=stuff.o
objects+=yeah.o
# The top-level 'all' target.
.PHONY: all
all: $(target)
$(DUMP_DOT_TAIL)
# Builds our final executable
$(target): $(objects)
$(CC_BIN)
# A standard clean target.
.PHONY: clean
clean:
-rm -f $(target) $(objects)
Now, you can do this:
make -B DUMP_DEPS=1
And it will go through and list all your pre-requisites is make style of "target: pre-requisite". Sample outputs:
Normal run:
cc -o main.o -c main.c
cc -o stuff.o -c stuff.c
cc -o yeah.o -c yeah.c
cc -o hello main.o stuff.o yeah.o
With make -B DUMP_DEPS=1:
main.o: main.c
stuff.o: stuff.c
yeah.o: yeah.c
hello: main.o stuff.o yeah.o
With make -B DUMP_DEPS=1 DUMP_DOT=1:
digraph dependencies {
"main.o" -> "main.c";
"stuff.o" -> "stuff.c";
"yeah.o" -> "yeah.c";
"hello" -> "main.o";
"hello" -> "stuff.o";
"hello" -> "yeah.o";
}
You could then run the following to output a pretty picture to an SVG image:
make -B DUMP_DEPS=1 DUMP_DOT=1 | dot -Tsvg > deps.svg
Here's what it looks like (this is actually a png, generated with -Tpng > deps.png):
I think this would need some extra work to produce accurate results in all situations, but the principle is sound (e.g. if you use gcc-generated dependency files, you'll need to create them first).
This should list all of the dependencies:
DEPEND = dep1 dep2 dep3
.PHONY: $(DEPEND)
dump_deps: $(DEPEND)
#printf "%s\n" $^
You should remove the line with .PHONY target for your needs. It is used for the sake of the example. And please note that there is a tab between the beginning of the line and printf.
use the buit in variables available with the make utility , $^ -- this represents all the dependencies of the rule.
also looking thru your code , i did make the rule1 into a variable / macro form to suit my purpose ......
rule1 := dep1 dep2 dep3

Referring to the target name from the list of the prerequisites

In a Makefile, I would like to refer to the target name from the list of prerequisites and to build something with it. Something of the form:
%.foo: $(addsuffix .bar, $(DATA_%))
#echo $<
So that, supposing you have:
DATA_test = 1 2 3
When you call it as:
make test
That will expand to:
1.bar 2.bar 3.bar
Is this somehow possible? What would be a better approach to the problem?
If your version of Make has secondary expansion, this will probably work (I can't test it because today all I have handy is an old version).
.SECONDEXPANSION:
%.foo: $$(addsuffix .bar, $$(DATA_$$*))
#echo $^
Without that, I don't see any better way to do it than this:
define FOO_RULE
$(1).foo: $(addsuffix .bar,$(DATA_$(1)))
endef
FOO_TYPES = test real whatever
$(foreach t,$(FOO_TYPES),$(eval $(call FOO_RULE,$(t))))
%.foo:
#echo building $# from $^

Automatically copying dependencies from other directories with make

I have a makefile with multiple targets that are generated by copying a file from outside the working directory.
a.tex : $(wildcard /foo/work1/a.tex)
cp -p $< $#
b.tex : $(wildcard /foo/work2/b.tex)
cp -p $< $#
I use $(wildcard) because sometimes I run Make on systems that do not have access to /foo.
What is the best way to avoid repeating the cp -p $< $# commands for every rule? Some options:
Setting up a %.tex : %.tex rule. This works, but it also applies to targets that aren't specifically indicated so I get lots of warnings like make: Circular a.tex <- a.tex dependency dropped.
Defining a sequence of commands with define. This seems pointless since the command is only one line. So instead of copying cp $< $# to every rule, I'd define a cp-dep sequence and copy cp-dep to every rule.
Defining the command as a variable so that I could do a.tex : $(wildcard /foo/work1/a.tex); $(CP-DEP)
Duplicating the target names as an additional rule. a.tex b.tex : ; cp -p $< $#. Error-prone.
Just copying and pasting. Clunky but effective and easy to understand.
I haven't tested it, but can't you just use a pattern rule without prerequisites, and specify the prerequisite for each target on a separate line?
a.tex: $(wildcard /foo/work1/a.tex)
b.tex: $(wildcard /foo/work2/b.tex)
%.tex:
cp -p $< $#
Btw. doesn't the wildcard function return the empty string when it doesn't find a match, so that $< is empty as well? Wouldn't that give a problem with cp?
I think your copyrule is overkill (and inflexible). If your objection to #eriktous's solution is that it will apply the rule to targets for which you haven't explicitly defined dependencies, that's easy to fix with a static pattern rule:
a.tex: $(wildcard /foo/work1/a.tex)
b.tex: $(wildcard /foo/work2/b.tex)
blue.tex: $(wildcard /some/other/path/green.tex)
TEXES = a.tex b.tex
$(TEXES): %.tex:
cp -p $< $#
(If this solves your problem you should accept eriktous's answer-- this is just a variation on it.)
I ended up doing this:
COPYFILES = /foo/work1/a.tex /foo/work2/b.tex
define copyrule
$(notdir $(1)): $$(wildcard $(1))
cp -p $$< $$#
endef
$(foreach file,$(COPYFILES),$(eval $(call copyrule,$(file))))
The advantage of this method is that I can easily add new files with a minimum of boilerplate text and I can easily copy the rule part of this to a new Makefile. The disadvantages are that I can no longer change the destination filename, and the implementation is rather opaque for people with less makefile experience.

Resources