gpt4 book ai didi

c++ - 使用 Catch2 编译多个测试源的正确方法是什么?

转载 作者:太空狗 更新时间:2023-10-29 23:10:46 26 4
gpt4 key购买 nike

我有以下项目结构:

test_main.cc

#define CATCH_CONFIG_MAIN

#include "catch2.hpp"

test1.cc

#include "catch2.hpp"
#include "test_utils.hpp"

TEST_CASE("test1", "[test1]") {
REQUIRE(1 == 1);
}

test2.cc

#include "catch2.hpp"
#include "test_utils.hpp"

TEST_CASE("test2", "[test2]") {
REQUIRE(2 == 2);
}

test_utils.hpp

#pragma once
#include <iostream>

void something_great() {
std::cout << ":)\n";
}

如果我使用类似 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)

Scaling Up Catch2 文档的一部分,他们提到为了拆分您的测试,您可能需要

Use as many additional cpp files (or whatever you call your implementation files) as you need for your tests, partitioned however makes most sense for your way of working. Each additional file need only #include "catch.hpp"

但是在examples section of the documentation我没有看到像我这样的用例。我读了this blog post其中描述了三种对我没有吸引力的解决方案:将函数定义为宏,或者使函数成为staticinline

是否有另一种方法来编译这些文件,生成一个具有 test_main.cc 定义的主要函数的可执行文件?

最佳答案

这实际上与Catch 或测试无关。当您在 C++ 中 #include 一个文件时,它会被逐字复制粘贴到 #include 行。如果您将自由函数定义放在 header 中,您会在构建实际程序等时看到这个问题。

潜在的问题是 #include 与等效指令 (import, require 等)在大多数语言中,在这种情况下做理智的事情(确认 header 与我们已经看到的相同,并忽略重复的方法定义)。

建议您编写 inline 的评论者在技术上是正确的,因为这将“解决您的问题”,因为您的编译器不会多次为该方法生成目标代码。但是,它并没有真正解释正在发生的事情或解决根本问题。


干净的解决方案是:

  • test_utils.hpp 中,将方法定义替换为方法声明:void something_great();
  • 使用方法定义创建 test_utils.cc(您当前在 .hpp 中)。
  • clang++ -std=c++17 test1.cc -c
  • clang++ -std=c++17 test2.cc -c
  • clang++ -std=c++17 test_main.cc -c
  • clang++ -std=c++17 test_utils.cc -c
  • clang++ -std=c++17 test1.o test2.o test_utils.o test_main.o

我还建议您阅读以下内容:What is the difference between a definition and a declaration?

明确地:

// 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();

和:

// 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"; }

看来您每次对测试进行更改时都担心“重新编译 Catch”。我不想告诉你,但你现在在 C++ 领域:你将毫无意义地重新编译很多东西。当包含它们的源文件更改时,像 Catch 这样的仅 header 库必须在某种程度上“重新编译”,因为无论好坏,如果源文件或从源文件传递包含的头文件包含 catch2.hpp,然后 catch2.hpp 的源代码将在读取该源文件时由编译器解析。

关于c++ - 使用 Catch2 编译多个测试源的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55172815/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com