Makefile和CMake的简单入门

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
    
    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 installmake 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.cppreply.hmain.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)
    

你可能感兴趣的:(C++,c++)