和我一起写Makefile(原创)

这里以实例形式来记录一步一步写出makefile的过程。
有关详细介绍和说明可见之前转载的一篇文章:《和我一起写Makefile(转载)》

先放图:
和我一起写Makefile(原创)_第1张图片

预备知识GCC

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的内容,就可以清楚的知道预编译的作用


开始写makefile

语法规则:

目标:依赖(条件)
命令

示例代码:

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 目录

你可能感兴趣的:(Linux)