I currently have this Makefile which :
Finds all *.f in the directory it is run
Looks for matching *.o in the specified subdir (as defined in Objets_dir)
Compiles and links
Code :
# Paths
# -----
# Where to put the *.o
Objets_dir = temp\Win
# Where to check for the *.o
VPATH = $(Objets_dir)
# Where to put the resulting binary
Executable = D:\Documents\out.exe
# List of needed objects
Objets = $(patsubst %.f,%.o,$(wildcard *.f))
# Rules
# -----
F_compilo = gfortran
F_compilo_options = -O3 -ffpe-trap=invalid,zero,overflow -mfpmath=sse -fmax-errors=3
Link = x86_64-w64-mingw32-gfortran
Link_options =
# Let's go
# --------
# Compile (generation of .o)
%.o:%.f
$(F_compilo) $(F_compilo_options) -c $< -o $(Objets_dir)\$#
# Link (generation of .exe)
$(Executable): $(Objets)
$(Link) $(Link_options) -o $# $(addprefix $(Objets_dir)\, $(Objets))
For information, I am using mingw32-make to execute this Makefile.
I would like to edit it so that I could specify a list of subfolders where it would also (in addition to the current folder) look for source files (*.f). It would then be a bit less generic but I would be very fine with this.
This makefile is something I retreived from the internet years ago and barely ever touched except to add some commentaries or edit compile flags.
I suppose the line that would require editing is the one with the "wildcard" call, but I am completely (completely) ignorant regarding Make language.
Can you suggest how to edit it ?
There is an instructive example of finding files in a list of sub-directories at: https://www.gnu.org/software/make/manual/html_node/Foreach-Function.html
Based on this, I've come up with the following. I've tested this using some example files on a linux system so can't guarentee it'll work "out of the box" on Windows, but shouldn't be far off.
It looks for all .f files in the directories given in dirs then proceeds much as before.
# Paths
# -----
# Where to put the *.o
Objets_dir = temp\Win
# Where to put the resulting binary
Executable = D:\Documents\out.exe
# List of directories to search for .f files:
dirs := . a b c d
# Extra directories to check for dependencies
VPATH = a b c d
# Make a list of *.f source files found in dirs
Sources := $(foreach dir,$(dirs),$(wildcard $(dir)\*.f))
# List of needed objects
Objets = $(patsubst %.f,%.o,$(Sources))
# Objects with full path names to their location in temp dir.
TempObjets = $(addprefix $(Objets_dir)\, $(notdir $(Objets)))
# Rules
# -----
F_compilo = gfortran
F_compilo_options = -O3 -ffpe-trap=invalid,zero,overflow -mfpmath=sse -fmax-errors=3
Link = x86_64-w64-mingw32-gfortran
Link_options =
# Let's go
# --------
# Compile (generation of .o)
$(Objets_dir)\%.o:%.f
$(F_compilo) $(F_compilo_options) -c $< -o $(Objets_dir)\$(notdir $#)
# Link (generation of .exe)
$(Executable): $(TempObjets)
$(Link) $(Link_options) -o $# $^
clean:
rm -f $(TempObjets) $(Executable)
Note that it strips the subdirectories off the filenames for building and linking, otherwise you'd need to create a bunch of matching temporary directories. So it is convenient to just dump all the .o files in the temporary directory. Note, however, that this will fail if some of the .f files in the subdirectories share the same name. In that case, you would need to set VPATH to a list of the temp directories (the list separator is ; on Windows, : on other systems) and remove the $(nordir ...) clauses from the build and link rules. However, you'll need to then create a directory in temp\Win to match each source directory.
Finally, it should be noted that this doesn't really count as a recursive use of make. For that, see: How to generate a Makefile with source in sub-directories using just one makefile
Related
I'm trying to make a Makefile. I have one folder called pictures and one called thumbs. In pictures there are pictures called pic1.jpg, pic2.jpg, pic3.jpg, and so on. I want to make thumbnails from these pictures and place them in the thumbs folder. This is what I have tried:
infiles = $(wildcard pictures/*.jpg)
outfiles = $(subst pictures,thumbs, $(infiles))
all : $(outfiles)
convert -thumbnail 100 pictures/*.jpg thumbs/*.jpg
Anyone knows what I'm doing wrong?
Your makefile says "here is how to crate all; it can be made when all the outfiles are up to date", but you don't say how to create those files.
A more idiomatic apprach is to specify a dependency for each individual file, and then Make can take it from there. In other words, say that all depends on outfiles just like you did, but then separately specify how each outfile depends on its respective infile.
infiles = $(wildcard pictures/*.jpg)
outfiles = $(subst pictures,thumbs, $(infiles))
.PHONY: all
all : $(outfiles)
thumbs/%.jpg: pictures/%.jpg
mkdir -p thumbs
# Guesswork here; probably update the command
convert -thumbnail 100 $< $#
The .PHONY declaration marks all as just a target name, not a file which needs to be built only if it doesn't exist, or is older than its dependencies.
For clarity, I am running this on windows with GnuWin32 make.
I have a set of directories with markdown files in at several different levels - theoretically they could be in the branch nodes, but I think currently they are only in the leaf nodes. I have a set of pandoc/LaTeX commands to run to turn the markdown files into PDFs - and obviously only want to recreate the PDFs if the markdown file has been updated, so a makefile seems appropriate.
What I would like is a single makefile in the root, which iterates over any and all sub-directories (to any depth) and applies the make rule I'll specify for running pandoc.
From what I've been able to find, recursive makefiles require you to have a makefile in each sub-directory (which seems like an administrative overhead that I would like to avoid) and/or require you to list out all the sub-directories at the start of the makefile (again, would prefer to avoid this).
Theoretical folder structure:
root
|-make
|-Folder AB
| |-File1.md
| \-File2.md
|-Folder C
| \-File3.md
\-Folder D
|-Folder E
| \-File4.md
|-Folder F
\-File5.md
How do I write a makefile to deal with this situation?
Here is a small set of Makefile rules that hopefuly would get you going
%.pdf : %.md
pandoc -o $# --pdf-engine=xelatex $^
PDF_FILES=FolderA/File1.pdf FolderA/File2.pdf \
FolderC/File3.pdf FolderD/FolderE/File4.pdf FolderD/FolderF/File5.pdf
all: ${PDF_FILES}
Let me explain what is going on here. First we have a pattern rule that tells make how to convert a Markdown file to a PDF file. The --pdf-engine=xelatex option is here just for the purpose of illustration.
Then we need to tell Make which files to consider. We put the names together in a single variable PDF_FILES. This value for this variable can be build via a separate scripts that scans all subdirectories for .md files.
Note that one has to be extra careful if filenames or directory names contain spaces.
Then we ask Make to check if any of the PDF_FILES should be updated.
If you have other targets in your makefile, make sure that all is the first non-pattern target, or call make as make all
Updating the Makefile
If shell functions works for you and basic utilities such as sed and find are available, you could make your makefile dynamic with a single line.
%.pdf : %.md
pandoc -o $# --pdf-engine=xelatex $^
PDF_FILES:=$(shell find -name "*.md" | xargs echo | sed 's/\.md/\.pdf/g' )
all: ${PDF_FILES}
MadScientist suggested just that in the comments
Otherwise you could implement a script using the tools available on your operating system and add an additional target update: that would compute the list of files and replace the line starting with PDF_FILES with an updated list of files.
Final version of the code that worked for Windows, based on #DmitiChubarov and #MadScientist's suggestions is as follows:
%.pdf: %.md
pandoc $^ -o $#
PDF_FILES:=$(shell dir /s /b *.md | sed "s/\.md/\.pdf/g")
all: ${PDF_FILES}
$make --- Will have normal build
$make CAdvisor
Above will do following steps:
1) Update variable CC, now it should become "cadvise -pdb mypdb +wlint +wall aCC"
2) Run all with updated CC option
CC = aCC
CFLAGS = -c #-Wall
LDFLAGS =
SOURCES = foo.cc
OBJECTS = $(SOURCES:.cc=.o)
EXECUTABLE = observer
RM=rm -rf
CADVISE_OPTS= -pdb mypdb +wlint
CADVISE= /opt/cadvise/bin/cadvise
.PHONY : CAdvisor update_cc clean all
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cc.o:
$(CC) $(CFLAGS) $< -o $#
clean:
$(RM) $(EXECUTABLE) $(OBJECTS)
update_cc: CC := ${$(CADVISE) $(CADVISE_OPTS) $(CC)}
CAdvisor: update_cc all;
#echo DEBD $(CC)
Now above code is giving me error:
**$ make CAdvisor
Make: Don't know how to make CC. Stop.
$**
How to fix this error
Any better option?
Linkes:link_how to call target from another
Thanks
Sorry, but that's not how target-specific variables work. Target-specific variables are scoped to their target and any prerequisite built as a result of building that target. It's not the case that the target-specific setting changes the value of the global variable for the rest of the recipes expanded by make.
In your example, all is not a prerequisite of update_cc, it's a sibling. So, target-specific variables that are set for update_cc have no impact on the all target.
Second, using ${$(CADVISE) $(CADVISE_OPTS) $(CC)} is definitely not right: the inside will be expanded first then because the entire thing is enclosed in ${...} it will be treated as a variable name, and that variable (which clearly doesn't exist) will be looked up, resulting in an empty string.
I don't know why you have added the extra target update_cc at all; why not just set the target-specific variable on the CAdvisor target?
CAdvisor: CC := $(CADVISE) $(CADVISE_OPTS) $(CC)
CAdvisor: all
#echo DEBD $(CC)
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.
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)))))