此文为:轻松入门cmake系列教程
目的:学习如何生成make install目标以在系统上安装文件以及二进制文件
编写代码
项目路径如下:
cmake_minimum_required(VERSION 3.5)
project(cmake_examples_install)
############################################################
# Create a library
############################################################
#Generate the shared library from the library sources
add_library(cmake_examples_inst SHARED
src/hello.cpp
)
target_include_directories(cmake_examples_inst
PUBLIC
${PROJECT_SOURCE_DIR}/include
)
############################################################
# Create an executable
############################################################
# Add an executable with the above sources
add_executable(cmake_examples_inst_bin
src/main.cpp
)
# link the new hello_library target with the hello_binary target
target_link_libraries( cmake_examples_inst_bin
PRIVATE
cmake_examples_inst
)
############################################################
# Install
############################################################
# Binaries
install (TARGETS cmake_examples_inst_bin
DESTINATION bin)
# Library
# Note: may not work on windows
install (TARGETS cmake_examples_inst
LIBRARY DESTINATION lib)
# Header files
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/
DESTINATION include)
# Config
install (FILES cmake-examples.conf
DESTINATION etc)
# Sample configuration file that could be installed
#ifndef __HELLO_H__
#define __HELLO_H__
class Hello
{
public:
void print();
};
#endif
#include
#include "installing/hello.h"
void Hello::print()
{
std::cout << "Hello Install!" << std::endl;
}
#include "installing/hello.h"
int main(int argc, char *argv[])
{
Hello hi;
hi.print();
return 0;
}
理论
(1)安装
cmake提供了添加make install目标的功能,以允许用户安装二进制文件、库和其他文件
CMAKE_INSTALL_PREFIX
控制cmake .. -DCMAKE_INSTALL_PREFIX=/install/location
调用cmake来设置。安装的文件由install()函数控制。
############################################################
# Install
############################################################
# Binaries
install (TARGETS cmake_examples_inst_bin
DESTINATION bin)
# Library
# Note: may not work on windows
install (TARGETS cmake_examples_inst
LIBRARY DESTINATION lib)
# Header files
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/
DESTINATION include)
# Config
install (FILES cmake-examples.conf
DESTINATION etc)
${CMAKE_INSTALL_PREFIX}/bin
中。install (TARGETS cmake_examples_inst_bin
DESTINATION bin)
${CMAKE_INSTALL_PREFIX}/lib
中。install (TARGETS cmake_examples_inst
LIBRARY DESTINATION lib)
注意 这在Windows上可能不起作用。在具有DLL目标的平台上,可能需要添加以下内容。
install (TARGETS cmake_examples_inst
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/
DESTINATION include)
install (FILES cmake-examples.conf
DESTINATION etc)
(2)在运行make install之后,CMake会生成一个install_mark.txt文件,其中包含所有已安装文件的详细信息。
构建
$ mkdir build
$ cd build/
$ cmake ..
-- The C compiler identification is GNU 4.8.4
-- The CXX compiler identification is GNU 4.8.4
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/matrim/workspace/cmake-examples/01-basic/E-installing/build
$ make
Scanning dependencies of target cmake_examples_inst
[ 50%] Building CXX object CMakeFiles/cmake_examples_inst.dir/src/Hello.cpp.o
Linking CXX shared library libcmake_examples_inst.so
[ 50%] Built target cmake_examples_inst
Scanning dependencies of target cmake_examples_inst_bin
[100%] Building CXX object CMakeFiles/cmake_examples_inst_bin.dir/src/main.cpp.o
Linking CXX executable cmake_examples_inst_bin
[100%] Built target cmake_examples_inst_bin
$ sudo make install
[ 50%] Built target cmake_examples_inst
[100%] Built target cmake_examples_inst_bin
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/bin/cmake_examples_inst_bin
-- Set runtime path of "/usr/local/bin/cmake_examples_inst_bin" to ""
-- Installing: /usr/local/lib/libcmake_examples_inst.so
-- Up-to-date: /usr/local/include
-- Installing: /usr/local/include/installing
-- Installing: /usr/local/include/installing/hello.h
-- Installing: /usr/local/etc/cmake-examples.conf
$ cat install_manifest.txt
/usr/local/bin/cmake_examples_inst_bin
/usr/local/lib/libcmake_examples_inst.so
/usr/local/include/installing/hello.h
/usr/local/etc/cmake-examples.conf
$ ls /usr/local/bin/
cmake_examples_inst_bin
$ ls /usr/local/lib
libcmake_examples_inst.so
$ ls /usr/local/etc/
cmake-examples.conf
$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib cmake_examples_inst_bin
Hello Install!
注意
(1)覆盖默认安装位置
如前所述,默认安装位置是从CMAKE_INSTALL_PERFIX设置的,默认为/usr/local/
如果你想为所有用户更改这个默认位置,可以在添加任何二进制文件或库之前将以下代码添加到你的顶端CMakeLists.txt中。
if( CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT )
message(STATUS "Setting default CMAKE_INSTALL_PREFIX path to ${CMAKE_BINARY_DIR}/install")
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE STRING "The path to use for make install" FORCE)
endif()
(2)目标文件夹(不推荐)
make install DESTDIR=/tmp/stage
这将为你的所有安装文件创建安装路径${DESTDIR}/${CMAKE_INSTALL_PREFIX}
。在此示例中,它将在路径/tmp/stage/usr/local下安装所有文件
$ tree /tmp/stage
/tmp/stage
└── usr
└── local
├── bin
│ └── cmake_examples_inst_bin
├── etc
│ └── cmake-examples.conf
└── lib
└── libcmake_examples_inst.so
(2)卸载
sudo xargs rm < install_manifest.txt
指定要在安装时运行的规则。
install(TARGETS <target>... [...])
install(IMPORTED_RUNTIME_ARTIFACTS <target>... [...])
install({FILES | PROGRAMS} <file>... [...])
install(DIRECTORY <dir>... [...])
install(SCRIPT <file> [...])
install(CODE <code> [...])
install(EXPORT <export-name> [...])
install(RUNTIME_DEPENDENCY_SET <set-name> [...])
该命令为项目生成安装规则。通过调用源目录中的Install()命令指定的安装规则在安装过程中按顺序执行。
在3.14版更改:调用add_subdirectory()命令添加的子目录中的安装规则与父目录中的安装规则交错,以声明的顺序运行(参见策略CMP0082)。
此命令有多个签名。其中一些定义了文件和目标的安装选项。这里讨论了多个签名的通用选项,但它们仅对指定它们的签名有效。常见的选项有:
PERMISSIONS
:
DESTINATION
:
CONFIGURATIONS
:
install(TARGETS target
CONFIGURATIONS Debug
RUNTIME DESTINATION Debug/bin)
install(TARGETS target
CONFIGURATIONS Release
RUNTIME DESTINATION Release/bin)
COMPONENT
:
EXCLUDE_FROM_ALL
:
RENAME
:
OPTIONAL
:
install(TARGETS targets... [EXPORT <export-name>]
[RUNTIME_DEPENDENCIES args...|RUNTIME_DEPENDENCY_SET <set-name>]
[[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDLE|
PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
[DESTINATION <dir>]
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[NAMELINK_COMPONENT <component>]
[OPTIONAL] [EXCLUDE_FROM_ALL]
[NAMELINK_ONLY|NAMELINK_SKIP]
] [...]
[INCLUDES DESTINATION [<dir> ...]]
)
TARGETS表单指定了从项目中安装目标的规则。有几种可能被安装的目标输出构建:
ARCHIVE
:这类目标构建包括下面这些:
LIBRARY
:这类目标构建包括下面这些:
RUNTIME
:这类目标构建包括下面这些:
OBJECTS
:
FRAMEWORK
:标记为FRAMEWORK属性的静态库和共享库都被视为macOS上的框架目标。BUNDLE
:标记为MACOSX_BUNDLE属性的可执行文件被视为macOS上的BUNDLE目标。PUBLIC_HEADER
:
PUBLIC_HEADER:
- 在框架共享库目标中指定公共头文件。
- 标记为FRAMEWORK属性的共享库目标在macOS、iOS上生成框架,在其他平台上生成普通的共享库。这个属性可以被设置为一个头文件列表,这些头文件将被放置在框架文件夹内的头文件目录中。在非苹果平台上,可以使用安装(TARGETS)命令的PUBLIC_HEADER选项来安装这些头文件。
PRIVATE_HEADER
:
PRIVATE_HEADER:
- 在框架共享库目标中指定私有头文件。
- 标记为FRAMEWORK属性的共享库目标在macOS、iOS上生成框架,在其他平台上生成普通的共享库。这个属性可以被设置为一个头文件列表,这些头文件将被放在框架文件夹内的PrivateHeaders目录中。在非苹果平台上,可以使用安装(TARGETS)命令的PRIVATE_HEADER选项来安装这些头文件。
RESOURCE
:
对于给出的每个参数,它们后面的参数只适用于参数中指定的目标或文件类型。如果没有给出,安装属性将应用于所有目标类型。如果只给出一个,那么只会安装该类型的目标(可以用来安装一个DLL或一个导入库)。
对于常规可执行文件、静态库和共享库,DESTINATION参数不是必需的。对于这些目标类型,当省略DESTINATION时,将从GNUInstallDirs的适当变量中获取默认目的地,或者如果未定义该变量,则将其设置为内置的默认值。通过PUBLIC_HEADER和PRIVATE_HEADER目标属性与安装的目标相关联的公共头和私有头也是如此。必须始终为模块库、Apple bundle和框架提供目的地。接口和对象库可以省略目的地,但它们的处理方式不同(请参阅本节末尾对该主题的讨论)。
下表显示了当没有给出目标时应用的目标类型及其相关变量和内置默认值:
希望遵循将头文件安装到特定于项目的子目录的常见做法的项目将需要提供一个目的地,而不是依赖于上述方法。
为了使包符合分发文件系统布局策略,如果项目必须指定DESTINATION,建议使用以适当的GNUInstallDirs变量开头的路径。这允许包维护人员通过设置适当的缓存变量来控制安装目标。下面的示例显示了一个静态库被安装到GNUInstallDirs提供的默认目的地,但是它的头文件被安装到一个项目特定的子目录中,该子目录遵循上面的建议:
add_library(mylib STATIC ...)
set_target_properties(mylib PROPERTIES PUBLIC_HEADER mylib.h)
include(GNUInstallDirs)
install(TARGETS mylib
PUBLIC_HEADER
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/myproj
)
除了上面列出的常见选项,每个目标可以接受以下附加参数:
NAMELINK_COMPONENT
:
lib.so -> lib.so.1
install(TARGETS mylib
LIBRARY
COMPONENT Libraries
NAMELINK_COMPONENT Development
PUBLIC_HEADER
COMPONENT Development
)
NAMELINK_ONLY
:
NAMELINK_SKIP
:
install(TARGETS)命令在顶层也可以接受以下选项:
EXPORT
:
INCLUDES DESTINATION
:
这个选项指定了一个目录列表,当通过install(EXPORT)命令导出时,这些目录将被添加到< targets >的INTERFACE_INCLUDE_DIRECTORIES目标属性中。
如果指定了相对路径,则将其视为相对于$< INSTALL_PREFIX >。
RUNTIME_DEPENDENCY_SET
:
RUNTIME_DEPENDENCIES
:
可以在对该命令的TARGETS形式的单个调用中指定一组或多组属性。一个目标可以被多次安装到不同的位置。考虑假设的目标myExe、mySharedLib和myStaticLib。代码:
install(TARGETS myExe mySharedLib myStaticLib
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/static)
install(TARGETS mySharedLib DESTINATION /some/full/path)
将myExe安装到< prefix>/bin,myStaticLib安装到< prefix>/lib/static。在非DLL平台上,mySharedLib将安装到< prefix >/lib和/some/full/path。在DLL平台上,mySharedLib DLL将安装到< prefix >/bin和/some/full/path,其导入库将安装到< prefix >/lib/static和/some/full/path。
接口库可能列在要安装的目标中。它们不安装任何工件,但将包含在关联的导出中。如果列出了对象库,但没有为其对象文件指定目标,则它们将作为接口库导出。这足以满足在实现中链接到对象库的其他目标的可传递使用需求。