cmake安装:download | cmake。
在这之前,我们介绍一下cmake。虽然make和makefile简化了手动构建的过程,但是编写makefile文件仍然是一个麻烦的工作,因此就有了cmake工具。cmake工具用于生成makefile文件,而如何生成makefile文件,则由cmakelists.txt文件指定。它们直接的关系如下图:
使用cmake生成makefile并编译的流程如下:
- 编写cmake配置文件cmakelists.txt。
- 执行命令 cmake path生成cmakefile。其中,path为cmakelists.txt所在的目录。
- 使用make命令进行编译。
指定编译器
特别注意的是,指定编译器的语句需要放在cmakelists.txt文件最前面。
指定gcc版本
在linux系统下,gcc一般在/user/bin
目录下。在里面可以看gcc的版本。
zhudk@vm1:/usr/bin$ cd
zhudk@vm1:~$ cd /usr/bin
zhudk@vm1:/usr/bin$ ls |grep gcc
c89-gcc
c99-gcc
gcc
gcc-7
gcc-ar
gcc-ar-7
gcc-nm
gcc-nm-7
gcc-ranlib
gcc-ranlib-7
x86_64-linux-gnu-gcc
x86_64-linux-gnu-gcc-7
x86_64-linux-gnu-gcc-ar
x86_64-linux-gnu-gcc-ar-7
x86_64-linux-gnu-gcc-nm
x86_64-linux-gnu-gcc-nm-7
x86_64-linux-gnu-gcc-ranlib
x86_64-linux-gnu-gcc-ranlib-7
如果没有指定编译器的话,默认使用的就是gcc编译器。如果系统中有多个版本gcc,需要指定gcc的版本,可以在环境变量中设置:
export cc=gcc-7
设置完成后,我们执行cmake
命令,会发现如下打印:
zhudk@vm1:/expand/zhudk/demo$ cmake .
-- the c compiler identification is gnu 7.5.0
-- the cxx compiler identification is gnu 7.5.0
-- check for working c compiler: /usr/bin/cc
-- check for working c compiler: /usr/bin/cc -- works
-- detecting c compiler abi info
-- detecting c compiler abi info - done
-- detecting c compile features
-- detecting c compile features - done
-- check for working cxx compiler: /usr/bin/c
-- check for working cxx compiler: /usr/bin/c -- works
-- detecting cxx compiler abi info
-- detecting cxx compiler abi info - done
-- detecting cxx compile features
-- detecting cxx compile features - done
-- configuring done
-- generating done
-- build files have been written to: /expand/zhudk/demo
使用交叉编译器
使用结对路径:
set(cross_compiler_path "/expand/zhudk/toolchain/opt/friendlyarm/toolchain/6.4-aarch64/bin/aarch64-linux-gcc")
set(cmake_c_compiler ${cross_compiler_path})
或者直接使用编译器名称:
set(cmake_c_compiler "aarch64-linux-gcc")
项目配置
指定cmake最小版本
cmake_minimum_required (version 3.10)
指定项目名
project (main)
# 或
project ("main")
指定编译语言与项目版本
project (main languages cxx version 1.0.0)
编译配置
添加编译选项
方式1
set(cmake_cxx_flags "-no-pie")
set(cmake_c_flags "-no-pie") # 命令行方式传入:-dcmake_c_flags=-no-pie
方式2
add_compile_options (
添加搜索路径
头文件
include_directories (inc)
库文件
link_directories (lib)
添加库文件
note:target_link_libraries
需要放于add_executable
之后
静态库
target_link_libraries(project_name mxnet) #添加libmxnet.a
动态库
target_link_libraries(project_name -lmxnet) #添加libmxnet.so
添加子目录编译
add_subdirectory (lib)
添加程序宏定义
为当前路径以及下层路径的目标加入编译器命令行定义,相当于在**c/c **程序中使用#define
对全部生成目标而言
add_definitions (-dfoo -dbar ...)
对单个生成目标而言
target_compile_definitions(
[items1...]
[ [items2...] ...]
)
生成目标
编译生成可执行文件
必须放在project的前面
add_executable (main main.cpp)
编译生成库
note:默认生成静态库,除非特意指定生成库的类型
- 静态库
add_library(archive static archive.cpp zip.cpp lzma.cpp)
- 动态库
add_library(archive shared archive.cpp zip.cpp lzma.cpp)
经典示例
多目录多源文件
# set(cross_compiler_path "/expand/zhudk/toolchain/opt/friendlyarm/toolchain/6.4-aarch64/bin/aarch64-linux-gcc")
# set(cmake_c_compiler ${cross_compiler_path})
set(cmake_c_compiler "aarch64-linux-gcc")
project(haha)
cmake_minimum_required(version 3.10)
set(cmake_c_flags "-g -wall -o2")
set(executable_output_path ${project_source_dir}/build/bin)
aux_source_directory(. src)
aux_source_directory(./aaa src)
aux_source_directory(./bbb src)
aux_source_directory(./ccc src)
add_executable(${project_name} ${src})
上述项目结构是一个不同目录下多个源文件的情况,根据代码功能不同放在不同的目录下。
set(executable_output_path ${project_source_dir}/build/bin)
是设置生成的可执行文件的路径,project_source_dir
:工程的根目录。
aux_source_directory(dir var)
是把指定目录下所有源文件存储在一个变量中(追加在这个变量中)。
add_executable(${project_name} ${src})
生成可执行文件。
关于头文件的引用,在aaa.c
文件中:
#include "aaa.h"
#include "../bbb/bbb.h"
#include "../ccc/ccc.h"
算是手动引用的。如果不想在include
的时候手动引用,则可以在cmakelists.txt中提前添加头文件搜索目录。
include_directories(./bbb)
现在我们来运行cmake。注意,因为运行cmake的时候会生成很多附带文件,如果直接在根目录下运行cmake的话,会对程序目录造成污染,所以,建议在./build
目录下运行cmake,然后可执行文件存放在./build/bin
。
zhudk@vm1:/expand/zhudk/demo/build$ cmake ..
-- the c compiler identification is gnu 7.5.0
-- the cxx compiler identification is gnu 7.5.0
-- check for working c compiler: /usr/bin/cc
-- check for working c compiler: /usr/bin/cc -- works
-- detecting c compiler abi info
-- detecting c compiler abi info - done
-- detecting c compile features
-- detecting c compile features - done
-- check for working cxx compiler: /usr/bin/c
-- check for working cxx compiler: /usr/bin/c -- works
-- detecting cxx compiler abi info
-- detecting cxx compiler abi info - done
-- detecting cxx compile features
-- detecting cxx compile features - done
-- configuring done
-- generating done
-- build files have been written to: /expand/zhudk/demo/build
zhudk@vm1:/expand/zhudk/demo/build$ make
scanning dependencies of target haha
[ 20%] building c object cmakefiles/haha.dir/main.c.o
[ 40%] building c object cmakefiles/haha.dir/aaa/aaa.c.o
[ 60%] building c object cmakefiles/haha.dir/bbb/bbb.c.o
[ 80%] building c object cmakefiles/haha.dir/ccc/ccc.c.o
[100%] linking c executable bin/haha
[100%] built target haha
生成库
aux_source_directory(. libsrc)
#设置库输出路径
set(library_output_path ../lib)
#生成静态库 最后的库名称会为libhello.a
#add_library(hello static ${libsrc})
#生成动态库 最后的库名称会为libhello.so
#add_library(hello shared ${libsrc})
#只是连续2次使用add_library指定库名称时(第一个参数),这个名称不能相同
#所以上述写法 不会生成动态库。可以先不使用相同的名称,再修改库的名称
add_library(hello_static static ${libsrc})
add_library(hello_shared shared ${libsrc})
set_target_properties(hello_static properties output_name hello)
set_target_properties(hello_shared properties output_name hello)
链接库
还是上述的库文件。
project(haha)
cmake_minimum_required(version 3.10)
set(cmake_c_flags "-g -wall -o2")
set(executable_output_path ${project_source_dir}/build/bin)
aux_source_directory(. src)
aux_source_directory(./aaa src)
aux_source_directory(./bbb src)
aux_source_directory(./ccc src)
include_directories(./include)
find_library(lib libhello.a hints ${project_source_dir}/lib)
add_executable(${project_name} ${src})
target_link_libraries(${project_name} ${lib})
- find_library: 在指定目录下查找指定库,并把库的绝对路径存放到变量里,其第一个参数是变量名称,第二个参数是库名称,第三个参数是hints,第4个参数是路径,其它用法可以参考cmake文档
- target_link_libraries: 把目标文件与库文件进行链接。
使用find_library的好处是在执行cmake ..
时就会去查找库是否存在,这样可以提前发现错误,不用等到链接时。
添加控制选项
在cmakelists.txt中使用变量
option(debug "a debug option" off) #0或者off 1或者on
if(debug)
message("debug is ${debug}")
else()
message("debug is ${debug}")
endif()
加入想在cmakelists.txt文件中控制一些语句,可以使用option定义变量。
option命令,其第一个参数是这个option的名字,第二个参数是字符串,用来描述这个option是来干嘛的,第三个是option的值,on或off,也可以不写,不写就是默认off
。
在执行cmake命令的时候,可以设置其值。cmake .. -ddebug=1
。
在源码中使用option变量
在cmakelists.txt中定义宏,可以直接在源码中使用。
add_definitions(-ddebug)
#include
#include "./aaa/aaa.h"
#include "./bbb/bbb.h"
#include "./ccc/ccc.h"
#include "hello.h"
int main(void)
{
printf("hello world!\n");
aaa();
bbb();
ccc();
hello();
#ifdef debug
printf("debug\n");
#endif
return 0;
}
可以直接在源码中使用,会打印debug
。
在源码中使用option变量
在cmakelists.txt中定义宏,可以直接在源码中使用。
add_definitions(-ddebug)
#include
#include "./aaa/aaa.h"
#include "./bbb/bbb.h"
#include "./ccc/ccc.h"
#include "hello.h"
int main(void)
{
printf("hello world!\n");
aaa();
bbb();
ccc();
hello();
#ifdef debug
printf("debug\n");
#endif
return 0;
}
可以直接在源码中使用,会打印debug
。
仔细想了一下,如果真的需要修改宏的时候,还不如直接修改源码,修改后直接make就可以了,如果修改了cmakelists.txt文件,那么还重新cmake。