当前位置: 首页 > 知识库问答 >
问题:

如何使用cmake创建共享库?

端木承业
2023-03-14

我已经编写了一个库,过去我使用自编的Makefile编译它,但现在我想切换到cmake。树是这样的(我删除了所有不相关的文件):

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

我只是想把它编译到一个共享的文件库中。

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

共有3个答案

孙乐逸
2023-03-14

我正在尝试自己学习如何实现这一点,您似乎可以这样安装库:

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})
田兴朝
2023-03-14

这是最小的CMakeLists。txt文件编译了一个简单的共享库:

cmake_minimum_required(VERSION 2.8)

project (test)
set(CMAKE_BUILD_TYPE Release)

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_library(test SHARED src/test.cpp)

但是,我没有使用CMake将文件复制到其他目的地的经验。带有COPY/INSTALL签名的file命令看起来可能有用。

越正阳
2023-03-14

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

cmake_minimum_required(VERSION 3.9)

您应该声明一个项目。cmake说它是强制性的,它将定义方便的变量PROJECT_NAMEPROJECT_VERSIONPROJECT_DESCRIPTION(后一个变量需要cmake 3.9):

project(mylib VERSION 1.0.1 DESCRIPTION "mylib description")

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

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

设置VERSION属性(可选,但这是一个良好的做法):

set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION})

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

set_target_properties(mylib PROPERTIES SOVERSION 1)

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

set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h)

如果您使用子目录,包含像".../包括/mylib. h"这样的相对路径不是很方便。所以,在包含的目录中传递一个顶部目录:

target_include_directories(mylib PRIVATE .)

或者

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

为你的库创建一个安装规则。我建议使用CMAKE_INSTALL_*DIR中定义的变量GNUInstallDir

include(GNUInstallDirs)

并声明要安装的文件:

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

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

  • 使用Makefile,请参见pkg-config
  • 使用自动工具,请参阅PKG_CHECK_MODULES
  • 使用cmake,请参见pkg_check_modules

创建一个名为mylib.pc.in的模板文件(有关详细信息,请参阅pc(5)manpage):

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}

在您的CMakeLists.txt中,添加一个扩展@宏的规则(@ONLY要求cmake不扩展表单${VAR}的变量):

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

最后,安装生成的文件:

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

您也可以使用cmakeEXPORT功能。然而,该功能仅与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)

编辑

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

 类似资料:
  • 我正在尝试链接一个名为libtest lib的预编译共享库文件。所以这是我在CMakeLists的底部所拥有的。txt: 如上所述,我得到以下错误: 如果我注释掉add_library行,我会得到以下结果: 在库中链接时,似乎绝对需要源文件(.c、cpp等)。但我如何在一个。那档案呢?这些文档对target_link_库()做了如下介绍: 被命名的必须是由add_executable()或add_

  • 我想为消息驱动的EJB创建一个主题上的共享、非持久订阅,并想知道如何使用@MessageDriven和@ActivationConfigProperty来实现这一点。 我发现一篇文章描述了类似的事情,但我不确定这是否适用于我的问题: 订阅的共享依赖于客户端id的设置,不仅对于持久订阅(总是需要客户端id),对于非持久订阅(通常不需要客户端id)也是如此。如果订阅是由资源适配器创建的,以供消息驱动b

  • JMS 2.0规范引入了共享持久订阅的概念。我有一个用例,我必须在服务器启动时以编程方式创建订阅。我们有集群的JBoss服务器。因此,每个JBoss都有类似的配置,每个JBoss都有将创建持久订阅者的应用程序(消息提供者是WMQ)。由于持久订阅必须有一个唯一的名称,我想到了使用共享订阅。现在的问题是Spring的4.0.6.RELEASE支持JMS 2.0中的新功能,但是我没有找到通过Spring

  • 我的groovy脚本都在git存储库中,使用jenkins checkout SCM。其中一个groovy脚本中有一些常用函数,我想使这个groovy成为一个共享库,而无需打开jenkins并在jenkins管理表中添加共享库。 我可以使用RESTAPI或其他方法添加新库吗?

  • 现在我想为我们的系统开发一个通用的邮件服务。在设计时,我们希望开发一个生产者和消费者。在消费者方面,我们可以开发和部署或应用程序,但在生产者方面,我们希望提供一个通用的邮件客户端,如下面的接口,并为其他系统建立jar依赖关系。 但我看到spring boot和spring cloud使用了许多声明性方法,似乎必须使用一个应用程序类,但我只想要一个类引用,不需要部署。我不知道如何实施它。

  • 我建立了一个具有两个节点和外部Zookeper集合的SOLR集群。该ZK集合有3个节点。我使用参数启动solr实例: 这意味着,我希望SOLR配置在/solr5下,而不是默认情况下的/下。 文件夹 /solr5在ZK中创建: 我还可以毫无问题地将SOLR配置上传到/solr5中。 我的问题是,在创建集合时,如何将生成的文件置于/solr5之下? 我用来创建集合的命令是: 我查看了本页上的文档,但没