准备
要看懂Makefile 首先得知道gcc怎么用吧?根据gcc –h的的内容可以看出,编译过各分为4个步骤:
- 预处理(preprocess) ,使用-E 选项,替换宏定义和头文件,默认输出到标准输出,不生成文件。
- 编译(compile),使用-S选项,生成汇编文件。
- 汇编(assemble),使用-c选项,成生目标文件。
- 连接(link),不添加选项,生成可执行文件。
实际上gcc会调不同的处理程序来完成这些任务,但这里不用管它。除了这些,还有一些常用的选项:
| 选项—————- | 说明 |
|---|---|
| -o | 指定目标的名称,上面4个步骤中,除了1,都有默认的名称。如果想修改名称,就可以使用这个选项,包 括指定预处理的目标 |
| -g | 给目标文件加上调试信息,只有这样才能被GDB调试。如果是-ggdb的话,将尽可能的生成gdb的可以使用的调试信息 |
| -v | 显示编译器的版本信息 |
| -I (大写的i) | 添加头文件的搜索路径 |
| -L | 添加库文件的路径,也可以修改环境变量LD_LIBRARY_PATH |
| -l(小写的L) | 在链接动态库文件时,除了指定路径,还需要指定其名字,编译器查找动态库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so或者.a来确定库的名称,默认优先选择.so,加-static时,只链接.a |
| -static | 禁止使用共享连接 |
| -shared | 生成共享目标文件。通常用在建立共享库时 |
| -w | 不生成任何警告信息 |
| -Wall | 生成所有警告信息 |
| -werror | 把所有的告警信息转化为错误信息,并在告警发生时终止编译过程 |
| -D | 添加宏定义 |
| -pthread | 链接 POSIX thread 库,相对于-lpthread,增加了_REENTRANT宏定义。推荐使用-pthread |
符号
main: main.c util.c defs.h
gcc -o $@ $^
$@ 代表目标文件main
$^ 代表所有的依赖文件main.c util.c defs.h
$< 代表第一个依赖文件main.c
函数
#这两种方法都能得到指定目录下的所有.c文件
SOURCES = $(shell ls *.c ./sub/*.c)
SOURCES = $(wildcard *.c ./sub/*.c)
#去掉路径信息
FILES = $(notdir $(SOURCES))
#更改后缀(只是为了得到一组文件名,不会更改原文件)
PROGRAMS = $(FILES :.c=) #去掉后缀
OBJ=$(FILES :.c=.o) #更改
#或者使用patsubst函数
OBJ=$(patsubst *.c *.o $(FILES))
简要说明
CFLAGS=-g
#定义变量
objects = main.o command.o
#第一个目标为最后生成的目标
edit : $(objects)
cc -o $@ $^ #cc是unix中常用编译器,linux下指向gcc.
main.o : main.c defs.h
cc -c main.c
command.o : command.c defs.h command.h
cc -c command.c
#.PHONY表示,clean是个伪目标文件,可以理解为是一个动作,一般用来清除make生成的文件。也可以是其它名字,通过make xxx来执行。
.PHONY clean
clean :
-rm edit $(objects) #减号表示忽略错误
make能自动推导和.o文件相同文件名的.c文件。于是可以简化成这样子:
objects = main.o command.o
edit : $(objects)
cc -o edit $(objects)
main.o : defs.h
command.o :defs.h command.h
.PHONY clean
clean :
-rm edit $(objects)
其中main.o 和 command.o都依赖了defs.h, 可以写成这样(不推荐这种写法,易混乱):
objects = main.o command.o
edit : $(objects)
cc -o edit $(objects)
main.o command.o : defs.h
command.o :command.h
.PHONY clean
clean :
-rm edit $(objects)
单目录下通用的Makefile
#for c
EXE=main
CC=gcc
SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
DEP=$(patsubst %.c,.%.d,$(SRC))
CFLAGS=-g
$(EXE):$(OBJ)
$(CC) $^ -o $@
$(DEP):.%.d:%.c
@set -e;\
rm -f $@;\
$(CC) -M $< > $@.$$$$;\
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@;\
rm -f .*.d*
-include $(DEP)
clean:
@rm $(EXE) $(OBJ) $(DEP) -f
#for c++
EXE=main
CC=g++
SRC=$(wildcard *.cpp)
OBJ=$(SRC:.cpp=.o)
DEP=$(patsubst %.cpp,.%.d,$(SRC))
CFLAGS=-g
$(EXE):$(OBJ)
$(CC) $^ -o $@
$(DEP):.%.d:%.cpp
@set -e;\
rm -f $@;\
$(CC) -MM $< > $@.$$$$;\
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@;\
rm -f .*.d*
-include $(DEP)
clean:
@rm $(EXE) $(OBJ) $(DEP) -f
其它细节
- make 支持的默认文件名:”GNUmakefile”、”makefile”、”Makefile”, 可以用
make -f filename指定makefile. - include foo.mk 包含其它makefile文件
- 默认会include 环境变量MAKEFILES 中的makefile,不建议设置这个变量。
深入理解Makefile与gcc编译流程

本文详细解析了Makefile的使用方法及其与gcc编译器之间的交互过程,涵盖了预处理、编译、汇编和链接四个关键步骤,同时介绍了常用的gcc选项和Makefile的高级特性,如依赖管理、函数和伪目标。通过实例展示了如何创建简洁且高效的Makefile,以自动化编译过程。
567

被折叠的 条评论
为什么被折叠?



