HELLO CMAKE-如何让自己的 CMake 工程支持 make install 命令

2,856 阅读4分钟

如何让自己的 CMake 工程支持 make install 命令

CMake 程序的安装通常分为两种,第一种是直接发布给用户源码,用户编译后直接使用 make install 命令安装到自己的电脑指定位置;第二种便是开发者将编译好的程序打包给用户,用户用包管理器安装到自己的电脑中。这里我为大家介绍第一种方式。

本文的测试代码可以在Github中找到,欢迎大家访问学习。

INSTALL 命令

CMake 有Install命令,可以配合 make install 使用,install的形式如下:

install(TARGETS targets... [EXPORT <export-name>]
          [[ARCHIVE|LIBRARY|RUNTIME|FRAMEWORK|BUNDLE|
            PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
                [DESTINATION <dir>]
                [PERMISSIONS permissions...]
                [CONFIGURATIONS [Debug|Release|...]]
                [COMPONENT <component>]
                [OPTIONAL] [NAMELINK_ONLY|NAMELINK_SKIP]
          ] [...])

最常用的參數是 DESTINATION,用以指定安裝的目的地。假如我們生成一个可执行程序 hello,install() 指令通常寫起來像這樣:

# 编译生成一个 可执行程序,文件名 hello
add_executable(hello main.cpp hello.cpp)
install(TARGETS hello DESTINATION bin)

那么实际使用 make install 命令时软件安装到了哪个路径呢?

在 windows 操作系统下,软件会安装到 C:\Program Files\,在 Linux、MacOS等操作系统下,则会安装到/usr/local/下。

我们可以通过设置CMake内置变量CMAKE_INSTALL_PREFIX的值来指定一个安装前缀,这个变量可以在CMakeLists.txt文件内设置,也可以不设置。如果不设置,我们在构建CMAKE工程时可以手动指定,通过cmake ../project_path -DCMAKE_INSTALL_PRFIX=./install,则安装的路径会在当前文件夹下的新建文件夹install文件夹下。

除了 CMAKE_INSTALL_PREFIX 之外,CMake 所產生出來的 Makefile 也支持 DESTDIR 变量。有下面兩種使用方式:

make install DESTDIR="/some/absolute/path"export DESTDIR="/some/absolute/path"
make install

如此一来,最后的保存文件位置便为:

    -DESTDIR/
        -CMAKE_INSTALL_PREFIX/
            -install 指定的 DESTINATION

实践

前一篇文章中,我们实现了一个第一个 CMake 工程,现在我们编辑该工程的CMakeLists.txt文件来实现安装功能,使文件内容如下:

project(HELLO_CMAKE)

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

add_executable(hello main.cpp hello.cpp)

# 安装 编译生成的 hello 文件到 CMAKE_INSATLL_PREFIX/bin
install(TARGETS hello DESTINATION bin)

然后我们重新构建工程,可能会见到如下的输出:

chaoqun@manjaro hello_cmake]$ ls
CMakeLists.txt  build  hello.cpp  hello.h  main.cpp
[chaoqun@manjaro hello_cmake]$ cd build/
[chaoqun@manjaro build]$ cmake .. -DCMAKE_INSTALL_PREFIX=./install
CMake Warning (dev) in CMakeLists.txt:
  No cmake_minimum_required command is present.  A line of code such as

    cmake_minimum_required(VERSION 3.15)

  should be added at the top of the file.  The version specified may be lower
  if you wish to support older CMake versions for this project.  For more
  information run "cmake --help-policy CMP0000".
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Configuring done
-- Generating done
-- Build files have been written to: /home/chaoqun/workspace/learning/hello_cmake/hello_cmake/build
[chaoqun@manjaro build]$ make
Scanning dependencies of target hello
[ 33%] Building CXX object CMakeFiles/hello.dir/main.o
[ 66%] Building CXX object CMakeFiles/hello.dir/hello.o
[100%] Linking CXX executable bin/hello
[100%] Built target hello
[chaoqun@manjaro build]$ make install
[100%] Built target hello
Install the project...
-- Install configuration: ""
-- Installing: /home/chaoqun/workspace/learning/hello_cmake/hello_cmake/build/install/bin/hello
chaoqun@manjaro build]$ ls
CMakeCache.txt  Makefile  cmake_install.cmake  install_manifest.txt
CMakeFiles      bin       install
[chaoqun@manjaro build]$ cd install/
[chaoqun@manjaro install]$ ls
bin
[chaoqun@manjaro install]$ cd bin/
[chaoqun@manjaro bin]$ ls
hello
[chaoqun@manjaro bin]$ ./hello 
Hello CMake!

由此可见,我们成功把文件安装到了自己想要放置的路径,如果想要安装到系统目录下,可以通过设置CMAKE_INSTALL_PREFIX的值为/usr/;那样 hello 文件会被放置到/usr/bin/文件夹下,而/usr/bin/是系统默认环境变量PATH中的一部分。需要注意的是,安装到系统变量里通常需要使用root权限,否则可能不具有写入该路径的权限。

install 支持的安装的文件种类

install 不止可以安装可执行程序,也支持更多种类:

  • TARGETS 将 make 编译出来的文件复制到指定文件夹
  • FILES 将一般的文件复制到指定文件夹
  • PROGRAMS 将脚本文件复制到指定文件夹,与FILES命令不同的是,该文件会具有可执行权限
  • DIRECTORY 将一个目录内的内容复制到指定文件夹
install(FILES files...
    DESTINATION <dir>
    [PERMISSIONS permissions...]
    [CONFIGURATIONS [Debug|Release|...]]
    [COMPONENT <component>]
    [RENAME <name>] [OPTIONAL]
    )
    
INSTALL(PROGRAMS files... DESTINATION <dir> 
    [PERMISSIONS permissions...]
    [CONFIGURATIONS [Debug|Release|...]]
    [COMPONENT <component>]
    [RENAME <name>] [OPTIONAL])
    
install(DIRECTORY dirs...
    DESTINATION <dir>
    [FILE_PERMISSIONS permissions...]
    [DIRECTORY_PERMISSIONS permissions...]
    [USE_SOURCE_PERMISSIONS] [OPTIONAL]
    [CONFIGURATIONS [Debug|Release|...]]
    [COMPONENT <component>] [FILES_MATCHING]
    [[PATTERN <pattern> | REGEX <regex>]
    [EXCLUDE] [PERMISSIONS permissions...]] [...]
    )    

如果我想把 hello.h复制到include文件夹,并把当前工程文件夹内的所有内容复制到src文件夹中,我们可以按如下方式修改CMakeLists.txt

project(HELLO_CMAKE)

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

add_executable(hello main.cpp hello.cpp)

# 安装 编译生成的 hello 文件到 CMAKE_INSATLL_PREFIX/bin
install(TARGETS hello DESTINATION bin)

# 复制 hello.h 文件到 CMAKE_INSATLL_PREFIX/include 文件夹中
install(FILES hello.h DESTINATION include)

# 复制整个文件夹内的文件到 CMAKE_INSATLL_PREFIX/src 文件夹中
install(DIRECTORY ${PROJECT_SOURCE_DIR} DESTINATION src)

最终效果如下:

[chaoqun@manjaro build]$ make
[100%] Built target hello
[chaoqun@manjaro build]$ make install
[100%] Built target hello
Install the project...
-- Install configuration: ""
-- Installing: /home/chaoqun/workspace/learning/hello_cmake/build/install/bin/hello
-- Installing: /home/chaoqun/workspace/learning/hello_cmake/build/install/include/hello.h
-- Installing: /home/chaoqun/workspace/learning/hello_cmake/build/install/src/hello_cmake
-- Installing: /home/chaoqun/workspace/learning/hello_cmake/build/install/src/hello_cmake/hello.h
-- Installing: /home/chaoqun/workspace/learning/hello_cmake/build/install/src/hello_cmake/CMakeLists.txt
-- Installing: /home/chaoqun/workspace/learning/hello_cmake/build/install/src/hello_cmake/main.cpp
-- Installing: /home/chaoqun/workspace/learning/hello_cmake/build/install/src/hello_cmake/hello.cpp
[chaoqun@manjaro build]$ ls
CMakeCache.txt  Makefile  cmake_install.cmake  install_manifest.txt
CMakeFiles      bin       install
[chaoqun@manjaro build]$ cd install/
[chaoqun@manjaro install]$ ls
bin  include  src

Reference

  1. 代码样例
  2. CMake Partice
  3. Wikipedia