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

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

Related

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 $# $<

Makefile to auto compile, assemble and link many files in a directory

Sorry for repetition, but I could not find the solution.
Following is the sequence of the commands I want Makefile to accomplish.
gcc-elf-gcc -S -combine loadStoreByte.c string.c lib_uart.c bubble_uart.c -o bubble_uart.s
gcc-elf-as -o startup.o startup.s;
gcc-elf-as -o handler.o handler.s;
gcc-elf-as -o bubble_uart.o bubble_uart.s;
gcc-elf-ld -o bubble_uart -T browtb.x bubble_uart.o startup.o handler.o;
That is, I want to compile all C files into a single S file and then assemeble all s files into corresponding object files and the link all object files into one executable.
I tried the following makefile. The individual targets work fine, but could not run all the target at the same time using "make all".
Please guide how to fix it.
CC = brownie32-elf-gcc
AS = brownie32-elf-as
LK = brownie32-elf-ld
SFILE = $(wildcard *.s)
OFILE = $(patsubst %.s,%,$(SFILE))
CFILE = $(wildcard *.c)
OBJ = $(wildcard *.o)
APP = bubble_uart
all: compile assemble link
link: $(OBJ)
$(LK) -o $(APP) -T browtb.x $^
assemble: $(OFILE)
%: %.s compile
$(AS) -o $#.o $<
compile: $(CFILE)
$(CC) -S -combine $^ -o $(APP).s
clean:
rm -f $(OBJ) $(APP) $(APP).s *.o
Thanks
Your makefile is not written with "best practices" and because of that it was easy for you to make mistakes. I will re-write your makefile here, with best practices, which solves all your problems. Please study it with the aid of the GNU Make manual.
The biggest single problem is that you have "procedures/actions", such as "assemble" as make targets. This makes the makefile into a kind of "procedural" program. GNU Make is not designed to be a procedural language, instead, it is a declarative language. The "targets" should not be actions, but actual files, or "phony" files, which should be collections of actual files.
The use of wildcard in makefiles is a bad idea - it is best to list your files explicitly, as I have shown.
Please consult my answer
makefile enforce library dependency ordering
for a discussion of good practices, including phony and real targets.
MAKEFILE := $(lastword $(MAKEFILE_LIST))
CFILES := \
loadStoreByte.c \
string.c \
lib_uart.c \
bubble_uart.c
SFILE_OUTPUT := bubble_uart.s
SFILES := $(SFILE_OUTPUT) \
startup.s \
handler.s
OFILES := $(SFILES:s=o)
APP := bubble_uart
.PHONY: all
all: $(APP)
$(APP): browtb.x $(OFILES) $(MAKEFILE)
gcc-elf-ld -o $# -T $< $(OFILES)
$(OFILES): %o : %s $(MAKEFILE)
gcc-elf-as -o $# $<
$(SFILE_OUTPUT): $(CFILES) $(MAKEFILE)
gcc-elf-gcc -S -combine $(CFILES) -o $#
It is usually best if the target of a rule is the name of the file the rule produces.
So the compile rule:
compile: $(CFILE)
$(CC) -S -combine $^ -o $(APP).s
should be this:
$(APP).s: $(CFILE)
$(CC) -S -combine $^ -o $#
Likewise the object rule:
%: %.s compile
$(AS) -o $#.o $<
should be this:
%.o: %.s
$(AS) -o $# $<
(There's no reason for it to depend on compile or $(APP).s, since bubble_uart.s is irrelevant to most object files.)
Then the list of object files should include bubble_uart.o:
SFILES = $(sort $(wildcard *.s) $(APP).s)
OFILES = $(patsubst %.s,%.o,$(SFILES))
(The sort is to remove duplicates.) Note that this is the list of object files needed for construction of the executable, not the list of object files that happen to exist at the beginning of the build process.
Finally, the executable:
$(APP): $(OFILES)
$(LK) -o $# -T browtb.x $^

Makefile: source files in a particular directory

What do I need to do if I want to compile several files (e.g. a.f90, b.f90, c.f90) in a given directory (say, MYDIR)?
My Makefile code is something like:
CC=gfortran
CFLAG=-g
HOME=MYDIR
SRC=$(HOME)/(a.f90,b.f90,c.f90)
OBJ=$(SRC:,=.o)
EXE=test.x
%.o: %.f90
$(CC) $(CFLAG) -c -o $# $<
$(EXE): $(OBJ)
$(CC) -o $# $^ $(CFLAG)
clean:
rm -f *.o
I think, the 4-th line is not correct. So what could be the replacement?
Another thought: Can I use a wildcard if I want to compile all .f90 file inside MYDIR?
There are lots of ways to do it. You can do something like:
SRC = $(addprefix $(HOME)/,a.f90 b.f90 c.f90)
Also your assignment of OBJ is wrong; there's no comma needed after the colon.
Yes you can use wildcard if you want.

Makefile target matching

I'm having troubles with my Makefile :-(
I have a mix of assembly and C sourcecode that I need to link together. I need different build-instructions for those two types. Since both the assembler and C compiler output *.o files, I cannot use the general %.o:%.c construction often found in example Makefiles
This what I'm trying now:
Get a list of all C files and their resulting output files:
C_SRCFILES := $(shell find $(SRCDIRS) -type -f -name "*.c")
C_OBJFILES := $(patsub %.c,%.o,$(C_SRCFILES))
Get a list of all asm files and their resulting output files:
A_SRCFILES := $(shell find $(SRCDIRS) -type -f -name "*.asm")
A_OBJFILES := $(patsub %.asm,%.o,$(A_SRCFILES))
When I echo those vars to the screen, they seem to be correct, but how I do define my targets now?
I tried something like this
$(A_OBJFILES): ($A_SRCFILES)
$(AS) $(AFLAGS) -o $# $*
$(C_OBJFILES): ($C_SRCFILES)
$(CC) $(CFLAGS) -c -o $# $*
all: $(A_OBJFILES) $(C_OBJFILES)
$(LD) $(LDFLAGS) $(A_OBJFILES) $(C_OBJFILES) -o $(TARGET_OUTPUT)
but ofcourse, this doesn't work...
Any suggestions?
First problem: a misplaced parenthesis or two.
$(A_OBJFILES): ($A_SRCFILES)
Notice that you have the $ inside the ( in ($A_SRCFILES). Make expands $A, which is nothing, and things go downhill. I think you meant $(A_SRCFILES), and the same thing in the other rule.
Second problem: I don't know the syntax of the assembler, but the syntax of the compiler command is wrong:
$(CC) $(CFLAGS) -c -o $# $*
The variable $* is nothing if we're not in a pattern rule, which we're not (yet). And anyway, if we were in a pattern rule and you were trying to build foo.o, this command would look for the source file foo, and there's no such file. Do it this way:
$(CC) $(CFLAGS) -c -o $# $<
Third problem: each object file depends on all source files (in each rule). Try this instead:
$(A_OBJFILES): %.o : %.asm
...
$(C_OBJFILES): %.o : %.c
...
(Now it's a pattern rule.)
Fourth problem: a lot of redundancy in the last rule. Change it to this:
all: $(A_OBJFILES) $(C_OBJFILES)
$(LD) $(LDFLAGS) $^ -o $(TARGET_OUTPUT)
or better still:
all: $(TARGET_OUTPUT)
$(TARGET_OUTPUT): $(A_OBJFILES) $(C_OBJFILES)
$(LD) $(LDFLAGS) $^ -o $#
Since both the assembler and C compiler output *.o files, I cannot use the general %.o:%.c construction often found in example Makefiles
Sure you can:
%.o : %.c
# commands to make .o from a corresponding .c
%.o : %.asm
# commands to make .o from a corresponding .asm

Wildcard targets in a Makefile

How can I compact the folllowing Makefile targets?
$(GRAPHDIR)/Complex.png: $(GRAPHDIR)/Complex.dot
dot $(GRAPHDIR)/Complex.dot -Tpng -o $(GRAPHDIR)/Complex.png
$(GRAPHDIR)/Simple.png: $(GRAPHDIR)/Simple.dot
dot $(GRAPHDIR)/Simple.dot -Tpng -o $(GRAPHDIR)/Simple.png
$(GRAPHDIR)/IFileReader.png: $(GRAPHDIR)/IFileReader.dot
dot $(GRAPHDIR)/IFileReader.dot -Tpng -o $(GRAPHDIR)/IFileReader.png
$(GRAPHDIR)/McCabe-linear.png: $(GRAPHDIR)/McCabe-linear.dot
dot $(GRAPHDIR)/McCabe-linear.dot -Tpng -o $(GRAPHDIR)/McCabe-linear.png
graphs: $(GRAPHDIR)/Complex.png $(GRAPHDIR)/Simple.png $(GRAPHDIR)/IFileReader.png $(GRAPHDIR)/McCabe-linear.png
--
Using GNU Make 3.81.
The concept is called pattern rules. You can read about it in GNU make manual.
$(GRAPHDIR)/%.png: $(GRAPHDIR)/%.dot
dot $< -Tpng -o $#
graphs: $(patsubst %,$(GRAPHDIR)/%.png, Complex Simple IFileReader McCabe)\
or just
%.png: %.dot
dot $< -Tpng -o $#
graphs: $(patsubst %,$(GRAPHDIR)/%.png, Complex Simple IFileReader McCabe)
You can also remove all repetition by extracting one of the patterns into a separate variable PNG_PATTERN like so:
PNG_pattern=$(GRAPHDIR)/%.png
$(PNG_pattern): $(GRAPHDIR)/%.dot
dot $< -Tpng -o $#
graphs: $(patsubst %,$(PNG_pattern), Complex Simple IFileReader McCabe)
Just in case you actually want to generate a .PNG for every .DOT within current directory:
%.png : %.dot
dot -Tpng -o $# $<
all: $(addsuffix .png, $(basename $(wildcard *.dot)))
I came up with this Makefile after reading the answer from #Pavel.
I think you want some pattern rules. Try this out.
TARGETS = $(GRAPHDIR)/Complex.png \
$(GRAPHDIR)/Simple.png \
$(GRAPHDIR)/IFileReader.png \
$(GRAPHDIR)/McCabe-linear.png
%.png : %.dot
dot $^ -Tpng -o $#
graphs: $(TARGETS)

Resources