如何使用cmake创建共享库?

Flo*_*n M 121 c++ compilation cmake shared-libraries

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

.
??? include
?   ??? animation.h
?   ??? buffers.h
?   ??? ...
?   ??? vertex.h
?   ??? world.h
??? src
    ??? animation.cpp
    ??? buffers.cpp
    ??? ...
    ??? vertex.cpp
    ??? world.cpp
Run Code Online (Sandbox Code Playgroud)

所以我要做的只是将源代码编译成共享库,然后使用头文件安装它.

我发现的大多数示例都使用一些共享库编译可执行文件,但从不只是一个普通的共享库.如果有人可以告诉我一个使用cmake的非常简单的库,那么我也可以使用它作为一个例子.

Jér*_*ler 165

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

cmake_minimum_required(VERSION 3.9)
Run Code Online (Sandbox Code Playgroud)

你应该申报一个项目.cmake说它是强制性的,它将定义方便的变量PROJECT_NAME,PROJECT_VERSION并且PROJECT_DESCRIPTION(后一个变量需要cmake 3.9):

project(mylib VERSION 1.0.1 DESCRIPTION "mylib description")
Run Code Online (Sandbox Code Playgroud)

声明一个新的库目标.请避免使用file(GLOB ...).此功能无法提供有关编译过程的精通.如果你很懒,复制粘贴输出ls -1 sources/*.cpp:

add_library(mylib SHARED
    sources/animation.cpp
    sources/buffers.cpp
    [...]
)
Run Code Online (Sandbox Code Playgroud)

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

set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION})
Run Code Online (Sandbox Code Playgroud)

您也可以设置SOVERSION为主要数量VERSION.所以libmylib.so.1将是一个符号链接libmylib.so.1.0.0.

set_target_properties(mylib PROPERTIES SOVERSION 1)
Run Code Online (Sandbox Code Playgroud)

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

set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h)
Run Code Online (Sandbox Code Playgroud)

如果使用子目录,那么包含相对路径就不太方便了"../include/mylib.h".因此,传递包含目录中的顶级目录:

target_include_directories(mylib PRIVATE .)
Run Code Online (Sandbox Code Playgroud)

要么

target_include_directories(mylib PRIVATE include)
target_include_directories(mylib PRIVATE src)
Run Code Online (Sandbox Code Playgroud)

为库创建安装规则.我建议使用以下CMAKE_INSTALL_*DIR定义的变量GNUInstallDirs:

include(GNUInstallDirs)
Run Code Online (Sandbox Code Playgroud)

并声明要安装的文件:

install(TARGETS mylib
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
Run Code Online (Sandbox Code Playgroud)

您也可以导出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}
Run Code Online (Sandbox Code Playgroud)

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

configure_file(mylib.pc.in mylib.pc @ONLY)
Run Code Online (Sandbox Code Playgroud)

最后,安装生成的文件:

install(FILES ${CMAKE_BINARY_DIR}/mylib.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)
Run Code Online (Sandbox Code Playgroud)

您也可以使用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)
Run Code Online (Sandbox Code Playgroud)

  • 只是补充@ Jezz的精彩解释:经过上述所有步骤,程序员可以通过`mkdir build && cd build/&& cmake .. && sudo make install`(或`sudo make install/strip`来安装_striped_库版). (8认同)
  • `add_library` 应该在没有 **STATIC/SHARED** 的情况下使用,必须使用 `BUILD_SHARED_LIBS`。https://cgold.readthedocs.io/en/latest/tutorials/libraries/static-shared.html (3认同)
  • 您有传递库依赖项的技术吗?例如,如果 mylib 依赖于 liblog4cxx,那么将其一直传输到 mylib.pc 的好方法是什么? (2认同)
  • 我将如何在另一个项目中使用这个库?你能扩展你的例子吗? (2认同)

Rob*_*nke 76

这个最小的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)
Run Code Online (Sandbox Code Playgroud)

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

  • 应省略CMAKE_BUILD_TYPE,因此决定由编译者决定. (29认同)

gro*_*190 23

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

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})
Run Code Online (Sandbox Code Playgroud)

  • 最简单直接的答案 (2认同)

Lui*_*uis 9

首先,这是我正在使用的目录布局:

.
??? include
?   ??? class1.hpp
?   ??? ...
?   ??? class2.hpp
??? src
    ??? class1.cpp
    ??? ...
    ??? class2.cpp
Run Code Online (Sandbox Code Playgroud)

经过几天的研究,这是我最喜欢的方式,这要归功于现代的CMake:

cmake_minimum_required(VERSION 3.5)
project(mylib VERSION 1.0.0 LANGUAGES CXX)

set(DEFAULT_BUILD_TYPE "Release")

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.")
  set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE)
  # Set the possible values of build type for cmake-gui
  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

include(GNUInstallDirs)

set(SOURCE_FILES src/class1.cpp src/class2.cpp)

add_library(${PROJECT_NAME} ...)

target_include_directories(${PROJECT_NAME} PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
    PRIVATE src)

set_target_properties(${PROJECT_NAME} PROPERTIES
    VERSION ${PROJECT_VERSION}
    SOVERSION 1)

install(TARGETS ${PROJECT_NAME} EXPORT MyLibConfig
    ARCHIVE  DESTINATION ${CMAKE_INSTALL_LIBDIR}
    LIBRARY  DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME  DESTINATION ${CMAKE_INSTALL_BINDIR})
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})

install(EXPORT MyLibConfig DESTINATION share/MyLib/cmake)

export(TARGETS ${PROJECT_NAME} FILE MyLibConfig.cmake)
Run Code Online (Sandbox Code Playgroud)

运行CMake并安装库后,无需使用Find***.cmake文件,它可以像这样使用:

find_package(MyLib REQUIRED)

#No need to perform include_directories(...)
target_link_libraries(${TARGET} mylib)
Run Code Online (Sandbox Code Playgroud)

就是这样,如果已经安装在标准目录中,它将被找到并且不需要做任何其他事情.如果它已经安装在非标准路径中,它也很容易,只需告诉CMake使用以下命令查找MyLibConfig.cmake:

cmake -DMyLib_DIR=/non/standard/install/path ..
Run Code Online (Sandbox Code Playgroud)

我希望这能帮助每个人,就像它帮助了我一样.这样做的旧方法非常繁琐.