Makefile和CMake的简单入门
- 从源代码到可执行文件
- Makefile的产生背景
- 从make的调用到Makefile
- Makefile的基本格式
- Makefile的扩展用法
- Makefile的生成和部署
一、从源代码到可执行文件
当编译文件依赖关系复杂的时候,make工具诞生了,而Makefile文件正是为make工具所使用的
1、可执行程序产生的过程
配置环境 -> 确定标准库和头文件的位置 -> 确定依赖关系 -> 头文件预编译 -> 预处理 -> 编译 -> 链接 -> 安装 -> 与操作系统减建立联系 -> 生成安装包
(1)预编译
预编译过程主要处理那些源代码文件中的以“#”
开始的预编译指令,比如“#include”
,“#define”
等,主要处理规则如下:
- 将所有的
“#define”
删除,并且展开所有的宏定义 - 处理所有条件预编译指令,比如
“#if”
、“#ifdef”
、“#elif”
、“#else”
、“#endif”
- 处理
“#include”
预编译指令,将被包含的文件插入到该预编译指令的位置。注意,这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。删除所有的注释“//”
和“/**/”
- 添加行号和文件名标识,比如
#2“a.c”2
,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号 - 保留所有的
#pragma
编译器指令,因为编译器需要使用它们
(2)编译
编译过程就是把预处理
完的文件进行一系列词法分析,语法分析,语义分析,代码优化及优化后生成相应的汇编代码文件
代码优化的优缺点:
(3)汇编
汇编过程就是由汇编器将汇编代码转变成机器可以执行的二进制指令
(4)链接
链接的主要内存就是把各个模块之间相互引用长度部分都处理好,使得各个模块之间能够正确的衔接。简单的理解为将各个目标文件链接起来生成最终的可执行文件
链接过程可以具体的分为以下四步:
-
合并段和符号表
合并多个文件的符号表及各段内容,放入一个新的文件中
-
符号解析
在每个文件符号引用(引用外部符号)的地方找到符号的定义。这就是符号解析
-
地址和空间分配
符号解析成功后,为程序分配虚拟地址空间
-
符号重定位 // 指令段
符号重定向就是对.o文件中.text段指令中的无效地址给出具体的虚拟地址或者相对位移偏移量
链接又分为静态链接
和动态链接
2、Makefile做了什么
描述了整个工程所有文件的编译顺序、编译规则
二、Makefile产生背景
1、多个文件编译的简单示例
先创建三个文件:
-
reply.h
#include<iostream>
class Reply
{
public:
Reply();
~Reply();
void PrintHello();
};
-
reply.cpp
#include"reply.h"
using namespace std;
Reply::Reply()
{}
Reply::~Reply()
{}
void Reply::PrintHello()
{
cout << "Hello World" << endl;
}
-
main.cpp
#include"reply.h"
int main()
{
Reply reply;
reply.PrintHello();
return 0;
}
我们使用c++编译命令:g++ main.cpp reply.h reply.cpp -o main
即可完成编译
2、Makefile最简单的语法
创建Makefile
文件
main: reply.o main.o
g++ reply.o main.o -o main
reply.o: reply.cpp
g++ -c reply.cpp -o reply.o
main.o: main.cpp
g++ -c main.cpp -o main.o
3、make的初步使用
使用make命令回车,见到下面的输出完成
g++ -c reply.cpp -o reply.o
g++ -c main.cpp -o main.o
g++ reply.o main.o -o main
三、从make的调用到Makefile
1、make究竟是什么
make是一个批处理工具,能执行一系列linux
命令
2、Makefile都有些什么
make工具就根据Makefile中的命令进行编译和链接的
3、其他的IDE
工具:CMake
等
帮助开发者快速、简化部署工程编译链接
四、Makefile的格式
1、Makefile的基本规则
目标(target): 依赖(prerequisites)
命令(command)
2、Makefile的简化规则
变量定义:变量=字符串
变量使用:$(变量名)
TARGET = main
OBJS = reply.o main.o
.PHONY: clean
$(TARGET):$(OBJS)
g++ $(OBJS) -o $(TARGET)
reply.o: reply.cpp
main.o: main.cpp
clean:
rm $(TARGET) $(OBJS)
TARGET = main
:定义变量.PHONY: clean
:当目录下存在clean文件时,执行make clean
会失效,声明clean为非实体文件clean:
:定义make clean
命令
3、改写Makefile的基本实例
注意:不生成目标文件的命令最好都设成假想目标
五、Makefile的扩展用法
1、make工程的安装和卸载
Makefile文件与上面类似
TARGET = main
OBJS = reply.o main.o
.PHONY: clean
$(TARGET):$(OBJS)
g++ $(OBJS) -o $(TARGET)
reply.o: reply.cpp
main.o: main.cpp
clean:
rm $(TARGET) $(OBJS)
install:
cp ./main /usr/local/bin/mainTest
uninstall:
rm /usr/local/bin/mainTest
之后在当前项目路径下执行:make install
和make uninstall
即可进行安装与卸载,记得使用root
权限!
2、Makefile中的变量
-
用户自定义变量
-
变量中的变量
让一个变量依赖一个还没有定义的变量,有一种延迟的效果,将变量的真实值放到之后来定义
foo = $(bar)
bar = $(ugh)
ugh = Huh
test1:
echo $(foo), foo
test2:
echo $(bar), bar
避免向后依赖使用:=
,如下:
y := $(x)bar
z = $(x)bar
x := foo
-
追加变量
接上面,如果我们追加一行:x += foo1
-
多行变量
define two-lines
foo
echo $(bar)
endef
test4:
echo $(two-lines)
-
环境变量
echo $(HOME), $(SHELL), $(LD_LIBRARY_PATH)
以下使用动态链接库来生成可执行文件
TARGET = main
OBJS = reply.o
LIB = libreply.so
CXXFLAGS = -c -fPIC
.PHONY: clean
$(TARGET):$(LIB) main.o
$(CXX) main.o -o $(TARGET) -L. -lreply -Wl,-rpath ./
$(LIB):$(OBJS)
$(CXX) -shared $(OBJS) -o $(LIB)
reply.o:reply.cpp
$(CXX) $(CXXFLAGS) reply.cpp -o $(OBJS)
main.o: main.cpp
$(CXX) $(CXXFLAGS) main.cpp -o main.o
-
自动变量 & 模式变量
-
自动匹配
六、Makefile的自动生成和部署
1、项目的生成和部署
一般来说,至少有下面的目录:
-
src
头文件的实现文件
-
include
用到的头文件
-
bin
可运行文件
-
build
临时构建的文件
2、关于automake/autoconfig、CMake的使用
依赖关系比较复杂的项目可以使用上面的两个工具来实现
3、CMake的使用
-
我们先需要安装CMake工具,具体安装过程Google
-
安装好以后,我们依然使用上面的reply.cpp
、reply.h
、main.cpp
简单demo来使用我们的CMake
-
先创建俩文件夹:src(放cpp文件)
、include(放h文件)
-
然后编写CMakeList.txt
# CMakeList.txt
# 设置cmake最低版本
cmake_minimum_required(VERSION 2.8.0)
# 设置c++标准
set(CMAKE_CXX_STANDARD 11)
# 项目名称
project(xxx)
# 包含的头文件目录
include_directories(./include)
set(SRC_DIR ./src)
# 指定生成链接库
add_library(XXX ${SRC_DIR}/XXX.cpp)
add_library(YYY ${SRC_DIR}/YYY.cpp)
# 设置变量
set(LIBRARIES XXX YYY)
set(OBJECT XXX_test)
# 生成可执行文件
add_executable(${OBJECT} ${SRC_DIR}/main.cpp)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)