Variable substitution in Makefile target dependency - makefile

I have a Makefile with targets that have associated dependencies. So I use lookup table like:
APPS = a b c
dependency.lookup.a := x
dependency.lookup.b := y
dependency.lookup.c := z
$(APPS): %: path/$(dependency.lookup.%).datafile
do something with $(dependency.lookup.$#)
This makefile gives me error.
*** No rule to make target 'path/.datafile'
Constraints: Only MinGW. can't use shell/MSYS. Also support FreeBSD.

This requires using Secondary Expansion feature:
.SECONDEXPANSION:
$(APPS): %: path/$$(dependency.loopup.$$*).datafile
#echo "$# depends on $^"
%.datafile : # Create one on demand for testing.
mkdir -p ${#D}
touch $#
Outputs:
mkdir -p path/
touch path/x.datafile
a depends on path/x.datafile
Alternatively, use regular dependencies:
a : path/x.datafile
b : path/y.datafile
c : path/z.datafile
$(APPS): % :
#echo "$# depends on $^"
The top 3 lines only add dependencies, the rule is specified separately. The output is the same.

I had the same problem but with rather long names. I didn't want to repeat them (in APPS = ...), so I used a generated auxiliary makefile.
Makefile:
all: build
include deps.mk
deps.mk: deps.txt deps.sh
./deps.sh <$< >$#
build: $(DEPS)
echo "DEPS are up-to-date." # or whatever
deps.sh:
#!/bin/bash
echo "# This file is generated by $0"
echo "DEPS ="
while read -r dst src; do
echo
echo "DEPS += $dst"
echo "$dst: $src"
echo -e '\t''cp $< $#' # or whatever
done
deps.txt (now only this file needs to be updated for new dependencies):
a x
b y
c z

Related

How to only print the variable name itself as part of the recipes?

Example:
var1 = x
dep : $(var1)
echo ($^ -> $#)
This will show x -> dep, but what I really want to show is var1 -> dep.
I basically want to sprinkle this echo all over the rules so I can make sense of a dependency graph. Nothing else worked.
Firstly, to work in my environment your makefile needs two slight modifications: replace the parentheses in echo with quotes, and add a rule for x, to give:
var1 = x
dep: $(var1)
echo "$^ -> $#"
x:
There appears to be no method to recover the unexpanded form of a variable name in a recipe. My suggested solution/work-around is twofold: cache the variable name in another variable, and as per MadScientist's comment use $(warning ...). For example, the makefile:
var1 = x
dep: var1_=var1
dep: $(var1)
#echo "$^ -> $#"
#echo "$(var1_) -> $#"
$(warning "Info: Using $^ to build $#")
$(warning "Info: Using $(var1) to build $#")
$(warning "Info: Using $(var1_) to build $#")
$(warning "Info: Using $($(var1_)) to build $#")
x:
will give:
Makefile:7: "Info: Using x to build dep"
Makefile:8: "Info: Using x to build dep"
Makefile:9: "Info: Using var1 to build dep"
Makefile:10: "Info: Using x to build dep"
x -> dep
var1 -> dep
The var1_ variable needs to be defined on a separate line (see https://stackoverflow.com/a/20714468/318716), which doesn't appear to be well-documented. And the order of the output is interesting.
Edit: A more simple variant of this idea is to replace:
var1 = x
dep: var1_=var1
with just:
var1 = x
var1_ = var1

Make: Setting target-specific variables in static pattern rules

I'm writing a Makefile using static pattern rules and I want for each element of TARGETS a variable assigned to the current target name (here the stem '%').
TARGETS = a b c d
all : $(TARGETS)
$(TARGETS) : % : DIR = %
$(TARGETS) : % : %_setup build
a_setup :
code for a
b_setup :
code for b
...
build
code using "DIR = XX" previously configured
but gnumake complains about the target-specific variable DIR:
make: *** No rule to make target 'DIR', needed by 'a'
Is it possible to mix static pattern rules and variable assignation? Thanks!
According to the GNU make manual you can't do it like that. However, you can use $#. In you example you can directly assign DIR=$# but more generally you can use $# in combination with patsubst:
TARGETS = a b c d
all : $(TARGETS)
$(TARGETS) : DIR = $(patsubst %,%,$#)
$(TARGETS) : % : %_setup build
echo $#: DIR:$(DIR)
%_setup :
echo $#
build:
echo $#

latex makefile not finding png: make: *** No rule to make target `pngfigure.pdf', needed by `main.pdf'. Stop

I'm having trouble getting one of my documents to compile. I've used this makefile before no problems. However, this time, It seems to have a problem recognising .png figures and tries to load them as .pdf.
main.tex
\documentclass[letterpaper, 10 pt, conference]{ieeeconf} % Comment this line out
% if you need a4paper
%\documentclass[a4paper, 10pt, conference]{ieeeconf} % Use this line for a4
% paper
\IEEEoverridecommandlockouts % This command is only
% needed if you want to
% use the \thanks command
\overrideIEEEmargins
% See the \addtolength command later in the file to balance the column lengths
% on the last page of the document
% The following packages can be found on http:\\www.ctan.org
\usepackage{graphics} % for pdf, bitmapped graphics files
\usepackage{epsfig} % for postscript graphics files
\usepackage{mathptmx} % assumes new font selection scheme installed
\usepackage{times} % assumes new font selection scheme installed
\usepackage{amsmath} % assumes amsmath package installed
\usepackage{amssymb} % assumes amsmath package installed
\usepackage{graphicx} % Include figures
\usepackage{float} % Include figures
\graphicspath{{./Figures/}} %Where the figures folder is located
\title{\LARGE \bf
.
.
.
\begin{document}
.
.
.
\begin{figure}[thpb]
\centering
\includegraphics[width=3in]{pngfigure}
\caption{pngfigure}
\label{fig:pngfigure}
\end{figure}
.
.
.
and my Makefile
# Makefile for LaTeX files
LATEX = pdflatex
BIBTEX = bibtex
MAKEINDEX = makeindex
OUTPUT_PDF_FILE_NAME = phd_conversion_report
RERUN = "(There were undefined references|Rerun to get (cross-references|the bars) right)"
RERUNBIB = "No file.*\.bbl|Citation.*undefined"
MAKEIDX = "^[^%]*\\makeindex"
MPRINT = "^[^%]*print"
USETHUMBS = "^[^%]*thumbpdf"
SRC := $(shell egrep -l '^[^%]*\\begin\{document\}' *.tex)
BIBFILE := $(shell perl -ne '($$_)=/^[^%]*\\bibliography\{(.*?)\}/;#_=split /,/;foreach $$b (#_) {print "$$b.bib "}' $(SRC))
PDFPICS := $(shell perl -ne '#foo=/^[^%]*\\(includegraphics)(\[.*?\])?\{(.*?)\}/g;if (defined($$foo[2])) { if ($$foo[2] =~ /.pdf$$/) { print "$$foo[2] "; } else { print "$$foo[2].pdf "; }}' *.tex)
DEP = *.tex
TRG = $(SRC:%.tex=%.pdf)
COPY = if test -r $(<:%.tex=%.toc); then cp $(<:%.tex=%.toc) $(<:%.tex=%.toc.bak); fi
RM = rm -f
OUTDATED = echo "EPS-file is out-of-date!" && false
all: $(TRG) copy clean
define run-latex
$(COPY);$(LATEX) $<
egrep -q $(MAKEIDX) $< && ($(MAKEINDEX) $(<:%.tex=%);$(COPY);$(LATEX) $<) ; true
egrep -c $(RERUNBIB) $(<:%.tex=%.log) && ($(BIBTEX) $(<:%.tex=%);$(COPY);$(LATEX) $<) ; true
egrep -q $(RERUN) $(<:%.tex=%.log) && ($(COPY);$(LATEX) $<) ; true
egrep -q $(RERUN) $(<:%.tex=%.log) && ($(COPY);$(LATEX) $<) ; true
if cmp -s $(<:%.tex=%.toc) $(<:%.tex=%.toc.bak); then true ;else $(LATEX) $< ; fi
$(RM) $(<:%.tex=%.toc.bak)
# Display relevant warnings
egrep -i "(Reference|Citation).*undefined" $(<:%.tex=%.log) ; true
endef
$(TRG): %.pdf: %.tex $(DEP) $(PDFPICS) $(BIBFILE)
#$(run-latex); \
PHONY: copy
copy:
cp $(TRG:%.pdf=%.pdf) $(OUTPUT_PDF_FILE_NAME).pdf
.PHONY: clean
clean:
-rm -f $(TRG) $(PSF) $(TRG:%.pdf=%.aux) $(TRG:%.pdf=%.bbl) $(TRG:%.pdf=%.blg) $(TRG:%.pdf=%.log) $(TRG:%.pdf=%.out); \
$(RM) *.toc *.lot *.lof *.log Sections/*.aux Sections/*.fls Sections/*.log Sections/*.fdb*; \
.PHONY: cleanpdf
cleanpdf:
-rm -f $(TRG) $(PSF) $(PDF) $(TRG:%.pdf=%.aux) $(TRG:%.pdf=%.bbl) $(TRG:%.pdf=%.blg) $(TRG:%.pdf=%.log) $(TRG:%.pdf=%.out); \
$(RM) *.toc *.lot *.lof Sections/*.aux Sections/*.fls Sections/*.log Sections/*.fdb*; \
$(RM) $(OUTPUT_PDF_FILE_NAME).pdf; \
.PHONY: view
view:
acroread $(TRG:%.pdf=%.pdf)
.PHONY: osx
osx:
open $(TRG:%.pdf=%.pdf)
.PHONY: count
count:
texcount main.tex
######################################################################
# Define rules for PDF source files.
.PHONY: pdf
%.pdf: %.eps
epstopdf $< > $(<:%.eps=%.pdf)
Running make, I get the error:
make: *** No rule to make target `pngfigure.pdf', needed by `main.pdf'. Stop.
If I run
$ pdflatex main.tex
It compiles fine and the images show up. The error only happens with make.
Also, as an add on to this question, in the makefile I use texcount to count the words, I couldn't figure out how to get it to load the main.tex file no matter what it was called. I had to resort to the actual filename. I think it should be something like
texcount %.tex
But that doesn't work
This error:
make: *** No rule to make target `pngfigure.pdf', needed by `main.pdf'. Stop.
means that you listed pngfigure.pdf as a prerequisite of main.pdf but that make doesn't know how to build that.
It doesn't know how to build that, presumably, because it isn't actually a pdf file (or a tex file that can be converted to a pdf file).
The incorrect prerequisite here is coming from the PDFPICS macro which is finding all the \includegraphics entries in the tex file and then spitting out $name.pdf for them. Clearly, at least in that case that is incorrect.
Additionally, simply updating the PDFPICS macro to use png instead of pdf is not enough if the images are not in the current directory (as they appear not to be in this case).
For that you'll need to incorporate parsing of \graphicspath from the document as well to include that in the PDFPICS generated prerequisites.

In Kernel makefile $(call cmd, tags) what is the cmd here refers to?

In Kernel Makefile i found the code like below:
ctags CTAGS CSCOPE: $(HEADERS) $(SOURCES)
$(ETAGS) $(ETAGSFALGS) $(HEADERS) $(SOURCES)
$(call cmd, ctags)
Also, where can i find the Macro or function ?
Using MadScientist's method on kernel v4.1:
make -p | grep -B1 -E '^cmd '
we find:
# makefile (from `scripts/Kbuild.include', line 211)
cmd = #$(echo-cmd) $(cmd_$(1))
scripts/Kbuild.include is included on the top level Makefile. It also contains:
echo-cmd = $(if $($(quiet)cmd_$(1)),\
echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
quiet: set at the top level makefile, depending on the value of V.
Will be either:
quiet_ to print CC file.c
empty to print the command on V=
silent_ to not print anything on make -s
escsq is defined as:
squote := '
escsq = $(subst $(squote),'\$(squote)',$1)
It escapes single quotes so that echo '$(call escsq,Letter 'a'.' will print properly in sh.
echo-why: defined further down at Kbuild.include.
It is used for make V=2, and says why a target is being remade.
The setup of make tags is done in the Makefile:
quiet_cmd_tags = GEN $#
cmd_tags = $(CONFIG_SHELL) $(srctree)/scripts/tags.sh $#
tags TAGS cscope gtags: FORCE
$(call cmd,tags)
Which shows the typical usage pattern for calling commands on kbuild:
quiet_cmd_XXX = NAME $#
cmd_XXX = actual-command $#
target: prerequisites
$(call cmd,tags)
A comment on the Makefile explains how all of this is done to make the make output prettier:
# Beautify output
# ---------------------------------------------------------------------------
#
# Normally, we echo the whole command before executing it. By making
# that echo $($(quiet)$(cmd)), we now have the possibility to set
# $(quiet) to choose other forms of output instead, e.g.
#
# quiet_cmd_cc_o_c = Compiling $(RELDIR)/$#
# cmd_cc_o_c = $(CC) $(c_flags) -c -o $# $<
If you run make -p it will print the entire database of all variables, rules, etc. with line numbers where they were last defined.

Makefile: using variable with computed name as prerequisite

In Make it's possible to compute variable names in runtime using double-evaluation, like $($(var)).
I'm interested if it's possible somehow to make this work:
one.js_DEPS=a b
two.js_DEPS=c b
all: one.js two.js
%.js: $(%.js_DEPS)
cat $^ > $#
I can make this work by declaring two rules with explicit dependencies, like this:
one.js: $(one.js_DEPS)
But this seems a bit anti-DRY. So I'm wondering if I miss something because make doesn't seem to understand me. I use GNU Make 3.81.
% and implicit rules are somewhat second-class citizens in make, since variable expansion seems to happen before implicit rule expansion. So, in your above Makefile, $(%.js_DEPS) is expanded to the empty string before % is substituted.
Alternative:
%.js: %.js_DEPS
cat $^ > $#
%.js_DEPS :
cat $^ > $#
.INTERMEDIATE: one.js_DEPS two.js_DEPS
or simply:
one.js : a b
two.js : c d
%.js :
cat $^ > $#
This could be done using Secondary Expansion.
JS := one.js two.js
all: $(JS)
.SECONDEXPANSION:
one.js_DEPS := a b
two.js_DEPS := c b
$(JS) : $$($$(#F)_DEPS)
cat $^ > $#
But in fact, the goal can be achieved much simply, without using any GNU Make extensions, as thiton has suggested in his answer:
all: one.js two.js
one.js : a b
two.js : c b
%.js :
cat $^ > $#

Resources