Cmake语法-makefile、cmake、shell 自动编译和链接
1.makefile、cmake 与 shell 之间的联系
-
makefile : 帮助我们管理编译项目
-
cmake:是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的 Makefile 或者 project 文件,CMake 并不直接建构出最终的软件,而是产生标准的建构档(如 Makefile 或 projects)。
-
shell 脚本:一系列命令和语法
2.makefile 自动编译和链接
2.1 gcc 如何编译相互依赖,却没直接引入的文件
Android.mk Application.mk
gcc hello.cpp div.cpp sub.cpp add.cpp -o hello
// hello.cpp 中并没引入 div.cpp等文件,但是这样编译会自动找寻到依赖的文件
gcc 四步骤:生成 .o 文件比较耗时(汇编阶段
)
上面的编译步骤其实就是省略了编译四步骤,假设现在我改了一个文件,需要重新编译,那么每次都会重新生成 .o 文件,因此需要把上面的步骤进行拆分
gcc -c sub.cpp -o sub.o
gcc -c add.cpp -o add.o
gcc -c div.cpp -o div.o
gcc -c hello.cpp -o hello.o
gcc add.o sub.o div.o hello.o -o hello
这样如何只修改了 sub.cpp ,就只需要重新生成 sub.o 文件,然后重新生成最终的可执行文件
2.2 如何编写Makefile文件
执行 Makefile 文件,只需要在Makefile 的目录下 执行make
指令就行
2.2.1. 一个规则(观看makefile、cmake、shell目录下的m1)
目标:依赖条件
(一个tab缩进) 命令
比如:
hello.out:hello.o sub.o add.o div.o
gcc hello.o sub.o add.o div.o -o hello.out
div.o:div.cpp
gcc -c div.cpp -o div.o
默认情况下只会执行 MakeFile 中的第一个命令。
-
但若想生成目标文件,则会检查命令中的依赖是否存在,如果不存在就会往下查找是否有生成该依赖条件的命令,如有就会执行生成依赖再生成目标文件。
-
会检测规则中的目标是否需要更新,必须先检测它的依赖性(通过更新时间判断),只需要重新生成依赖中被修改的依赖,然后再更新目标文件
2.2.2. 两个函数(观看makefile、cmake、shell目录下的m2)
src = $(wildcard *.cpp)
// 找到当前目录下所有后缀为.cpp的文件,然后赋值给src$(src) 取变量src的值
obj = $(patsubst %cpp,%o,$(src))
//把src变量中所有后缀为.cpp的文件替换成.o文件$(obj) 取变量obj的值
make clean -n 注意加上 -n 预执行
make clean 执行 clean 命令
如果目录下有 clean 文件夹,则会有冲突,这时只需要生成伪目标就行
src = $(wildcard *.cpp)
obj = $(patsubst %cpp,%o,$(src))
# 默认情况下只会执行第一个
hello.out:$(obj)
gcc $(obj) -o hello.out
div.o:div.cpp
gcc -c div.cpp -o div.o
add.o:add.cpp
gcc -c add.cpp -o add.o
sub.o:sub.cpp
gcc -c sub.cpp -o sub.o
hello.o:hello.cpp
gcc -c hello.cpp -o hello.o
# $(xxx) 取变量的值
clean:
rm -rf $(obj) hello.out
# 生成伪目标
.PHONY: clean
2.2.3. 三个自动变量(观看makefile、cmake、shell目录下的m3)
多行注释 :'
- $@:表示规则中的目标
- $^:表示规则中所有的依赖条件,组成一个列表,以空格隔开,如果这个列表有重复项则消除重复项
- $<:表示规则中的第一个依赖条件,如果运行在模式套用中,相当于取出依赖条件套用在该模式中
src = $(wildcard *.cpp)
obj = $(patsubst %cpp,%o,$(src))
# 默认情况下只会执行第一个
hello.out:$(obj)
gcc $^ -o $@
:'
div.o:div.cpp
gcc -c $< -o $@
add.o:add.cpp
gcc -c $< -o $@
sub.o:sub.cpp
gcc -c $< -o $@
hello.o:hello.cpp
gcc -c $< -o $@
:'
# 模式规则
# gcc -c $(src) -o $(obj)
%o:%cpp
gcc -c $< -o $@
# $(xxx) 取变量的值
clean:
rm -rf $(obj) hello.out
# 生成伪目标
.PHONY: clean
3.cmake简介和安装
写 CMakeLists.txt 里面用 CMake 语法写,会帮我们生成 Makefile 用于编译管理项目
- 去官网 下载cmake的最新linux版本,这里下载的是
cmake-3.18.3.tar.gz
拷贝
到linux系统的/lib
目录下新建的cmake目录
并解压
,需要root权限- cd到解压后的cmake目录中运行
sudo ./bootstrap
命令进行安装 - 安装完成执行
sudo make
- 最后执行
sudo make install
- 可以在任一位置 使用
cmake --version
查看安装的版本
如果不能在任一位置 使用`cmake --version` 查看安装的版本,则配置环境变量
配置环境变量 vim /etc/profile
文件最后面输入:
export CMAKE_PATH=/lib/cmake/cmake-3.18.3/bin
export PATH=$CMAKE_PATH:$PATH
使环境变量生效 source /etc/profile
安装问题:
有的会出现没安装 make的情况,使用以下命令
sudo apt-get install make
Could not find OpenSSL. Install an OpenSSL development package or
configure CMake with -DCMAKE_USE_OPENSSL=OFF to build without OpenSSL.
解决:sudo apt-get install libssl-dev
Error when bootstrapping CMake:
Cannot find a C++ compiler that supports both C++11 and the specified C++ flags.
1.没有装gcc 和 g++。使用 sudo apt-get install g++ 安装
2. gcc 或者 g++ 版本过低,需要安装高版本的。升级风险较大,可以采用新的编译环境安装新版本的 gcc和g++ 。
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install gcc-7 g++-7
你在安装完之后可以采用下面的指令来查看当前系统中安装的所有的gcc和g++的版本:
ls /usr/bin/gcc*
ls /usr/bin/g++*
将gcc-6加入gcc候选中,最后的数字是优先级,我自己是直接设为100(测试没有问题)
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-6 100
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-6 100
完成上面的操作之后,我们就可以通过下面的指令来选择不同的gcc和g++的版本了
sudo update-alternatives --config gcc
sudo update-alternatives --config g++
注意一个问题:
当切换使用了其他版本的gcc时,请务必保持g++的版本和gcc版本的一致性,否则用cmake配置出来的项目遇到c++代码还是会用之前版本的gcc。