【cmake系列使用教程】
这个系列的文章翻译自官方cmake教程: cmake tutorial 。
示例程序地址: github.com/rangaofei/t…
不会仅仅停留在官方教程。本人作为一个安卓开发者,实在是没有linux c程序开发经验,望大佬们海涵。教程是在macos下完成,大部分linux我也测试过,有特殊说明的我会标注出来。本教程基于cmake-3.10.2,同时认为你已经安装好cmake。
简介
cmake中的file使用也很简单,与c语言的文件io相似。file命令属于脚本命令,可以卸载脚本中。后边讲到的
aux_source_directory
属于工程命令,不能用在脚本中。
首先来说一个我在编写程序的时候遇到的问题,在学习apue的过程中,有许多实例小程序,因为IDE用的是Clion,所以需要在cmake脚本中生成执行文件,最开始的时候是简单的添加
add_executable
命令来不断的增加新的程序构建,随着学习的深入,手动添加太麻烦了,于是写了一个简单的脚本来半自动构建程序,目录结构如下:
apue git:(master) ✗ cd src
➜ src git:(master) ✗ tree
.
├── CmakeLists.txt
├── part1
│ ├── CmakeLists.txt
│ ├── copytest.c
│ ├── groupid.c
│ ├── mycopy.c
│ ├── myerror.c
│ ├── myls.c
│ ├── myshell.c
│ ├── mystdcopy.c
│ ├── newshell.c
│ └── processid.c
├── part11
│ ├── CmakeLists.txt
│ ├── pthread1.c
│ ├── pthread2.c
│ ├── pthread3.c
│ └── pthread4.c
├── part3
│ ├── CmakeLists.txt
│ ├── holetest.c
│ └── seektest.c
├── unp_1
│ ├── CMakeLists.txt
│ ├── daytimetcpcli.c
│ ├── daytimetcpcliv6.c
│ └── daytimetcpsrv.c
└── unp_3
├── CMakeLists.txt
└── byteorder.c
src是apue的源代码目录,包含多个章节对应的文件夹和一个主cmakelist文件,章节文件夹下是具体的c和h文件和一个cmakelist文件,看一下part3章节文件夹中的cmakelist文件:
AUX_SOURCE_DIRECTORY(. PART_THREE)
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
FOREACH (FILE ${PART_THREE})
MESSAGE(STATUS ${FILE})
STRING(REPLACE "./" "" LIB_NAME ${FILE})
STRING(REPLACE ".c" "" LIB_NAME ${LIB_NAME})
add_executable(${LIB_NAME} ${FILE})
target_link_libraries(${LIB_NAME} apue.a)
ENDFOREACH ()
这段代码首先将当前章节的所有文件收入到PART_THREE变量中,以list形式存储,下边两行代码设置了可执行文件和库文件的存储路径,然后FOREACHE循环中输出了所有的可执行文件和链接库,可执行文件名称是用.c文件用正则替换无用信息后生成的。
然后在主cmakelist中添加
add_subdirectory(part3)
后直接执行即可。这也是今天要讲的主要内容。
文件写入与追加
file(WRITE <filename> <content>...)
file(APPEND <filename> <content>...)
将content的内容写入filename中,假如文件不存在则会创建文件,假如filename中包含路径,则相应的文件夹也会被创建。WRITE会擦出文件内容,重新写入content,APPEND会在文件末尾追加内容。写一个最简单的测试:
file(WRITE test.txt "this is a test to wirte\n")
file(APPEND test/test.txt "this is a test to append")
file(APPEND test.txt "this is a test to append")
此时目录结构如下:
.
└── write.cmake
0 directories, 1 file
执行该脚本后:
➜ Stepfile git:(master) ✗ cmake -P write.cmake
➜ Stepfile git:(master) ✗ tree
.
├── test
│ └── test.txt
├── test.txt
└── write.cmake
1 directory, 3 files
前边介绍过configure_file这个命令,是用来在构建工程时替换文件内容的,注意一下区别。
文件的读取
file(READ <filename> <variable>
[OFFSET <offset>] [LIMIT <max-in>] [HEX])
这个也比较简单: 将filename文件中的内容读取到variable总,可以指定OFFSET的值,也就是开始读取的位置,指定LISTMI的值,读取的长度,HEX是否以16进制形式读取。
file(STRINGS <filename> <variable> [<options>...])
类似于读取字符码,而不读取字节码。这个命令会将filename中的字符串读取到variable中,并且variable是一个list,每个元素保存每行的内容。二进制文件不会被读取,并且换行符会被忽略。举个例子,我们刚才写入的
test.txt
的文件内容是:
this is a test to wirte
this is a test to append
have tab #这个是我手动添加的
我们读取这个文件并打印结果,编写
string.cmake
文件如下:
file(STRINGS test.txt strings)
foreach(str IN LISTS strings)
message(STATUS ${str})
endforeach(str)
因为结果会用list保存,所以用foreach循环来查看结果:
-- this is a test to wirte
-- this is a test to append
-- have tab
关于一些选项,用的不太多:
OPTION | 说明 |
---|---|
LENGTH_MAXIMUM | 读取字符的最大个数 |
LENGTH_MINIMUM | 读取的字符的最少个数 |
LIMIT_COUNT | 提取的不同字符的最大数量 |
LIMIT_INPUT | 限制读取的最大字节 |
LIMIT_OUTPUT | 限制写入变量的最大字节 |
NEWLINE_CONSUME | 不忽略换行符 |
NO_HEX_CONVERSION | 不需要自动转换为16进制 |
REGEX | 提取匹配正则表达式的字符串 |
ENCODING | 重新编码UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE |
文件的hash码
file(<HASH> <filename> <variable>)
利用这个命令可以提取出文件的hash码