我正在尝试更新我的Makefile以支持构建我的项目的二进制文件,以及一些单元测试的二进制文件。
我的目录结构如下
|-code/
|--|--src/
|--|--inc/
|
|-tests/
|--|--src/
|--|--inc/
我的makefile很好地编译了代码中的二进制文件,但是测试时遇到了一些问题。测试文件夹包含一些单元测试,用于测试code / src /中的某些类。我在code / src /中有一个main.cpp文件,它包含main()函数,还有另一个文件,test / src中名为test.cpp,包含自己的main()函数。
这让我想到了这个复杂的Makefile:
CC = g++
FLAGS = -g -c -Wall
INCLUDEDIR = -Icode/inc -Itests/inc
BUILDDIR = build
SOURCEDIR = code/src
SOURCES = $(wildcard $(addsuffix /*.cpp,$(SOURCEDIR)))
TEMP_OBJ = $(SOURCES:%.cpp=%.o)
NOT_DIR = $(notdir $(TEMP_OBJ))
OBJECTS = $(addprefix $(BUILDDIR)/, $(NOT_DIR))
TEST_DIR = tests/src
TEST_SOURCES = $(wildcard $(addsuffix /*.cpp,$(TEST_DIR)))
TEST_TEMP_OBJ = $(TEST_SOURCES:%.cpp=%.o)
TEST_NOT_DIR = $(notdir $(TEST_TEMP_OBJ))
TEST_OBJECTS = $(addprefix $(BUILDDIR)/, $(TEST_NOT_DIR))
EXECUTABLE = Client
TEST_EXECUTABLE = TestUnit
all: $(BUILDDIR) $(BUILDDIR)/$(EXECUTABLE) $(BUILDDIR)/$(TEST_EXECUTABLE)
$(BUILDDIR):
mkdir -p $@
$(BUILDDIR)/$(EXECUTABLE): $(OBJECTS)
$(CC) $^ -o $@
$(BUILDDIR)/%.o : code/src/%.cpp
$(CC) $(FLAGS) $< $(INCLUDEDIR) -o $@
$(BUILDDIR)/$(TEST_EXECUTABLE): $(OBJECTS) $(TEST_OBJECTS)
@rm -f $(BUILDDIR)/main.o
$(CC) $^ -o $@
$(BUILDDIR)/%.o : tests/src/%.cpp
$(CC) $(FLAGS) $< $(INCLUDEDIR) -o $@
clean:
rm -rf $(BUILDDIR)
失败并显示错误:
g++: error: build/main.o: No such file or directory
make: *** [build/TestUnit] Error 1
这是因为我有这条线:
@rm -f $(BUILDDIR)/main.o
但否则我会得到错误(main.cpp和test.cpp中的main分别位于code / src /和tests / code /中):
/tests/src/test.cpp:7: multiple definition of `main'
code/src/main.cpp:6: first defined here
collect2: error: ld returned 1 exit status
我的Makefile中有很多重复,我希望得到一些更简洁的东西来实现从这两个文件夹构建2个二进制文件的目的,尽管代码是共享的。
任何帮助都将不胜感激。非常感谢你!
答案 0 :(得分:1)
此makefile存在许多问题。
首先,没有规则来构建测试对象文件,例如test.o
。构建对象的唯一规则要求源位于code/src/
;我不知道你怎么能够看到链接器错误。
让我们将对象规则更改为静态模式规则:
$(OBJECTS) : $(BUILDDIR)/%.o : code/src/%.cpp
$(CC) $(FLAGS) $< $(INCLUDEDIR) -o $@
然后我们可以为测试对象添加一个额外的规则:
$(TEST_OBJECTS) : $(BUILDDIR)/%.o : tests/src/%.cpp
$(CC) $(FLAGS) $< $(INCLUDEDIR) -o $@
(别担心现在的冗余 - 我们必须先让它工作。)
现在我们应该在此规则中看到链接器错误:
$(BUILDDIR)/$(TEST_EXECUTABLE): $(OBJECTS) $(TEST_OBJECTS)
...
在该先决条件列表中有两个文件,main.o
和test.o
争夺谁来定义main()
。我们需要test.o
,因此main.o
必须:
$(BUILDDIR)/$(TEST_EXECUTABLE): $(filter-out build/main.o,$(OBJECTS)) $(TEST_OBJECTS)
...
试试这个并告诉我们结果。一旦它工作,我们可以减少它。