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):
我已经编写了一个使用自写Makefile来编译的库,但是现在我想切换到cmake。树看起来是这样的(我删除了所有无关的文件):
.
├── 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.
我发现的大多数示例都是使用一些共享库编译可执行文件的,但绝不仅仅是一个普通的共享库。如果有人能告诉我一个使用cmake的非常简单的库,这也很有帮助,所以我可以以这个为例。
3 个解决方案
#1
35
Always specifiy minimum required version of cmake
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):
您应该声明一个项目。cmake说它是强制性的,它将定义方便的变量PROJECT_NAME、PROJECT_VERSION和PROJECT_DESCRIPTION(后面的变量需要cmake 3.9):
project(mylib VERSION 1.0.1 DESCRIPTION "mylib description")
Declare a new library target. Please avoid use of file(GLOB ...)
. This feature does not provide attended mastery of compilation process. If you are lazy, copy-paste output of ls -1 sources/*.cpp
:
声明一个新的库目标。请避免使用文件(GLOB…)。该特性不提供对编译过程的精通。如果你是懒惰的,复制粘贴输出的ls -1源/*。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 major number of VERSION
. So libmylib.so.1
will be a symlink to libmylib.so.1.0.0
.
您还可以将SOVERSION设置为主要版本。所以libmylib.so。1将是libmylib.so.1.0.0的符号链接。
set_target_properties(mylib PROPERTIES SOVERSION 1)
Declare public API of your library. This API will be installed for 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 been installed and I strongly suggest to place them with sources files.
声明库的公共API。这个API将被安装到第三方应用程序中。将其隔离在项目树中是一种很好的做法(比如将它放置在/目录中)。注意,不应该安装私有头文件,我强烈建议将它们与源文件放在一起。
set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h)
If you work with subdirectories, it is not very convenient to include relative path like "../include/mylib.h"
. So, pass top directory in included directories:
如果您使用子目录,那么包括“./include/mylib.h”之类的相对路径并不十分方便。因此,在包含目录中通过top目录:
target_include_directories(mylib PRIVATE .)
or
或
target_include_directories(mylib PRIVATE include)
target_include_directories(mylib PRIVATE src)
Create install rule for your library. I suggest to use variables CMAKE_INSTALL_*DIR
defined in GNUInstallDirs
:
为您的库创建安装规则。我建议使用在GNUInstallDirs中定义的变量CMAKE_INSTALL_*DIR:
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 files allows third-party application to easily import your library:
您还可以导出一个pkg配置文件。此文件允许第三方应用程序轻松导入您的库:
- with Makefile, see
pkg-config
- Makefile,看到pkg-config
- with Autotools, see
PKG_CHECK_MODULES
- Autotools,看到PKG_CHECK_MODULES
- with cmake, see
pkg_check_modules
- 使用cmake,看到pkg_check_modules
Create a template file named mylib.pc.in
:
创建一个名为mylib.pc的模板文件:
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}
):
在你CMakeLists。txt,添加一条规则扩展@宏(@ only要求cmake不扩展表单${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.
您也可以使用cmake导出功能。但是,这个特性只与cmake兼容,我觉得很难使用。
Finally the entire CMakeLists.txt
should looks like:
最后整个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)
#2
66
This minimal CMakeLists.txt file compiles a simple shared library:
这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)
However, I have no experience copying files to a different destination with CMake. The file command with the COPY/INSTALL signature looks like it might be useful.
但是,我没有使用CMake将文件复制到另一个目的地的经验。带有拷贝/安装签名的文件命令看起来很有用。
#3
15
I'm trying to learn how to do this myself, and it seems you can install the library like this:
我在试着自己做这件事,好像你可以像这样安装图书馆:
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})
#1
35
Always specifiy minimum required version of cmake
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):
您应该声明一个项目。cmake说它是强制性的,它将定义方便的变量PROJECT_NAME、PROJECT_VERSION和PROJECT_DESCRIPTION(后面的变量需要cmake 3.9):
project(mylib VERSION 1.0.1 DESCRIPTION "mylib description")
Declare a new library target. Please avoid use of file(GLOB ...)
. This feature does not provide attended mastery of compilation process. If you are lazy, copy-paste output of ls -1 sources/*.cpp
:
声明一个新的库目标。请避免使用文件(GLOB…)。该特性不提供对编译过程的精通。如果你是懒惰的,复制粘贴输出的ls -1源/*。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 major number of VERSION
. So libmylib.so.1
will be a symlink to libmylib.so.1.0.0
.
您还可以将SOVERSION设置为主要版本。所以libmylib.so。1将是libmylib.so.1.0.0的符号链接。
set_target_properties(mylib PROPERTIES SOVERSION 1)
Declare public API of your library. This API will be installed for 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 been installed and I strongly suggest to place them with sources files.
声明库的公共API。这个API将被安装到第三方应用程序中。将其隔离在项目树中是一种很好的做法(比如将它放置在/目录中)。注意,不应该安装私有头文件,我强烈建议将它们与源文件放在一起。
set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h)
If you work with subdirectories, it is not very convenient to include relative path like "../include/mylib.h"
. So, pass top directory in included directories:
如果您使用子目录,那么包括“./include/mylib.h”之类的相对路径并不十分方便。因此,在包含目录中通过top目录:
target_include_directories(mylib PRIVATE .)
or
或
target_include_directories(mylib PRIVATE include)
target_include_directories(mylib PRIVATE src)
Create install rule for your library. I suggest to use variables CMAKE_INSTALL_*DIR
defined in GNUInstallDirs
:
为您的库创建安装规则。我建议使用在GNUInstallDirs中定义的变量CMAKE_INSTALL_*DIR:
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 files allows third-party application to easily import your library:
您还可以导出一个pkg配置文件。此文件允许第三方应用程序轻松导入您的库:
- with Makefile, see
pkg-config
- Makefile,看到pkg-config
- with Autotools, see
PKG_CHECK_MODULES
- Autotools,看到PKG_CHECK_MODULES
- with cmake, see
pkg_check_modules
- 使用cmake,看到pkg_check_modules
Create a template file named mylib.pc.in
:
创建一个名为mylib.pc的模板文件:
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}
):
在你CMakeLists。txt,添加一条规则扩展@宏(@ only要求cmake不扩展表单${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.
您也可以使用cmake导出功能。但是,这个特性只与cmake兼容,我觉得很难使用。
Finally the entire CMakeLists.txt
should looks like:
最后整个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)
#2
66
This minimal CMakeLists.txt file compiles a simple shared library:
这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)
However, I have no experience copying files to a different destination with CMake. The file command with the COPY/INSTALL signature looks like it might be useful.
但是,我没有使用CMake将文件复制到另一个目的地的经验。带有拷贝/安装签名的文件命令看起来很有用。
#3
15
I'm trying to learn how to do this myself, and it seems you can install the library like this:
我在试着自己做这件事,好像你可以像这样安装图书馆:
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})