准备
要看懂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,不建议设置这个变量。