Makefile的学习之路

目录

1、简介

2、语法规则

3、变量

4、函数

5、伪目标.PHONY

6、嵌套执行makefile

7、makefile示例

 8、gcc编译选项

基本选项

调试选项

优化选项

警告选项

语言选项

链接选项

预处理选项

其他选项

1、简介

makefile是一个用于自动化构建程序的脚本文件,它包含一组规则,这些规则描述了如何从一个或多个源文件(如.c/.cpp文件)编译生成目标文件(如.o文件)再链接生成可执行文件(如.exe文件)或库(如.dll文件)。makefile的好处就是自动编译,只需一个make命令就能完成整个工程的编译。

gcc:可以简单的认为是编译器,它可以编译多种语言(如C、C++、Java等)。我们的程序中包含很多的源文件,都可以用gcc命令逐个编译,但当源文件太多时就容易混乱且工作量大,这时就需要批量处理,因此就有了make工具。

make:可以看成是一个智能的批处理工具,它没有编译和链接功能,而是通过执行makefile文件中用户指定的命令来完成编译和链接。

makefile:该文件中包含了调用gcc去编译某个源文件的命令。当工程非常大时,手写makefile也比较麻烦,因此就有了cmake工具辅助生成makefile文件。

cmake:也有自己的一套规则,它根据CMakeLists.txt文件更简单的生成makefile文件。

那有没有更简单的工具来生成CMakeLists.txt文件呢?

答:no,这就需要自己动手了。

2、语法规则

目标 ... : 依赖 ...
	命令1
	命令2
	. . .

目标:即要生成的文件,默认情况下makefile的第一个目标为终极目标;

依赖:即生成目标文件所需要的源文件;

命令:即通过执行命令由依赖文件生成目标文件,注意每条命令之前必须有一个tab;

all:makefile文件默认只生成第一个目标文件即完成编译,但我们可以通过all指定所需要生成的目标文件。

all: target1 target2 target3
target1:
# 编译规则1
target2:
# 编译规则2
target3:
# 编译规则3

3、变量

‘$’符号通常表示取变量的值,当变量名多于一个字符时,使用"( )";

‘$^’ 表示所有的依赖文件;

‘$@’ 表示生成的目标文件;

‘$<’ 表示第一个依赖文件;

‘:=’ 符号用于变量赋值(当前值);

‘=’ 符号用于变量赋值(整个makefile中最后被指定的值);

‘?=’ 符号表示如果该变量没有被赋值,则赋值等号后的值;

‘+=’ 符号表示将符号后面的值追加到前面的变量上;

4、函数

# 匹配当前目录下所有.c文件
SRC = $(wildcard *.c)

# 将SRC中所有文件名中的.c替换成.o
OBJ = $(patsubst %.c, %.o, $(SRC))

ALL: hello.out

hello.out: $(OBJ)
    gcc $(OBJ) -o hello.out

%.o: %.c
    gcc -c $< -o $@

clean:
        rm -rf $(OBJ) hello.out
 
.PHONY: clean ALL

wildcard:是make工具提供的一个函数,用于查找匹配模式的所有文件名;

patsubst:该函数用于匹配模式替换,基于一种模式替换文本字符串中另一部分;

5、伪目标.PHONY

为目标只是个标签,clean是个伪目标,没有依赖文件,只有make来调用时才执行;

6、嵌套执行makefile

在一些大工程中,会把不同模块的源文件放在不同目录中,我们可以在每个目录中都写一个makefile,这有利于让我们的makefile更简洁。列如在子目录subdir目录下有个Makefile文件,来指明这个目录下文件的编译规则。外部总控Makefile可以这样写

subsystem:
            cd subdir && $(MAKE)
其等价于:
subsystem:
            $(MAKE) -C subdir

如果需要传递变量到下级makefile中,可以这样写

export variable := value

如果不想传递变量到下级makefile中,可以这样写

unexport variable := value

7、makefile示例

假设有一个项目结构如下:

myproject/  
├── Makefile    # 主Makefile  
├── src/  
│   ├── main.c  
│   └── Makefile # src目录的Makefile  
└── include/  
    └── myheader.h

主makefile

# myproject/Makefile  
  
# 设置编译器和编译选项  
CC=gcc  
CFLAGS=-Wall -Iinclude  
  
# 定义子目录  
SUBDIRS=src  
  
# 默认目标  
all: $(SUBDIRS)  
  
# 伪目标,用于构建子目录  
.PHONY: $(SUBDIRS)  
  
# 递归地调用子目录中的Makefile  
$(SUBDIRS):  
    $(MAKE) -C $@  
  
# 清理目标,也递归地调用子目录中的清理目标  
clean:  
    for dir in $(SUBDIRS); do \  
        $(MAKE) -C 
$$
dir clean; \  
    done  
  
# 安装目标(示例)  
install:  
    # 这里你可以添加安装命令,比如复制到某个目录  
    echo "Installing project..."  
  
# 卸载目标(示例)  
uninstall:  
    # 这里你可以添加卸载命令,比如从某个目录删除文件  
    echo "Uninstalling project..."

 src目录下makefile

# myproject/src/Makefile  
  
# 假设我们有一个名为main的目标文件  
OBJ=main.o  
  
# 链接main.o生成可执行文件  
main: $(OBJ)  
    $(CC) $(CFLAGS) -o $@ $^  
  
# 编译main.c生成main.o  
%.o: %.c  
    $(CC) $(CFLAGS) -c $< -o $@  
  
# 清理目标  
clean:  
    rm -f $(OBJ) main  
  
# 依赖项(如果需要)  
# DEPS = ...  
# ...(依赖项的处理)

 8、gcc编译选项

GCC(GNU Compiler Collection)提供了大量的编译选项,这些选项允许用户定制编译过程以满足不同的需求。以下是一些常用的GCC编译选项的概述:

基本选项

  • -c:只编译不链接,生成目标文件(.o)。
  • -o <output_file>:指定输出文件名。
  • -S:只进行编译预处理和汇编,生成汇编文件(.s)。
  • -E:只进行编译预处理,生成预处理后的文件(通常是.i文件,但默认输出到标准输出)。

调试选项

  • -g:生成调试信息,使调试器(如GDB)能够使用。
  • -ggdb:生成GDB可以使用的调试信息。
  • -g3:生成包含额外调试信息的调试信息。

优化选项

  • -O0:不进行优化(默认)。
  • -O1:进行基本优化。
  • -O2:进行更多的优化,但不增加编译时间太多。
  • -O3:进行更多的优化,可能会增加编译时间。
  • -Os:优化生成代码的大小。
  • -Ofast:进行所有可能的优化,包括那些可能改变程序行为的优化(如浮点运算的舍入模式)。

警告选项

  • -Wall:显示所有警告信息。
  • -Wextra:显示额外的警告信息。
  • -Werror:将警告信息当作错误处理。
  • -Wno-<warning>:禁用指定的警告(例如,-Wno-unused-variable禁用未使用变量的警告)。

语言选项

  • -std=<standard>:指定C或C++语言标准(如-std=c99-std=c++11)。
  • -fPIC:生成位置无关代码(Position Independent Code),常用于共享库。
  • -fPIE:生成位置无关的可执行文件。

链接选项

  • -L<directory>:添加库文件的搜索目录。
  • -l<library>:链接指定的库(如-lm链接数学库)。
  • -static:静态链接库(而不是默认的动态链接)。
  • -shared:生成共享库(动态链接库)。

预处理选项

  • -I<directory>:添加头文件搜索目录。
  • -D<macro>:定义宏(如-DDEBUG)。
  • -U<macro>:取消定义宏。

其他选项

  • -v:显示详细的编译和链接过程。
  • -version:显示GCC版本信息。
  • -M:生成依赖关系(通常是预处理器的依赖关系),但不编译。
  • -MM:与-M类似,但忽略系统头文件。
  • -MP:生成phony目标,以便在头文件更改时重新编译。
  • -MT:指定目标名称,通常与-M-MM一起使用。

这只是一个GCC编译选项的简要概述,GCC还提供了许多其他选项和功能。要获取完整的选项列表和详细信息,请查阅GCC的官方文档或使用gcc --help命令。

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值