I have a repository structure where dependencies can either be svn:external'd either in this repository or in a super-repository which has svn:external'd this one. The externals are only one level deep and so if my repo is externalized by a super-repository, then I need to be able to detect where to find the dependency at a higher level, and copy over all relevant data. If the dependency is indeed found in my own repository, then I need to build it.
I am having problems creating my makefile recipe to do this. Here is what I have so far:
DEPENDENCIES = dep1 dep2
ROOTDIR = .
deps :
for dep in $(DEPENDENCIES); do \
if [ -e $(ROOTDIR)/ext/$$dep ]; then \
depdir = $(ROOTDIR)/ext/$$dep; \
$(MAKE) -C $depdir; \
elif [ -e $(ROOTDIR)/../$$dep ]; then \
depdir = $(ROOTDIR)/../$$dep; \
else \
$(error Could not find dependency: $$dep) \
fi \
cp $$depdir/bin/* $(ROOTDIR)/bin; \
cp $$depdir/lib/* $(ROOTDIR)/lib; \
cp $$depdir/inc/$$dep $(ROOTDIR)/inc/$$dep; \
done
First problem is the $(error ) line. I'd like to be able to throw an error, but this is clearly not subjected to the bash condition statements. This is the output:
$ make deps
makefile:108: *** Could not find dependency: $dep. Stop.
If I comment out that else statement, then I'm still having troubles
$ make deps
for dep in dep1 dep2; do \
if [ -e ./ext/$dep ]; then \
/bin/sh: -c: line 2: syntax error: unexpected end of file
make: *** [makefile:106: deps] Error 1
Could someone provide some hints regarding how to accomplish this? I'm running GNU make in both cygwin and linux environments.
Edit: I'd really prefer to keep this as close to make as possible (and as little shell stuff). I think I've gotten a little closer, but still need to repeat this for each item in $(DEPENDENCIES).
DEPENDENCIES = foo bar
ROOTDIR = .
EXTDIR = $(ROOTDIR)/ext
BINDIR = $(ROOTDIR)/bin
INCDIR = $(ROOTDIR)/inc
# Need a foreach DEP in $(DEPENDENCIES) here
ifneq("$(wildcard $(EXTDIR)/$(DEP))","")
DEPDIR = $(EXTDIR)/$(DEP)
BUILDDEP = $(MAKE) -C $(DEPDIR)/build
else ifneq("$(wildcard $(ROOTDIR)../$(dep))", "")
DEPDIR = $(ROOTDIR)/../$(dep)
else
$(error Could not find dependency: $(DEP))
endif
$(DEPDIR) :
$(BUILDDEP)
cp $(DEPDIR)/bin/* $(BINDIR)
cp $(DEPDIR)/inc/$(DEP)/* $(INCDIR)/$(DEP)
Edit2:
I think I'm getting closer. The following looks more like what I want, but it still have problems:
1) I don't know how to call each recipe
2) It doesn't give an error if it doesn't find all dependencies
3) It doesn't let me dictate the build order
4) It doesn't let me filter to use only folders listed in dependencies (it does all folders)
ifneq "$(wildcard $(EXTDIR)/%/build)" ""
$(EXTDIR)/%:
$(MAKE) -C $(EXTDIR)/%/build
cp $(EXTDIR)/%/bin/* $(BINDIR)
cp $(EXTDIR)/%/int/*.a $(INTDIR)
cp $(EXTDIR)/%/inc/%/* $(INCDIR)/%
endif
ifneq "$(wildcard $(ROOTDIR)/../%/build)" ""
DEPDIR = $(ROOTDIR)/..
$(DEPDIR)/%:
cp $(DEPDIR)/%/bin/* $(BINDIR)
cp $(DEPDIR)/%/int/*.a $(INTDIR)
cp $(DEPDIR)/%/inc/%/* $(INCDIR)/%
endif
Edit3
After being told I was trying to solve too many problems at once, I've reduced it to this:
DEPENDENCIES = dep1 dep2 dep3
for each DEP in $(DEPENDENCIES)
$(DEP) :
$(MAKE) -C ../ext/$(DEP)
How can I create a recipe ($(DEP) ) for each item in $(DEPENDENCIES)?
Solved. This solves the problem above:
DEPENDENCIES = dep1 dep2 dep3
$(DEPENDENCIES) :
$(MAKE) -C ../ext/$#
The answer is very simple. I wish I knew enough about this stuff to ask a more legible question.
Related
I have the following Makefile and I get an error when I use all target. I am not sure what is the root cause of the problem.
APSTOP= ../..
VERSION=2.12.8
SVERSION=2.12
SCALAC= /afs/package/scala/scala-${VERSION}/common/bin/scalac
APSLIB = ${APSTOP}/lib/aps-library-${SVERSION}.jar
COOLCOMPILERDIR= /afs/project/cool/scala
SCALAFLAGS= -cp .:${APSLIB}
SCALACFLAGS= ${SCALAFLAGS}
APS2SCALA = ${APSTOP}/bin/aps2scala
APS2SCALAFLAGS = -p ..:${APSTOP}/base -G
SCALASRC = cool-symbol.handcode.scala cool-semant-driver.scala cool-handcode.scala cool-noinherit-semant-driver.scala
SCALAGEN = cool-symbol.scala cool-tree.scala \
cool-noinherit-semant.scala cool-dynamic-semant.scala
SCALACOPY= basic.scala A2I.scala \
CoolTokens.scala CoolScanner.scala CoolOptions.scala \
CoolParser.scala
SCALAHAND = CoolCompiler.scala
EXAMPLEDIR = ../examples
.PHONY: all clean src
src : ${SCALASRC}
all : ${SCALAGEN}
all : cool_symbol_implicit.class \
cool_tree_implicit.class \
cool_noinherit_semant_implicit.class \
cool_dynamic_semant_implicit.class
%.scala : ../%.aps
${APS2SCALA} ${APS2SCALAFLAGS} $*
cool-symbol.scala : ../cool-symbol.aps
${APS2SCALA} ${APS2SCALAFLAGS} --omit SYMBOL --omit gensym cool-symbol
%_implicit.class : %.scala
${SCALAC} ${SCALACFLAGS} $*.scala
cool_symbol_implicit.class : cool-symbol.scala cool-symbol.handcode.scala
${SCALAC} ${SCALACFLAGS} cool-symbol.scala cool-symbol.handcode.scala
cool_tree_implicit.class : cool-tree.scala cool_symbol_implicit.class
${SCALAC} ${SCALACFLAGS} cool-tree.scala
cool_noinherit_semant_implicit.class : cool-noinherit-semant.scala
${SCALAC} ${SCALACFLAGS} $<
cool_dynamic_semant_implicit.class : cool-dynamic-semant.scala
${SCALAC} ${SCALACFLAGS} $<
%.scala : RCS/%.scala,v
co $<
.PHONY: %.run
%.run : %.class
scala ${SCALAFLAGS} $*
.PHONY: %.compile
%.compile : %.scala
scalac ${SCALACFLAGS} $*.scala
.PHONY: %.semant
%.semant : ${EXAMPLEDIR}/%.cool Semant.class
scala ${SCALAFLAGS} CoolCompiler $<
.PHONY: %.debug
%.debug : ${EXAMPLEDIR}/%.cool Semant.class
scala ${SCALAFLAGS} CoolCompiler -s $<
COOLCOMPILERSCALA = \
cool-symbol.scala cool-symbol.handcode.scala cool-tree.scala \
cool-handcode.scala ${SCALACOPY} \
cool-dummy-semant-driver.scala ${SCALAHAND}
${SCALACOPY} :
echo "import cool_implicit._" | cat - ${COOLCOMPILERDIR}/$# > $#
CoolParser.scala :
echo "import cool_implicit._" | cat - ${COOLCOMPILERDIR}/$# > $#.tmp
sed 's/result.set_inheritablep(/t_Tree.s_inheritablep(result,/' \
< $#.tmp > $#
cool-parser-${SVERSION}.jar : ${COOLCOMPILERSCALA}
#rm -f *.class
${SCALAC} -deprecation ${SCALACFLAGS} ${COOLCOMPILERSCALA}
jar cvf $# *.class
install: cool-parser-${SVERSION}.jar
cp cool-parser-${SVERSION}.jar ../../lib/.
clean:
rm -f *.class ${SCALAGEN} ${SCALACOPY} *.jar
Error:
Makefile:79: warning: overriding recipe for target 'CoolParser.scala'
Makefile:76: warning: ignoring old recipe for target 'CoolParser.scala'
make: Nothing to be done for 'src'.
That is not an error: if it was an error the build would have failed. This build succeeded. In make error messages contain ***. This is just a warning about a weird thing in your makefile.
To understand it you just have to look at the lines in your makefile that make is complaining about, and read the message it printed.
You have this variable set:
SCALACOPY= basic.scala A2I.scala \
CoolTokens.scala CoolScanner.scala CoolOptions.scala \
CoolParser.scala
So this variable contains CoolParser.scala.
Next at Makefile line 76, you have this:
${SCALACOPY} :
echo "import cool_implicit._" | cat - ${COOLCOMPILERDIR}/$# > $#
This defines rules telling make how to build all the targets in the variable SCALACOPY, including CoolParser.scala.
Then at Makefile line 79, you have this:
CoolParser.scala :
echo "import cool_implicit._" | cat - ${COOLCOMPILERDIR}/$# > $#.tmp
sed 's/result.set_inheritablep(/t_Tree.s_inheritablep(result,/' \
< $#.tmp > $#
This tells make ANOTHER rule also to build CoolParser.scala, which you already provided a rule for; make will drop the first rule and use the second rule, but it will also give you a warning message telling you about it because this is very unusual and not usually what you want to do:
Makefile:79: warning: overriding recipe for target 'CoolParser.scala'
Makefile:76: warning: ignoring old recipe for target 'CoolParser.scala'
If a file exists, I want to add a target to build. If the file does not exist, I want the target to be skipped.
an example:
FILENAME = f
TARGETS := normal
ifneq($(shell stat test_$(FILENAME).c), "")
TARGETS += test
endif
all: $(TARGETS)
normal:
#echo normal
test:
#echo test
I'm not sure the $(shell stat ...) part even works, but the bigger problem is that make with any file test_f.c in the current folder gives:
Makefile:4: *** multiple target patterns. Stop.
Removing the ifneq ... endif block makes the target normal. How can I only run the target test if test_f.c exists?
What you can do is generate a string variable (let's call it OPTIONAL) such that when 'test_f.c' exists, OPTIONAL=test; otherwise, OPTIONAL=_nothing_. And then add OPTIONAL as a prerequisite of all. e.g.:
FILENAME = f
TARGETS = normal
OPTIONAL = $(if $(wildcard test_f.c), test, )
all: $(TARGETS) $(OPTIONAL)
normal:
#echo normal
test:
#echo test
You can also iterate over targets with for loop
.PHONY: all
RECIPES = one
all: RECIPES += $(if $(wildcard test_f.c), two, )
all:
for RECIPE in ${RECIPES} ; do \
$(MAKE) $${RECIPE} ; \
done
one:
$(warning "One")
two:
$(warning "Two")
> make
for RECIPE in one ; do \
/Applications/Xcode.app/Contents/Developer/usr/bin/make ${RECIPE} ; \
done
makefile:11: "One"
make[1]: `one' is up to date.
> touch test_f.c
> make
for RECIPE in one two ; do \
/Applications/Xcode.app/Contents/Developer/usr/bin/make ${RECIPE} ; \
done
makefile:11: "One"
make[1]: `one' is up to date.
makefile:14: "Two"
make[1]: `two' is up to date.
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.
I'm trying to create a Makefile which can build/clean recursively when it's called. I have the build working, but I'm getting errors with the clean command.
My directory structure is something like:
main
|
+-- Makefile
|
+-- common
| |
| +-- gcas_debug
| | |
| | +-- Makefile
| + -- gcas_nvdata
| |
| +-- Makefile
+-- gcinit
+-- Makefile
When I call make in the main directory it goes through and builds everything as I desire, but when I call make clean it does with:
mike#mike-VirtualBox:~/iCOM/framework$ make clean
for d in common/gcas_debug common/gcas_nvdata; \
do \
make --directory=$f clean; \
done
make: the `-C' option requires a non-empty string argument
Usage: make [options] [target] ...
Options:
-b, -m Ignored for compatibility.
...
I don't understand why the clean command isn't working... Any suggestions?
Full (main) Makefile:
lib_gcas_debug := common/gcas_debug
lib_gcas_nvdata := common/gcas_nvdata
libraries := $(lib_gcas_debug) $(lib_gcas_nvdata)
DESTDIR=$(PWD)/output
bindir=
gc_init := gcinit
EXE := $(gc_init)/$(gc_init)
.PHONY: all $(gc_init) $(libraries)
all: $(gc_init)
$(gc_init) $(libraries):
$(MAKE) --directory=$#
$(gc_init): $(libraries)
install: $(gc_init)
install -d -m 0755 $(DESTDIR)$(bindir)
install -m 0755 $(EXE) $(DESTDIR)$(bindir)
clean:
for d in $(libraries); \
do \
$(MAKE) --directory=$$f clean; \
done
EDIT: If I swap the for d with for $d I get instead:
mike#mike-VirtualBox:~/iCOM/framework$ make clean
for in common/gcas_debug common/gcas_nvdata; \
do \
make --directory= clean; \
done
/bin/sh: -c: line 0: syntax error near unexpected token `common/gcas_debug'
/bin/sh: -c: line 0: `for in common/gcas_debug common/gcas_nvdata; \'
make: *** [clean] Error 1
This worked for me:
SUBDIRS := foo bar baz
.PHONY: subdirs $(SUBDIRS) clean all
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $# $(MAKECMDGOALS)
clean: $(SUBDIRS)
rm -rf dist
dist: $(SUBDIRS) dist/.build_marker
dist/.build_marker:
mkdir -p dist
for d in $(SUBDIRS) ; do cp $$d/dist/* dist ; done
touch dist/.build_marker
I only need to use the for loop in the dist target to copy files. This allows make -j build parallelism, not to mention simpler-to-read Makefiles.
Read the for loop again:
for d in [...]; do make --directory=$f
Didn't you mean $d, as in
for d in [...]; do make --directory=$d
So, the Makefile should look:
for d in common/gcas_debug common/gcas_nvdata; \
do \
make --directory=$d clean; \
done
Hey, I have a simple "master" Makefile who simply calls other makefiles. I'm trying to do the following in order to build components in the right order:
LIB_A = folder_a
LIB_B = folder_b
LIB_C = folder_c
MY_TARGETS = $(LIB_A) $(LIB_B) $(LIB_C)
.PHONY: $(LIB_A)
$(LIB_A):
#$(MAKE) -C $#;
.PHONY: $(LIB_B)
$(LIB_B):
#$(MAKE) -C $#;
.PHONY: $(LIB_C)
$(LIB_C): $(LIB_A) $(LIB_B)
#$(MAKE) -C $#;
.PHONY: all
all: $(MY_TARGETS)
However, when I make, only LIB_A gets built.
(I don't even get a folder_b up-to-date message or whatever).
Any hint ?
You need to make all the default. You can do this in either of these ways:
move it to be the first target in the file
Add .DEFAULT_GOAL := all
Alternatively, you could run make all instead of just make.
Neil Butterworth solved the problem, but you can also make this makefile a little more concise:
LIB_A = folder_a
LIB_B = folder_b
LIB_C = folder_c
MY_TARGETS = $(LIB_A) $(LIB_B) $(LIB_C)
.PHONY: all $(MY_TARGETS)
all: $(MY_TARGETS)
$(MY_TARGETS):
#$(MAKE) -C $#;
$(LIB_C): $(LIB_A) $(LIB_B)