CMake第二课--安装文件
CMake第二课 安装文件
一.完整过程
手把手教你学CMake,上一节讲的HelloWorld比较简单。这一节我们对它进行完善,让它看起来更像一个工程;并把它安装到自己的电脑上。
====================================================================================
#先建一个空文件夹“2” 它的路径是/home/guo/cmake_practice/2 标红的那部分改成自己的用户名
绝对路径:/home/guo/cmake_practice/2(工程目录)
----------------------------------------------------------
目标:
1.为工程添加一个子目录 src,用来放置工程源代码;
2.添加一个子目录 doc,用来放置这个工程的文档 hello.txt
3.在工程目录添加文本文件 COPYRIGHT, README;
4.在工程目录添加一个 runhello.sh 脚本,用来调用 hello二进制可执行程序
5.最终安装这些文件:
将 hello 二进制与 runhello.sh 安装至/home/guo/ cmake_practice/2/usr/bin;
将 doc 目录的内容安装到/home/guo/cmake_practice/2/usr/doc;
将COPYRIGHT/README 安装到/home/guo/cmake_practice/2/usr/share
----------------------------------------------------------
工程目录结构(按照下面结构添加文件夹和文件):
1.在主工程目录(/home/guo/cmake_practice/2)建一个CMakeLists.txt文件,
CMakeLists.txt文件内容为:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8) # 声明要求的 cmake 最低版本 PROJECT(hello) # 声明一个 cmake 工程 ADD_SUBDIRECTORY(src bin) INSTALL(FILES COPYRIGHT README DESTINATION usr/share) INSTALL(PROGRAMS runhello.sh DESTINATION usr/bin) INSTALL(DIRECTORY doc/ DESTINATION usr/doc)
2.建一个空的COPYRIGHT.txt和README.txt文件
3.一个runhello.sh文件 内容为./hello(hello为生成的可执行二进制文件名)
4.一个doc文件夹 里面建一个空的hello.txt文件
5.一个usr空文件夹 存放安装结果,可建可不建,执行install命令后相关路径文件夹会自动创建
6.一个src文件夹(/home/guo/cmake_practice/2/src)里面main.cpp 和 CMakeLists.txt
src/main.cpp 文件内容:
#include <iostream> using namespace std; int main( int argc, char** argv ) { cout<<"Hello World!"<<endl; return 0; }
src/CmakeLists.txt 文件内容:
CMAKE_MINIMUM_REQUIRED( VERSION 2.8 ) # 声明要求的 cmake 最低版本 #SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) #SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) ADD_EXECUTABLE( hello main.cpp ) INSTALL( TARGETS hello RUNTIME DESTINATION usr/bin)
-------------------------------------------------------------------------------
外部编译
开终端
cd /home/guo/cmake_practice/2
mkdir build (新建build文件夹)
cd build
cmake -DCMAKE_INSTALL_PREFIX=/home/guo/cmake_practice/2 ..
(指定绝对路径 <prefix>;因外部编译,所以用‘ ..’)
make
sudo make install
这样我们就把想要安装的文件安到了指定路径。
====================================================================================
二.详细解释
1. ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
- 这个指令用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置。EXCLUDE_FROM_ALL 参数的含义是将这个目录从编译过程中排除。比如,工程的 example,可能就需要工程构建完成后,再进入 example 目录单独进行构建。
- 上面的例子定义了将 src 子目录加入工程,并指定编译输出(包含编译中间结果)路径为bin 目录。如果不进行 bin 目录的指定,那么编译结果(包括中间结果)都将存放在build/src 目录(这个目录跟原有的 src 目录对应);指定 bin 目录后,相当于在编译时将 src 重命名为 bin,所有的中间结果和目标二进制都将存放在 bin 目录。
2. ADD_SUBDIRECTORY 指令不论是否指定编译输出目录,我们都可以通过 SET 指令重新定义 EXECUTABLE_OUTPUT_PATH 和 LIBRARY_OUTPUT_PATH 变量来指定最终的目标二进制的位置(指最终生成的 hello 或者最终的共享库,不包含编译生成的中间文件)。
- SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) #可执行二进制的输出路径为 build/bin
- SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) #库的输出路径为 build/lib
- <projectname>_BINARY_DIR 和 PROJECT_BINARY_DIR 变量,他们指的编译发生的当前目录;如果是内部编译,就相当于 PROJECT_SOURCE_DIR 也就是工程代码所在目录;如果是外部编译,指的是外部编译所在目录,也就是本例中的 build目录。
注意:应该把这两条指令写在工程的 CMakeLists.txt 还是 src 目录下的CMakeLists.txt ?
把握一个简单的原则,在哪里 ADD_EXECUTABLE 或 ADD_LIBRARY,如果需要改变目标存放路径,就在哪里加入上述的定义!在这个例子里,当然就是指 src 下的 CMakeLists.txt 了。
3. 安装 COPYRIGHT/README
直接修改主工程文件 CMakelists.txt,加入以下指令:
INSTALL(FILES COPYRIGHT README DESTINATION usr/share)
4. 安装 runhello.sh
直接修改主工程文件 CMakeLists.txt,加入如下指令:
INSTALL(PROGRAMS runhello.sh DESTINATION usr/bin)
5. 安装 doc 中的 hello.txt
这里采用的方式是安装 doc目录中的内容,也就是使用 ” doc/”.在工程文件中添加:
INSTALL(DIRECTORY doc/ DESTINATION usr/doc)
6. 安装二进制可执行文件
在scr文件夹下的 CMakeLists.txt中(在哪里 ADD_EXECUTABLE 或 ADD_LIBRARY,就在哪添加添加)
INSTALL( TARGETS hello RUNTIME DESTINATION usr/bin)
7. 如果没有定义 CMAKE_INSTALL_PREFIX 会安装到什么地方?
你可以尝试以下,cmake .. ; make ; make install,你会发现CMAKE_INSTALL_PREFIX 的默认定义是/usr/local(根目录下的)。
-------------------------------------------------------------------------------
三.如何安装?(大体分为四个步骤)
- 第一步:在对应的CMakeLists.txt文件中,添加INSTALL 指令,用于定义安装规则。安装的内容可以包括目标二进制、动态库、静态库以及文件、目录、脚本等。
- 第二步:终端输入,指定绝对路径 cmake -DCMAKE_INSTALL_PREFIX=/home/guo /cmake_practice/2 ..(外部编译)
- 第三步:make
- 第四步:sudo make install
1. 目标文件的安装
INSTALL(TARGETS targets...
[[ARCHIVE|LIBRARY|RUNTIME]
[DESTINATION <dir>]
[PERMISSIONS permissions...]
[CONFIGURATIONS
[Debug|Release|...]]
[COMPONENT <component>]
[OPTIONAL]
] [...])
- 参数中的 TARGETS 后面跟的就是我们通过 ADD_EXECUTABLE 或者 ADD_LIBRARY 定义的目标文件,可能是可执行二进制、动态库、静态库;
- 目标类型也就相对应的有三种,ARCHIVE 特指静态库,LIBRARY 特指动态库,RUNTIME特指可执行目标二进制;
- DESTINATION 定义了安装的路径,如果路径以“ / ”开头,那么指的是绝对路径,这时候CMAKE_INSTALL_PREFIX 其实就无效了。如果你希望使用CMAKE_INSTALL_PREFIX 来定义安装路径,就要写成相对路径,即不要以“ / ”开头,那么安装后的路径就是${CMAKE_INSTALL_PREFIX}/<DESTINATION 定义的路径>
举个简单的例子:(注意 在哪ADD_EXECUTABLE的 或者 ADD_LIBRARY 的 ,就写在那个文件里的CMakeLists.txt)
INSTALL(TARGETS myrun mylib mystaticlib
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION libstatic )
上面的例子会将:
- 可执行二进制 myrun 安装到${CMAKE_INSTALL_PREFIX}/bin 目录
- 动态库 libmylib 安装到${CMAKE_INSTALL_PREFIX}/lib 目录
- 静态库 libmystaticlib 安装到${CMAKE_INSTALL_PREFIX}/libstatic 目录
注意:我们自己定义的库名XXXX,生成的库会自动脑补成libXXXX
- 绝对路径:是从根目录开始的路径;形如/home/guo/lib。
- 相对路径:是从当前路径开始的路径;假如当前路径为/home/guo 要描述上述路径,只需输入lib。
2. 普通文件的安装
INSTALL(FILES files... DESTINATION <dir>
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[RENAME <name>] [OPTIONAL])
可用于安装一般文件,并可以指定访问权限,文件名是此指令所在路径下的相对路径。如果默认不定义权限 PERMISSIONS,安装后的权限为:
OWNER_WRITE, OWNER_READ,GROUP_READ,和 WORLD_READ,即 644 权限。
3. 非目标文件的可执行程序安装(比如脚本之类)
INSTALL(PROGRAMS files... DESTINATION <dir>
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[RENAME <name>] [OPTIONAL])
跟上面的 FILES 指令使用方法一样,唯一的不同是安装后权限为:OWNER_EXECUTE, GROUP_EXECUTE, 和 WORLD_EXECUTE,即 755 权限。
4. 目录的安装
INSTALL(DIRECTORY dirs... DESTINATION <dir>
[FILE_PERMISSIONS permissions...]
[DIRECTORY_PERMISSIONS permissions...]
[USE_SOURCE_PERMISSIONS]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[[PATTERN <pattern> | REGEX <regex>]
[EXCLUDE] [PERMISSIONS permissions...]] [...])
这里主要介绍其中的 DIRECTORY、PATTERN 以及 PERMISSIONS 参数。
- DIRECTORY 后面连接的是所在 Source 目录的相对路径,但务必注意: abc 和 abc/有很大的区别。如果目录名不以" / "结尾,那么这个目录将被安装为目标 路径下的 abc;如果目录名以" / "结尾,代表将这个目录中的内容安装到目标路径,但不包括这个目录本身。
- PATTERN 用于使用正则表达式进行过滤。
- PERMISSIONS 用于指定 PATTERN 过滤后的文件权限。
例子:
INSTALL(DIRECTORY icons scripts/ DESTINATION share/myproj
PATTERN "CVS" EXCLUDE
PATTERN "scripts/*"
PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
GROUP_EXECUTE GROUP_READ)
这条指令的执行结果是:
- 将 icons 目录安装到 <prefix>/share/myproj ;
- 将 scripts/中的内容安装到<prefix>/share/myproj不包含目录名为 CVS 的目录;对于 scripts/* 文件指定权限为 OWNER_EXECUTE, OWNER_WRITE ,OWNER_READ ,GROUP_EXECUTE, GROUP_READ。