I have an included file for a makefile that has these rules:
$(OUT_DIR)/%.0: %.c
$(CC) $(CFLAGS) -c -o $# $<
$(CC) $(CFLAGS) -E -P $< -o $(OUT_DIR)/$<.preproc
$(CC) $(CFLAGS) -E -dD $< -o $(OUT_DIR)/$<.macros
Works great. But, for some targets, I only want this:
$(OUT_DIR)/%.0: %.c
$(CC) $(CFLAGS) -c -o $# $<
can I do something like this using a predefined (or command line) variable:
$(OUT_DIR)/%.0: %.c
$(CC) $(CFLAGS) -c -o $# $<
ifeq ($(CIFLAG), 1)
$(CC) $(CFLAGS) -E -P $< -o $(OUT_DIR)/$<.preproc
$(CC) $(CFLAGS) -E -dD $< -o $(OUT_DIR)/$<.macros
endif
I'm sure I can include a different file based on the CIFLAG value, but was hoping I could do it by modifying the pattern rule.
Any ideas?
Thanks!
I did as MadScientist suggested (thanks for the education) but don't get what I want. My file now appears as:
$(OUT_DIR)/%.0: %.c
$(CC) $(CFLAGS) -c -o $# $<
[ $(CI_BUILD) -eq 0 ] \
|| {$(CC) $(CFLAGS) -E -P $< -o $(OUT_DIR)/$<.preproc \
&& $(CC) $(CFLAGS) -E -dD $< -o $(OUT_DIR)/$<.macros; }
But, when I execute, I get this (lots of irrelevant output trimmed):
cc -c -o test.o
[ 1 -eq 0 ] \
|| {cc -E -P test.c -o test.c.preproc \
&& cc -E -dD test.c -o test.c.macros; }
/bin/sh: -c: line 2: syntax error near unexpected token '}'
Is the ';' a problem?
You mustn't indent the Make conditional with tabs:
$(OUT_DIR)/%.0: %.c
$(CC) $(CFLAGS) -c -o $# $<
ifeq ($(CIFLAG), 1)
$(CC) $(CFLAGS) -E -P $< -o $(OUT_DIR)/$<.preproc
$(CC) $(CFLAGS) -E -dD $< -o $(OUT_DIR)/$<.macros
endif
See bullet 4: https://www.gnu.org/software/make/manual/html_node/Recipe-Syntax.html
You cannot use make conditionals like ifeq in the recipe passed to the shell, because the shell runs the recipe not make. You can use shell conditionals:
$(OUT_DIR)/%.0: %.c
$(CC) $(CFLAGS) -c -o $# $<
[ ($(CIFLAG) -ne 1 ] \
|| { $(CC) $(CFLAGS) -E -P $< -o $(OUT_DIR)/$<.preproc \
&& $(CC) $(CFLAGS) -E -dD $< -o $(OUT_DIR)/$<.macros; }
Of course, you haven't discussed how you plan to set the CIFLAG variable for some targets but not others...
I was able to make it work by changing the code to:
$(OUT_DIR)/%.0: %.c
$(CC) $(CFLAGS) -c -o $# $<
if [ ($(CIFLAG) -ne 1 ]; then \
$(CC) $(CFLAGS) -E -P $< -o $(OUT_DIR)/$<.preproc; \
$(CC) $(CFLAGS) -E -dD $< -o $(OUT_DIR)/$<.macros; fi
Related
Executing make fails because it cannot find the previously defined rule in the make file. Also the "dir" rule only works if I use "make dir" but when I added it to the composed rule it lists the files in the working directory....
make test_tester
dir
base_types.c dynamic_array.c gists hashtable.c linked_list.c Makefile Makefile_OLD object.c object_table.c out.txt READ_THIS.txt sstring.c tester.c tests ttime.c
build/test_tester.o
make: build/test_tester.o: Command not found
Makefile:7: recipe for target 'test_tester' failed
make: *** [test_tester] Error 127
CC=gcc
CFLAGS=-Wall -I ../include
TEST_DIR=tests
BUILD_DIR=build
test_tester:
dir
$(BUILD_DIR)/test_tester.o
$(BUILD_DIR)/tester.o
$(BUILD_DIR)/base_types.o
$(BUILD_DIR)/object.o
$(BUILD_DIR)/sstring.o
$(CC) $(CFLAGS) $(BUILD_DIR)/test_tester.o $(BUILD_DIR)/tester.o $(BUILD_DIR)/base_types.o \
$(BUILD_DIR)/object.o $(BUILD_DIR)/sstring.o
$(BUILD_DIR)/test_tester.o:
$(CC) $(CFLAGS) -c $(TEST_DIR)/test_tester.c -o $#
$(BUILD_DIR)/tester.o: tester.c
$(CC) $(CFLAGS) -c tester.c -o $#
$(BUILD_DIR)/base_types.o: base_types.c
$(CC) $(CFLAGS) -c base_types.c -o $#
$(BUILD_DIR)/object.o: object.c
$(CC) $(CFLAGS) -c object.c -o $#
$(BUILD_DIR)/sstring.o: sstring.c
$(CC) $(CFLAGS) -c sstring.c -o $#
dir: mkdir -p $(BUILD_DIR)
.PHONY: clean
clean:
rm -f $(BUILD_DIR)/*.o
I figured it out thanks.
CC=gcc
CFLAGS=-Wall -I ../include
TEST_DIR=tests
BUILD_DIR=build
test_tester: dir test_tester.o tester.o base_types.o object.o sstring.o
$(CC) $(CFLAGS) $(BUILD_DIR)/test_tester.o $(BUILD_DIR)/tester.o $(BUILD_DIR)/base_types.o $(BUILD_DIR)/object.o $(BUILD_DIR)/sstring.o -o $#
test_tester.o:
$(CC) $(CFLAGS) -c $(TEST_DIR)/test_tester.c -o $(BUILD_DIR)/$#
tester.o: tester.c
$(CC) $(CFLAGS) -c tester.c -o $(BUILD_DIR)/$#
base_types.o: base_types.c
$(CC) $(CFLAGS) -c base_types.c -o $(BUILD_DIR)/$#
object.o: object.c
$(CC) $(CFLAGS) -c object.c -o $(BUILD_DIR)/$#
sstring.o: sstring.c
$(CC) $(CFLAGS) -c sstring.c -o $(BUILD_DIR)/$#
dir:
mkdir -p $(BUILD_DIR)
.PHONY: clean
clean:
rm -fr $(BUILD_DIR)
I have a binary that I need to build multiple times with different compiler flags. Therefore, I have a Makefile that states something like:
OBJECTS_A := $(addprefix $(OBJFOLDER)/, $(SOURCES:.cpp=.a.o))
OBJECTS_B := $(addprefix $(OBJFOLDER)/, $(SOURCES:.cpp=.b.o))
OBJECTS_C := $(addprefix $(OBJFOLDER)/, $(SOURCES:.cpp=.c.o))
I also define a rule to change the flags for each OBJECTS_x:
$(OBJECTS_B): DEFINES+=-D_B
$(OBJECTS_C): DEFINES+=-D_C
And this is where the problem happens: If I state the targets separately, as:
$(OBJFOLDER)/%.a.o: %.cpp
$(COMPILER) $(CFLAGS) $(INCFOLDER) $(DEFINES) -c $< -o $#
$(OBJFOLDER)/%.b.o: %.cpp
$(COMPILER) $(CFLAGS) $(INCFOLDER) $(DEFINES) -c $< -o $#
$(OBJFOLDER)/%.c.o: %.cpp
$(COMPILER) $(CFLAGS) $(INCFOLDER) $(DEFINES) -c $< -o $#
All works. However, if I merge all rules into one, only the first is evaluated:
$(OBJFOLDER)/%.a.o $(OBJFOLDER)/%.b.o $(OBJFOLDER)/%.c.o: %.cpp
$(COMPILER) $(CFLAGS) $(INCFOLDER) $(DEFINES) -c $< -o $#
What I get on a dry run is that only $(OBJFOLDER)/%.a.o objects are build, but on the linking rule each binary requires its objects (and b and c binaries fail to build, therefore).
Any ideas?
Thank you!
You can achieve this using secondary expansion :
.SECONDEXPANSION:
$(OBJFOLDER)/%.o: $$(basename $$*).cpp
$(COMPILER) $(CFLAGS) $(INCFOLDER) $(DEFINES) -c $< -o $#
Note that this is not a very idiomatic way of doing this, a more usual define / call / eval combo can be used to generate rules as in your first solution :
VARIANTS=a b c
DEFINES_FOR_a=
DEFINES_FOR_b=-D_B
DEFINES_FOR_c=-D_C
define make_target =
$$(OBJFOLDER)/%.$(1).o: %.cpp
$$(COMPILER) $$(CFLAGS) $$(INCFOLDER) $$(DEFINES_FOR_$(1)) -c $$< -o $$#
endef
$(eval $(foreach variant,$(VARIANTS),$(call make_target,$(variant))))
Another way is to create symlinks to your source files and compile those with different flags. This way the same one generic pattern rule (OBJFOLDER)/%.o: %.cpp can build all of your targets:
OBJECTS_A := $(SOURCES:%.cpp=$(OBJFOLDER)/%.a.o)
OBJECTS_B := $(SOURCES:%.cpp=$(OBJFOLDER)/%.b.o)
OBJECTS_B := $(SOURCES:%.cpp=$(OBJFOLDER)/%.c.o)
$(OBJECTS_B): DEFINES+=-D_B
$(OBJECTS_C): DEFINES+=-D_C
%.a.cpp : %.cpp
ln -s $< $#
%.b.cpp : %.cpp
ln -s $< $#
%.c.cpp : %.cpp
ln -s $< $#
$(OBJFOLDER)/%.o: %.cpp
$(COMPILER) $(CFLAGS) $(INCFOLDER) $(DEFINES) -c -o $# $<
I'm playing with makefile for class project.
(1) I need to create debug rule. But I don't know how to give specific names to object files that I need (do I need?) to create that debug-enabled executable.
(2)I assume file can be further reduced to fewer lines of code. Could you suggest how?
This is my makefile:
CC = gcc
CFLAGS = -Wall -Wextra -std=c11
OBJ = hospital.o parse.o structure.o description.o patientList.o diseaseList.o
DOBJ = hospital.dbg.o parse.dbg.o structure.dbg.o description.dbg.o patientList.dbg.o diseaseList.dbg.o
all: hospital
hospital: $(OBJ)
$(CC) $^ -o $#
hospital.o: hospital.c structure.h
$(CC) $(CFLAGS) -c $^
parse.o: parse.c parse.h
$(CC) $(CFLAGS) -c $^
structure.o: structure.c structure.h
$(CC) $(CFLAGS) -c $^
patientList.o: patientList.c patientList.h
$(CC) $(CFLAGS) -c $^
diseaseList.o: diseaseList.c diseaseList.h
$(CC) $(CFLAGS) -c $^
description.o: description.c description.h
$(CC) $(CFLAGS) -c $^
debug: $(DOBJ)
$(CC) $^ -o hospital.dbg
hospital.dbg.o: hospital.c
$(CC) $(CFLAGS) -g $# $< -c
parse.dbg.o: parse.c parse.h
$(CC) $(CFLAGS) -g $# $< -c
structure.dbg.o: structure.c structure.h
$(CC) $(CFLAGS) -g $# $< -c
patientList.dbg.o: patientList.c patientList.h
$(CC) $(CFLAGS) -g $# $< -c
diseaseList.dbg.o: diseaseList.c diseaseList.h
$(CC) $(CFLAGS) -g $# $< -c
description.dbg.o: description.c description.h
$(CC) $(CFLAGS) -g $# $< -c
clean:
rm *.o hospital.dbg hospital *~
.PHONY: all clean
Thanks
I've the following situation:
SOURCES=home/main.cpp modelChecking/Configuracao.cpp modelChecking/Estado.cpp modelChecking/Formula.cpp modelChecking/ModelChecking.cpp lib/VisitTree.cpp
SUFIX=$(SOURCES:.cpp=.o)
OBJECTS=$(SUFIX)
all: refiner
refiner: $(OBJECTS)
$(CC) $^ -o refiner
home/main.o: home/main.cpp
$(CC) $(CFLAGS) $< -o $#
modelChecking/Configuracao.o: modelChecking/Configuracao.cpp
$(CC) $(CFLAGS) $< -o $#
modelChecking/Estado.o: modelChecking/Estado.cpp
$(CC) $(CFLAGS) $< -o $#
...
...and so on.
As you can see, I have different directories to compile my executable.
Now, I want to put every file .o in the bin/ folder and the variable OBJECT must replace the every parent directory, and I tried different ways:
OBJECTS=$(SUFIX:%/ = bin/)
OBJECTS=$(subst %/,bin/,$(SUFIX))
OBJECTS=$(patsubst %/,bin/,$(SUFIX))
When I use something like this $(subst home/,bin/,$(SUFIX)) it works, because I type the substring "home/", but I need of a regular expression to replace all directories.
And I'll need to change the target too, perhaps the code below will works:
%.o: %.cpp
$(CC) $(CFLAGS) $< -o $#
... But I prefer every target separate
You are looking for SUFIX=$(addprefix bin/,$(notdir $(SOURCES:.cpp=.o)))
The Makefile will look like:
SOURCES=home/main.cpp modelChecking/Configuracao.cpp
SUFIX=$(addprefix bin/,$(notdir $(SOURCES:.cpp=.o)))
OBJECTS=$(SUFIX)
all: refiner
refiner: $(OBJECTS)
$(CC) $^ -o refiner
bin/main.o: home/main.cpp
$(CC) $(CFLAGS) -c $< -o $#
bin/Configuracao.o: modelChecking/Configuracao.cpp
$(CC) $(CFLAGS) -c $< -o $#
However I suggest to use SUBDIRS instead. Create to Makefiles
Makefile
SUBDIRS = bin
.PHONY: subdirs $(SUBDIRS)
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $#
bin/Makefile
SOURCES=../home/main.cpp ../modelChecking/Configuracao.cpp
SUFIX=$(addprefix bin/,$(notdir $(SOURCES:.cpp=.o)))
OBJECTS=$(SUFIX)
all: refiner
refiner: $(OBJECTS)
$(CC) $^ -o refiner
main.o: ../home/main.cpp
$(CC) $(CFLAGS) -c $< -o $#
Configuracao.o: ../modelChecking/Configuracao.cpp
$(CC) $(CFLAGS) -c $< -o $#
This way you will not have to worry about object prefix.
Can anybody please explain the meaning of $< and $# in a Makefile?
$< evaluates to the first "prerequisite" in the make rule, and $# evaluates to the "target" in the make rule.
Here's an example:
file.o : file.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $#
In this case, $< will be replaced with file.c and $# will be file.o.
These are more useful in generic rules like this:
%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $#
See this manual for more info.
$# is the target of the current rule.
$< is the name of the first prerequisite ("source") of the current rule.
So for example:
.c.o:
$(CC) -c $(CFLAGS) -o $# $<
This will expand to a command something like:
gcc -c -Wall -o foo.o foo.c
See also the GNU make manual ยง 10.5.3, "Automatic Variables".