我有以下项目结构:
test_main.cc
#define CATCH_CONFIG_MAIN
#include "catch2.hpp"
Run Code Online (Sandbox Code Playgroud)
测试1.cc
#include "catch2.hpp"
#include "test_utils.hpp"
TEST_CASE("test1", "[test1]") {
REQUIRE(1 == 1);
}
Run Code Online (Sandbox Code Playgroud)
测试2.cc
#include "catch2.hpp"
#include "test_utils.hpp"
TEST_CASE("test2", "[test2]") {
REQUIRE(2 == 2);
}
Run Code Online (Sandbox Code Playgroud)
test_utils.hpp
#pragma once
#include <iostream>
void something_great() {
std::cout << ":)\n";
}
Run Code Online (Sandbox Code Playgroud)
如果我使用类似的东西进行编译clang++ -std=c++17 test_main.cc test1.cc test2.cc,则该函数something_great在 test1.o 和 test2.o 中都有定义。这会导致类似的错误
duplicate symbol __Z15something_greatv in:
test1.cc.o
test2.cc.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Run Code Online (Sandbox Code Playgroud)
在Catch2 文档的Scaling Up部分,他们提到为了拆分您的测试,您可能想要
根据测试需要使用尽可能多的其他 cpp 文件(或任何您称之为实现文件的文件),但分区对您的工作方式最有意义。每个附加文件只需要 #include "catch.hpp"
但在文档的示例部分,我没有看到像我这样的用例。我阅读了这篇博客文章,其中描述了三种对我没有吸引力的解决方案:将函数定义为宏,或者将函数static或inline.
有没有另一种方法来编译这些文件,这些文件会生成一个具有由 定义的主函数的单个可执行文件test_main.cc?
这实际上与 Catch 或测试无关。当您#include使用 C++ 编写文件时,它会#include逐字复制粘贴到行中。如果您将自由函数定义放在头文件中,您会在构建实际程序等时看到这个问题。
根本的问题是,#include是不是同一种进口一个模块的指令作为是等效指令(import,require,等),在大多数的语言,做理智的事情是这样的(确认的情况下,该头是一样的我们已经看到并忽略了重复的方法定义)。
建议您编写的评论者inline在技术上是正确的,因为这将“解决您的问题”,因为您的编译器不会多次为该方法生成目标代码。然而,它并没有真正解释正在发生的事情或解决潜在的问题。
干净的解决方案是:
test_utils.hpp,用方法声明替换方法定义:void something_great();。test_utils.cc与方法(您目前的定义.hpp)。clang++ -std=c++17 test1.cc -cclang++ -std=c++17 test2.cc -cclang++ -std=c++17 test_main.cc -cclang++ -std=c++17 test_utils.cc -cclang++ -std=c++17 test1.o test2.o test_utils.o test_main.o我还建议您阅读以下内容:定义和声明之间有什么区别?
明确:
// test_utils.hpp
#pragma once
// This tells the compiler that when the final executable is linked,
// there will be a method named something_great which takes no arguments
// and returns void defined; the definition lives in test_utils.o in our
// case, although in practice the definition could live in any .o file
// in the final linking clang++ call.
void something_great();
Run Code Online (Sandbox Code Playgroud)
和:
// test_utils.cpp
#include "test_utils.hpp"
#include <iostream>
// Generates a DEFINITION for something_great, which
// will get put in test_utils.o.
void something_great() { std::cout << "Hi\n"; }
Run Code Online (Sandbox Code Playgroud)
每次对测试进行更改时,您似乎都担心“重新编译 Catch”。我不想告诉你,但你现在在 C++ 领域:你将毫无意义地重新编译很多东西。当包含它们的源文件发生变化时,像 Catch 这样的头文件库必须在一定程度上“重新编译”,因为无论好坏,如果源文件或从源文件传递地包含的头文件包含catch2.hpp,那么源代码catch2.hpp将读取该源文件时由编译器解析。
| 归档时间: |
|
| 查看次数: |
3792 次 |
| 最近记录: |