如何使用 cmake 创建共享库?
问题描述
我已经写了一个库,我曾经使用自己编写的 Makefile 进行编译,但现在我想切换到 cmake.树看起来像这样(我删除了所有不相关的文件):<预><代码>.├── 包括│ ├── animation.h│ ├── buffers.h│ ├── ...│ ├── vertex.h│ └── world.h└── src├──动画.cpp├──缓冲区.cpp├── ...├── 顶点.cpp└── world.cpp
所以我想要做的只是将源代码编译成共享库,然后与头文件一起安装.
我发现的大多数示例都使用一些共享库编译可执行文件,但绝不仅仅是一个普通的共享库.如果有人能告诉我一个使用 cmake 的非常简单的库也会很有帮助,所以我可以以此为例.
始终指定 cmake
cmake_minimum_required(VERSION 3.9)您应该声明一个项目.cmake 说这是强制性的,它将定义方便的变量 PROJECT_NAME、PROJECT_VERSION 和 PROJECT_DESCRIPTION(后一个变量需要 cmake3.9):
project(mylib 版本 1.0.1 描述mylib 描述")声明一个新的库目标.请避免使用file(GLOB ...).此功能不提供编译过程的有人参与的掌握.如果你懒惰,复制粘贴 ls -1 sources/*.cpp 的输出:
add_library(mylib 共享来源/动画.cpp源/缓冲区.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 私有源代码)为您的库创建安装规则.我建议使用 GNUInstallDirs 中定义的变量 CMAKE_INSTALL_*DIR:
include(GNUInstallDirs)并声明要安装的文件:
安装(目标 mylib图书馆目的地 ${CMAKE_INSTALL_LIBDIR}PUBLIC_HEADER 目的地 ${CMAKE_INSTALL_INCLUDEDIR})您也可以导出 pkg-config 文件.此文件允许第三方应用程序轻松导入您的库:
- 使用 Makefile,参见 
pkg-config - 对于 Autotools,请参阅 
PKG_CHECK_MODULES - 使用 cmake,请参阅 
pkg_check_modules一个> 
创建一个名为 mylib.pc.in 的模板文件(参见 pc(5) 手册页了解更多信息):
prefix=@CMAKE_INSTALL_PREFIX@exec_prefix=@CMAKE_INSTALL_PREFIX@libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@includeir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@姓名:@PROJECT_NAME@描述:@PROJECT_DESCRIPTION@版本:@PROJECT_VERSION@要求:库:-L${libdir} -lmylibCflags: -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)您也可以使用 cmake <代码>导出代码>功能.不过这个功能只兼容cmake,我觉得很难用.
最后整个 CMakeLists.txt 应该看起来像:
cmake_minimum_required(VERSION 3.9)项目(mylib 版本 1.0.1 描述mylib 描述")包括(GNUInstallDirs)add_library(mylib 共享 src/mylib.c)set_target_properties(mylib 属性版本 ${PROJECT_VERSION}SOVERSION 1PUBLIC_HEADER api/mylib.h)配置文件(mylib.pc.in mylib.pc @ONLY)target_include_directories(mylib PRIVATE .)安装(目标 mylib图书馆目的地 ${CMAKE_INSTALL_LIBDIR}PUBLIC_HEADER 目的地 ${CMAKE_INSTALL_INCLUDEDIR})安装(文件 ${CMAKE_BINARY_DIR}/mylib.pc目的地 ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)编辑
正如评论中提到的,为了符合标准,您应该能够生成静态库和共享库.这个过程有点复杂,与最初的问题不符.但值得一提的是,它在这里有很好的解释.
I have written a library that I used to compile using a self-written Makefile, but now I want to switch to cmake. The tree looks like this (I removed all the irrelevant files):
.
├── include
│   ├── animation.h
│   ├── buffers.h
│   ├── ...
│   ├── vertex.h
│   └── world.h
└── src
    ├── animation.cpp
    ├── buffers.cpp
    ├── ...
    ├── vertex.cpp
    └── world.cpp
So what I am trying to do is just to compile the source into a shared library and then install it with the header files.
Most examples that I have found compile executables with some shared libraries but never just a plain shared library. It would also be helpful if someone could just tell me a very simple library that uses cmake, so I can use this as an example.
Always specify the minimum required version of cmake
cmake_minimum_required(VERSION 3.9)
You should declare a project. 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")
Declare a new library target. Please avoid the use of file(GLOB ...). This feature does not provide attended mastery of the compilation process. If you are lazy, copy-paste output of ls -1 sources/*.cpp :
add_library(mylib SHARED
    sources/animation.cpp
    sources/buffers.cpp
    [...]
)
Set VERSION property (optional but it is a good practice):
set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION})
You can also set SOVERSION to a major number of VERSION. So libmylib.so.1 will be a symlink to libmylib.so.1.0.0.
set_target_properties(mylib PROPERTIES SOVERSION 1)
Declare public API of your library. This API will be installed for the third-party application. It is a good practice to isolate it in your project tree (like placing it include/ directory). Notice that, private headers should not be installed and I strongly suggest to place them with the source files.
set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h)
If you work with subdirectories, it is not very convenient to include relative paths like "../include/mylib.h". So, pass a top directory in included directories:
target_include_directories(mylib PRIVATE .)
or
target_include_directories(mylib PRIVATE include)
target_include_directories(mylib PRIVATE src)
Create an install rule for your library. I suggest to use variables CMAKE_INSTALL_*DIR defined in GNUInstallDirs:
include(GNUInstallDirs)
And declare files to install:
install(TARGETS mylib
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
You may also export a pkg-config file. This file allows a third-party application to easily import your library:
- with Makefile, see 
pkg-config - with Autotools, see 
PKG_CHECK_MODULES - with cmake, see 
pkg_check_modules 
Create a template file named mylib.pc.in (see pc(5) manpage  for more information):
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)
And finally, install generated file:
install(FILES ${CMAKE_BINARY_DIR}/mylib.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)
You may also use cmake EXPORT feature. However, this feature is only compatible with cmake and I find it difficult to use.
Finally the entire CMakeLists.txt should looks like:
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)
EDIT
As mentioned in comments, to comply with standards you should be able to generate a static library as well as a shared library. The process is bit more complex and does not match with the initial question. But it worths to mention that it is greatly explained here.
这篇关于如何使用 cmake 创建共享库?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
