我正在尝试构建我的项目以包含生产源(在 src
子文件夹中)和测试(在 test
子文件夹中)。我正在使用 CMake 来构建它。作为一个最小的例子,我有以下文件:
CMakeLists.txt:
cmake_minimum_required (VERSION 2.8)
project (TEST)
add_subdirectory (src)
add_subdirectory (test)
src/CMakeLists.txt:
add_executable (demo main.cpp sqr.cpp)
src/sqr.h
#ifndef SQR_H
#define SQR_H
double sqr(double);
#endif // SQR_H
src/sqr.cpp
#include "sqr.h"
double sqr(double x) { return x*x; }
src/main.cpp - 使用 sqr,没关系
测试/CMakeLists.txt:
find_package(Boost COMPONENTS system filesystem unit_test_framework REQUIRED)
include_directories (${TEST_SOURCE_DIR}/src)
ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK)
add_executable (test test.cpp ${TEST_SOURCE_DIR}/src/sqr.cpp)
target_link_libraries(test
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
)
enable_testing()
add_test(MyTest test)
测试/test.cpp:
#define BOOST_TEST_MODULE SqrTests
#include <boost/test/unit_test.hpp>
#include "sqr.h"
BOOST_AUTO_TEST_CASE(FailTest)
{
BOOST_CHECK_EQUAL(5, sqr(2));
}
BOOST_AUTO_TEST_CASE(PassTest)
{
BOOST_CHECK_EQUAL(4, sqr(2));
}
几个问题:
这种结构有意义吗?构建此代码时的最佳实践是什么? (我来自 C# 和 java,从某种意义上说它更容易)我不喜欢必须在 test/CMakeLists.txt 文件中列出 src 文件夹中的所有文件的事实。如果这是一个图书馆项目,我只会链接图书馆。有没有办法避免列出来自其他项目的所有 cpp 文件? enable_testing() 和 add_test(MyTest test) 这行在做什么?我没有看到任何效果。如何从 CMake(或 CTest)运行测试?到目前为止,我刚刚跑了 cmake 。在根文件夹中,但这会在各处造成临时文件的混乱。如何以合理的结构获得编译结果?
对于问题 1 和 2,我建议从您的非测试文件中创建一个库,不包括 main.cpp(在这种情况下只是 src/sqr.cpp 和 src/sqr.h),然后您可以避免列出(更重要的是重新编译)所有源代码两次。
对于问题 3,这些命令会添加一个名为“MyTest”的测试,它会调用您的可执行文件“test”而无需任何参数。但是,由于您已将这些命令添加到 test/CMakeLists.txt 而不是您的顶级 CMakeLists.txt,因此您只能从构建树的“test”子目录中调用测试(尝试 cd test && ctest -N
)。如果您希望可以从顶级构建目录运行测试,则需要从顶级 CMakeLists.txt 调用 add_test
。这也意味着您必须使用更详细的 add_test
形式,因为您的测试 exe 没有在同一个 CMakeLists.txt 中定义
在您的情况下,由于您在根文件夹中运行 cmake,因此您的构建树和源代码树是一回事。这被称为源内构建,并不理想,这导致了问题 4。
生成构建树的首选方法是进行源外构建,即在源代码树之外的某个位置创建一个目录并从那里执行 cmake。即使在项目的根目录中创建一个“构建”目录并执行 cmake ..
也会提供一个不会干扰源代码树的干净结构。
最后一点是避免调用可执行文件“测试”(区分大小写)。原因见this answer。
为了实现这些更改,我将执行以下操作:
CMakeLists.txt:
cmake_minimum_required (VERSION 2.8)
project (TEST)
add_subdirectory (src)
add_subdirectory (test)
enable_testing ()
add_test (NAME MyTest COMMAND Test)
src/CMakeLists.txt:
add_library (Sqr sqr.cpp sqr.h)
add_executable (demo main.cpp)
target_link_libraries (demo Sqr)
测试/CMakeLists.txt:
find_package (Boost COMPONENTS system filesystem unit_test_framework REQUIRED)
include_directories (${TEST_SOURCE_DIR}/src
${Boost_INCLUDE_DIRS}
)
add_definitions (-DBOOST_TEST_DYN_LINK)
add_executable (Test test.cpp)
target_link_libraries (Test
Sqr
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
)
我喜欢@Fraser 的示例,但会在 test/CMakeLists.txt 中使用 add_test 命令,并在 add_subdirectory(test) 之前使用 enable_testing。
这样,您可以从顶级构建目录运行测试,同时在 test/CMakeLists.txt 中指定测试。
结果将如下所示(我重用了@Fraser 的示例):
CMakeLists.txt
cmake_minimum_required (VERSION 2.8)
project (TEST)
add_subdirectory (src)
enable_testing ()
add_subdirectory (test)
src/CMakeLists.txt
add_library (Sqr sqr.cpp sqr.h)
add_executable (demo main.cpp)
target_link_libraries (demo Sqr)
测试/CMakeLists.txt
find_package (Boost COMPONENTS system filesystem unit_test_framework REQUIRED)
include_directories (${TEST_SOURCE_DIR}/src
${Boost_INCLUDE_DIRS}
)
add_definitions (-DBOOST_TEST_DYN_LINK)
add_executable (Test test.cpp)
target_link_libraries (Test
Sqr
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
)
add_test (NAME MyTest COMMAND Test)
ctest -N
显示任何测试。
project (TEST)
时由 CMake 自动设置 - 请参阅 cmake.org/cmake/help/v3.6/variable/PROJECT-NAME_SOURCE_DIR.htmladd_test
的情况下有效地添加它们?