美文网首页
CMake教程(4):添加库

CMake教程(4):添加库

作者: MemetGhini | 来源:发表于2022-04-06 07:56 被阅读0次

    在之前的基础上本文中将讲解如何把代码以库的形式引到工程中。在子目录中写一个简单的数学库,里面实现一个平方运算方法。本文中用到的CMake函数尽量只讲解本文中涉及到的部分。后面会专门会详细介绍平时常用的函数。

    工程结构

    先贴出组织的工程结构:

    .
    ├── CMakeLists.txt          ->根目录CMake配置
    ├── MathFunctions           ->数学库目录
    │   ├── CMakeLists.txt      ->数学库CMake配置
    │   ├── MathFunctions.h     ->数学库头文件
    │   └── MySquare.cpp        ->数学库实现文件
    ├── Tutorial.cpp            ->可执行文件源码
    ├── TutorialConfig.h        ->工程配置头文件
    └── build                   ->构建编译目录
    

    实现数学库

    首先,实现咱们简单的数学库MathFunctions。数学库的头文件 MathFunctions.h目前只声明一个函数。内容为:

    double mySquare(double inputValue);
    

    数学库实现文件MySquare.cpp,把上面的函数实现一遍。内容为:

    double mySquare(double inputValue) 
    {
        return inputValue * inputValue;
    }
    

    就这样数学库的代码写好了。接下来就是怎么把这个组织为一个库的呢?

    CMake组织库

    需要用上CMake的add_library方法。
    add_library作用是用指定文件给工程添加一个库。包括如下几种:

    • 普通库
    • 对象库
    • 接口库
    • 导入库
    • 别名库

    其参数如下:

    add_library(<name> [STATIC | SHARED | MODULE]
                [EXCLUDE_FROM_ALL]
                [<source>...])
    

    本文中先介绍普通库。其中name属性必须全局唯一。生成的library名会根据STATICSHARED成为name.a或name.so。
    这里的STATICSHARED可不设置,通过全局的 BUILD_SHARED_LIBSFALSETRUE 来指定。最后就是源代码目录了。所以此CMake文件内容为:

    add_library(MathFunctions MySquare.cpp)
    

    编写执行代码

    库写好之后接下来就是把它引到咱们的可执行文件中。需要借助于CMake的add_subdirectory函数。其作用为为工程添加一个子目录去编译。add_subdirectory指定源文件和源CMakeLists.txt文件的目录。所以根目录的CMakeLists.txt文件内容为:

    cmake_minimum_required(VERSION 3.10)
    project(Tutorial)
    add_subdirectory(MathFunctions)
    add_executable(Tutorial Tutorial.cpp)
    #函数为把库连接到可执行文件中
    target_link_libraries(Tutorial PUBLIC MathFunctions)
    #指定头文件搜索目录
    target_include_directories(Tutorial PUBLIC MathFunctions)
    

    这两个函数后面文章中专门拿出篇幅来讲,暂时了解一下作用就行。

    接下来写可执行文件代码,引相关头文件来使用它来验证了。可想而知其内容为:

    #include <iostream>
    #include <MathFunctions.h>
    
    int main() {
        double inputValue = 5.0;
        double outputValue = mySquare(inputValue);
        std::cout << "result: " << outputValue << std::endl;
        return 0;
    }
    

    构建和编译项目:

    > cmake ..
    > make
    > ./Tutorial
    

    执行结果为:

    > result: 25
    

    符合项目预期。

    如何让这个库变成可选?

    此时需要了解一下cmake命令option命令。并为根目录的cmake添加:

    option(USE_MYMATH "Use code provided math implementation" ON)
    

    然后按照这个选项的值来让编译器编译连接此库。为此我们把根目录的CMakelists.txt改造为。

    if (USE_MYMATH)
        add_subdirectory(MathFunctions)
        list(APPEND EXTRA_LIBS MathFunctions)
        list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
    endif()
    

    用if检查选项值,在if块内用add_subdirectory把子目录添加进来。

    用list命令来在列表中保存需要连接的库和需要导入的头文件。cmake中的list时以;分割的字符串。

    list(APPEND <list> [<element> ...])
    
    • APPEND为修改命令,为list中添加元素。
    • <list>为list的变量名,如果当前作用域中不存在这个变量名则作为空list为其添加
    • [<element> ...]为list添加的元素

    ps:也可以用set来创建list,例如:set(var a b c d) var的值为a;b;c;d;然后照样可以用list的命令来处理var

    之后在详细介绍此两个命令。目前简单理解就行。并且这种动态控制的方法是较为常见的形式。

    add_executable(Tutorial Tutorial.cpp)
    
    target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
    
    target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}" ${EXTRA_INCLUDES})
    
    • target_link_libraries是把我们的库连接到可执行文件
    • target_include_directories是为可执行文件Tutorial添加头文件搜索目录,否则会找不到我们的头文件

    对源码也做同样的改造,用宏USE_MYMATH来决定用哪一个平方函数:

    #include <iostream>
    #include <TutorialConfig.h>
    
    #ifdef USE_MYMATH
    #include "MathFunctions.h"
    #else
    #include <cmath>
    #endif
    
    int main() 
    {
        double inputValue = 5.0;
    #ifdef USE_MYMATH
        double outputValue = mySquare(inputValue);
        std::cout << "mySquare func called!" << std::endl;
    #else
        double outputValue = pow(inputValue, 2);
        std::cout << "pow func called!" << std::endl;
    #endif
        std::cout << "result: " << outputValue << std::endl;
        return 0;
    }
    

    由于我们在源码中用到了USE_MYMATH,所以我们可以在TutorialConfig.h中添加#cmakedefine USE_MYMATH来让CMake为我们定义USE_MYMATH宏。
    configure_file之前介绍过是复制一份到指定目录,并替换里面的变量。 #cmakedefine var是如果var在cmake中有设定会被替换为#define VAR否则/* #undef VAR */相当于什么都不做。

    ps:当然也可以不用TutorialConfig.h这种形式来让cmake为我们定义USE_MYMATH,直接add_definitions(-DUSE_MYMATH)来为源码库编译添加一个宏

    接下来就编译看看是否符合预期。进入build目录

    cmake .. -DUSE_MYMATH=OFF
    或者
    cmake .. -DUSE_MYMATH=ON
    

    相关文章

      网友评论

          本文标题:CMake教程(4):添加库

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