这本教程很短,总共只有47页,然而下来共花费约8个小时。其中,阅读+例程实践共花费(3.4日 - 3.10日)共花费5小时21分钟;整理笔记+发博客(3.11日和3.29日)共花费2小时25分钟 。
放一张阅读时间记录图。
做笔记总结真的太耗时了,而且自己很抗拒。由上图知,假如说只在文档上做标记,确实很简单,用5天的时间就看完了。然而起后便扔下不管了,直到今天快月底了才不得不写一篇总结,努力往上爬真他妈难啊。。。。
阅读完的时候,自己的任务也就结束了,可这样总感觉不是自己的东西,不如整理一下,吸收其中自己认为最有用的东西,这样也能极大的减轻自己的记忆负担。
当然,与自己使用marddown语法不熟练和MarkdownPad 2这个软件不好用也有关系,导致自己排版也花费了好多精力,下次直接在csdn里的markdown记录就行了,不要用MarkdownPad 2,别人觉得好用了不一定适合自己!!!
记笔记的教训总结一下:
- 最后总结的时候,不要事无巨细都想记录下来。只记录自己觉得最有用的就行了,想象如果只让你记录三点你会记录哪些,以此来帮助自己筛选重要的东西。
- 工具用好,以后就在csdn里面记录了,统一工具也避免不必要的麻烦!
笔记从第三章开始,包括一些文档里的错误所造成的坑!
三 初试 cmake – cmake 的 helloworld
遇到的坑
不要直接复制原文中代码,原文中代码""用的是中文字符,所以编译会出错,而且不好发现
-
cmake … 之后make
首先注意的是,当你定义了工程名时,cmake会预定义一些带有工程名的cmake变量。 PROJECT (HELLO) HELLO_BINARY_DIR HELLO_SOURCE_DIR PROJECT_BINARY_DIR PROJECT_SOURCE_DIR 如果是内部编译,就相当于 PROJECT_SOURCE_DIR 也就是 工程代码所在目录,如果是外部编译,**指的是外部编译所在目录**
-
指令是大小写无关的,参数和变量是大小写相关的 ; IF中使用变量名,不需要${变量名}
-
清理工程 make clean
-
内部构建和外部构建,cmake强烈推荐的是外部构建(out-of-source build)
内部构建就是在工程主目录下,也就是CMakeLists.txt所在的文件夹下编译; 而外部构建不是在此目录下编译的。一般是新建一个build文件夹,在此文件夹下cmake ..,生成makefile文件,然后再make编译。
四 更好一点的 Hello World
工程中多了src目录存放源文件。
-
需要为任何子目录建立一个 CMakeLists.txt
PROJECT(HELLO)
ADD_SUBDIRECTORY(src bin)
应该把这两条指令写在工程的 CMakeLists.txt 还是 src 目录下的CMakeLists.txt?
把握一个简单的原则,在哪里 ADD_EXECUTABLE 或 ADD_LIBRARY,
如果需要改变目标存放路径,就在哪里加入上述的定义 -
如何安装文件
如果你希望使用 CMAKE_INSTALL_PREFIX 来定义安装路径,就要写成相对路径,即不要以/开头,那么安装后的路径就是
${CMAKE_INSTALL_PREFIX}/<DESTINATION 定义的路径>。
安装的需要有两种,一种是从代码编译后直接 make install 安装,一种是打包时的指定目录安装。make和make install 的区别: make是在本地编译,编译所产生的文件在编译的文件夹里; make install则把编译产生的文件(如库文件,可执行文件,以及cmake指定的要安装的文件)安装到某个目录(一般是系统目录),这样其他程序就可以调用编译的这些东西了。
安装需要这个变量:CMAKE_INSTALL_PREFIX ,格式如下:
cmake -DCMAKE_INSTALL_PREFIX=/usr .
即生成安装到/usr目录的make file -
INSTALL一共有如下几种形式:
- 目标文件的安装:
INSTALL(TARGETS targets... [ARCHIVE|LIBRARY|RUNTIME] [DESTINATION dirname] [PERMISSIONS permissions...] [...])
如INSTALL(TARGETS myrun mylib mystaticlib RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION libstatic )
可执行二进制 myrun 安装到 C M A K E I N S T A L L P R E F I X / b i n 目 录 动 态 库 l i b m y l i b 安 装 到 {CMAKE_INSTALL_PREFIX}/bin 目录 动态库 libmylib 安装到 CMAKEINSTALLPREFIX/bin目录动态库libmylib安装到{CMAKE_INSTALL_PREFIX}/lib 目录
静态库 libmystaticlib 安装到${CMAKE_INSTALL_PREFIX}/libstatic 目录
特别注意的是你不需要关心 TARGETS 具体生成的路径,只需要写上 TARGETS 名称就可以
了。 - 普通文件的安装
INSTALL(FILES files... DESTINATION <dir> [PERMISSIONS permissions...])
非目标文件的可执行程序安装(比如脚本之类):
INSTALL(PROGRAMS files... DESTINATION <dir> [PERMISSIONS permissions...])
脚本安装后注意设置权限为:
OWNER_EXECUTE, GROUP_EXECUTE, 和 WORLD_EXECUTE,即 755 权限 - 目录的安装
INSTALL(DIRECTORY dirs... DESTINATION <dir> [FILE_PERMISSIONS permissions...])
DIRECTORY 后面连接的是所在 Source 目录的相对路径,但务必注意:
abc 和 abc/有很大的区别。
如果目录名不以/结尾,那么这个目录将被安装为目标路径下的 abc,如果目录名以/结尾,
代表将这个目录中的内容安装到目标路径,但不包括这个目录本身。 - 安装时CMAKE脚本的执行:
INSTALL([[SCRIPT <file>] [CODE <code>]] [...])
- 目标文件的安装:
五 静态库与动态库构建
本章主要讲了如何编译动态库/静态库,并安装库文件与头文件(.h)到系统目录中,以便其他程序调用这个库.
动态库是 .so文件,又叫共享库,静态库是.a文件。
- 如何通过 ADD_LIBRARY 指令构建动态库和静态库;
- 如何通过 SET_TARGET_PROPERTIES 同时构建同名的动态库和静态库;
- 如何通过 SET_TARGET_PROPERTIES 控制动态库版本;
- 最后将头文件和共享库安装到系统目录/usr/lib 和/usr/include/hello
所有的添加目录操作ADD_SUBDIRECTORY(lib)都在最外层的CMakeLists.txt中添加,且目录都是相对最外层的,不是绝对路径。
六 如何使用外部共享库和头文件
main.c中包含头文件hello.h会失败,因为hello.h 位于/usr/include/hello 目录中,并没有位于系统标准的头文件路径(系统标准头文件路径在/usr/include,其子目录hello并不是)
#include <hello.h>
int main()
{
HelloFunc();
return 0;
}
所以需要引入头文件搜索路径
INCLUDE_DIRECTORIES(/usr/include/hello)
此时编译还是会失败,因为没有链接到hello库文件。
所以需为 target 添加共享库
讲了两个指令
LINK_DIRECTORIES(directory1 directory2 ...)
添加非标准的共享库搜索路径,这个对应上面的INCLUDE_DIRECTORIES,本例没有用到此指令。
TARGET_LINK_LIBRARIES(main hello)
七 cmake 常用变量和常用环境变量
需要注意cmake变量分为隐式定义和显式定义两种。可以理解为隐式变量就是cmake自动生成的,直接可以用的。
隐式定义如PROJECT 指令,他
会隐式的定义_BINARY_DIR 和_SOURCE_DIR 两个变
量。显式定义如 SET 指令,就可以构建一个自定义变量了。
八 cmake 常用指令
主要讲了基本指令,INSTALL指令,FIND_指令(如FIND_FILE,FIND_LIBRARY,FIND_PATH,FIND_PACKAGE)
- 基本指令
ADD_DEPENDENCIES,定义 target 依赖的其他 target,确保在编译本 target 之前,其他的 target 已经被构建。
CMAKE_MINIMUM_REQUIRED
比如 CMAKE_MINIMUM_REQUIRED(VERSION 2.5 FATAL_ERROR)
如果 cmake 版本小与 2.5,则出现严重错误,整个过程中止。 - FIND指令
找到目标之后都会存到VAR变量里面。
FIND_FILE( name1 path1 path2 …)
FIND_LIBRARY( name1 path1 path2 …)
FIND_PATH( name1 path1 path2 …)
FIND_PROGRAM( name1 path1 path2 …)
FIND_PACKAGE()
九 复杂的例子:模块的使用和自定义模块
FIND_PACKAGE(CURL)
这句指令会自动产生一些变量,如CURL_FOUND CURL_INCLUDE_DIR CURL_LIBRARY,每一个模块都会定义以下几个变量:
- _FOUND
- _INCLUDE_DIR or _INCLUDES
- _LIBRARY or _LIBRARIES
FIND_PACKAGE([package name] REQUIRED) REQUIRED 参数,其含义是指这个共享库是否是工程必须的,如果使用了这个参数,说明这个链接库是必备库,如果找不到这个链接库,则工程不能编译。