how to compact this Makefile pattern? - makefile

How to rewrite Makefile paragraph-pairs like this, into one single paragraph? I have:
$(BUILD_DIR_DEBUG)/args.o: \
$(SRC)/args.c \
$(SRC)/args.h \
$(SRC)/something_else.h
$(CC) $(CFLAGS) $(CFLAGS_DEBUG) -c -o $# $<
$(BUILD_DIR_RELEASE)/args.o: \
$(SRC)/args.c \
$(SRC)/args.h \
$(SRC)/something_else.h
$(CC) $(CFLAGS) $(CFLAGS_RELEASE) -c -o $# $<
I'd be happy to get something like this (do not assume correct syntax), but I don't know how to define such:
# ${BUILD_TYPE} to be iterated as "DEBUG" and "RELEASE" to get two current
# runtime rules from one actually written rule.
$(BUILD_DIR_$(BUILD_TYPE))/args.o: \
$(SRC)/args.c \
$(SRC)/args.h \
$(SRC)/something_else.h
$(CC) $(CFLAGS) $(CFLAGS_$(BUILD_TYPE)) -c -o $# $<

You don't really describe how you want to use these rules so there may be simpler solutions, such as using recursive make. However if you want just the most basic answer to exactly the question you asked, then the answer is eval.
First you write a variable containing your rule:
define RULE
$(BUILD_DIR_$(BUILD_TYPE))/args.o: \
$(SRC)/args.c \
$(SRC)/args.h \
$(SRC)/something_else.h
$$(CC) $$(CFLAGS) $$(CFLAGS_$(BUILD_TYPE)) -c -o $$# $$<
endef
$(foreach BUILD_TYPE,DEBUG RELEASE,$(eval $(RULE)))
Note carefully the escaped $$ in the recipe of the rule variable. This is needed because this variable is expanded once before being parsed by eval, and you don't want these recipe variables to be expanded there, you want to defer their expansion until the recipe is actually run.
You might find the set of blog posts here (start with the last one in the list, which was the first one written) to learn more about this: http://make.mad-scientist.net/category/metaprogramming/

short answer:
ifeq ($(DEBUG), 1)
BUILD_DIR = $(BUILD_DIR_DEBUG)
CFLAGS = $(CFLAGS_DEBUG)
else
BUILD_DIR = $(BUILD_DIR_RELEASE)
CFLAGS = $(CFLAGS_RELEASE)
endif
$(BUILD_DIR)/args.o: \
$(SRC)/args.c \
$(SRC)/args.h \
$(SRC)/something_else.h
$(C) $(CFLAGS) -c -o $# $<
and set the variable DEBUG as you see fit. for example make DEBUG=1
see also:
How can I configure my makefile for debug and release builds?
https://www.gnu.org/software/make/manual/html_node/Conditional-Example.html

Related

Why is Makefile not including the header?

I'm trying to make a library for my project but I am very very new to Makefiles. I tried several configurations and adding -I but none worked.
I have the following three:
libft/
../includes/
....libft.h
../lst
....ft_lstnew.c
....ft_lstadd_front.c
....ft_lstadd_back.c
.... [...]
../src
....ft_isalpha.c
....ft_isalnum.c
.... [...]
And the following makefile:
NAME=libft.a
LIBSO=libft.so
CC=gcc
CFLAGS=-Wall -Wextra -Werror
SRC_DIR=src/
BONUS_DIR=lst/
OBJ_DIR=obj/
SRC_FILES= ft_bzero.c \
ft_isalmun.c \
ft_isalpha.c \
ft_isascii.c \
ft_isdigit.c \
ft_isprint.c \
ft_memchr.c \
ft_memcpy.c \
ft_memmove.c \
ft_memset.c \
ft_strchr.c \
ft_strlcat.c \
ft_strlcpy.c \
ft_strlen.c \
ft_strncmp.c \
ft_strrchr.c \
ft_tolower.c \
ft_toupper.c
BONUS_FILES=ft_lstadd_back.c \
ft_lstadd_front.c \
ft_lstdelone.c \
ft_lstclear.c \
ft_lstiter.c \
ft_lstlast.c \
ft_lstmap.c \
ft_lstnew.c \
ft_lstsize.c
SRC_PATH=$(addprefix $(SRC_DIR), $(SRC_FILES))
BONUS_PATH=$(addprefix $(BONUS_DIR), $(BONUS_FILES))
SRC_NAMES=$(SRC_FILES:.c=.o)
BONUS_NAMES=$(BONUS_FILES:.c=.o)
SRC_PATH_O=$(addprefix $(SRC_DIR), $(SRC_NAMES))
BONUS_PATH_O=$(addprefix $(BONUS_DIR), $(BONUS_NAMES))
HDR_NAME=libft.h
HDR_DIR=includes/
HDR= $(addprefix $(HDR_DIR),$(HDR_NAME))
all: $(NAME)
$(NAME): $(SRC_PATH_O)
ar rc $# $<
ranlib $#
$(OBJ_DIR):
mkdir $#
$(OBJ_DIR)%.o: $(SRC_DIR)%.c $(HDR_NAME)
$(CC) $(CFLAGS) -c $< -o $# -I $(HDR)
clean:
rm -rf $(OBJ_DIR)
fclean: clean
rm -f $(NAME)
re: fclean all
.PHONY: all clean fclean re
And I keep getting this each time I type make on the terminal:
gcc -Wall -Wextra -Werror -c -o src/ft_bzero.o src/ft_bzero.c
src/ft_bzero.c:1:10: fatal error: libft.h: No such file or directory
1 | #include "libft.h"
| ^~~~~~~~~
compilation terminated.
make: *** [<builtin>: src/ft_bzero.o] Error 1
Am I missing something? It's literally my first time.
Yes, you're missing some things.
First, look at the command line make shows:
gcc -Wall -Wextra -Werror -c -o src/ft_bzero.o src/ft_bzero.c
Note that the output here is not right for the recipe of the pattern rule you created: there's no -I option, and the object file is being written to src/ not obj/.
From this you should realize that your pattern rule is not being used at all, and instead make is using its built-in rule for building object files.
Why isn't your pattern rule being used? Let's look at it:
$(OBJ_DIR)%.o: $(SRC_DIR)%.c $(HDR_NAME)
what is this after variable expansion?
obj/%.o: src/%.c libft.h
This pattern (like all patterns) can only match if ALL the prerequisites either already exist or can be built. The src/%.c exists, after the pattern substitution. What about libft.h? No, that doesn't exist. What does exist is includes/libft.h but that's not the same thing.
So, this rule fails to match and make goes back to using its default rules.
If you want to say that every object file depends on that header, you have to use the correct path to the header file when you write the pattern.
Next, this is wrong:
$(CC) $(CFLAGS) -c $< -o $# -I $(HDR)
What is $(HDR)? It's the name of the file: include/libft.h. You don't include header file names with -I; you include directories that headers are looked for in. So you need $(HDR_DIR) here instead.

makefile C code compile and link in one step but want two separate steps

My currently working makefile uses gcc to compile and link in one step. It is 600 lines long so I have cut it down to just show you the 'compile and link' and hex stages (very cut down code here!)
$(PROGRAM_ELF): \
$(BSP_DIR)/install/lib/$(CONFIGURATION)/libmetal.a \
$(BSP_DIR)/install/lib/$(CONFIGURATION)/libmetal-gloss.a \
$(BSP_DIR)/metal.$(LINK_TARGET).lds
mkdir -p $(dir $#)
$(MAKE) -C $(SRC_DIR) $(basename $(notdir $#)) \
PORT_DIR=$(PORT_DIR) \
AR=$(RISCV_AR) \
CC=$(RISCV_GCC) \
CXX=$(RISCV_GXX) \
ASFLAGS="$(RISCV_ASFLAGS)" \
CCASFLAGS="$(RISCV_CCASFLAGS)" \
CFLAGS="$(RISCV_CFLAGS)" \
CXXFLAGS="$(RISCV_CXXFLAGS)" \
XCFLAGS="$(RISCV_XCFLAGS)" \
LDFLAGS="$(RISCV_LDFLAGS)" \
LDLIBS="$(RISCV_LDLIBS)" \
PROJ_SRC="$(PROJ_SRC)"
$(PROGRAM_HEX): \
$(PROGRAM_ELF)
$(RISCV_OBJCOPY) -O ihex $(PROGRAM_ELF) $#
mv $(PROGRAM_HEX) $(PROGRAM_TMP)
$(RISCV_OBJCOPY) -O verilog $(PROGRAM_ELF) $#
cp $(PROGRAM_HEX) $(PROGRAM_MEM)
mv $(PROGRAM_TMP) $(PROGRAM_HEX)
However, I need the 'compile and link stage' to be in 2 steps now as I'll be using a different compiler which has separate compile and link exes. How would I do this ? So the above would need to be split into 2. Examples online are a bit vague.
at its simplest, you use the gcc (or g++) -c option to compile the source without linking. This will generate an object file - which you can use in the linker state. Here is a simple example:
SOURCE = test.cpp
OBJECT = test.o
OUTPUT = run
all:
#g++ $(SOURCE) -c -o $(OBJECT) <------ Compile test.cpp, produces test.o
#g++ $(OBJECT) -o $(OUTPUT) <------ Links test.o into executable `run`
clean:
#$(RM) -rf $(OBJECT) $(OUTPUT)
That's it...
I did this which seemed to work:
#list of all files
PROJ_SRC = $(SRC_DIR)/plsi2c_riscv.c \
$(SRC_DIR)/SimSpi.c \
etc
#assume BUILD_FOLDER defined already
OBJ_FILES = $(addprefix $(BUILD_FOLDER)/,$(PROJ_SRC:.c=.o))
$(BUILD_FOLDER)/%.o: %.c
#Create the folder structure for the output file
#mkdir -p $(dir $#)
$(MY_CC) $(CCFLAGS) $< -o $#
$(BUILD_FOLDER)/example: $(OBJ_FILES)
mkdir -p $(dir $#)
#echo Linking $(notdir $#)
$(MY_LINK) $(LFLAGS) $^ $(LDLIBS) -o $#

gfortran makefile not working on mac

I am trying to run a makefile with gfortran in my mac. It compiles without problem in Fedora 18, but I can't make it work in Mac OS 10.8.4 with the last gfortran from HPC.
I am newbie on fortran, so some light would be appreciated.
Here is the Make file:
# Makefile made to work with GNU Make
.DEFAULT:
BIN=bin
OBJ=obj
vpath= %$(OBJ)/.o $(OBJ)
vpath= %.mod $(OBJ)
EXES= pasos \
pasosng \
pasosm \
trans \
cost \
lcal \
fluj \
loc \
eval \
impas \
imptra \
mats \
imploc \
matesp \
dimen
FC=gfortran
LN=gfortran
FCFLAGS=$(USER_FCFLAGS) -g3 -B $(OBJ) -J $(OBJ) #fc_options #fc_warnings
LFLAGS=$(USER_LFLAGS)
ifdef SystemRoot
dotexe=.exe
endif
ifdef F_PROFILE
FCFLAGS:=$(FCFLAGS) -pg
LFLAGS:=$(LFLAGS) -pg
endif
ifdef F_TEST
FCFLAGS:=-O0 -fbounds-check $(FCFLAGS)
else
FCFLAGS:=-O3 $(FCFLAGS)
endif
COMPILE=$(FC) $(FCFLAGS) -o $# -c $<
LINK=$(LN) $(LFLAGS) -o $# -Wl,-Map=$#.map $^
%.o : %.f90
$(COMPILE)
all: prepare $(EXES)
$(OBJ)/%.o : %.f90
$(COMPILE)
clean:
rm -rf $(OBJ) $(BIN)
prepare: $(BIN) $(OBJ)
$(BIN):
mkdir $(BIN)
$(OBJ):
mkdir $(OBJ)
pasos: prepare $(BIN)/pasos$(dotexe)
#echo $#
$(BIN)/pasos$(dotexe) : $(OBJ)/pasos.o \
$(OBJ)/nodes.o \
$(OBJ)/io_list.o \
$(OBJ)/rcomm.o \
$(OBJ)/tparc.o \
$(OBJ)/zcomm.o \
$(OBJ)/rcomm.o \
$(OBJ)/pcomm.o \
$(OBJ)/getoptm.o \
$(OBJ)/control.o \
$(OBJ)/heap.o \
$(OBJ)/gener.o \
$(OBJ)/param.o \
$(OBJ)/ascii.o \
$(OBJ)/pcomm.o \
$(OBJ)/mensamod.o \
$(OBJ)/optionsm.o \
$(OBJ)/debugm.o
$(LINK)
The file is longer, but I dont know if it is needed to understand the error. The error I get when I run make over the directory is:
tcapelle$ gnumake
gfortran -o bin/pasos -Wl,-Map=bin/pasos.map obj/pasos.o obj/nodes.o obj/io_list.o obj/rcomm.o obj/tparc.o obj/zcomm.o obj/pcomm.o obj/getoptm.o obj/control.o obj/heap.o obj/gener.o obj/param.o obj/ascii.o obj/mensamod.o obj/optionsm.o obj/debugm.o
ld: unknown option: -Map=bin/pasos.map
collect2: error: ld returned 1 exit status
gnumake: *** [bin/pasos] Error 1
Edit:
I changed in the makefile
LINK=$(LN) $(LFLAGS) -o $# -Wl,-Map=$#.map $^
to
LINK=$(LN) $(LFLAGS) -o $# $^
and it compiles with some errors, but it worked.
What does this -Wl,-Map= thing do?
The problem is that the BSD linker (in contrast to the GNU linker) does not recognize options, if they are separated from the corresponding value by an equal sign (instead of a whitespace). So
ld -Map test.map
is fine, while
ld -Map=test.map
is not. Therefore, you must make sure, the compiler passes the linker options to the linker in the latter form. For that you need
gfortran -Wl,-Map,test.map ...
which you can achieve by changing the definition of the LINK variable to:
LINK=$(LN) $(LFLAGS) -o $# -Wl,-Map,$#.map $^

Argh, makefile won't pick up dependencies correctly

My simple little makefile is exhibiting behavior which I'm not able to understand. If I touch any source file except Dictionary.cpp then no targets are built, and if I touch Dictionary.cpp then it compiles but doesn't link. Source files are in src/ object (.o) and dependencies (.d) are in obj/ and binary goes into bin/
If I rm obj/* then everything builds OK but the timestamps don't seem to be being picked up. Can anyone tell me where I'm going wrong?
The .d files seem to be being created correctly, here's Dictionary.d:
obj/Dictionary.o: src/Dictionary.cpp src/pch.h src/Types.h src/Util.h \
src/Refcount.h src/Dictionary.h
src/Dictionary.cpp:
src/pch.h:
src/Types.h:
src/Util.h:
src/Refcount.h:
src/Dictionary.h:
Which looks correct to me. Here's the makefile:
sources = Dictionary.cpp \
Util.cpp \
Tile.cpp \
Board.cpp \
Vec2.cpp \
Letter.cpp \
Random.cpp \
Server.cpp \
main.cpp
objects = $(patsubst %.cpp,obj/%.o,$(sources))
depends = $(patsubst %.cpp,obj/%.d,$(sources))
CXX = g++
CPPFLAGS = -Isrc -std=c++0x
CXXFLAGS = -c
-include $(depends)
bin/dictionary: $(objects)
#echo Link...
$(CXX) $(CPPFLAGS) $(objects) -o bin/dictionary -lrt
obj/%.o: src/%.cpp
#echo [$*]
#$(CXX) $(CPPFLAGS) $(CXXFLAGS) src/$*.cpp -o obj/$*.o
#$(CXX) $(CPPFLAGS) -MM src/$*.cpp -MF obj/$*.d
#mv -f obj/$*.d obj/$*.d.tmp
#sed -e 's|.*:|obj/$*.o:|' < obj/$*.d.tmp > obj/$*.d
#sed -e 's/.*://' -e 's/\\$$//' < obj/$*.d.tmp | fmt -1 | sed -e 's/^ *//' -e ' s/$$/:/' >> obj/$*.d
#rm -f obj/$*.d.tmp
You have to move the include to the end, or put the bin/dictionary rule before it, or add an all: bin/dictionary rule before the include, or something.
Or, resign yourself to always running make bin/dictionary, which will work as well.
Remember make, by default, tries to build the first target in the makefile. Because you have the include line before any other target, the first target defined by an included file will be considered the default goal, and that happens to be obj/Dictionary.o.

Using make to generate bison grammar

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

Resources