这里以实例形式来记录一步一步写出makefile的过程。
有关详细介绍和说明可见之前转载的一篇文章:《和我一起写Makefile(转载)》
先放图:
GCC参数:
-v 查看版本
-I 指定头文件目录,注意-I后没有空格
gcc -I./include main.c a.c -o app
-c 只编译,生成.o文件,不进行链接
-g 包含调试信息
gcc main.c a.c -g -o app1
-On n=0~3 编译优化,n越大优化的越多
-Wall 提示更多警告信息 严格编译
-D 编译时定义宏,注意-D和之间没有空格
gcc main.c -DDEBUG -o app
-o 指定输出文件名
gcc -o myapp main.cpp
或
g++ main.cpp -o myapp
这样生产的可执行名为myapp,默认生成的叫a.out
-E 预编译 生成预处理文件 所有程序编译时都先预编译,将所有的头文件放到.cpp文件中去。
gcc -E a.cpp -o a1.cpp
vi a1.cpp
这样看看a1.cpp的内容,就可以清楚的知道预编译的作用
目标:依赖(条件)
命令
main.cpp
#include
#include "a.h"
using namespace std;
int main()
{
test();
cout << "hello world" << endl;
return 0;
}
a.h
#ifndef A_H_
#define A_H_
void test();
#endif
a.cpp
#include
using namespace std;
void test()
{
cout << "hello yangzheng" << endl;
}
编译:
g++ main.cpp a.cpp -o mycpp
这样虽然可以编译,但当有成千上万.cpp时,效率就很低了。
所以,我们开始写makefile
start:
g++ -o main.o -c main.cpp
g++ -o a.o -c a.cpp
g++ -o myapp a.o main.o
这样make一下就能产生a.o main.o mycpp三个文件
start: 在这里是Makefile中的第一个目标,Makefile默认执行第一个出现的目标,可通过make dest指定要执行的目标
注意:start下的语句前必须是一个Tab,而不能是多个空格,否则会出错。
start:
g++ -o main.o -c main.cpp
g++ -o a.o -c a.cpp
g++ -o myapp a.o main.o
clean:
rm -rf main.o a.o
make默认只执行第一个标号,所以要加一个参数,make clean一下,执行clean下的语句,即将main.o a.o文件删除。
make不管理.h文件,.h文件由编译器管理。所以.h文件修改后,应把对应的.o文件删了再编译。
CC=g++
start:
$(CC) -o main.o -c main.cpp
$(CC) -o a.o -c a.cpp
$(CC) -o myapp a.o main.o
clean:
rm -rf main.o a.o
CC=g++ CC是定义的变量,一般在makefile中变量习惯大写。这样就能用$(CC)代替原来的g++。这样就方便以后的修改,不用一个一个改,只需改一个变量即可。
CC=g++
start: a.o main.o
$(CC) -o myapp a.o main.o
a.o:
$(CC) -o a.o -c a.cpp
main.o
$(CC) -o main.o -c main.cpp
clean:
rm -rf main.o a.o
Makefile中的依赖关系:start:a.o main.o 这样,在执行start前,依赖于a.o main.o。
这样,当a.o或main.o不存在时,就先执行a.o或main.o中的语句。
当项目很大时,修改文件后重新编译时,已有的.o文件,就不会再重复编译了。从而达到只编译修改的文件的目的。
make是根据.cpp和.o文件最后的修改时间来判断.cpp问文件是否需要编译。如果.o文件不存在,make会失去判断条件,那么就一定会编译.cpp文件。所以,如果服务器的时间改了,那么整个项目都会重新编译。
CC=g++
start: a.o main.o
$(CC) -o myapp a.o main.o
.cpp.o:
$(CC) -o $@ -c $<
clean:
rm -rf main.o a.o
Makefile有三个非常有用的变量。分别是 @, ^, <代表的意义分别是: @–目标文件, −−所有的依赖文件, <–第一个依赖文件。使用上面三个变量,可以简化我们的Makefile文件.
当然,这样还不够,一个好的Makefile中start下应该都是变量。这样便于大型项目的维护。
CC=g++
SRCS=main.cpp\
a.cpp
OBJS=main.o\
a.o
EXEC=myapp
start: $(OBJS)
$(CC) -o $(EXEC) $(OBJS)
.cpp.o:
$(CC) -o $@ -c $<
clean:
rm -rf $(OBJS)
一般用SRC代表源文件,OBJ代表.o文件,EXEC代表可执行文件
SRCS=main.cpp\
a.cpp
分行写便于修改、添加和查看。
这样,Makefile已写的差不多了,还有一个不完美的地方是,如果这时要再SRCS添加一个b.cpp的同时要在OBJS中添加一个b.o文件,所以……
CC=g++
SRCS=main.cpp\
a.cpp
OBJS=$(SRCS:.cpp=.o)
EXEC=myapp
start: $(OBJS)
$(CC) -o $(EXEC) $(OBJS)
.cpp.o:
$(CC) -o $@ -c $<
clean:
rm -rf $(OBJS)
OBJS=$(SRCS:.cpp=.o) 意思是把SRCS当成字符串,将字符串中的.cpp换为.o,再赋值给OBJS。
就这样,产生了一个完整的Makefile。
另一个笔记:
Makefile:
#阶段一
#app:add.c sub.c dive.c mul.c main.c
# gcc add.c sub.c dive.c mul.c main.c -o app
#阶段二
#app:add.o sub.o dive.o mul.o main.o
# gcc add.o sub.o dive.o mul.o main.o -o app
#add.o:add.c
# gcc -c add.c
#sub.o:sub.c
# gcc -c sub.c
#dive.o:dive.c
# gcc -c dive.c
#mul.o:mul.c
# gcc -c mul.c
#.PHONY:clean
#clean:
# -rm -f *.o
# -rm -f app
#阶段三
# $@表示目标 $^表示所有依赖 $<表示依赖中的第一个
##obj=add.o sub.o mul.o dive.o main.o
#src = $(wildcard *.c) #wildcard函数可以找到当前目录下所有.c文件
#obj = $(patsubst %.c,%.o,$(src)) #将src展开,将所有.c替换为.o
#target = app
#$(target):$(obj)
# gcc $^ -o $@
#%.o:%c
# gcc -c %< -o $@
#.PHONY:clean
#clean:
# -rm -f *.o
# -rm -f app
#阶段四
CPPFLAGS= -Iinclude #预处理器,指定头文件在那个目录 这里的include代表一个文件夹
CFLAGS= -g -Wall #编译时的参数
LDFLAGS= -L../lib -lmycalc #加载时的参数 这里的mycalc代表一个库
CC=gcc
src = $(wildcard *.c) #wildcard函数可以找到当前目录下所有.c文件
obj = $(patsubst %.c,%.o,$(src)) #将src展开,将所有.c替换为.o
target = app
$(target):$(obj)
$(CC) $^ $(LDFLAGS) -o $@
%.o:%c
$(CC) -c %< $(CFLAGS) $(CPPFLAGS) -o $@
.PHONY:clean
#清楚生成的过程文件
clean:
-rm -f *.o
-rm -f app
#清楚生成的过程文件和生成配置文件
distclean:
rm /usr/bin/app
install:
cp app /usr/bin
test:
@echo $(src)
@echo $(obj)
其他:
进入目录执行某目录中的makefile
make -C 目录