CMake
CMake是开源、跨平台的构建工具,可以让我们通过编写简单的配置文件去生成本地的Makefile,这个配置文件是独立于运行平台和编译器的,这样就不用亲自去编写Makefile了,而且配置文件可以直接拿到其它平台上使用,无需修改,非常方便。
Linux下CMake简明教程_linux中cmake_爱就是恒久忍耐的博客-CSDN博客
CMake 的安装
Ubuntu下的安装
1 2 3 4 5 6
| $ sudo apt-get install cmake
$ cmake --version cmake version 3.16.3 ..... # 这样就安装好了
|
CMake语法
最简单的版本
环境:只有一个main.c的hello world
文件,没有任何依赖。
在main.c
的同级目录下建立一个文件,文件名叫CMakeFileLists.txt
,这个文件名不能变更,只能是这个形式。
文件内容如下:
1 2 3 4 5 6 7 8
| cmake_minimum_required(VERSION 2.8)
project(download)
add_executable(main, main.c)
|
我们在当前目录(main.c
和CMakeFileLists.txt
的目录下)运行cmake .
,含义就是在当前目录下执行cmake。执行成功后会生成Makefils
以及一些cmake运行时自动生成的文件。
这个时候我们使用命令make
就可以看到正确编译了。
一个目录下的多个源文件
1 2 3 4 5 6 7 8 9
| cmake_minimum_required (VERSION 2.8)
project (demo)
aux_source_directory(. SRC_LIST)
add_executable(main ${SRC_LIST})
|
aux_source_directory()
也存在弊端,它会把指定目录下的所有源文件都加进来,可能会加入一些我们不需要的文件,此时我们可以使用set命令去新建变量来存放需要的源文件
1 2 3 4 5 6 7 8 9 10 11
| cmake_minimum_required (VERSION 2.8)
project (demo)
set( SRC_LIST ./main.c ./testFunc1.c ./testFunc.c)
add_executable(main ${SRC_LIST})
|
不同目录下的多个源文件
文件结构
1 2 3 4 5 6 7 8
| ./bin ./build ./include xx.h xxx.h ./src xxx.c xx.c
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| cmake_minimum_required (VERSION 2.8)
project (demo)
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
aux_source_directory (src SRC_LIST)
include_directories (include)
add_executable (main ${SRC_LIST})
|
静态库和动态库的编译
编译出动态库和静态库,然后等着让其它程序去使用。
文件结构
1 2 3 4 5 6 7 8 9
| ./bin ./build ./lib ./include xx.h xxx.h ./src xxx.c xx.c
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| cmake_minimum_required (VERSION 3.5)
project (demo)
set (SRC_LIST ${PROJECT_SOURCE_DIR}/src/xxx.c)
add_library (testFunc_shared SHARED ${SRC_LIST}) add_library (testFunc_static STATIC ${SRC_LIST})
set_target_properties (testFunc_shared PROPERTIES OUTPUT_NAME "testFunc") set_target_properties (testFunc_static PROPERTIES OUTPUT_NAME "testFunc")
set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
|
对库进行链接
1 2 3
| find_library(TESTFUNC_LIB testFunc HINTS ${PROJECT_SOURCE_DIR}/testFunc/lib)
target_link_libraries (main ${TESTFUNC_LIB})
|
- find_library: 在指定目录下查找指定库,并把库的绝对路径存放到变量里,其第一个参数是变量名称,第二个参数是库名称,第三个参数是HINTS,第4个参数是路径,其它用法可以参考cmake文档
- target_link_libraries: 把目标文件与库文件进行链接
ps:在lib目录下有testFunc的静态库和动态库,find_library(TESTFUNC_LIB testFunc …默认是查找动态库,如果想直接指定使用动态库还是静态库,可以写成find_library(TESTFUNC_LIB libtestFunc.so …或者find_library(TESTFUNC_LIB libtestFunc.a …
ps: 查看elf文件使用了哪些库,可以使用readelf -d ./xx来查看
之前本节教程使用的是库查找方法是link_directories,但是很多读者反映运行时有问题,本人去官方文档上查了下,发现不建议使用了,推荐使用find_library或者find_package
添加编译选项
有时编译程序时想添加一些编译选项,如-Wall,-std=c++11等,就可以使用add_compile_options来进行操作。
add_compile_options(-std=c++11 -Wall)
更加完善的目录结构及编译选项
文件结构
构建的时候我们需要先cd build
,然后再cmake ..
构建,最后make -j8
编译即可。
1 2 3 4 5 6 7 8 9 10 11 12 13
| . ├── build ├── CMakeLists.txt ├── libzip │ ├── ioapi.c │ ├── ioapi.h │ ├── unzip.c │ └── unzip.h ├── main │ └── curl_zip.c ├── tools └── log └── log.h
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| cmake_minimum_required(VERSION 3.0) project(curl_zip)
set(Target down)
# 设置语言标准 set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17)
# 为当前路径以及子目录的源文件加入由-D预编译定义 # add_definitions(-DFOO -DDEBUG ...)
# 设置C++编译参数(CMAKE_CXX_FLAGS是全局变量) # set(CMAKE_CXX_FLAGS "-Wall std=c++11 -Wextra -fPIC -g")
# 设置指定的C++编译器版本是必须的,如果不设置,或者为OFF,则指定版本不可用时,会使用上一版本。 # set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 设置编译器选项 add_compile_options(-O3 -Wall)
message("Target=" ${Target}) message("---------- Start building ----------")
# 设置包含路径 include_directories( ${PROJECT_SOURCE_DIR}/libzip ${PROJECT_SOURCE_DIR}/tools/log )
# 把xxx目录下所有源文件写入变量SRC_LIST aux_source_directory(${PROJECT_SOURCE_DIR}/libzip SRC_LIST) aux_source_directory(${PROJECT_SOURCE_DIR}/src/curl SRC_LIST) aux_source_directory(${PROJECT_SOURCE_DIR}/main SRC_LIST)
# 以SRC_LIST为源文件生成目标文件xxx add_executable(${Target} ${SRC_LIST})
# 创建库文件 # add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1 source2 ... sourceN)
# 目标文件链接的库 # target_link_libraries() 总是指明 PRIVATE、PUBLIC 、INTERFACE target_link_libraries( ${Target} pthread curl z )
message("---------- Stop building ----------")
|