As a follow-up to my question from a few years ago, I'm currently converting a very similar project from using recursive automake to a single non-recursive Makefile. This works fine for C++ source code and checks. However, when building the documentation (i.e. running PDFLaTeX to convert .tex files to .pdf files) I run into trouble: make works fine, but make distcheck fails with the following error:
make[1]: *** No rule to make target `doc//UserGuide.tex', needed by `doc//UserGuide.aux'. Stop.
The directory structure is as follows:
project/
|-- Makefile.am
|-- configure.ac
|-- src/ # containing all .cpp and .h files
|-- doc/
\-- UserGuide.tex
configure.ac has some code to detect the presence of pdflatex and allow the user to disable compiling the documentation (e.g. in case a certain LaTeX package isn't installed):
# The user can disable building of the PDF of the manual, for example
# if the required LaTeX packages are not installed
AC_ARG_ENABLE([latex-doc],
[AS_HELP_STRING([--disable-latex-doc], [disable building the PDF
documentation from LaTeX source])],
[latexdoc=no],
[latexdoc=yes])
if test "x$latexdoc" = "xyes"; then
AC_MSG_NOTICE([building of the PDF of the user manual from LaTeX source is enabled])
# Check for presence of pdfLaTeX
AC_CHECK_PROGS(PDFLATEX, pdflatex)
if test -z "$PDFLATEX"; then
AC_MSG_NOTICE([pdflatex not found - Unable to create PDF version of the user manual])
fi
fi
AM_CONDITIONAL([HAVE_PDFLATEX], test -n "$PDFLATEX")
AM_CONDITIONAL([BUILD_latexdoc], test "x$latexdoc" = "xyes")
And in Makefile.am I defined the following relevant parts:
## Stuff needed for documentation in the doc/ directory
dist_doc_DATA = doc/howtocompile.txt doc/UserGuide.tex \
COPYING INSTALL ChangeLog AUTHORS
## Build the PDF documentation if building of the LaTeX docs is
## enabled via ./configure.
if BUILD_latexdoc
if HAVE_PDFLATEX
DOCDIR = doc/
MANNAME = $(DOCDIR)/UserGuide
MANPDF = $(MANNAME).pdf
MANTEXSRC = $(MANNAME).tex
MANAUX = $(MANNAME).aux
doc_DATA = $(MANPDF)
PDFLATEXOPTS = --output-directory=$(DOCDIR)
CLEANFILES += $(MANPDF) $(MANNAME).log $(MANNAME).idx $(MANNAME).out \
$(MANNAME).toc $(MANNAME).idx $(MANNAME).ilg $(MANNAME).ind $(MANAUX) .btmp
endif
endif
The problem is most likely with the custom suffix rules I set up (which work fine in the case of recursive make):
# Several make rules to generate the PDF from the LaTeX source
.aux.pdf:
#echo === Making PDF: $# from $^ ===
$(PDFLATEX) $(PDFLATEXOPTS) $(srcdir)/$(MANTEXSRC)
#while ( grep "Rerun to " \
$(MANNAME).log ); do \
echo '** Re-running LaTeX **'; \
$(PDFLATEX) $(PDFLATEXOPTS) $(srcdir)/$(MANTEXSRC); \
done
if [ -f $(MANNAME).idx ]; then \
echo === Making index ===; \
makeindex $(MANNAME); \
fi
#echo === Making final PDF ===
$(PDFLATEX) $(PDFLATEXOPTS) $(srcdir)/$(MANTEXSRC)
.tex.aux:
#echo === Making $# file from $^ ===
$(PDFLATEX) $(PDFLATEXOPTS) $(srcdir)/$(MANTEXSRC)
## Look for citations. Make sure grep never returns an error code.
#grep "^\\\\citation" $(MANAUX) > .btmp.new || true
## If the citations are not changed, don't do anything. Otherwise replace
## the .btmp file to make sure BibTeX will be run.
#if ( diff .btmp.new .btmp > /dev/null ); then \
rm .btmp.new; \
else \
mv .btmp.new .btmp; \
fi
# A target needed to keep track of the nr. of LaTeX runs
.btmp:
I tried changing the .tex.aux rule to a GNU Make pattern rule (%.aux: $(srcdir)/%.tex), which seemed to work (although Automake gave a warning about this being a GNU Make functionality), but when I tried to do the same for the .aux.pdf rule this didn't work, giving the following error message:
make: *** No rule to make target `UserGuide.pdf', needed by `all-am'. Stop.
My guess is that it has something to do with the VPATH build that make distcheck performs as the doc/ directory doesn't show up in the _build directory.
Any suggestions on how to make this work or improve it?
Well, it turns out there were two things I needed to change:
Explicitly mention the extensions .tex, .aux and .pdf in a SUFFIX rule
Tell Automake to create the target directory where the PDF documentation will end up (the $(DOCDIR) variable in my case.
The last section of code from the question now reads:
SUFFIXES = .tex .aux .pdf
# Several make rules to generate the PDF from the LaTeX source
.aux.pdf:
#echo === Making PDF: $# from $^ ===
$(MKDIR_P) $(DOCDIR)
$(PDFLATEX) $(PDFLATEXOPTS) $(srcdir)/$(MANTEXSRC)
#while ( grep "Rerun to " \
$(MANNAME).log ); do \
echo '** Re-running LaTeX **'; \
$(PDFLATEX) $(PDFLATEXOPTS) $(srcdir)/$(MANTEXSRC); \
done
if [ -f $(MANNAME).idx ]; then \
echo === Making index ===; \
makeindex $(MANNAME); \
fi
#echo === Making final PDF ===
$(PDFLATEX) $(PDFLATEXOPTS) $(srcdir)/$(MANTEXSRC)
.tex.aux:
#echo === Making $# file from $^ ===
$(MKDIR_P) $(DOCDIR)
$(PDFLATEX) $(PDFLATEXOPTS) $(srcdir)/$(MANTEXSRC)
## Look for citations. Make sure grep never returns an error code.
#grep "^\\\\citation" $(MANAUX) > .btmp.new || true
## If the citations are not changed, don't do anything. Otherwise replace
## the .btmp file to make sure BibTeX will be run.
#if ( diff .btmp.new .btmp > /dev/null ); then \
rm .btmp.new; \
else \
mv .btmp.new .btmp; \
fi
# A target needed to keep track of the nr. of LaTeX runs
.btmp:
I've added the $(MKDIR_P) lines to both suffix rules, just to be sure. Probably it'll be enough to only have it in the .tex.aux rule.
Related
I want to check whether exists files with a certain extension in a makefile, however this piece of code does not work:
ejecutar: $(OUTPUT) clean
ifeq (,$(wildcard *.dat))
./$(OUTPUT) < $(OUTPUT).dat >$(OUTPUT).txt
else
./$(OUTPUT) < $(OUTPUT).dat >$(OUTPUT).txt
The error is said to be in the ifeq line.
The stuff in the recipe should be shell script, not Makefile syntax. Anything that Make interprets gets expanded as the Makefile is being read, where you typically want your recipe to examine things as they are when that specific recipe is executed. (This is a common beginner FAQ.)
Checking whether a wildcard matches any files in shell script is surprisingly unobvious, too.
ejecutar: $(OUTPUT) clean
set -- *.dat \
; if [ -e "$$1" ]; then \
./$< < $<.dat >$<.txt; \
else \
./$< < $<.dat >$<.txt; \
fi
It's also weird that your then and else cases are identical, but I'm not judging.
I have a GNU makefile written for linux operating system. I want to compile it on windows but there are some syntax changes for windows. I have done some changes but I am getting an error on for loop syntax.
Make file code is already written and I have to modify it for running on windows OS. Original code is attached and the changes i made are also given
Original code:
This is the original code:
#for i in $(subdirs); do \ (cd $$i && $(MAKE) $#) || break; \ done
After changes:
# pass make directives to subdirectories
SHELL = sh
%:
for f in $$(subdirs); \
do \
(cd $$i && $(MAKE) $#) || break; \
done
# eof
I am getting the error on line 16 which is first line of for loop
GNUmakefile(16) : fatal error U1035: syntax error : expected ':' or '=' separator
I made certain changes after reading nmake syntax. Now the problem is resolved.
The %: is not needed and #for does not work. So we need to turn off echo using #echo off: and then for loop will work with simple 'for' keyword instead of #for.
Working code is here:
SHELL = sh
# %:
#echo off :
for i in $(subdirs) ; \
do \
(cd $$i && $(MAKE) $#) || break; \
done
# eof
I wanted to write some Makefile for testing C code via Unity test framework.
However when I want to test it I get the message make: *** No rule to make target 'unity_build/results/test_unity_dumb_example.unity_res', needed by 'unity_test'. Stop. . I can not figure out what is wrong because there is the rule for files that match the pattern: $(UNITY_PATHR)%.unity_res:.
Here is beginning of my Makefile:
UNITY_PATHU = ${UNITY_INSTALL_DIR}/
UNITY_PATHS = src/
UNITY_PATHS += src/unity_dumb_example/
UNITY_PATHT = unity_test/
UNITY_PATHB = unity_build/
UNITY_PATHD = unity_build/depends/
UNITY_PATHO = unity_build/objs/
UNITY_PATHR = unity_build/results/
UNITY_BUILD_PATHS = $(UNITY_PATHB) $(UNITY_PATHD) $(UNITY_PATHO) $(UNITY_PATHR)
# Tell compiler where to look for all test files
UNITY_SRCT = $(wildcard $(UNITY_PATHT)*.c)
UNITY_COMPILER=gcc -c
UNITY_LINKER=gcc
UNITY_DEPEND=gcc -MM -MG -MF
UNITY_CFLAGS=-I. -I$(UNITY_PATHU) -I$(UNITY_PATHS) -DTEST
UNITY_RESULTS = $(patsubst $(UNITY_PATHT)test_%.c,$(UNITY_PATHR)test_%.unity_res,$(UNITY_SRCT))
unity_test: $(UNITY_BUILD_PATHS) $(UNITY_RESULTS)
#echo "-----------------------\nIGNORES:\n-----------------------"
#echo `grep -s IGNORE $(UNITY_PATHR)*.unity_res`
#echo "-----------------------\nFAILURES:\n----------------------"
#echo `grep -s FAIL $(UNITY_PATHR)*.unity_res`
#echo "\nDONE"
$(UNITY_PATHR)%.unity_res: $(UNITY_PATHB)%.out
./$< > $# 2>&1
In GNU make manual I have read
The target is a pattern for matching file names; the ā%ā
matches any nonempty substring, while other characters match only themselves.
I do not understand why make complains because there is no misspell.
EDIT:
After full clean the output is as follows:
mkdir -p unity_build/
mkdir -p unity_build/depends/
mkdir -p unity_build/objs/
mkdir -p unity_build/results/
make: *** No rule to make target 'unity_build/results/test_unity_dumb_example.unity_res', needed by 'unity_test'. Stop.
All the needed paths exist.
When I run make in debug mode -d I can see that make is trying pattern rule with stem test_test_unity_dumb_example instead of test_unity_dumb_example, for example:
Trying pattern rule with stem 'test_test_unity_dumb_example'
test_test_ was my mistake but I have fixed it. I still can't make it work.
When I run with -p I can find something like this in the output:
# Implicit Rules
unity_build/results/%.unity_res: unity_build/%.out
# recipe to execute (from 'Makefile.unity', line 30):
./$< > $# 2>&1
SOLVED
The problem was with the prerequisite of the prerequisite of the $(UNITY_PATHB)%.out. Precisely, path to one crucial source file was ${UNITY_INSTALL_DIR}/src instead of ${UNITY_INSTALL_DIR}/ .
However I still find it weird that make was complaining about the rule to target that is 2 level above the target that could not be built.
I have the following folder structure
1st-grade-math-class/
common/
mystyle.sty
mysubstyle.sty
fonts/
font1.ttf
font2.ttf
font3.ttf
week01/
handout.tex
image1.pdf
image2.pdf
week02/
handout.tex
image1.pdf
image2.pdf
...
week13/
handout.tex
output/
[empty]
And I would like to create a Makefile - in the best way - to do the following:
make sure I include the common directory properly in TEXINPUTS
compile the handout.tex into a PDF (using either pdflatex or xelatex) and have it in the output directory as week01-handout-student.pdf
compile the handout.tex with a line of LaTeX prepended to the beginning of the file (that sets a flag) into a PDF and have it in the output directory as week01-handout-teacher.pdf
clean everything up (the log, aux, etc. files)
I am not sure I know how to this in any other way than manually duplicating an elementary Makefile/bash script in every subdirectory, then calling each of them one by one with a for loop.
I would appreciate help on how to build this process, ideally with a single Makefile in the root directory. Thanks.
UPDATE: I purposefully did not want to give any details about how I compile LaTeX, in case somebody has a better suggestion than my current usage. Right now I am using Latexmk (which is already a make-like wrapper of LaTeX):
latexmk -pdf file.tex generates file.pdf
to add the line of code, I do a simple echo "line of code" > temp.tex and cat handout.tex >> temp.tex, then the same latexmk command
latexmk -c file.tex in a directory cleans all temporary files used to compile file.tex
TEXINPUTS is the TeX path variable, to let TeX find (in its path) the style files: I do TEXINPUTS=full-path-to/common and then export TEXINPUTS before compiling anything.
If anybody has a better suggestion, I am a willing taker.
Something like this should do what you want I believe:
OUTDIR := output
# Tell make to export this environment variable to all recipe lines it runs.
export TEXINPUTS := $(abspath common)
# Get the list of all of our week directories.
weekdirs := $(wildcard week*)
#$(info weekdirs:$(weekdirs))
# Create student output filenames from week directory names.
STUDENT_HANDOUTS := $(patsubst %,$(OUTDIR)/%-handout-student.pdf,$(weekdirs))
#$(info STUDENT_HANDOUTS:$(STUDENT_HANDOUTS))
# Create teacher output filenames from week directory names.
TEACHER_HANDOUTS := $(patsubst %,$(OUTDIR)/%-handout-teacher.pdf,$(weekdirs))
#$(info TEACHER_HANDOUTS:$(TEACHER_HANDOUTS))
# Default target depends on all output files.
all: $(STUDENT_HANDOUTS) $(TEACHER_HANDOUTS)
# Pattern rule for building pdf files.
%.pdf:
#echo + Making $# from $^
#echo cd $(#D) && echo latexmx -pdf $(abspath $<)
#echo cd $(#D) && echo latexmk -c $(abspath $<)
# Static pattern rule mapping student output files to input files.
$(STUDENT_HANDOUTS) : $(OUTDIR)/%-handout-student.pdf : %/handout.tex
# Pattern rule to generate temporary input files from original input files.
%/handout-tmp.tex: %/handout.tex
#echo echo 'line of code' '>' $#
#echo cat $^ '>>' $#
# Static pattern rule mapping teacher output files to (temporary) input files.
$(TEACHER_HANDOUTS) : $(OUTDIR)/%-handout-teacher.pdf : %/handout-tmp.tex
Uncomment the $(info) lines to see a bit of how the variables are put together.
This uses latexmk -c to clean up auxiliary files after creating the output files.
Technique 1. The echo foo >$#; cat $< >>$# thing is something I've done before; I think it's reasonable.
Technique 2. Another technique is to have your .tex document, or a package file it uses, include a line like:
\InputIfFileExists{lecturenotes.config}{}{}
That allows you to make certain adjustments in a makefile, as in for example:
# any bits of configuration that should be in all the .config files
SWITCHES=\makeindex
%-notes.pdf: %.tex
printf '$(SWITCHES)\\ExecuteOptions{sidenotes}\n' >lecturenotes.config
TEXINPUTS=styles: pdflatex $<
mv ${<:.tex=.pdf} $#
rm lecturenotes.config
%-single.pdf: %.tex
printf '$(SWITCHES)\\ExecuteOptions{oneside}\n' >lecturenotes.config
TEXINPUTS=styles: pdflatex $<
mv ${<:.tex=.pdf} $#
rm lecturenotes.config
Technique 3. A third technique for controlling LaTeX from outside is to include in your document (or in a package file):
\newif\ifdemonstrator
\expandafter\ifx\csname demonstrator\endcsname\relax
\demonstratorfalse
\else
\demonstratortrue
\fi
...
\ifdemonstrator
\typeout{Demonstrator is TRUE}
\else
\typeout{Demonstrator is FALSE}
\fi
Then call latex with:
%-plain.pdf: %.tex
latex $<
mv ${<:.tex=.pdf} $#
%-demo.pdf: %.tex
latex --jobname ${<:.tex=} '\def\demonstrator{x}\input{$<}`
mv ${<:.tex=.pdf} $#
Technique 1 is a bit of a blunt instrument, but if that's all that's needed, it's pretty lightweight.
Technique 2 is probably the most neatly engineered, but it is slightly more effort.
Technique 3 is probably the one I use most in this sort of circumstance.
I'm trying to create a makefile (GNU make) that does the following:
A script generates a bunch of files--filenames not known in advance.
Each one of these files is converted to a different file.
After all are converted, all of these files are combined into a single output file.
How do I create a makefile with a "bellcurve"-patterned dependency graph, where the intermediate source and target files are not known in advance?
Conceptually I'm doing the following:
combined.pdf: $(filter combined.pdf, $(wildcard *.pdf))
cat *.pdf > combined.pdf
%.pdf: %.svg
cp $^ $#
$(wildcard *.svg):
# recipe is for simple example
# actually the *.svg files are not known in advance
echo a > a.svg
echo b > b.svg
echo c > c.svg
.PHONY: clean
clean:
${RM} *.svg *.pdf *.d
Of course this doesn't work: Make evaluates the targets and sources before it runs the target that actually creates the svg. Also, there's no way to make sure all svgs are converted before they are combined.
I realized I could create dependencies and include them into the makefile, but I had trouble getting this to work too:
.PHONY: clean
include deps.d
combined.pdf: deps.d
cat *.pdf > combined.pdf
%.pdf: %.svg
cp $^ $#
deps.d:
## recipe is for simple example
## actually the *.svg files are not known in advance
echo a > a.svg
echo b > b.svg
echo c > c.svg
## we know what files exist now, so we can establish dependencies
## "a.pdf : a.svg"
echo *.svg : > deps.d
## combined.pdf: a.pdf b.pdf c.pdf
ls *.svg \
| awk '{targetfn=$$0; sub(/\.svg$$/, ".pdf", targetfn); print targetfn, ":", $$0;}' \
>> deps.d
## combined.pdf: a.pdf b.pdf c.pdf
echo combined.pdf : $$(echo *.svg | sed -e 's/\.svg/\.pdf/g') >> deps.d
clean:
${RM} *.pdf *.svg *.d
However this still isn't connecting the dependency graph properly. When I run this, make quits as follows:
Makefile:3: deps.d: No such file or directory
echo a > a.svg
echo b > b.svg
echo c > c.svg
echo *.svg : > deps.d
ls *.svg \
| awk '{targetfn=$0; sub(/\.svg$/, ".pdf", targetfn); print targetfn, ":", $0;}' \
>> deps.d
echo combined.pdf : $(echo *.svg | sed -e 's/\.svg/\.pdf/g') >> deps.d
make: Nothing to be done for `a.svg'.
I still seem to have the problem that the make doesn't know about the rules in deps.d.
Also, this still doesn't solve the problem of building all the dependencies. I thought of using a marker file like this:
%.pdf: %.svg
cp $^ $#
## if all svgs are converted, touch a target allpdfs
if [ $(ls -1 *.svg | wc -l) -eq $(ls -1 *.pdf | grep -v combined\.pdf | wc -l) ]; touch allpdfs; fi
But there's no way to inform make that "allpdfs" may be created by this rule.
I'm surprised that moving the include directive makes a difference (what version of Make are you using?), but there is a simpler way. Your use of deps.d is in effect a recursive use of Make -- Make is arranging to execute itself a second time -- so we might as well make it official:
combined.pdf: ALL_SVGS
$(MAKE) ALL_PDFS
rm -f $# # just in case it exists already
cat *.pdf > $#
.PHONY: ALL_SVGS
ALL_SVGS:
# recipe is for simple example
# actually the *.svg files are not known in advance
echo a > a.svg
echo b > b.svg
echo c > c.svg
# These variables will be empty in the first execution of Make
SVGS = $(wildcard *.svg)
PDFS = $(patsubst %.svg,%.pdf,$(SVGS))
.PHONY: ALL_PDFS
ALL_PDFS: $(PDFS))
%.pdf: %.svg
cp $^ $#
This isn't an answer exactly, because I don't know why this works, but I discovered that if I move the include directive after the target that creates the included file, everything works.
I.e. do this:
deps.d:
....
include deps.d
Because my deps.d includes enough dependency information, there's no need to have an intermediate target allpdfs file. Everything Just Works, even with make -j.
However, I don't know why this works. The include documentation isn't enlightening me.
UPDATE
I noticed the following note at the very bottom of the make manual discussing Automatic Prerequisites:
Note that the ā.dā files contain target definitions; you should be sure to place the include directive after the first, default goal in your makefiles or run the risk of having a random object file become the default goal. See How Make Works.
So what happened is that the first rule inside the generated deps.d became the default target, causing the mysterious premature completion of the build. So the solution is just to make sure include directives are not before your intended default target.
I was just working on this exact problem in a slightly different setting. Here is a clean solution - no need for recursion and such (and you can tweak the sed if you like):
include deps.d
combined.pdf:
cat *.pdf > combined.pdf
%.pdf: %.svg
cp $^ $#
deps.d:
echo a > a.svg
echo b > b.svg
echo c > c.svg
echo 'combined.pdf:' *.svg | sed 's/\.svg/\.pdf/g' > deps.d
Enjoy!