如何使用 cmake 创建共享库? [英] How to create a shared library with cmake?

查看:20
本文介绍了如何使用 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_NAMEPROJECT_VERSIONPROJECT_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 文件.此文件允许第三方应用程序轻松导入您的库:

创建一个名为 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:

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 创建共享库?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆