CMake:带有单元测试的项目结构


139

我正在尝试构建项目以包括生产源(在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 / 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));
}

几个问题:

  1. 这种结构有意义吗?构建此代码时的最佳做法是什么?(我来自C#和Java,从某种意义上讲,它更容易实现)
  2. 我不喜欢必须从src文件中的test/CMakeLists.txt文件夹列出所有文件的事实。如果这是一个图书馆项目,我将链接图书馆。有没有办法避免列出另一个项目中的所有cpp文件?
  3. 哪些线路enable_testing()add_test(MyTest test)在干什么?我没有看到任何效果。如何从CMake(或CTest)运行测试?
  4. 到目前为止,我只是运行cmake .在根文件夹中,但是这到处都是临时文件。如何获得合理结构的编译结果?

我认为自己是CMake的新手,所以我不知道公认的最佳实践是什么,但是FWIW我将创建一个“ sqr”库*,它既依赖于主程序,也依赖于测试。(*或等同于道德的)
user786653

Answers:


125

对于问题1和问题2,我建议您使用非测试文件(不包括main.cpp(在本例中仅是src / sqr.cpp和src / sqr.h))制作一个库,这样您就可以避免列出(更重要的是,重新编译)所有源两次。

对于问题3,这些命令添加了一个名为“ MyTest”的测试,该测试将在不带任何参数的情况下调用可执行文件“ test”。但是,由于已将这些命令添加到test / CMakeLists.txt而不是顶级CMakeLists.txt,因此只能在构建树的“ test”子目录中调用测试(try cd test && ctest -N)。如果您想从顶层构建目录中运行测试,则需要add_test从顶层CMakeLists.txt 调用。这也意味着您必须使用更详细的形式,add_test因为您的测试exe不在同一CMakeLists.txt中定义

就您而言,由于您在根文件夹中运行cmake,因此您的构建树和源树是相同的。这被称为源内构建,但并不理想,这导致了问题4。

生成构建树的首选方法是执行源外构建,即在源树之外的某个地方创建目录并从那里执行cmake。即使在项目的根目录中创建一个“ build”目录并执行,cmake ..也将提供一个干净的结构,不会干扰您的源代码树。

最后一点是避免将可执行文件称为“测试”(区分大小写)。由于某些原因,请参见此答案

为了实现这些更改,我将执行以下操作:

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

2
我只是注意到您也将.h文件相应地添加到了CMakeLists.txt文件中。需要吗?如果我把它们留在外面怎么办?
Grzenio 2013年

3
@Grzenio这只是一项便利功能-它们像MSVC一样出现在IDE中,成为目标的一部分,但否则无效。
Fraser

1
TEST_SOURCE_DIR设置在哪里?
aggsol

6
调用时由CMake自动设置project (TEST)-请参见cmake.org/cmake/help/v3.6/variable/PROJECT-NAME_SOURCE_DIR.html
Fraser,

>它们像目标的一部分一样出现在IDE中,就像MSVC一样--- MSVC不支持将带有标头的目录标记为“包含目录”吗?
notullxbh 18-10-26

46

我喜欢@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)

1
谢谢,ctest -N直到您添加子目录之前启用测试的提示,我才显示任何测试。
alaferg '16

@alaferg:否则,它们将最终出现在构建目录中的test子目录中。
gauteh

4
我希望CMake的结构类似。
ruipacheco
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.