美文网首页C/CPP工程实践
CMake构建一个静态链接库的实例

CMake构建一个静态链接库的实例

作者: EVANMORE | 来源:发表于2018-05-05 20:15 被阅读934次

    1. 首先是当前这个例子中要用到的一些命令

    1.1. add_library

    添加一个lib到工程中,指定这个lib的源文件
    函数定义

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

    <name>是目标库的名字,这个名字在工程内全局唯一,最终编译出来的目标文件名字取决于目标平台(比如说lib<name>.a<name>.lib

    STATIC, SHARED, 或MODULE用来指定要创建的lib的类型。

    • STATIC, 代表静态链接库,编译的时候link到工程中;
    • SHARED,代表动态链接库,运行时候加载;
    • MODULE,是一些插件,运行时候使用dlopen-like的功能进行动态加载;

    EXCLUDE_FROM_ALL 会在目标文件上设置相应的属性(执行默认make的时候,这个目标文件会被排除在外,不被编译)


    add_library(<name> <SHARED|STATIC|MODULE|UNKNOWN> IMPORTED
                [GLOBAL])
    

    一个Imported Lib目标代表一个工程外部的库文件,当前这个工程内灭有命令来编译这个库,并且这个库的IMPORT属性是true。
    没有设置GLOBAL的时候,这个目标名称的作用域只在创建它的目录以及子目录;设置了之后,全局可见。

    NOTE: Imported Target通常代表一个工程的一个依赖,一般只能作为诸如target_link_libraries()这样命令的右值,不能修改


    add_library(<name> OBJECT <src>...)
    

    创建一个特殊的“object library” 目标。这种库只编译源文件生成目标文件,但是不把这些目标文件打包进一个lib。当其他的库或者目标文件要使用这些目标文件的时候,会以这样的形式来添加,objlib是这个库的名字

    add_library(... $<TARGET_OBJECTS:objlib> ...)
    add_executable(... $<TARGET_OBJECTS:objlib> ...)
    

    add_library(<name> INTERFACE [IMPORTED [GLOBAL]])
    

    创建一个Interface库,一个INTERFACE库不会直接创建编译目标文件,即使这个库可以设置一些属性并且可以被installed,exported和imported。通常来说使用set_property()target_link_libraries(INTERFACE)target_include_directories(INTERFACE)target_compile_options(INTERFACE)target_compile_definitions(INTERFACE)这些函数来设置INTERFACE_*属性,然后这个库可以像其他库一样作为target_link_libraries()命令的参数。

    这里还可以通过设置IMPORTED标志来生成一个INTERFACE imported Target,表示这个库文件在工程外。

    1.2. target_include_directories

    target_include_directories(<target> [SYSTEM] [BEFORE]
      <INTERFACE|PUBLIC|PRIVATE> [items1...]
      [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
    

    指定编译目标文件的时候需要包含的路径和内容, <target> 必须是一个已经通过诸如 add_executable()或者add_library()函数创建了的目标,并且不是一个标注成IMPORTED目标。
    INTERFACE, PUBLICPRIVATE这些关键字用来指定后面这些参数的作用范围。PUBLICINTERFACE的条目会产生目标对象的INTERFACE_INCLUDE_DIRECTORIES属性(也就是说添加了的公共默认搜索路径),后面的参数定义了包含路径。

    指定的包含路径可以是绝对路径也可以是相对路径,重复调用相同的<target>会把这些条目按次序添加到对象上。如果指定了SYSTEM属性,则意味着这个路径是一个系统路径

    target_include_directories 的参数可以使用“生成表达式”,语法是$<...>

    包含路径的使用要求对于build树和instal树通常是不太一样的。BUILD_INTERFACEINSTALL_INTERFACE 生成表达式可以用来描述不同的使用要求。

    target_include_directories(mylib PUBLIC
      $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/mylib>
      $<INSTALL_INTERFACE:include/mylib>  # <prefix>/include/mylib
    )
    

    2. 实例

    1. 首先看一下当前工程的目录
    .
    ├── CMakeLists.txt
    ├── include
    │   └── Logger.hpp
    └── src
        └── Logger.cpp
    

    很简单的一个工程,提供了spdlog的一个简单封装,其他文件要使用日志功能的时候只要包含Logger.hpp头文件就可以了。

    1. 下面是CMakeLists.txt文件
    set(module_name logger)
    project(${module_name} CXX)
    
    message(STATUS "Configuring ${module_name}")
    
    set(sources 
        src/Logger.cpp
    )
    
    set(headers
        include/Logger.hpp
    )
    
    #依赖开源的interface库spdlog,添加一个interface类型的库目标
    add_library(spdlog INTERFACE)
    #给这个interface库添加属性,也就是这个spdlog的头文件的相对路径
    target_include_directories(
        spdlog
        INTERFACE
        "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../externals/spdlog/include>"
    )
    
    #spdlog依赖的线程库
    find_package(Threads)
    
    #添加要编译的logger库
    add_library(${module_name} ${sources} ${headers})  
    target_link_libraries(${module_name} spdlog ${CMAKE_THREAD_LIBS_INIT})
    
    #和之前一样,指定需要包含的路径(这个时候spdlog库里面已经包含了spdlog的头文件搜索路径了,所以当前这个logger库就不用额外指定了)
    target_include_directories(
        ${module_name} 
        PUBLIC
        "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
    )
    
    1. 使用logger库的主工程
      这个cmake只要把logger库link进来就可以了,logger库内的头文件搜索路径都被一并继承了。
    set(module_name sctp_proxy)
    project(&{module_name} CXX)
    
    add_subdirectory(libs)
    
    add_executable(${module_name} main.cpp)
    target_link_libraries(${module_name} logger)
    

    相关文章

      网友评论

        本文标题:CMake构建一个静态链接库的实例

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