Wildcard in GNU makefile - makefile

I have many text files in a markdown text format and I want to use GNU make for generating HTML output. I have this Makefile that works with only one file:
MARKDOWN=markdown2
all: my_article_1242323266.html
%.html: %.markdown
$(MARKDOWN) $< $#
clean:
rm -f *html
Now, I want to get it working with all the markdown/html files, but I do not want to list all my files in the Makefile. I tried $(wildcard *.html) but it cannot not work as I dont have the "source" files in the directory yet. How to do that?

MARKDOWN = markdown2
HTMLS = $(patsubst %.markdown,%.html,$(wildcard *.markdown))
all: $(HTMLS)
%.html: %.markdown
$(MARKDOWN) $< $#
clean:
rm -f $(HTMLS)

Use something like this SOURCES=$(shell find . -name "*.cpp" -print | sort). This will get all the cpp files

Thank v01d, I modified his solution into this:
MARKDOWN=markdown2
SOURCES=$(shell find . -name "*.markdown" | sed 's/markdown/html/')
all: $(SOURCES)
%.html: %.markdown
$(MARKDOWN) $< $#
clean:
rm -f *html

Related

Makefile seems to take both inputs instead of one at a time

I have two files 1.gv and 2.gv which are Graphviz files.
I wrote this Makefile from what I could figure out:
DOT=dot
FORMAT=svg
SRC=$(wildcard *.gv)
OUT=$(subst .gv,.$(FORMAT),$(SRC))
all: $(OUT)
$(OUT): $(SRC)
$(DOT) -T$(FORMAT) $^ -o $#
.PHONY: clean
clean:
rm -f $(OUT)
The clean seems to work, the only problem seems to be is it runs:
dot -Tsvg 1.gv 2.gv -o 1.svg
dot -Tsvg 1.gv 2.gv -o 2.svg
instead of:
dot -Tsvg 1.gv -o 1.svg
dot -Tsvg 2.gv -o 2.svg
In your Makefile make sees that it needs all gv-files (SRC) to make one file: 1.gv (OUT) so in the loop the prerequisite changes $< but not the target $#.
You need to match a pattern and use patsubst instead of subst so OUT is a pattern of files.
I removed most variables for clarity. Feel free to add them back.
SRC = $(wildcard *.gv)
OUT = $(patsubst %.gv,%.svg,$(SRC))
%.svg: %.gv
dot -Tsvg $< -o $#
all: $(OUT)
.PHONY: clean
clean:
$(RM) *.svg

Is it possible to create a target that repeats an action for different files?

I'm trying to build a Makefile that simplifies compilation for a C assignment. The Makefile works fine for now, however, I would like to add a new target that executes a previous target and creates files.
The objective is the following:
Compile a given program (figures.c)
Execute it (this creates a bunch of .gv files)
Transform every .gv file to a .pdf file
I know how to transform a single file (I have the command), but can't seem to figure out how to loop through every file, without typing them all out.
I've already tried doing a different type of target, but does not work (see commented target)
# COMPILATION
CC=gcc
CFLAGS=-Wall -ansi -pedantic
# DOSSIERS
SOURCEDOC=sourcedoc
DOC=doc
SRC=src
INC=inc
OBJ=build
FIGS=images
FILES=$(wildcard $(FIGS)/*.gv)
.PHONY: clean doc archive author all
.SILENT : clean
# Targets
all : clean test images
test : $(OBJ)/Test_arbre.o $(OBJ)/aux.o $(OBJ)/Affichage.o $(OBJ)/ArbreBinaire.o $(OBJ)/arbres.o
$(CC) $^ -o $# $(CFLAGS)
figures : $(OBJ)/figures.o $(OBJ)/Affichage.o $(OBJ)/ArbreBinaire.o $(OBJ)/aux.o $(OBJ)/arbres.o
$(CC) $^ -o $# $(CFLAGS)
%.pdf: $(FIGS)/%.gv
dot -Tpdf -o $(FIGS)/$# $^
#$(FILES): $(FIGS)/%.pdf : $(FIGS)/%.gv
# dot -Tpdf -o $# $^
images : figures $(FILES)
#=========== Objets ===========
$(OBJ)/arbres.o : $(INC)/arbres.h $(INC)/aux.h $(INC)/Affichage.h $(INC)/ArbreBinaire.h
$(OBJ)/Affichage.o : $(INC)/Affichage.h $(INC)/ArbreBinaire.h
$(OBJ)/exemple*_arbre.o : $(INC)/Affichage.h $(INC)/ArbreBinaire.h
$(OBJ)/aux.o : $(INC)/aux.h
$(OBJ)/figures.o : $(INC)/Affichage.h $(INC)/ArbreBinaire.h $(INC)/arbres.h
$(OBJ)/Test_arbre.o : $(INC)/arbres.h $(INC)/ArbreBinaire.h $(INC)/Affichage.h
# Dummy rule
$(OBJ)/%.o : $(SRC)/%.c
#mkdir -p $(#D)
#$(CC) $< $(CFLAGS) -I $(INC)/ -c -o $#
# Miscellaneous
clean:
rm -f *~ */*~
rm -rf __pycache__ src/__pycache__
rm -rf $(DOC)
rm -f $(PROJECT)_$(AUTHOR12)_$(AUTHOR22).zip
rm -f conf.py-e
rm -rf $(OBJ)
rm -f $(FIGS)/*.pdf $(FIGS)/*.gv
rm -f test
The current Makefile works fine on all other commands than images.
If any of you could help, it would mean a lot!
Your definition of FILES should map the *.gv files to the corresponding *.pdf files;
FILES=$(patsubst %.gv,%.pdf,$(wildcard $(FIGS)/*.gv))
The rule which says how to generate a PDF should factor out the directory name;
%.pdf: %.gv
dot -Tpdf -o $# $^
Now, if make tries to create $(FIGS)/ick.pdf, the input will be $(FIGS)/ick.gv - the pattern says to substitute the extension .gv with the extension .pdf, and the rest of the file name stays unmodified, exactly like you'd want. A rule like
%.pdf: $(FIGS)/%.gv # error, don't use
says you need to find the source file in a subdirectory $(FIGS); so if you tried to make $(FIGS)/ick.pdf, that means make would need to find or generate $(FIGS)/$(FIGS)/ick.gv as input according to this rule.
If you absolutely cannot predict what files will be created on step (2) (and so confined to using $(wildcard ...)), you still must execute it after (2) is finished.
It's ugly but I can't think of better alternative than using "recursive make". I mean something like this:
...
.PHONY: images pdf
images: figures
# use figures to generate all .gv files
##figures --create-all-gv-files
# invoke make recursively
#$(MAKE) --no-print-directory pdf
# ensure $(wildcard ...) is invoked only if needed
ifeq ($(MAKECMDGOALS),pdf)
PDF_FILES:=$(patsubst %.gv,%.pdf,$(wildcard $(FIGS)/*.gv))
endif
pdf: $(PDF_FILES)
%.pdf: %.gv
dot -Tpdf -o $# $<

Depend on subdirectory creation in makefile rule

I have a project with sources in the src/ directory and its subdirectories (e.g. src/foo/ and src/bar/), and the objects in the obj directory and the matching subdirectories (e.g. obj/foo/ and obj/bar/).
I use the following (smimplified) Makefile:
SOURCES=$(shell find src/ -type f -name '*.c')
OBJECTS=$(patsubst src/%.c,obj/%.o,$(SOURCES))
all: $(OBJECTS)
obj/%.o: src/%.c
gcc -c $< -o $#
The problem
The problem is that if obj/ or one of its subdirectories doesn't exist, I get the following error:
Fatal error: can't create obj/foo/f1.o: No such file or directory
How can I tell make that %.o files depend on the creation of their containing directory?
What I tried
One solution when there are no subdirectories is to use "order only prerequisites":
$(OBJECTS): | obj
obj:
mkdir $#
But that fixes the problem only with obj/, but not obj/foo and obj/bar/. I thought about using $(#D), but I don't know how to get all this together.
I have also used hidden marker files in each directory, but that's just a hack, and I have also put a mkdir -p just before the GCC command but that also feels hacky. I'd rather avoid using recursive makefiles, if that were a potential solution.
Minimal example
To create a minimal project similar to mine you can run:
mkdir /tmp/makefile-test
cd /tmp/makefile-test
mkdir src/ src/foo/ src/bar/
echo "int main() { return 0; }" > src/main.c
touch src/foo/f1.c src/bar/b1.c src/bar/b2.c
I don't know why you consider adding mkdir -p before each compiler operation to be "hacky"; that's probably what I'd do. However, you can also do it like this if you don't mind all the directories created all the time:
First, you should use := for assigning shell variables, not =. The former is far more efficient. Second, once you have a list of filenames it's easy to compute the list of directories. Try this:
SOURCES := $(shell find src/ -type f -name '*.c')
OBJECTS := $(patsubst src/%.c,obj/%.o,$(SOURCES))
# Compute the obj directories
OBJDIRS := $(sort $(dir $(OBJECTS))
# Create all the obj directories
__dummy := $(shell mkdir -p $(OBJDIRS))
If you really want to have the directory created only when the object is about to be, then you'll have to use second expansion (not tested):
SOURCES := $(shell find src/ -type f -name '*.c')
OBJECTS := $(patsubst src/%.c,obj/%.o,$(SOURCES))
# Compute the obj directories
OBJDIRS := $(sort $(dir $(OBJECTS))
.SECONDEXPANSION:
obj/%.o : src/%.c | $$(#D)
$(CC) -c $< -o $#
$(OBJDIRS):
mkdir -p $#
I'd do it this way:
SOURCES=$(shell find src -type f -name '*.c') # corrected small error
...
obj/%.o: src/%.c
if [ ! -d $(dir $#) ]; then mkdir -p $(dir $#); fi
gcc -c $< -o $#

Use make to copy files with different filenames

I would like to have a makefile copy files from another directory and change their names. At the moment, I do something like this:
ALL: figure1.eps figure2.eps figure3.eps
figure1.eps: ../other_directory/a_nice_graph.eps
cp $< $#
figure2.eps: ../other_directory/a_beautiful_graph.eps
cp $< $#
figure3.eps: ../other_directory/an_ugly_graph.eps
cp $< $#
I would like to avoid writing the same rule (cp $< $#) for every line. I can't use the standard wildcards (%.eps) because the filenames do not match. Is there any way to do this?
Try this:
ALL: figure1.eps figure2.eps figure3.eps
%.eps:
cp $< $#
figure1.eps: ../other_directory/a_nice_graph.eps
figure2.eps: ../other_directory/a_beautiful_graph.eps
figure3.eps: ../other_directory/an_ugly_graph.eps

Expanding dependency's dirname for Makefile wildcard

Following on from Build script to Makefile, which lives in this upstream location. I want to include the Javascript examples that are included into this generated HTML document as dependencies.
INFILES = $(shell find . -name "index.src.html")
OUTFILES = $(INFILES:.src.html=.html)
TEMP:= $(shell mktemp -u /tmp/specs.XXXXXX)
all: $(OUTFILES)
# Problem line:
%.html: %.src.html $(wildcard contacts/*js)
#echo Dependencies: $^
cd $(#D) && m4 -PEIinc index.src.html > $(TEMP)
anolis --max-depth=3 $(TEMP) $#
rm -f $(TEMP)
clean:
rm -f $(OUTFILES)
PHONY: all clean
I want $(wildcard contacts/*js) to be $(wildcard $(#D)/*js) or $(wildcard $(dirname %)/*js), but nothing I've tried works. There must be some sort of keyword to get the parent directory of the target or dependency so I can reference the javascript dependencies.
AFAIK, using $(#D) and other automatic variables inside list of prerequisites can only be achieved using secondary expansion feature of GNU Make.
Thus, your problem probably can be solved as follows:
.SECONDEXPANSION:
%.html: %.src.html $$(wildcard $$(#D)/*js)
However, I'm not sure whether it will work with pattern rules.

Resources