cmake install_CMAKE最全实战(1)

1.cmake

cmake 是kitware 公司以及⼀些开源开发者在开发⼏个⼯具套件(VTK)的过程中衍⽣品,最终形成体系,成为⼀个独⽴的开放源代码项⽬。官⽅⽹站是www.cmake.org,可以通过访问官⽅⽹站获得更多关于cmake 的信息。

说就是:只有少数⼏个“编译专家”能够掌握 KDE 现在的构建体系(admin/Makefile.common),在经历了unsermake, scons 以及cmake 的选型和尝试之后,KDE4 决定使⽤cmake 作为⾃⼰的构建系统。在迁移过程中,进展异常的顺利,并获得了cmake 开发者的⽀持。所以,⽬前的 KDE4 开发版本已经完全使⽤cmake 来进⾏构建。像kdesvn,rosegarden 等项⽬也开始使⽤cmake,这也注定了cmake 必然会成为⼀个主流的构建体系。

特点

cmake 的特点主要有:

1.开放源代码,使⽤类BSD 许可发布。http://cmake.org/HTML/Copyright.html

2.跨平台,并可⽣成native 编译配置⽂件,在Linux/Unix 平台,⽣成 makefile,在苹果平台,可以⽣成xcode,在 Windows 平台,可以⽣成 MSVC 的⼯程⽂件。

3.能够管理⼤型项⽬,KDE4 就是最好的证明。

4.简化编译构建过程和编译过程。Cmake 的⼯具链⾮常简单:cmake+make。

5.⾼效虑,按照KDE 官⽅说法,CMake 构建KDE4 的 kdelibs 要⽐使⽤autotools 来构建KDE3.5.6 的kdelibs 快40%,主要是因为 Cmake 在⼯具链中没有libtool。

6.可扩展,可以为cmake 编写特定功能的模块,扩充cmake 功能。

问题

难道就没有问题?

1.cmake 很简单,但绝对没有听起来或者想象中那么简单。

2.cmake 编写的过程实际上是编程的过程,跟以前使⽤autotools ⼀样,不过你需要编写的是CMakeLists.txt(每个⽬录⼀个),使⽤的是”cmake 语⾔和语法”。

3.cmake 跟已有体系的配合并不是特别理想,⽐如pkgconfig,您在实际使⽤中会有所体会,虽然有⼀些扩展可以使⽤,但并不理想。

建议

1.如果你没有实际的项⽬需求,那么看到这⾥就可以停下来了,因为cmake 的学习过程就是实践过程,没有实践,读的再多⼏天后也会忘记。

2.如果你的⼯程只有⼏个⽂件,直接编写Makefile 是最好的选择。

3.如果使⽤的是C/C++/Java 之外的语⾔,请不要使⽤cmake(⾄少⽬前是这样)

4.如果你使⽤的语⾔有⾮常完备的构建体系,⽐如java 的 ant,也不需要学习cmake,虽然有成功的例⼦,⽐如QT4.3 的csharp 绑定qyoto。

5.如果项⽬已经采⽤了⾮常完备的⼯程管理⼯具,并且不存在维护问题,没有必要迁移到 cmake

6.如果仅仅使⽤qt 编程,没有必要使⽤ cmake,因为qmake 管理 Qt ⼯程的专业性和⾃动化程度⽐cmake 要⾼很多。

安装 cmake

(1)卸载已经安装的旧版的CMake(⾮必需)

apt-get autoremove cmake

(2)⽂件下载解压

wget https://cmake.org/files/v3.9/cmake-3.9.1-Linux-x86_64.tar.gz

tar zxvf cmake-3.9.1-Linux-x86_64.tar.gz

查看解压后⽬录:

0ef79f74cecdba12e1ffd772c1748d9e.png
4de29f20d80faa9138833f4d6342c078.png

bin下⾯有各种cmake家族的产品程序.

创建软链接

注: ⽂件路径是可以指定的, ⼀般选择在 /opt 或 /usr 路径下, 这⾥选择 /opt

mv cmake-3.9.1-Linux-x86_64 /opt/cmake-3.9.1

ln -sf /opt/cmake-3.9.1/bin/* /usr/bin/

cmake 的 helloworld

本节并不会深⼊的探讨cmake,仅仅展示⼀个简单的例⼦,并加以粗略的解释。

准备⼯作

⾸先,建⽴⼀个cmake ⽬录,⽤来放置我们学习过程中的所有练习。 mkdir -p cmake以后我们所有的cmake 练习都会放在cmake 的⼦⽬录下(你也可以⾃⾏安排⽬录,这个并不是限制,仅仅是为了叙述的⽅便),然后在cmake 建⽴第⼀个练习⽬录t1。

cd cmake

mkdir t1

cd t1

在 t1(hello-world) ⽬录建⽴main.c 和 CMakeLists.txt(注意⽂件名⼤⼩写):

main.c ⽂件内容:

51ccb856ce38efa7f8a32d6d5712a8b0.png

CmakeLists.txt ⽂件内容:

1abe52a9b099209b78415523d24e4bb8.png

开始构建

所有的⽂件创建完成后,t1 ⽬录中应该存在main.c 和 CMakeLists.txt 两个⽂件接下来我们来构建这个⼯程,在这个⽬录运⾏:

cmake . (注意命令后⾯的点号,代表本⽬录)。

输出⼤概是这个样⼦:

0c9e3617f75d03a8b831367740f213c8.png

再让我们看⼀下⽬录中的内容, 你会发现,系统⾃动⽣成了:

CMakeFiles, CMakeCache.txt, cmake_install.cmake 等⽂件,并且⽣成了 Makefile。不需要理会这些⽂件的作⽤,以后你也可以不去理会。最关键的是,它⾃动⽣成了 Makefile。然后进⾏⼯程的实际构建,在这个⽬录输⼊ make 命令,⼤概会得到如下的彩⾊输出:

09dcc599a54f1dda53b0f7e7ac2e8683.png

如果你需要看到make 构建的详细过程,可以使⽤make VERBOSE=1 或者VERBOSE=1 make 命令来进⾏构建。这时候,我们需要的⽬标⽂件hello 已经构建完成,位于当前⽬录,尝试运⾏⼀下:

./hello

得到输出:

Hello World from Main

简单的解释

我们来重新看⼀下 CMakeLists.txt,这个⽂件是 cmake 的构建定义⽂件,⽂件名是⼤⼩写相关的,如果⼯程存在多个⽬录,需要确保每个要管理的⽬录都存在⼀个CMakeLists.txt。(关于多⽬录构建,后⾯我们会提到,这⾥不作过多解释)。

上⾯例⼦中的CMakeLists.txt ⽂件内容如下:

6b8494dff2ee2e4a2531068b5e3d4825.png

PROJECT

PROJECT 指令的语法是:

PROJECT(projectname [CXX] [C] [Java])

你可以⽤这个指令定义⼯程名称,并可指定⼯程⽀持的语⾔,⽀持的语⾔列表是可以忽略的,默认情况表示⽀持所有语⾔。这个指令隐式的定义了两个 cmake 变量: _BINARY_DIR 以及_SOURCE_DIR,这⾥就是 HELLO_BINARY_DIR 和HELLO_SOURCE_DIR(所以CMakeLists.txt 中两个MESSAGE指令可以直接使⽤了这两个变量),因为采⽤的是内部编译,两个变量⽬前指的都是⼯程所在路cmake/t1,后⾯我们会讲到外部编译,两者所指代的内容会有所不同。同时cmake 系统也帮助我们预定义PROJECT_BINARY_DIR 和PROJECT_SOURCE_DIR变量,他们的值分别跟HELLO_BINARY_DIR 与HELLO_SOURCE_DIR ⼀致。

为了统⼀起⻅,建议以后直接使⽤PROJECT_BINARY_DIR,PROJECT_SOURCE_DIR,即使修改了⼯程名称,也不会影响这两个变量。如果使⽤了_SOURCE_DIR,修改⼯程名称后,需要同时修改这些变量。

SET

SET 指令的语法是:

SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])

现阶段,你只需要了解SET 指令可以⽤来显式的定义变量即可。⽐如我们⽤到的是SET(SRC_LIST main.c),如果有多个源⽂件,也可以定义成:

SET(SRC_LIST main.c t1.c t2.c)。

MESSAGE

MESSAGE 指令的语法是:

MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)

这个指令⽤于向终端输出⽤户定义的信息,包含了三种类型:

(1)SEND_ERROR,产⽣错误,⽣成过程被跳过。

(2)SATUS,输出前缀为—的信息。

(3)FATAL_ERROR,⽴即终⽌所有cmake 过程

在这⾥使⽤的是STATUS 信息输出,演示了由PROJECT 指令定义的两个隐式变量HELLO_BINARY_DIR 和HELLO_SOURCE_DIR。

ADD_EXECUTABLE

ADD_EXECUTABLE(hello ${SRC_LIST})

定义了这个⼯程会⽣成⼀个⽂件名为hello 的可执⾏⽂件,相关的源⽂件是 SRC_LIST 中定义的源⽂件列表, 本例中你也可以直接写成ADD_EXECUTABLE(hello main.c)。

在本例我们使⽤了${}来引⽤变量,这是cmake 的变量应⽤⽅式。

注意:有⼀些例外,⽐如在IF 控制语句,变量是直接使⽤变量名引⽤,⽽不需要${}。如果使⽤了${}去应⽤变量,其实IF 会去判断名为${}所代表的值的变量,那当然是不存在的了。

将本例改写成⼀个最简化的CMakeLists.txt:

PROJECT(HELLO)

ADD_EXECUTABLE(hello main.c)

基本语法规则

前⾯提到过,cmake 其实仍然要使⽤”cmake 语⾔和语法”去构建,上⾯的内容就是所谓的 ”cmake 语⾔和语法”,最简单的语法规则是:

(1)变量使⽤${}⽅式取值,但是在IF 控制语句中是直接使⽤变量名。

(2)指令(参数1 参数 2...)

参数使⽤括弧括起,参数之间使⽤空格或分号分开。以上⾯的ADD_EXECUTABLE 指令为例,如果存在另外⼀个 func.c 源⽂件,就要写成:

ADD_EXECUTABLE(hello main.c func.c)或者ADD_EXECUTABLE(hello main.c;func.c)

(3)指令是⼤⼩写⽆关的,参数和变量是⼤⼩写相关的。推荐你全部使⽤⼤写指令。上⾯的MESSAGE 指令我们已经⽤到了这条规则:

MESSAGE(STATUS “This is BINARY dir” ${HELLO_BINARY_DIR})

也可以写成:

MESSAGE(STATUS “This is BINARY dir ${HELLO_BINARY_DIR}”)

这⾥需要特别解释的是作为⼯程名的HELLO 和⽣成的可执⾏⽂件 hello 是没有任何关系的

⼯程名和执⾏⽂件

hello 定义了可执⾏⽂件的⽂件名,你完全可以写成:ADD_EXECUTABLE(t1 main.c)编译后会⽣成⼀个t1 可执⾏⽂件。

关于语法的疑惑

cmake 的语法还是⽐较灵活⽽且考虑到各种情况,⽐如:

SET(SRC_LIST main.c)也可以写成 SET(SRC_LIST “main.c”)

这两种方式是没有区别。

注意:但是假设⼀个源⽂件的⽂件名是 fu nc.c(⽂件名中间包含了空格)。这时候就必须使⽤双引号,如果写成了 SET(SRC_LIST fu nc.c),就会出现错误,提示你找不到fu ⽂件和nc.c ⽂件。这种情况,就必须写成:

SET(SRC_LIST "fu nc.c")

此外,你可以可以忽略掉source 列表中的源⽂件后缀,⽐如可以写成如下:

ADD_EXECUTABLE(t1 main)。

cmake 会⾃动的在本⽬录查找main.c 或者main.cpp等,当然,最好不要偷这个懒,以免这个⽬录确实存在⼀个 main.c ⼀个main.

同时参数也可以使⽤分号来进⾏分割。下⾯的例⼦也是合法的:

ADD_EXECUTABLE(t1 main.c t1.c)可以写成ADD_EXECUTABLE(t1 main.c;t1.c).我们只需要在编写CMakeLists.txt 时注意形成统⼀的⻛格即可。

清理⼯程

跟经典的autotools 系列⼯具⼀样,运⾏:

make clean

问题

我尝试运⾏了 make distclean,这个指令⼀般⽤来清理构建过程中产⽣的中间⽂件的,如果要发布代码,必然要清理掉所有的中间⽂件,但是为什么在 cmake ⼯程中这个命令是⽆效的?cmake 并不⽀持 make distclean,关于这⼀点,官⽅是有明确解释的:

因为CMakeLists.txt 可以执⾏脚本并通过脚本⽣成⼀些临时⽂件,但是却没有办法来跟踪这些临时⽂件到底是哪些。因此,没有办法提供⼀个可靠的 make distclean ⽅案

ca03173509d69b2aa733b26bacd08330.png

同时,还有另外⼀个⾮常重要的提示,就是:我们刚才进⾏的是内部构建(in-source build),⽽ cmake强烈推荐的是外部构建(out-of-source build)。

内部构建与外部构建

上⾯的例⼦展示的是“内部构建”,相信看到⽣成的临时⽂件⽐您的代码⽂件还要多的时候,估计这辈⼦你都不希望再使⽤内部构建。

对于cmake,内部编译上⾯已经演示过了,它⽣成了⼀些⽆法⾃动删除的中间⽂件,所以,引出了我们对外部编译的探讨,外部编译的过程如下:

(1)⾸先,请清除t1 ⽬录中除main.c CmakeLists.txt 之外的所有中间⽂件,最关键的是CMakeCache.txt。

(2)在 t1 ⽬录中建⽴build ⽬录,当然你也可以在任何地⽅建⽴build ⽬录,不⼀定必须在⼯程⽬录中。

(3)进⼊ build ⽬录,运⾏cmake ..(注意,..代表⽗⽬录,因为⽗⽬录存在我们需要的CMakeLists.txt,如果你在其他地⽅建⽴了build ⽬录,需要运⾏cmake ),查看⼀下build ⽬录,就会发现了⽣成了编译需要的Makefile 以及其他的中间⽂件.

(4)运⾏ make 构建⼯程,就会在当前⽬录(build ⽬录)中获得⽬标⽂件 hello。

上述过程就是所谓的out-of-source 外部编译,⼀个最⼤的好处是,对于原有的⼯程没有任何影响,所有动作全部发⽣在编译⽬录。通过这⼀点,也⾜以说服我们全部采⽤外部编译⽅式构建⼯程。⽽ HELLO_BINARY_DIR 则指代编译路径,即cmake/t1/build

本⼩节描述了使⽤cmake 构建Hello World 程序的全部过程,并介绍了三个简单的指令:PROJECT/MESSAGE/ADD_EXECUTABLE 以及变量调⽤的⽅法,同时提及了两个隐式变量_SOURCE_DIR 及_BINARY_DIR,演示了变量调⽤的⽅法,从这个过程来看,有些开发者可能会想,这实在⽐我直接写 Makefile 要复杂多了,甚⾄我都可以不编写Makefile,直接使⽤gcc main.c 即可⽣成需要的⽬标⽂件。是的,正如第⼀节提到的,如果⼯程只有⼏个⽂件,还是直接编写 Makefile 最简单。但是, kdelibs 压缩包达到了50 多M,您认为使⽤什么⽅案会更容易⼀点呢?

4 更好⼀点的 Hello World

从本⼩节开始,后⾯所有的构建我们都将采⽤ out-of-source 外部构建,约定的构建⽬录是⼯程⽬录下的build ⾃录。

建设一个真正的工程,需要如下步骤:

(1)为⼯程添加⼀个⼦⽬录src,⽤来放置⼯程源代码

(2)添加⼀个⼦⽬录doc,⽤来放置这个⼯程的⽂档hello.txt

(3)在⼯程⽬录添加⽂本⽂件COPYRIGHT, README

(4)在⼯程⽬录添加⼀个runhello.sh 脚本,⽤来调⽤hello ⼆进制

(5)将构建后的⽬标⽂件放⼊构建⽬录的bin ⼦⽬录

(6)最终安装这些⽂件:将hello ⼆进制与runhello.sh 安装⾄/usr/bin,将doc ⽬录的内容以及

COPYRIGHT/README 安装到/usr/share/doc/cmake/t2。

具体工作如下:

(1)在cmake/⽬录下建⽴t2 (hello-world-clear)⽬录。并将 t1 ⼯程的 main.c 和 CMakeLists.txt 拷⻉到t2 ⽬录中。

(2)添加⼦⽬录src。

mkdir src

mv main.c src

现在的⼯程看起来是这个样⼦:⼀个⼦⽬录src,⼀个 CMakeLists.txt。

上⼀节我们提到,需要为任何⼦⽬录建⽴⼀个 CMakeLists.txt,进⼊⼦⽬录src,编写 CMakeLists.txt

如下:

ADD_EXECUTABLE(hello main.c)

将 t2 ⼯程的 CMakeLists.txt 修改为:

PROJECT(HELLO)

ADD_SUBDIRECTORY(src bin)

然后建⽴build ⽬录,进⼊build ⽬录进⾏外部编译。

cmake ..

make

构建完成后,你会发现⽣成的⽬标⽂件 hello 位于 build/bin ⽬录中。

语法解释

ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

这个指令⽤于向当前⼯程添加存放源⽂件的⼦⽬录,并可以指定中间⼆进制和⽬标⼆进制存放的位置。EXCLUDE_FROM_ALL 参数的含义是将这个⽬录从编译过程中排除,⽐如,⼯程的 example,可能就需要⼯程构建完成后,再进⼊ example ⽬录单独进⾏构建(当然,你也可以通过定义依赖来解决此类问题)。

上⾯的例⼦定义了将src ⼦⽬录加⼊⼯程,并指定编译输出(包含编译中间结果)路径为 bin ⽬录。如果不进⾏ bin ⽬录的指定,那么编译结果(包括中间结果)都将存放在 build/src ⽬录(这个⽬录跟原有的src ⽬录对应),指定 bin ⽬录后,相当于在编译时将src 重命名为bin,所有的中间结果和⽬标⼆进制都将存放在bin ⽬录

如果我们在上⾯的例⼦中将ADD_SUBDIRECTORY (src bin)修改为SUBDIRS(src)。那么在build ⽬录中将出现⼀个src ⽬录,⽣成的⽬标代码 hello 将存放在src ⽬录中。

这里提下SUBDIRS 指令,SUBDIRS(dir1 dir2...),这个指令已经不推荐使⽤。可以⼀次添加多个⼦⽬录,并且,即使外部编译,⼦⽬录体系仍然会被保存。

换个地⽅保存⽬标⼆进制

不论是SUBDIRS 还是 ADD_SUBDIRECTORY 指令(不论是否指定编译输出⽬录),我们都可以通过SET指令重新定义EXECUTABLE_OUTPUT_PATH 和LIBRARY_OUTPUT_PATH 变量来指定最终的⽬标⼆进制的位置(指最终⽣成的hello 或者最终的共享库,不包含编译⽣成的中间⽂件).

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

在第⼀节我们提到了_BINARY_DIR 和PROJECT_BINARY_DIR 变量,他们指的编译发⽣的当前⽬录,如果是内部编译,就相当于 PROJECT_SOURCE_DIR 也就是⼯程代码所在⽬录,如果是外部编译,指的是外部编译所在⽬录,也就是本例中的 build ⽬录。

上⾯两个指令分别定义了:可执⾏⼆进制的输出路径为build/bin 和库的输出路径为build/lib

没有提到共享库和静态库的构建,所以,你可以不考虑第⼆条指令。我应该把这两条指令写在⼯程的 CMakeLists.txt 还是 src ⽬录下的CMakeLists.txt,把握⼀个简单的原则,在哪⾥ADD_EXECUTABLE 或ADD_LIBRARY,如果需要改变⽬标存放路径,就在哪⾥加⼊上述的定义。在这个例⼦⾥,当然就是指src 下的CMakeLists.txt 了

如何安装

安装的需要有两种,⼀种是从代码编译后直接 make install 安装,⼀种是打包时的指定⽬录安装。所以,即使最简单的⼿⼯编写的Makefile,将 hello 直接安装到/usr/bin ⽬录,也可以通过make install DESTDIR=/tmp/test 将安装在/tmp/test/usr/bin ⽬录,打包时这个⽅式经常被使⽤,看起来也是这个样⼦的:

DESTDIR=

install:

mkdir -p $(DESTDIR)/usr/bin install -m 755 hello $(DESTDIR)/usr/bin

make install

稍微复杂⼀点的是还需要定义PREFIX,⼀般autotools ⼯程,会运⾏这样的指令:

./configure –prefix=/usr 或者./configure --prefix=/usr/local 来指定 PREFIX

⽐如上⾯的Makefile 就可以改写成:

DESTDIR=

PREFIX=/usr

install:

mkdir -p $(DESTDIR)/$(PREFIX)/bin install -m 755 hello $(DESTDIR)/$(PREFIX)/bin

那么我们的HelloWorld 应该怎么进⾏安装呢?这⾥需要引⼊⼀个新的cmake 指令 INSTALL 和⼀个⾮常有⽤的变量

CMAKE_INSTALL_PREFIX。

CMAKE_INSTALL_PREFIX 变量类似于configure 脚本的 –prefix,常⻅的使⽤⽅法看起来是这个样⼦:

cmake -DCMAKE_INSTALL_PREFIX=/usr .

INSTALL 指令⽤于定义安装规则,安装的内容可以包括⽬标⼆进制、动态库、静态库以及⽂件、⽬录、脚本等。

INSTALL 指令包含了各种安装类型,我们需要⼀个个分开解释:

⽬标⽂件的安装:

0dc0f4bc3c94ae0457ff281805bd22b8.png

参数中的TARGETS 后⾯跟的就是我们通过ADD_EXECUTABLE 或者ADD_LIBRARY 定义的⽬标⽂件,可能是可执⾏⼆进制、动态库、静态库

⽬标类型也就相对应的有三种,ARCHIVE 特指静态库,LIBRARY 特指动态库,RUNTIME特指可执⾏⽬标⼆进制。

DESTINATION 定义了安装的路径,如果路径以/开头,那么指的是绝对路径,这时候CMAKE_INSTALL_PREFIX 其实就⽆效了。如果你希望使⽤CMAKE_INSTALL_PREFIX 来定义安装路径,就要写成相对路径,即不要以/开头,那么安装后的路径就是${CMAKE_INSTALL_PREFIX}/。

注意:特别注意的是你不需要关⼼TARGETS 具体⽣成的路径,只需要写上TARGETS 名称就可以了。

简单的例⼦:

73a71cd296fc792f1639d7d5224acfc7.png

上⾯的例⼦会将:

(1)可执⾏⼆进制myrun 安装到${CMAKE_INSTALL_PREFIX}/bin

(2)⽬录动态库libmylib 安装到${CMAKE_INSTALL_PREFIX}/lib ⽬录

(3)静态库libmystaticlib 安装到${CMAKE_INSTALL_PREFIX}/libstatic ⽬录

普通⽂件的安装:

4eaca2b9a4aee05800309f90219aa259.png

可⽤于安装⼀般⽂件,并可以指定访问权限,⽂件名是此指令所在路径下的相对路径。如果默认不定义权限PERMISSIONS,安装后的权限为:

OWNER_WRITE, OWNER_READ, GROUP_READ,和WORLD_READ,即 644 权限。

⾮⽬标⽂件的可执⾏程序安装(⽐如脚本之类):

d2f44df9e92c768b918944da32107031.png

跟上⾯的FILES 指令使⽤⽅法⼀样,唯⼀的不同是安装后权限为:

OWNER_EXECUTE, GROUP_EXECUTE, 和WORLD_EXECUTE,即755 权限⽬录的安装:

下面主要介绍其中的DIRECTORY、PATTERN 以及 PERMISSIONS 参数。

1de5f6e744e4984c0f6bf76a1789ac77.png

注意:abc 和 abc/有很⼤的区别。DIRECTORY 后⾯连接的是所在Source ⽬录的相对路径。如果⽬录名不以/结尾,那么这个⽬录将被安装为⽬标路径下的abc,如果⽬录名以/结尾,代表将这个⽬录中的内容安装到⽬标路径,但不包括这个⽬录本身。

PATTERN ⽤于使⽤正则表达式进⾏过滤,PERMISSIONS ⽤于指定PATTERN 过滤后的⽂件权限。

例⼦:

8b114ec19b3f1b8c59d0863d80031858.png

这条指令的执⾏结果是:

将 icons ⽬录安装到 /share/myproj,将 scripts/中的内容安装到 /share/myproj不包含⽬录名为 CVS 的⽬录,对于scripts/*⽂件指定权限为 OWNER_EXECUTE OWNER_WRITEOWNER_READ GROUP_EXECUTE GROUP_READ。

安装时CMAKE 脚本的执⾏:

INSTALL([[SCRIPT ] [CODE ]] [...])

SCRIPT 参数⽤于在安装时调⽤cmake 脚本⽂件(也就是.cmake ⽂件)

CODE 参数⽤于执⾏CMAKE 指令,必须以双引号括起来。⽐如:

INSTALL(CODE "MESSAGE("Sample install message.")")

安装还有⼏个被标记为过时的指令,⽐如 INSTALL_FILES 等,这些指令已经不再推荐使⽤,所以,这⾥就不再赘述了。

下⾯,我们就来改写我们的⼯程⽂件,让他来⽀持各种⽂件的安装,并且,我们要使⽤CMAKE_INSTALL_PREFIX 指令。

修改 Helloworld ⽀持安装

在本节开头我们定义了本节的任务如下:

(1)为⼯程添加⼀个⼦⽬录src,⽤来存储源代码。

(2)添加⼀个⼦⽬录doc,⽤来存储这个⼯程的⽂档hello.txt。

(3)在⼯程⽬录添加⽂本⽂件COPYRIGHT, README。

(4)在⼯程⽬录添加⼀个runhello.sh 脚本,⽤来调⽤hello ⼆进制。

(5)将构建后的⽬标⽂件放⼊构建⽬录的bin ⼦⽬录。

(6)最终安装这些⽂件:将hello ⼆进制与runhello.sh 安装⾄//bin,将 doc ⽬录中的 hello.txt以及COPYRIGHT/README 安装到//share/doc/cmake/t2,将⾸先我们先补上为添加的⽂件。

添加doc ⽬录及⽂件:

cd cmake/t2

mkdir doc

vi doc/hello.txt

在⼯程⽬录添加runhello.sh 脚本,内容为:

hello

添加⼯程⽬录中的COPYRIGHT 和 README

touch COPYRIGHT

touch README

下⾯改写各⽬录的CMakeLists.txt ⽂件

(1)安装 COPYRIGHT/README,直接修改主⼯程⽂件CMakelists.txt,加⼊以下指令:

INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/t2)

(2)安装 runhello.sh,直接修改主⼯程⽂件CMakeLists.txt,加⼊如下指令:

INSTALL(PROGRAMS runhello.sh DESTINATION bin)

(3)安装 doc 中的hello.txt,这⾥有两种⽅式:⼀是通过在doc ⽬录建⽴ CMakeLists.txt 并将 doc ⽬录通过ADD_SUBDIRECTORY 加⼊⼯程来完成。另⼀种⽅法是直接在⼯程⽬录通过INSTALL(DIRECTORY 来完成),前者⽐较简单,各位可以根据兴趣⾃⼰完成,我们来尝试后者,顺便演示以下DIRECTORY 的安装。

(4)因为hello.txt 要安装到//share/doc/cmake/t2,所以我们不能直接安装整个doc ⽬录,这⾥采⽤的⽅式是安装 doc ⽬录中的内容,也就是使⽤”doc/”

在⼯程⽂件中添加

INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake/t2)

尝试我们修改的结果:

现在进⼊build ⽬录进⾏外部编译,注意使⽤ CMAKE_INSTALL_PREFIX 参数,这⾥我们将它安装到了/tmp/t2 ⽬录:

cmake -DCMAKE_INSTALL_PREFIX=/tmp/t2/usr ..

然后运⾏

make

make install

让我们进⼊/tmp/t2 ⽬录看⼀下安装结果:

15b22f0ee38a2418851e4376201a54f6.png

如果你要直接安装到系统,可以使⽤如下指令:

cmake -DCMAKE_INSTALL_PREFIX=/usr ..

如果我没有定义CMAKE_INSTALL_PREFIX 会安装到什么地⽅?你可以尝试以下,cmake ..;make;make install,你会发现 CMAKE_INSTALL_PREFIX 的默认定义是/usr/local

描述了如何在⼯程中使⽤多⽬录、各种安装指令以及CMAKE_INSTALL_PREFIX 变量。

在下一篇文章将讨论如何在cmake中构建动态库和静态库,以及如何使用外部头文件和外部共享库。这篇文章就分享到这里,欢迎到关注,点赞,收藏,转发

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
cmake_minimum_required(VERSION 3.8.0 FATAL_ERROR) project(mcu_kit VERSION 0.1.0 DESCRIPTION "mcu-kit SDK" LANGUAGES C ) set(PROJECT_BRIEF "vDiscovery") set(CMAKE_C_STANDARD 11) set(CMAKE_C_EXTENSIONS ON) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_POSITION_INDEPENDENT_CODE ON) add_compile_options(-Wall) list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") include(CMakePrintHelpers) include(ConfigureChecks) if(EXISTS "${PROJECT_SOURCE_DIR}/config.cmake") include(config.cmake) else() message(FATAL_ERROR "Can't find cmake.config file") endif() if(${CMAKE_CROSSCOMPILING}) set(LV_SIMULATOR_ON_PC OFF) else() set(LV_SIMULATOR_ON_PC ON) endif() configure_file( "${PROJECT_SOURCE_DIR}/base/base_sdk_version.h.in" "${PROJECT_SOURCE_DIR}/base/base_sdk_version.h" ) configure_file( "${PROJECT_SOURCE_DIR}/base/base_config.h.in" "${PROJECT_SOURCE_DIR}/base/base_config.h" ) set(CMAKE_INSTALL_BINDIR ${CMAKE_INSTALL_PREFIX}/bin) set(CMAKE_INSTALL_SBINDIR ${CMAKE_INSTALL_PREFIX}/sbin) set(CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_PREFIX}/lib) set(CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/include) set(CMAKE_INSTALL_SYSCONFDIR ${CMAKE_INSTALL_PREFIX}/etc) set(CMAKE_INSTALL_SHARESTATEDIR ${CMAKE_INSTALL_PREFIX}/com) set(CMAKE_INSTALL_LOCALSTATEDIR ${CMAKE_INSTALL_PREFIX}/var) set(CMAKE_INSTALL_INFODIR ${CMAKE_INSTALL_PREFIX}/info) set(CMAKE_INSTALL_LOCALEDIR ${CMAKE_INSTALL_PREFIX}/locate) set(CMAKE_INSTALL_MANDIR ${CMAKE_INSTALL_PREFIX}/man) set(CMAKE_INSTALL_DOCDIR ${CMAKE_INSTALL_PREFIX}/doc) set(CMAKE_INSTALL_RESDIR ${CMAKE_INSTALL_PREFIX}) include(PrepareInstall) set(KIT_ROOT_DIR ${CMAKE_SOURCE_DIR}) add_subdirectory("base") # add_subdirectory("third-party") add_subdirectory("lib") add_subdirectory("drivers") add_subdirectory("framework") add_subdirectory("sysapp") add_subdirectory("app") include(GeneratePkgConfig) include(Linux-kitInfo)详细注释一下这段代码
最新发布
05-25

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值