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)
Related
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
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 $^
I have a bunch of .dot files (for example, a.dot, b.dot, c.dot) and I want to compile them to .png files with neato. Currently, the make command I have to do that looks something like this:
neato -Tpng -o a.png a.dot
neato -Tpng -o b.png b.dot
neato -Tpng -o c.png c.dot
Obviously, this is completely non-scalable, and I'd like to write something that will take every file with a .dot extension, and compile it to an equivalently-named .png file. I'm not sure how to write such a loop in make - any help would be appreciated.
This is pretty much basic make 101:
SRCS = a.dot b.dot c.dot
OBJS = $(SRCS:%.dot=%.png)
all: $(OBJS)
%.png : %.dot
neato -Tpng -o $# $<
You don't do "loops" in make; you define targets and prerequisites.
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
In a project that uses make and bison, I'm having difficulty specifying that the compiled grammar grammar.tab.c depends on the grammar input grammar.y, that each object file depends on a corresponding source file (including grammar.tab.o), and that the executable depends on all object files.
The problem is that running make when grammar.tab.c does not yet exist means that there is no attempt to build it, and when the executable is built the yyparse function is missing.
My Makefile is:
CFLAGS = -g -Wall
YACC = bison -d -r all
OBJ=$(patsubst %.c, %.o, $(wildcard *.c))
HEADERS=grammar.tab.h hex.h compiler.h types.h
all: grammar.tab.h c
clean:
rm -f $(OBJ) *.tab.c *.tab.h c c.exe *.output
c: $(OBJ)
$(CC) -o $# $(OBJ) $(CFLAGS)
grammar.tab.c: grammar.y
$(YACC) grammar.y
grammar.tab.h: grammar.y
$(YACC) grammar.y
%.o: %.c $(HEADERS)
$(CC) -c $< $(CFLAGS)
If I change it with:
OBJ=$(patsubst %.c, %.o, $(wildcard *.c)) grammar.tab.o
Then it will build the compiled grammar if it doesn't already exist. But if it does already exist, then
when building the executable, there will be an error about yyparse being provided twice (presumably because $OBJ contains grammar.tab.o twice).
What I'm aiming for is a Makefile that:
Will correctly build the executable on a make command, rebuilding intermediate files as necessary.
Will pick up all *.c files in the directory (i.e. doesn't need to be changed when new source files are added).
Is easy to read and understand. I don't mind learning new make features as long as it's only one or two at a time.
How do others' grammar-building Makefiles work?
Edit Ok, those are great answers. I went with the filter-out one, since it was the smallest change. I'm really glad that everyone seemed to know exactly what I'm talking about -- I was apprehensive about being told to use something byzantine like automake ;-).
Thanks everyone.
For the general 'run yacc' rule you want something like
%.tab.c: %.y
$(YACC) $<
%.tab.h: %.tab.c
#touch $#
To get all the sources you want
OBJ=$(sort $(patsubst %.c, %.o, $(wildcard *.c)) $(patsubst %.y, %.tab.o, $(wildcard *.y)))
You need the 'sort' mostly for its automatic removal of duplicates
# you can consolidate both rules into one:
grammar.tab.c grammar.tab.h: grammar.y
$(YACC) grammar.y
# but I find ``make'' more workable without many-to-one target-to-prerequisites
grammar.tab.c: grammar.tab.h
touch $#
grammar.tab.h: grammar.y
$(YACC) $<
# your problem, though, does seem to be with linking ``grammar.tab.o''
# you can exclude grammar.tab.o
OBJ =: $(filter-out grammar.tab.o,$(patsubst %.c,%.o,$(wildcard *.c))) grammar.tab.o
# you can remove duplicates from $(OBJ)
OBJ =: $(sort $(patsubst %.c,%.o,$(wildcard *.c)) grammar.tab.o)
# you can remove duplicates when linking
c: $(OBJ)
$(CC) $(LDFLAGS) -o $# $(sort $^) $(LDLIBS)
# but personally, I prefer not to use $(wildcard) at all,
# explicitly updating the makefile as needed
If you're using GNU make, you can use the filter-out predicate to manually exclude a particular file from the dependencies of a target. Like so: OBJ=$(filter-out $(grammar.tab.o), $(patsubst %.c, %.o, ...)) grammar.tab.o.
You first exclude grammar.tab.o from the existing object files (it might not be there), then add it back in all cases. Admittedly a bit roundabout, but it works. That's what we use at work.
Something like this... you'll have to play around with it. This is kind-sort-a how
I did this in the 90's... it's unconventional but served its purpose
SRCS = foo.c bar.c lex.c yacc.c
OBJS = $(SRCS:%.c=$(OBJ_DEST_DIR)/%.o)
OBJS.d = $(SRCS:%.c=$(OBJ_DEST_DIR)/%.d)
CC_RULE = $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
YACC_RULE = cd $(#D); $(YACC) $(YFLAGS) -o $(#F) $<
LEX_RULE = cd $(#D); $(LEX) $(LEXFLAGS) -o$(#F) $<
CC_DEP_RULE = #echo -n "$(#D)/" > $#;
CC_DEP_RULE += gcc -M $(DEFINES) $(INCLUDES) $< |
CC_DEP_RULE += sed -e 's#:#: $(MAKEFILE_DEPS) #' >> $#;
$(OBJ_DEST_DIR)/%.o: $(OBJ_DEST_DIR)/%.c
$(CC_RULE)
$(OBJ_DEST_DIR)/%.c: $(SRC_DIR)/%.l
$(LEX_RULE)
$(OBJ_DEST_DIR)/%.c: $(SRC_DIR)/%.y
$(YACC_RULE)
$(OBJ_DEST_DIR)/%.o: $(SRC_DIR)/%.c
$(CC_RULE)
$(OBJ_DEST_DIR)/%.d: $(OBJ_DEST_DIR)/%.c
$(CC_DEP_RULE)
$(OBJ_DEST_DIR)/%.d: $(SRC_DIR)/%.c
$(CC_DEP_RULE)
-include $(OBJS.d)
This is what one of the .d files will look like
/tmp/builds/objs/opt/libiberty/static/alloca.o: /tmp/src/binutils-2.20/libiberty/alloca.c \
/tmp/src/binutils-2.20/libiberty/config.h \
/tmp/src/binutils-2.20/include/libiberty.h \
/tmp/src/binutils-2.20/include/ansidecl.h \
/usr/lib/gcc/i686-apple-darwin10/4.2.1/include/stddef.h \
/usr/lib/gcc/i686-apple-darwin10/4.2.1/include/stdarg.h \
/usr/include/stdio.h /usr/include/_types.h /usr/include/sys/_types.h \
/usr/include/sys/cdefs.h /usr/include/machine/_types.h \
/usr/include/i386/_types.h /usr/include/secure/_stdio.h \
/usr/include/secure/_common.h /usr/include/string.h \
/usr/include/secure/_string.h /usr/include/stdlib.h \
/usr/include/Availability.h /usr/include/AvailabilityInternal.h \
/usr/include/sys/wait.h /usr/include/sys/signal.h \
/usr/include/sys/appleapiopts.h /usr/include/machine/signal.h \
/usr/include/i386/signal.h /usr/include/i386/_structs.h \
/usr/include/sys/_structs.h /usr/include/machine/_structs.h \
/usr/include/mach/i386/_structs.h /usr/include/sys/resource.h \
/usr/include/machine/endian.h /usr/include/i386/endian.h \
/usr/include/sys/_endian.h /usr/include/libkern/_OSByteOrder.h \
/usr/include/libkern/i386/_OSByteOrder.h /usr/include/alloca.h \
/usr/include/machine/types.h /usr/include/i386/types.h \
You can play around with the MAKEFILE_DEPS variable to insert other dependencies too