美文网首页
CMake使用教程(三)

CMake使用教程(三)

作者: 张坤的笔记 | 来源:发表于2019-11-19 15:55 被阅读0次

    CMake 是一种跨平台的免费开源软件工具,用于使用与编译器无关的方法来管理软件的构建过程。在 Android Studio 上进行 NDK 开发默认就是使用 CMake 管理 C/C++ 代码,因此在学习 NDK 之前最好对 CMake 有一定的了解。

    本文主要以翻译 CMake官方教程文档为主,加上自己的一些理解,该教程涵盖了 CMake 的常见使用场景。由于能力有限,翻译部分采用机翻+人工校对,翻译有问题的地方,说声抱歉。

    开发环境:

    • macOS 10.14.6
    • CMake 3.15.1
    • CLion 2018.2.4

    指定编译定义

    示例程序地址

    在上一步 “系统自检” 中,除了在 TutorialConfig.h 中保存 HAVE_LOGHAVE_EXP 值之外,还有更好的做法吗?对于此示例,我们将尝试使用 target_compile_definitions

    首先,从 TutorialConfig.h.in 中删除上一步的定义,在 mysqrt.cxx 中不再包含 TutorialConfig.h,移除上一步在 MathFunctions/CMakeLists.txt 中增加的额外包含。

    接下来,我们可以将 HAVE_LOGHAVE_EXP 的检查移至 MathFunctions/CMakeLists.txt,然后添加将这些值指定为 PRIVATE 编译定义。

    # does this system provide the log and exp functions?
    # 该系统是否提供log和exp函数?
    include(CheckSymbolExists)
    set(CMAKE_REQUIRED_LIBRARIES "m")
    check_symbol_exists(log "math.h" HAVE_LOG)
    check_symbol_exists(exp "math.h" HAVE_EXP)
    
    if(HAVE_LOG AND HAVE_EXP)
      target_compile_definitions(MathFunctions
                                 PRIVATE "HAVE_LOG" "HAVE_EXP")
    endif()
    

    完成这些更新后,在项目根目录运行命令编译项目和生成可执行文件:

    cmake -B cmake-build-debug
    cmake --build cmake-build-debug
    

    在项目根目录运行生成的可执行文件:

    ./cmake-build-debug/Tutorial 2
    

    终端输出:

    Computing sqrt of 2 to be 1.41421 using log and exp
    The square root of 2 is 1.41421
    

    添加自定义命令和生成的文件

    示例程序地址

    假设,出于本教程的目的,我们决定不再使用平台日志和exp函数,而是希望生成一个可在 mysqrt 函数中使用的预计算值表。在本节中,我们将在构建过程中创建表,然后将该表编译到我们的应用程序中。

    首先,让我们取消对 MathFunctions/CMakeLists.txt 中的 logexp 函数的检查。然后从 mysqrt.cxx 中删除对 HAVE_LOGHAVE_EXP 的检查。同时,我们可以删除 #include <cmath>

    MathFunctions 子目录中,提供了一个名为 MakeTable.cxx 的新源文件来生成表。

    // A simple program that builds a sqrt table
    #include <cmath>
    #include <fstream>
    #include <iostream>
    
    int main(int argc, char *argv[]) {
        // make sure we have enough arguments
        if (argc < 2) {
            return 1;
        }
    
        std::ofstream fout(argv[1], std::ios_base::out);
        const bool fileOpen = fout.is_open();
        if (fileOpen) {
            fout << "double sqrtTable[] = {" << std::endl;
            for (int i = 0; i < 10; ++i) {
                fout << sqrt(static_cast<double>(i)) << "," << std::endl;
            }
            // close the table with a zero
            fout << "0};" << std::endl;
            fout.close();
        }
        return fileOpen ? 0 : 1; // return 0 if wrote the file
    }
    

    我们可以看到生成的表不是简单的文本,而是一段C++代码。并且该文件的文件名是由参数传入决定的。

    下一步是将适当的命令添加到 MathFunctions/CMakeLists.txt 文件中,以构建MakeTable 可执行文件,然后在构建过程中运行它。需要一些命令来完成此操作。

    首先,在 MathFunctions/CMakeLists.txt 的顶部,添加 MakeTable 的可执行文件,就像添加任何其他可执行文件一样。

    # first we add the executable that generates the table
    # 首先,我们添加生成表的可执行文件
    add_executable(MakeTable MakeTable.cxx)
    

    然后,我们添加一个自定义命令,该命令指定如何通过运行 MakeTable 来产生 Table.h

    # add the command to generate the source code
    # 添加命令以生成源代码
    add_custom_command(
            OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
            COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
            DEPENDS MakeTable
    )
    

    接下来,我们必须让 CMake 知道 mysqrt.cxx 依赖生成的文件 Table.h。这是通过将生成的 Table.h 添加到库 MathFunctions 的源列表中来完成的。

    # add the main library
    # 添加主库
    add_library(MathFunctions
            mysqrt.cxx
            ${CMAKE_CURRENT_BINARY_DIR}/Table.h
            )
    

    我们还必须将当前的二进制目录添加到包含目录列表中,以便 mysqrt.cxx 可以找到并包含 Table.h

    # state that anybody linking to us needs to include the current source dir
    # to find MathFunctions.h, while we don't.
    # 说明与我们链接的任何人都需要包含当前源目录才能找到 MathFunctions.h,而我们不需要。
    # state that we depend on Tutorial_BINARY_DIR but consumers don't, as the
    # Table.h include is an implementation detail
    # state that we depend on our binary dir to find Table.h
    # 声明我们依赖Tutorial_BINARY_DIR但消费者不依赖,因为包含Table.h是一个实现细节,我们依赖二进制目录来查找Table.h
    target_include_directories(MathFunctions
            INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
            PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
            )
    

    现在,使用生成的表。首先,修改 mysqrt.cxx 以包含 Table.h 。接下来,我们可以重写 mysqrt 函数以使用该表:

    double mysqrt(double x) {
        if (x <= 0) {
            return 0;
        }
    
        double result = x;
        if (x >= 1 && x < 10) {
            std::cout << "Use the table to help find an initial value " << std::endl;
            result = sqrtTable[static_cast<int>(x)];
        }
    
        // do ten iterations
        for (int i = 0; i < 10; ++i) {
            if (result <= 0) {
                result = 0.1;
            }
            double delta = x - (result * result);
            result = result + 0.5 * delta / result;
            std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
        }
        return result;
    }
    

    在项目根目录运行命令编译项目和生成可执行文件:

    cmake -B cmake-build-debug
    cmake --build cmake-build-debug
    

    在项目根目录运行生成的可执行文件:

    ./cmake-build-debug/Tutorial 2
    

    终端输出:

    Use the table to help find an initial value 
    Computing sqrt of 2 to be 1.41421
    Computing sqrt of 2 to be 1.41421
    Computing sqrt of 2 to be 1.41421
    Computing sqrt of 2 to be 1.41421
    Computing sqrt of 2 to be 1.41421
    Computing sqrt of 2 to be 1.41421
    Computing sqrt of 2 to be 1.41421
    Computing sqrt of 2 to be 1.41421
    Computing sqrt of 2 to be 1.41421
    Computing sqrt of 2 to be 1.41421
    The square root of 2 is 1.41421
    

    在项目根目录运行生成的可执行文件:

    ./cmake-build-debug/Tutorial 12
    

    终端输出:

    Computing sqrt of 12 to be 6.5
    Computing sqrt of 12 to be 4.17308
    Computing sqrt of 12 to be 3.52433
    Computing sqrt of 12 to be 3.46462
    Computing sqrt of 12 to be 3.4641
    Computing sqrt of 12 to be 3.4641
    Computing sqrt of 12 to be 3.4641
    Computing sqrt of 12 to be 3.4641
    Computing sqrt of 12 to be 3.4641
    Computing sqrt of 12 to be 3.4641
    The square root of 12 is 3.4641
    

    生成安装程序

    示例程序地址

    接下来,假设我们想将项目分发给其他人,以便他们可以使用它。我们希望在各种平台上提供二进制和源代码分发。这与我们之前在 “安装” 示例进行的安装有些不同,在之前安装中,我们根据源代码构建的二进制文件进行安装。

    在此示例中,我们将构建支持二进制安装和程序包管理功能的安装程序包。为此,我们将使用 CPack 创建平台特定的安装程序。具体来说,我们需要在顶级 CMakeLists.txt 文件的底部添加几行。

    # setup installer
    # 设置安装程序
    include(InstallRequiredSystemLibraries)
    set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
    set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
    set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
    include(CPack)
    

    这就是全部,我们首先包含 InstallRequiredSystemLibraries,该模块将包含项目在当前平台所需的任何运行时库。

    接下来,我们将一些项目信息设置给 CPack 变量,比如项目的许可证和版本信息。本示例中 License.txt 内容如下:

    This is a License file.
    

    最后,我们包含 CPack 模块,该模块将使用这些变量和当前系统的其他一些属性来设置安装程序。

    在项目根目录运行命令编译项目:

    cmake -B cmake-build-debug
    

    在项目根目录运行命令构建二进制发行版

    cd cmake-build-debug
    cpack
    

    在项目根目录下生成了文件:

    .
    ├── ...
    ├── Tutorial-1.0-Darwin.sh
    ├── Tutorial-1.0-Darwin.tar.gz
    └── ...
    

    注意:要指定生成器,请使用 -G 选项。对于多配置构建,请使用 -C 指定配置。例如:

    cpack -G ZIP -C Debug
    

    在项目根目录运行命令构建源代码分发

    cd cmake-build-debug
    cpack --config CPackSourceConfig.cmake
    

    在项目根目录下生成了文件:

    .
    ├── ...
    ├── Tutorial-1.0-Source.tar.Z
    ├── Tutorial-1.0-Source.tar.bz2
    ├── Tutorial-1.0-Source.tar.gz
    ├── Tutorial-1.0-Source.tar.xz
    └── ...
    

    添加对仪表板的支持

    示例程序地址

    我们已经在 "测试" 示例中为我们的项目定义了许多测试。现在,我们只需要运行这些测试并将其提交到仪表板即可。为了包括对仪表板的支持,我们在顶层 CMakeLists.txt 中包含了 CTest 模块。

    将以下内容:

    # enable testing
    # 启用测试
    enable_testing()
    

    替换为:

    # enable dashboard scripting
    # 启用仪表板脚本
    include(CTest)
    

    CTest 模块将自动调用 enable_testing(),因此我们可以将其从 CMake 文件中删除。我们还需要在顶级目录中创建一个 CTestConfig.cmake 文件,在该文件中我们可以指定项目的名称以及提交仪表板的位置。

    set(CTEST_PROJECT_NAME "CMakeTutorial")
    set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
    
    set(CTEST_DROP_METHOD "http")
    set(CTEST_DROP_SITE "my.cdash.org")
    set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial")
    set(CTEST_DROP_SITE_CDASH TRUE)
    

    CTest 将在运行时读入该文件。

    在项目根目录运行命令编译项目:

    cmake -B cmake-build-debug
    

    在项目根目录运行命令生成仪表板:

    cd cmake-build-debug
    ctest –D Experimental
    # 或者:ctest -VV –D Experimental
    

    注意:对于多配置生成器(例如Visual Studio),必须指定配置类型:

    ctest [-VV] -C Debug –D Experimental
    

    或者从 IDE中 构建 Experimental 目标。

    ctest 将构建和测试项目,并将结果提交给Kitware公共仪表板。仪表板的结果将被上传到Kitware的公共仪表板:https://my.cdash.org/index.php?project=CMakeTutorial,如下图所示:

    CMake使用教程系列文章

    相关文章

      网友评论

          本文标题:CMake使用教程(三)

          本文链接:https://www.haomeiwen.com/subject/qxtgictx.html