此文为:轻松入门cmake系列教程
实验
目的:学习如何生成make install目标以在系统上安装文件以及二进制文件
编写代码
项目路径如下:
- [CMakeLists.txt]
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)
- [cmake-examples.conf] - 示例配置文件
# Sample configuration file that could be installed
- [include/installing/hello.h] - 要包含的标题文件
#ifndef __HELLO_H__
#define __HELLO_H__
class Hello
{
public:
void print();
};
#endif
- [src/hello.cpp] - 要编译的源文件
#include <iostream>
#include "installing/hello.h"
void Hello::print()
{
std::cout << "Hello Install!" << std::endl;
}
- [src/main.cpp] - 主源文件
#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_examples_inst_bin生成的二进制文件安装到目标目录
${CMAKE_INSTALL_PREFIX}/bin
中。
install (TARGETS cmake_examples_inst_bin
DESTINATION bin)
- 将目标cmake_examples_inst生成的共享库安装到目标目录
${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)
- 将针对cmake_examples_inst库进行开发的头文件安装到${CMAKE_INSTALL_PREFIX}/include目录中。
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/
DESTINATION include)
- 将配置文件安装到目标${CMAKE_INSTALL_PREFIX}/etc
install (FILES cmake-examples.conf
DESTINATION etc)
(2)在运行make install之后,CMake会生成一个install_mark.txt文件,其中包含所有已安装文件的详细信息。
- 注意:如果你以root身份运行make install命令,则install_mark.txt文件将归root所有。
构建
$ 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参数。
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
指定要在安装时运行的规则。
概要
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
:- 为安装的文件指定权限。
- 有效权限为OWNER_READ、OWNER_WRITE、OWNER_EXECUTE、GROUP_READ、GROUP_WRITE、GROUP_EXECUTE、WORLD_READ、WORLD_WRITE、WORLD_EXECUTE、SETUID、SETGID。
- 在某些平台上没有意义的权限在这些平台上被忽略。
DESTINATION
:- 指定磁盘上要安装文件的目录。参数可以是相对路径或绝对路径。
- 如果给出了一个相对路径,它将相对于CMAKE_INSTALL_PREFIX变量的值进行解释。该前缀可以在安装时使用CMAKE_INSTALL_PREFIX变量文档中解释的DESTDIR机制重新定位。
- 由于cpack安装程序生成器不支持绝对路径,所以最好始终使用相对路径。特别是,不需要通过前置CMAKE_INSTALL_PREFIX使路径成为绝对路径;如果DESTINATION是相对路径,则默认使用该前缀。
CONFIGURATIONS
:- 指定一个应用安装规则的构建配置列表(调试、发布等)
- 注意,为该选项指定的值仅适用于CONFIGURATIONS选项之后列出的选项。
- 注意,CONFIGURATIONS必须出现在RUNTIME DESTINATION之前。
- 例如,要为Debug和Release配置设置单独的安装路径,请执行以下操作:
install(TARGETS target
CONFIGURATIONS Debug
RUNTIME DESTINATION Debug/bin)
install(TARGETS target
CONFIGURATIONS Release
RUNTIME DESTINATION Release/bin)
COMPONENT
:- 指定与安装规则相关联的安装组件名称,例如“runtime”或“development”。
- 在特定于组件的安装过程中,只会执行与给定组件名相关联的安装规则。
- 在完全安装期间,所有组件都被安装,除非标记为EXCLUDE_FROM_ALL。
- 如果没有提供COMPONENT,则会创建一个默认组件“Unspecified”。
- 默认组件名可以用CMAKE_INSTALL_DEFAULT_COMPONENT_NAME变量控制。
EXCLUDE_FROM_ALL
:- 3.6新版功能。
- 指定将该文件排除在完整安装之外,只作为特定于组件的安装的一部分安装
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
:这类目标构建包括下面这些:- 静态库
- DLL导入库(在所有基于windows的系统上,包括Cygwin;它们的扩展名是.lib,而不是去运行时的.dll);
- 在AIX上,为启用了ENABLE_EXPORTS的可执行文件创建的链接器导入文件。
LIBRARY
:这类目标构建包括下面这些:- 共享库,除了
- dll(这些转到RUNTIME,见下面),
- 在macOS上被标记为FRAMEWORK时(见下文)。
- 共享库,除了
RUNTIME
:这类目标构建包括下面这些:- 可执行文件(macOS上标记为MACOSX_BUNDLE时除外,参见下面的BUNDLE);
- dll(在所有基于windows的系统上,包括Cygwin;注意,附带的导入库类型是ARCHIVE)。
OBJECTS
:- 3.9新版功能。
- 与对象库相关联的对象文件。
FRAMEWORK
:标记为FRAMEWORK属性的静态库和共享库都被视为macOS上的框架目标。BUNDLE
:标记为MACOSX_BUNDLE属性的可执行文件被视为macOS上的BUNDLE目标。PUBLIC_HEADER
:- 在非苹果平台上,与库相关的任何PUBLIC_HEADER文件都安装在PUBLIC_HEADER参数指定的目标中。
- 这个参数定义的规则在苹果平台上的框架库中被忽略,因为相关的文件被安装到框架文件夹中的适当位置。
- 详见PUBLIC_HEADER。
PUBLIC_HEADER:
- 在框架共享库目标中指定公共头文件。
- 标记为FRAMEWORK属性的共享库目标在macOS、iOS上生成框架,在其他平台上生成普通的共享库。这个属性可以被设置为一个头文件列表,这些头文件将被放置在框架文件夹内的头文件目录中。在非苹果平台上,可以使用安装(TARGETS)命令的PUBLIC_HEADER选项来安装这些头文件。
PRIVATE_HEADER
:- 类似于PUBLIC_HEADER,但用于PRIVATE_HEADER文件。详见PRIVATE_HEADER。
PRIVATE_HEADER:
- 在框架共享库目标中指定私有头文件。
- 标记为FRAMEWORK属性的共享库目标在macOS、iOS上生成框架,在其他平台上生成普通的共享库。这个属性可以被设置为一个头文件列表,这些头文件将被放在框架文件夹内的PrivateHeaders目录中。在非苹果平台上,可以使用安装(TARGETS)命令的PRIVATE_HEADER选项来安装这些头文件。
RESOURCE
:- 类似于PUBLIC_HEADER和PRIVATE_HEADER,但用于资源文件。详细信息请参见参考资料。
对于给出的每个参数,它们后面的参数只适用于参数中指定的目标或文件类型。如果没有给出,安装属性将应用于所有目标类型。如果只给出一个,那么只会安装该类型的目标(可以用来安装一个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
:- 版本3.12中的新功能。
- 在某些平台上,版本化共享库具有符号链接,例如:
lib<name>.so -> lib<name>.so.1
- NAMELINK_COMPONENT选项与COMPONENT选项类似,但如果生成了一个共享库名称链,它会更改安装组件。如果没有指定,则默认为COMPONENT的值。在LIBRARY块之外使用此参数是错误的。
- 看个例子:
install(TARGETS mylib
LIBRARY
COMPONENT Libraries
NAMELINK_COMPONENT Development
PUBLIC_HEADER
COMPONENT Development
)
-
- 在这个场景中,如果您选择只安装开发组件,那么headers和namelink都将在没有库的情况下安装(如果不同时安装Libraries组件,namelink将是一个悬挂符号链接,链接到库的项目将出现生成错误。)如果只安装Libraries组件,则只安装库,而不安装头和namelink。
- 此选项通常用于具有独立运行时和开发包的包管理器。例如,在Debian系统上,库应该在 runtime package中,headers和namelink应该在开发包中。
- 有关创建版本化共享库的详细信息,请参阅VERSION和SOVERSION target属性。
- 在这个场景中,如果您选择只安装开发组件,那么headers和namelink都将在没有库的情况下安装(如果不同时安装Libraries组件,namelink将是一个悬挂符号链接,链接到库的项目将出现生成错误。)如果只安装Libraries组件,则只安装库,而不安装头和namelink。
NAMELINK_ONLY
:- 此选项导致在安装库目标时仅安装名称链接。
- 在版本控制的共享库没有名称链接的平台上,或者当库没有版本控制时,NAMELINK_ONLY选项不安装任何东西。
- 在LIBRARY块之外使用此参数是错误的。
- 当指定了NAMELINK_ONLY时,可以使用NAMELINK_COMPONENT或COMPONENT来指定NAMELINK_COMPONENT的安装组件,但通常应该优先使用COMPONENT。
NAMELINK_SKIP
:- 类似于NAMELINK_ONLY,但它有相反的效果:当安装库目标时,它会导致库文件的安装,而不是名称链接。当没有给出NAMELINK_ONLY或NAMELINK_SKIP时,将安装这两个部分。在版本控制的共享库没有符号链接的平台上,或者当一个库没有版本控制时,NAMELINK_SKIP会安装这个库。在LIBRARY块之外使用此参数是错误的。
- 如果指定了NAMELINK_SKIP,则NAMELINK_COMPONENT无效。不推荐将NAMELINK_SKIP和NAMELINK_COMPONENT一起使用。
install(TARGETS)命令在顶层也可以接受以下选项:
EXPORT
:- 这个选项将安装的目标文件与一个名为< export-name >的导出关联起来。
- 它必须出现在任何目标选项之前。
- 要实际安装导出文件本身,请调用 install(EXPORT),如下所示。
- 请参阅EXPORT_NAME目标属性的文档,以更改导出目标的名称。
INCLUDES DESTINATION
:
-
这个选项指定了一个目录列表,当通过install(EXPORT)命令导出时,这些目录将被添加到< targets >的INTERFACE_INCLUDE_DIRECTORIES目标属性中。
-
如果指定了相对路径,则将其视为相对于$< INSTALL_PREFIX >。
-
RUNTIME_DEPENDENCY_SET
:- 3.21新版功能。
- 此选项将导致已安装的可执行程序、共享库和模块目标的所有运行时依赖项添加到指定的运行时依赖项集。稍后可以使用install(RUNTIME_DEPENDENCY_SET)命令安装该集合。
- 此参数和RUNTIME_DEPENDENCIES参数是互斥的。
-
RUNTIME_DEPENDENCIES
:- 3.21新版功能。
- 此选项导致已安装的可执行程序、共享库和模块目标的所有运行时依赖项与目标本身一起安装。RUNTIME、LIBRARY、FRAMEWORK和泛型参数用于确定这些依赖项安装的属性(DESTINATION、COMPONENT等)
- 此参数与RUNTIME_DEPENDENCY_SET参数是互斥的。
可以在对该命令的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。
接口库可能列在要安装的目标中。它们不安装任何工件,但将包含在关联的导出中。如果列出了对象库,但没有为其对象文件指定目标,则它们将作为接口库导出。这足以满足在实现中链接到对象库的其他目标的可传递使用需求。