add_executable(helloworldexe helloworld.cpp) #将库链接到可执行文件。 target_link_libraries(helloworldexe message)

2. CMake语言说明

(1)cmake_minimum_required

设置CMake所需的最低版本。如果使用的CMake版本低于该版本,则会发出致命错误。

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

(2)project

声明了项目的名称(buildLib)和支持的编程语言(CXX代表C++)。

project(buildLib LANGUAGES CXX)

(3)add_library

创建目标——静态库。库的名称(message)和 源码 文件名相同。

add_library(message STATIC Message.cpp Message.h)

CMake接受其他值作为 add_library 的第二个参数的有效值:

  • STATIC:用于创建静态库,即编译文件的打包存档,以便在链接其他目标时使用,例如:可执行文件。
  • SHARED:用于创建动态库,即可以动态链接,并在运行时加载的库。
  • OBJECT:用于创建对象库,可将给定 add_library 的列表中的源码编译到目标文件,不将它们归档到静态库中, 也不能将它们链接到共享对象中。如果需要一次性创建静态库和动态库,那么使用对象库尤其有用。
  • MODULE:又为DSO组。与 SHARED 库不同,它们不链接到项目中的任何目标,不过可以进行动态加载。该参数可以用于构建运行时插件。
  • CMake还能够生成特殊类型的库,这不会在构建系统中产生输出,但是对于组织目标之间的依赖关系, 和构建需求非常有用:

  • IMPORTED:此类库目标表示位于项目外部的库。此类库的主要用途是,对现有依赖项进行构建。 因此, IMPORTED 库将被视为不可变的。我们将在本书的其他章节演示使用 IMPORTED 库的示例。
  • INTERFACE:与 IMPORTED 库类似。不过,该类型库可变,没有位置信息。它主要用于项目之外的目标构建使用。我们将在本章第5节中演示 INTERFACE 库的示例。
  • ALIAS:顾名思义,这种库为项目中已存在的库目标定义别名。不过,不能为 IMPORTED 库选择别名。
  • (4)add_executable

    指示CMake创建一个新目标:可执行文件(helloworldexe)。

    add_executable(helloworldexe helloworld.cpp)

    将目标库(message)链接到可执行目标(helloworldexe)。

    target_link_libraries(helloworldexe message)

    三、cmake配置及编译

    1.cmake配置

    使用 cmake .. 来进行配置,生成buildLib.sln项目:

    2.构建/编译

    使用 cmake --build . 来进行构建,生成静态库及可执行文件:

    【扩展】编译动态库

    在 Windows 平台中生成动态库的源码和静态库是不同的。

    在 Windows 平台中,我们导出动态库时,除了会生成 .dll 动态库之外还会生成一个 .lib 文件。这个 .lib 文件和静态库的 .lib 文件不同,它里面并不保存代码生成的二进制文件,而是所有需要导出符号的符号表。因此这个 .lib 文件和编译静态库生成的 .lib 文件相比会小很多。

    这个导出的符号表是需要我们在源码中进行指定的。如果我们希望将将一个符号(symbol)导出(这里的符号可以指类、函数等各种类型):

  • 方法一:需要在其前面加上 __declspec(dllexport) 标志。这样这个符号的相关信息就会导出的 .lib 中的符号表中了。
  • 方法二:在CMakeLists.txt里添加 set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
  • 如果我们的源码中没有任何 __declspec(dllexport) ,并且没有在CMakeLists.txt里设置"导出所有符号"的话,我们依然可以成功的编译出动态库,但是并不会生成保存符号表的 .lib 文件。这也是在 Windows 平台下编译动态库经常出现的问题。

    (1)修改CMakeLists.txt

    1.需要保证编译的目标文件与生成位置无关, 可以通过使用 set_target_properties 命令,设 置 message-objs 目标的相应属性来实现。( 可能在某些平台和/或使用较老的编译器上,需要显式地为目标设置 POSITION_INDEPENDENT_CODE 属性。

    2.引用对象库的生成器表达式语法: $<TARGET_OBJECTS:message-objs>

    (2)构建及编译

    (3)修改库名称

     #修改动态库名称
    set_target_properties(message-shared
    	PROPERTIES
    	OUTPUT_NAME "shared-message"
    #修改静态库名称
    set_target_properties(message-static
    	PROPERTIES
    	OUTPUT_NAME "static-message"