This question is similar in spirit to question 2543127.
I have a gnu makefile with a list of header files. Each header file may be located in a different directory, e.g.,
HEADERS = $(wildcard *.h) $(wildcard foo/*.h) $(wildcard bar/*.h)
and I want to have the makefile copy all headers to an include directory
INCDIR = ../include
and when a dummy target, e.g., ALL is invoked, it will update the header files in the include directory appropriately, i.e.,
.PHONY: ALL
ALL : $(addprefix $(INCDIR)/,$(notdir $(HEADERS)))
Obviously, I could accomplish what I want quite easily if I knew what the lists of directories were. If I did, then I could write some rules (something) like so (not entirely correct, but you get the jist):
$(addprefix $(INCDIR)/,$(notdir $(filter foo/%.h,$(HEADERS)))) : %.h : foo/%.h
#cp -f $< $#
$(addprefix $(INCDIR)/,$(notdir $(filter bar/%.h,$(HEADERS)))) : %.h : bar/%.h
#cp -f $< $#
$(addprefix $(INCDIR)/,$(notdir $(filter-out bar/%.h,$(filter-out foo/%.h,$(HEADERS))))) : %.h : %.h
#cp -f $< $#
There are two problems with this approach, (1) It becomes tedious as the number of directories increases and (2) I am writing this in a makefile include, which doesn't know directories, all it knows are the variables INCDIR and HEADERS; it does not directly know the directories foo/, bar/, and ./ other than through $(sort $(dir $(HEADERS)))
Question: How can I write a rule to achieve the desired effect under the constraints of only being provided the INCDIR and HEADERS variables.
This should do it:
HFILES = $(notdir $(HEADERS))
DIRS = $(dir $(HEADERS))
TARGETS = $(addprefix $(INCDIR)/, $(HFILES))
all: $(TARGETS)
$(INCDIR)/%.h: %.h
cp $< $#
vpath %.h $(DIRS)
OK. The answer is pretty "easy", although it requires usage of some gnu make that I haven't previously used. My solution, creates a subroutine that requires 2 arguments: (1) the name of the file (sans directory) and (2) the name of the directory in which it resided.
The "subroutine" is a template for a rule. When one evaluates the call to the subroutine, one initiates another rules, just as if one had written it explicitly.
define COPY_HEADER
$$(INCDIR)/$(2) : $(1)$(2)
#cp -f $$< $$#
endef
One then evaluates this subroutine for every header file and passes in the directory part and the file part of each header file.
$(foreach file,$(HEADERS),$(eval $(call COPY_HEADER,$(dir $(file)),$(notdir $(file)))))
Related
i have my source files inside the src folder and when i run make (windows) i get the following error
make: *** No rule to make target '%.o', needed by 'Program.exe'. Stop.
VPATH := src
Program.exe : %.o
g++.exe -o bin/program.exe $<
%.o : %.cpp
echo $<
g++ -c -ILibraries/include -LLibraries/lib $< -lgdi32
The % in make is not a wildcard that matches files. Just as well, because when make starts there won't be any .o files to match.
The % in make is a pattern match and it only works in pattern rules: pattern rules must have a % in the target (like the second rule you have, %.o : %.c). If you don't have a % in the target, then make just thinks that the % in the prerequisite list is a normal character like an a or b or whatever. Make doesn't know how to create a file named, literally, %.o because there is no matching %.cpp file.
Also it's always wrong in make to create a file that is not equal to $#. Here your target is Program.exe but your recipe creates a file bin/program.exe: those are not the same thing so it's wrong.
Also $< is only the FIRST prerequisite: when you want to link lots of files together you want to use $^ which is all the prerequisites.
You need to list all the object files you want to create:
bin/program.exe: src/foo.o src/bar.o src/baz.o
g++.exe -o $# $^
If you want to automatically generate all the object files then, assuming you want to compile all the source files, you can do something like:
OBJS := $(patsubst %.cpp,%.o,$(wildcard src/*.cpp))
bin/program.exe: $(OBJS)
g++.exe -o $# $^
You don't need to set VPATH in this situation; it doesn't help.
In a toplevel (unix, GNU) Makefile I want to iterate over a list of subdirs and execute tasks in there but exclude some of them. In this case exclude all subdirs starting with an underscore (_)
The following is working in iterating but ignores the exclusion regex. It still visits dir "_exclude".
In particular I think it ignores the "start of string" ^ (or it takes it literally). I have tried other regexes and they do work. Any idea how to fix that? Or indeed if you have any idea how to eliminate the shelling out or not using GNU makefile extensions?
SHELL=/bin/bash
EXCLUDE_DIRS_REGEX=^_
# later addition:
ALLMAKEFILES = $(shell find . -maxdepth 2 -type f -name Makefile)
SUBDIRS = $(filter-out ./,$(dir $(ALLMAKEFILES)))
all:
for dir in $(SUBDIRS); do \
if [[ "$$dir" =~ $(EXCLUDE_DIRS_REGEX) ]]; then continue; fi; \
make -C $$dir all; \
done
You have two problems to solve:
compute the list of target directories
call make in each of them
For the first one a mixture of make and shell functions or built-ins could be something like:
REGEX := ^_
ALLMAKEDIRS := $(patsubst %/,%,$(dir $(wildcard */Makefile)))
SUBDIRS := $(shell for d in $(ALLMAKEDIRS); \
do ! [[ "$$d" =~ $(REGEX) ]] && echo "$$d"; done)
I kept the REGEX just in case you have more complex regular expressions or you would like it to be easily modified. But of course if it is exactly ^_ and you never change it the following is simpler:
SUBDIRS := $(filter-out _%,$(patsubst %/,%,$(dir $(wildcard */Makefile))))
For the second one your approach is not very make-ish. A better approach would be to have one rule per subdirectory. The following is an example:
.PHONY: all $(SUBDIRS)
all: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $# all
It has several advantages:
there is no need to loop over subdirectories in a complicated recipe, make will do it for you,
make can launch several jobs in parallel (see the -j option) and this will speed-up your build.
Note: calling make in a Makefile is not recommended. Prefer $(MAKE). See this section of the manual for the details.
Say I have a list of source files like this:
SOURCE=aaa.src bbb.src ccc.src
I want to create a rule to build each corresponding target in its own folder, the name of which depends on the soruce file.
Sourcefile ----> Corresponding output file / target
aaa.src -------------------> aaa/aaa.out
bbb.src -------------------> bbb/bbb.out
ccc.src -------------------> ccc/ccc.out
How do I write a rule for this using GNUMake? My best effort was the following Makefile:
.PHONY: all clean
CC=somecompiler
SOURCE := aaa.src bbb.src ccc.src
RTARGS := $(SOURCE:%.src=%.out)
TDIRS := $(addsuffix /,$(basename $(SOURCE)))
TARGS := $(join $(TDIRS), $(RTARGS))
all:$(TARGS)
%.out: $(SOURCE) # Better source specification?
#[ ! -d "$(dir $*)" ] && mkdir "$(dir $*)"
$(CC) "$(patsubst %/,%,$(dir $*)).src" "$#"
clean:
rm -f $(TARGS)
rmdir --ignore-fail-on-non-empty $(TDIRS)
The problem here is, that any one target (i.e. .out file) depends on every source (i.e. .src file), instead of just the one that has the same basename. I could change the commented line to %.out: %.src but than the source file would have to be in the same directory as the output file. I could also compile it something like this:
%.out: %.src
$(CC) "$>" -o "$*/$#"
But then make would always compile every target regardless of whether it already exists or not.
How do I get make to use the appropriate source file only. What is the proper way of specifying dependences for each target separately in a generic rule?
In GNU Make you can specify prerequisites separately from recipes and still have a generic / pattern rule for all .out files:
.PHONY: all clean
all :
SOURCES := aaa.src bbb.src ccc.src
OUTPUTS := $(foreach src,${SOURCES},$(basename ${src})/${src:%.src=%.out})
# Build dependencies in the form of x/x.out : x.src | x
define ESTABLISH_DEPENDENCY =
$(basename ${1})/${1:%.src=%.out} : ${1} | $(basename ${1}) # Also depend on the output directory.
$(basename ${1}) : # Rule to create the output directory.
mkdir $$#
endef
$(foreach src,${SOURCES},$(eval $(call ESTABLISH_DEPENDENCY,${src})))
all : ${OUTPUTS}
# Generice rule for all .out files.
%.out :
#echo "build $# from $^"
touch $#
%.src : # For debugging only.
touch $#
.PHONY: all
Output:
$ make
touch aaa.src
mkdir aaa
build aaa/aaa.out from aaa.src
touch aaa/aaa.out
touch bbb.src
mkdir bbb
build bbb/bbb.out from bbb.src
touch bbb/bbb.out
touch ccc.src
mkdir ccc
build ccc/ccc.out from ccc.src
touch ccc/ccc.out
Note that it is more efficient and elegant to have order-only dependencies on directories and let make create them, than to have each recipe checking directory existence first.
I'm learning to write makefiles. I made my own simple one just to try and test, but every time I run make, i get:
make: *** No rule to make target `/%.cpp', needed by `obj'. Stop.
I googled. I'm pretty sure I typed everything correctly, and my folders are set up the way they should be. Here is the makefile:
CC = g++
LD = g++
NAME = app
OBJ_DIR = obj
SRC_DIR = src
CC_FLAGS = -std=c++0x
all: $(NAME)
$(NAME): $(OBJ_DIR)/%.o
$(LD) $(OBJ_DIR)/%.o -o $#
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CC) $< -o $# $(CC_FLAGS)
clean:
rm $(NAME) $(OBJ_DIR) -rf
What is the problem?
The line:
$(NAME): $(OBJ_DIR)/%.o
is not correct. This is not a pattern rule (because the target doesn't contain a pattern character, %) and so it's interpreted as an explicit rule, saying that app depends on the actual file named obj/%.o which doesn't exist, and make doesn't know how to build it (because there's no file src/%.cpp).
You need to change this to:
$(NAME): $(OBJ_DIR)/foo.o ...
or whatever object files you have.
I have a number of latex files, and I want to be able to compile them all conveniently. My makefile is currently as follows.
targets := $(patsubst %.tex, %.pdf, $(wildcard *.tex))
.PHONY: all
all: $(targets)
.SECONDEXPANSION:
%.pdf: %.tex $$(wildcard $$*_inc/*.*)
pdflatex $<
This way, if an include folder exists, everything within that folder will be treated as a dependency.
However, I also want to automate the running of dependent python scripts. These might be the creation of plots or the calculation of values to be included. I attempted to make the following modification.
targets := $(patsubst %.tex, %.pdf, $(wildcard *.tex))
all: $(targets)
.PHONY: all run_%
.SECONDEXPANSION:
%.pdf: %.tex $$(wildcard $$*_inc/*.*) $$(patsubst %, run_%, $$(wildcard $$*_inc/*.py))
pdflatex $<
run_%: %
$<
However, this does not work as I would expect to. I have the following folder structure.
|
|-Makefile
|-paper.tex
|-paper_inc/
|---a.txt
|---b.py
I would expect this to run b.py, then run pdflatex paper.tex. However, b.py is not run. If I look at the dependencies created, I see that paper_inc/a.txt and paper_inc/b.py are dependencies of paper.pdf, but run_paper_inc/b.py is not.
I'm not entirely certain what is the issue with this, as it feels that it should work. In addition, I tried the following lines as well for the %.pdf rule.
%.pdf: %.tex $$(wildcard $$*_inc/*.*) $$(addprefix run_,$$(wildcard $$*_inc/*.py))
%.pdf: %.tex $$(wildcard $$*_inc/*.*) $$(shell ls $$*_inc/*.py | sed 's/^/run/')
%.pdf: %.tex $$(wildcard $$*_inc/*.*) $$(shell ls $$*_inc/*.py | awk '{print "prefix "$0}')
With each of these rules, though, I receive the error message make: *** No rule to make target 'paper.pdf'. Stop.
What should be be done to fix this error, or, alternatively, what should I use instead of make?
You have two problems.
First:
run_%: %
$<
From the manual:
When the target pattern does not contain a slash (and it usually does
not), directory names in the file names are removed from the file name
before it is compared with the target prefix and suffix. After the
comparison of the file name to the target pattern, the directory
names, along with the slash that ends them, are added on to the
prerequisite file names generated from the pattern rule's prerequisite
patterns and the file name.
This is a little hard to follow, but basically when Make tries to build run_paper_inc/b.py, it looks for a pattern rule that matches b.py. The rule above doesn't fit. But this does:
%.py:
$(subst run_,,$#)
Second:
.SECONDEXPANSION:
%.pdf: ... $$(patsubst %, run_%, $$(wildcard $$*_inc/*.py))
...
One of Make's big shortcomings is its weak handling of wildcards. In this case % can't work for the pattern rule and the patsubst at the same time. But there's a way:
.SECONDEXPANSION:
%.pdf: ... $$(addprefix run_,$$(wildcard %_inc/*.py))
...