如何使用 cmake 创建共享库?

新手上路,请多包涵

我已经编写了一个库,我曾经使用自写的 Makefile 进行编译,但现在我想切换到 cmake。树看起来像这样(我删除了所有不相关的文件):

 .
├── include
│   ├── animation.h
│   ├── buffers.h
│   ├── ...
│   ├── vertex.h
│   └── world.h
└── src
    ├── animation.cpp
    ├── buffers.cpp
    ├── ...
    ├── vertex.cpp
    └── world.cpp

所以我要做的只是将源代码编译成一个共享库,然后将它与头文件一起安装。

我发现的大多数示例都使用一些共享库编译可执行文件,但绝不只是普通共享库。如果有人能告诉我一个使用 cmake 的非常简单的库,那也会很有帮助,所以我可以以此为例。

原文由 Florian M 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 985
2 个回答

始终指定 cmake 的最低要求版本

cmake_minimum_required(VERSION 3.9)

你应该声明一个项目。 cmake says it is mandatory and it will define convenient variables PROJECT_NAME , PROJECT_VERSION and PROJECT_DESCRIPTION (this latter variable necessitate cmake 3.9):

 project(mylib VERSION 1.0.1 DESCRIPTION "mylib description")

声明一个新的库目标。请避免使用 file(GLOB ...) 。此功能不提供对编译过程的有人参与的掌握。如果您很懒惰,请复制粘贴 ls -1 sources/*.cpp 的输出:

 add_library(mylib SHARED
    sources/animation.cpp
    sources/buffers.cpp
    [...]
)

设置 VERSION 属性(可选,但这是一个好习惯):

 set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION})

您还可以将 SOVERSION 设置为主要编号 VERSION 。所以 libmylib.so.1 将是 libmylib.so.1.0.0 的符号链接。

 set_target_properties(mylib PROPERTIES SOVERSION 1)

声明库的公共 API。将为第三方应用程序安装此 API。将它隔离在您的项目树中是一个很好的做法(例如将其放置在 include/ 目录中)。请注意,不应安装私有头文件,我强烈建议将它们与源文件一起放置。

 set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h)

如果您使用子目录,则包含 "../include/mylib.h" 类的相对路径不是很方便。因此,在包含的目录中传递一个顶级目录:

 target_include_directories(mylib PRIVATE .)

或者

target_include_directories(mylib PRIVATE include)
target_include_directories(mylib PRIVATE src)

为您的库创建安装规则。我建议使用变量 CMAKE_INSTALL_*DIR 定义在 GNUInstallDirs 中:

 include(GNUInstallDirs)

并声明要安装的文件:

 install(TARGETS mylib
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

您也可以导出 pkg-config 文件。此文件允许第三方应用程序轻松导入您的库:

创建一个名为 mylib.pc.in 的模板文件(有关更多信息,请参见 pc(5) 手册页):

 prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@
libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@

Name: @PROJECT_NAME@
Description: @PROJECT_DESCRIPTION@
Version: @PROJECT_VERSION@

Requires:
Libs: -L${libdir} -lmylib
Cflags: -I${includedir}

In your CMakeLists.txt , add a rule to expand @ macros ( @ONLY ask to cmake to not expand variables of the form ${VAR} ):

 configure_file(mylib.pc.in mylib.pc @ONLY)

最后,安装生成的文件:

 install(FILES ${CMAKE_BINARY_DIR}/mylib.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)

您也可以使用 cmake EXPORT 功能。不过这个功能只兼容 cmake 我觉得很难用。

最后整个 CMakeLists.txt 应该看起来像:

 cmake_minimum_required(VERSION 3.9)
project(mylib VERSION 1.0.1 DESCRIPTION "mylib description")
include(GNUInstallDirs)
add_library(mylib SHARED src/mylib.c)
set_target_properties(mylib PROPERTIES
    VERSION ${PROJECT_VERSION}
    SOVERSION 1
    PUBLIC_HEADER api/mylib.h)
configure_file(mylib.pc.in mylib.pc @ONLY)
target_include_directories(mylib PRIVATE .)
install(TARGETS mylib
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES ${CMAKE_BINARY_DIR}/mylib.pc
    DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)

编辑

正如评论中提到的,为了符合标准,您应该能够生成静态库和共享库。这个过程有点复杂,与最初的问题不匹配。但值得一提的是, 这里 有很大的解释。

原文由 Jérôme Pouiller 发布,翻译遵循 CC BY-SA 4.0 许可协议

我正在尝试自己学习如何做到这一点,看来您可以像这样安装库:

 cmake_minimum_required(VERSION 2.4.0)

project(mycustomlib)

# Find source files
file(GLOB SOURCES src/*.cpp)

# Include header files
include_directories(include)

# Create shared library
add_library(${PROJECT_NAME} SHARED ${SOURCES})

# Install library
install(TARGETS ${PROJECT_NAME} DESTINATION lib/${PROJECT_NAME})

# Install library headers
file(GLOB HEADERS include/*.h)
install(FILES ${HEADERS} DESTINATION include/${PROJECT_NAME})

原文由 birgersp 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题