C++开发(四)

C++开发(四)

find_package

CMake中find_package这个命令,实际上是根据指定的包名查找与该包名对应的CMake模块文件(Find<PackageName>.cmake)或配置文件(<PackageName>Config.cmake)。CMake自带了一些库的查找模块,这些模块文件通常位于CMake的模块路径中。

如果自己安装的第三方包没有把这个文件弄到CMake的模块路径中,这时候就需要我们手动指定一个包含了对应.cmake文件的路径:

1
2
set(PYBIND11_ROOT "D:/Anaconda3/envs/PhononMC/Lib/site-packages/pybind11/share/cmake/pybind11")
find_package(pybind11 REQUIRED PATHS ${PYBIND11_ROOT})

著注意不是这个包的根路径,而是包含了对应.cmake文件的路径。

如果找到了 Find<PackageName>.cmake 文件,CMake 会执行这个文件中的逻辑。通常,该文件会尝试通过环境变量、系统默认路径或用户指定的路径来查找包的安装位置。

如果找到了 <PackageName>Config.cmake 文件,CMake 会直接加载该文件,通常该文件由库的开发者或安装脚本生成,包含了该库的详细信息,如库文件路径、头文件路径、依赖关系等。

一旦找到库或软件包,find_package 会设置一些变量,这些变量通常包括:

  • <PackageName>_FOUND: 指示是否成功找到了指定的包。
  • <PackageName>_INCLUDE_DIRS<PackageName>_INCLUDES: 该包的头文件目录。
  • <PackageName>_LIBRARIES: 该包的库文件列表。
  • <PackageName>_DEFINITIONS: 该包需要的编译选项或预处理宏。

如果没有找到库或软件包,这些变量通常不会被设置,且 find_package 会返回 NOT_FOUND。另外,一些包还会定义一些CMake宏或者函数,用于执行一些特定的操作。比如对于Pybind11,就提供了一个帮助创建Python模块的函数pybind11_add_module。他会设置所有必要的编译选项、链接库和目标属性,以确保生成的模块可以正确地导入到Python中;还有常用的比如pybind11::module,大概定义了需要的库一类的。

add_library

add_library是CMake中的一个核心命令,用于定义一个库目标(静态库、共享库或模块库)。add_library的基本用法是:

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

<name>:库的名称。将会生成名为 lib<name>.alib<name>.so<name>.dll 等的文件,具体取决于库的类型和平台。

STATIC:生成静态库(.lib.a)。

SHARED:生成共享库(.dll.so.dylib)。

MODULE:生成模块库。模块库是共享库,但不支持动态链接,通常用于插件系统。对于 Python 扩展模块等情况,使用 MODULE 是合适的。

EXCLUDE_FROM_ALL:该库不会默认作为 all 目标的一部分构建,除非明确要求。

STATIC:

  • 静态库在编译时会将所有相关的代码打包到一个二进制文件中。这个库在链接到可执行文件时被包含在内。
  • 生成的文件通常是 lib<name>.a 或者 name.lib

SHARED:

  • 共享库会在运行时被动态链接。这种库可以被多个可执行文件共享,而不需要每个可执行文件都包含库的代码。
  • 生成的文件通常是 lib<name>.so(Linux)、<name>.dll(Windows)或 lib<name>.dylib(macOS)。

MODULE:

  • 模块库是动态链接库,但不在标准的链接过程中使用。它们通常用于插件或扩展模块(如 Python 扩展模块)。
  • 生成的文件通常是平台特定的动态库格式,但它们的使用方式不同于 SHARED 库。例如,在 Python 扩展模块中,生成的文件是 .pyd(Windows)或 .so(Linux)。

Pybind11

pybind11非常轻量,它实际上就是一堆头文件,不是像许多其他库那样需要编译成静态库或动态库来链接使用。在使用 pybind11 时,主要的工作就是包含它的头文件,并且在 CMake 或其他构建系统中设置好包含路径。pybind11_add_module 这样的工具会自动处理这些设置。

例如,在 CMake 中你只需要这样做:

1
2
find_package(pybind11 REQUIRED)
pybind11_add_module(my_module my_module.cpp)

CMake 会处理 pybind11 的相关依赖。另外,其实在使用 pybind11 时,唯一需要额外链接的库就是 Python 本身的库。具体来说,pybind11 只依赖于 Python 的开发环境,这包括:

  1. Python 头文件:用于包含 Python C API,通常在 Python 的 include 目录中,例如 Python.h
  2. Python 库文件:通常是 pythonX.lib 或者 libpythonX.Y.so 这样的库文件,用于链接 Python 的运行时库。