0

我正在尝试更新我的 Makefile 以支持构建我的项目的二进制文件和一些单元测试的二进制文件。

我的目录结构如下

|-code/
|--|--src/
|--|--inc/
|
|-tests/
|--|--src/
|--|--inc/

我的 makefile 可以很好地从代码编译二进制文件,但在测试时遇到了一些问题。test 文件夹包含一些单元测试,用于测试 code/src/ 中的某些类。我在 code/src/ 中有一个包含 main() 函数的文件 main.cpp,还有另一个名为 test.cpp 在 tests/src 中的文件,它包含自己的 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 分别在 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 个文件夹构建 2 个二进制文件的目的。

任何帮助将不胜感激。非常感谢!

4

1 回答 1

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)
    ...

试试这个,告诉我们结果。一旦它起作用了,我们就可以把它瘦下来。

于 2013-07-31T20:31:01.260 回答