In the following Makefile, I'm modifying the content of $(SRC) based on whether the target rule is 'test'. This rule is supposed to be for unit testing.
My objects are built with the implicit ruleOBJ = $(SRC:.cpp=.o)
but when building the object, even if the SRC variable changes, it always uses its default value. Here is the Makefile :
CC = g++
SRC_DIR = src
SRC_TEST_DIR = tests/src
INC_DIR = include/
test: INC_DIR += tests/include/
SRC_MAIN = $(SRC_DIR)/main.cpp
test: SRC_MAIN = $(SRC_TEST_DIR)/main.cpp
SRC = $(SRC_MAIN) \ # <=== The value that changes in SRC
$(SRC_DIR)/minicalc.cpp \
$(SRC_DIR)/io.cpp
OBJ = $(SRC:.cpp=.o)
CPPFLAGS += -I$(INC_DIR) -g -Wall -Wextra
test: LDFLAGS += -lcppunit
OUT = minicalc
test: OUT = tests/tests
all: $(OBJ)
# DEBUG :
@echo SRC: '$(SRC)'
@echo OBJ: '$(OBJ)'
$(CC) $(OBJ) -o $(OUT) $(LDFLAGS)
test: all
ls $(OUT) && ./$(OUT)
Here are the outputs :make
gives expected output with default value of SRC :
g++ -Iinclude/ -g -Wall -Wextra -c -o src/main.o src/main.cpp
g++ -Iinclude/ -g -Wall -Wextra -c -o src/minicalc.o src/minicalc.cpp
g++ -Iinclude/ -g -Wall -Wextra -c -o src/io.o src/io.cpp
SRC: src/main.cpp src/minicalc.cpp src/io.cpp
OBJ src/main.o src/minicalc.o src/io.o
g++ src/main.o src/minicalc.o src/io.o -o minicalc
But make test
doesn't build test/src/main.o even if it is in SRC :
g++ -Iinclude/ -g -Wall -Wextra -c -o src/main.o src/main.cpp
g++ -Iinclude/ -g -Wall -Wextra -c -o src/minicalc.o src/minicalc.cpp
g++ -Iinclude/ -g -Wall -Wextra -c -o src/io.o src/io.cpp
SRC: tests/src/main.cpp src/minicalc.cpp src/io.cpp
OBJ: tests/src/main.o src/minicalc.o src/io.o
g++ tests/src/main.o src/minicalc.o src/io.o -o tests/tests -lcppunit
g++: error: tests/src/main.o: No such file or directory
make: *** [Makefile:41: all] Error 1
all
requires $(OBJ)
, but the object created are not corresponding to the content of the $(SRC)
variable
Not using the implicit .cpp.o rules by doing it manually WORKS :
Same Makefile but replaced $(OBJ)
by the rule create_obj
CC = g++
SRC_DIR = src
SRC_TEST_DIR = tests/src
INC_DIR = include/
test: INC_DIR += tests/include/
SRC_MAIN = $(SRC_DIR)/main.cpp
test: SRC_MAIN = $(SRC_TEST_DIR)/main.cpp
SRC = $(SRC_MAIN) \
$(SRC_DIR)/minicalc.cpp \
$(SRC_DIR)/io.cpp
OBJ = $(SRC:.cpp=.o)
CPPFLAGS += -I$(INC_DIR) -g -Wall -Wextra
test: LDFLAGS += -lcppunit
OUT = minicalc
test: OUT = tests/tests
all: create_obj
# DEBUG :
@echo SRC: '$(SRC)'
@echo obj: '$(OBJ)'
$(CC) $(OBJ) -o $(OUT) $(LDFLAGS)
create_obj:
@echo Crafting Files:
@$(foreach file, $(SRC), \
echo $(file),; \
$(CC) -c $(file) -o $(file:.cpp=.o) $(CPPFLAGS) $(LDFLAGS); \
)
test: all
ls $(OUT) && ./$(OUT)
Here are the outputs :make
:
Crafting Files:
src/main.cpp,
src/minicalc.cpp,
src/io.cpp,
SRC: src/main.cpp src/minicalc.cpp src/io.cpp
OBJ: src/main.o src/minicalc.o src/io.o
g++ src/main.o src/minicalc.o src/io.o -o minicalc
make test
Crafting Files:
tests/src/main.cpp,
src/minicalc.cpp,
src/io.cpp,
SRC: tests/src/main.cpp src/minicalc.cpp src/io.cpp
OBJ tests/src/main.o src/minicalc.o src/io.o
g++ tests/src/main.o src/minicalc.o src/io.o -o tests/tests -lcppunit
ls tests/tests && ./tests/tests
tests/tests
OK (0)
Why does the implicit building of my objects not change when changing my sources, while doing it manually works ?