Makefile的在工程中的一般性应用

这几天查看了一下unp的源代码,发现makefile的书写真是一门学问,通过查看unpmakefile如何书写,本人从中间学到了很多东西。


一般的做法

这里,我已自己的一个demo为例子,简单地记录一下在大型的工程中如何使用makefile文件。

现在假设我有一个demo的项目,为了分类文件,我在demo下面建立了一个bin文件夹,用来放置本工程经常用到的库源文件,然后是一个bin文件夹,这个文件夹里面才是我们的main程序所在的目录。

---demo----lib
       |---bin

一般而言,我们在demo目录下设定一些常用的参数,在demo目录下,我们建立一个Make.defines文件,文件内容如下:

# 使用的是gcc编译器
CC=gcc
# -I 选项告诉编译器查找文件中所需要的.h文件请到../lib目录下面去找
CFLAGS=-g -Wall -I../lib
# 这里主要是为了方便,将lib下的.o文件压成了.a文件
LIBS=../lib.a

现在文件结构如下:

---demo----lib
       |---bin
       |---Make.defines

我们一般先写几个lib文件,让函数调用,好了,我们在lib目录下写几个文件吧!

---demo----lib----lib.h
       |      |---lib.c
       |      |---Makefile
       |---bin
       |---Make.defines

下面是lib.h文件:

int add();

下面是lib.c文件:

#include <stdio.h>

int add()
{
    printf("我们现在在lib中调用add\n");
    return 0;
}

很简单的代码,现在我们要将编译这些lib,顺便在该目录下建立一个Makefile文件:

# 添加上级目录下面的Make.defines文件,主要用到她里面的一些变量
include ../Make.defines
LIB_OBJS=lib.o

all:    ${LIB_OBJS}
    # 下面的命令主要是用于打包,将LIB_OBJS所代表的文件打包至LIBS(../lib.a)
    ar rcs ${LIBS} ${LIB_OBJS}
# 将所有的.c文件编译成.o文件
%.o:%.c
    $(CC) $(CFLAGS) -c $< -o $@

然后执行make命令,我们会发现上级目录下多了一个lib.a文件,我们查看一下该文件下有什么:

这里写图片描述

恰好是我们的lib.o文件。
现在的目录结构变成了下面的样子:

---demo----lib----lib.h
       |      |---lib.c
       |      |---Makefile
       |---bin
       |---Make.defines
       |---lib.a

然后我们到bin目录下建立我们的主程序,文件结构如下:

---demo----lib----lib.h
       |      |---lib.c
       |      |---Makefile
       |---bin----demo.c
       |      |---Makefile
       |---Make.defines
       |---lib.a

下面是demo.c文件:

#include <stdio.h>
#include "lib.h"

int main()
{
    add();
    return 0;
}

然后是Makefile文件:

# 同上面,加载Make.defines文件,该文件记录了各个目录下都要用到的一次额公用变量,如CC,CFLAGS等。
include ../Make.defines
# 程序的名称
PROGS=demo
# all是伪目标
all:$(PROGS)
# *.o依赖于*.c,将*.c-->*.o,这里的*的代表的东西是一致的
%.o:    %.c
    $(CC) $(CFLAGS) -c $< -o $@
# 下面指示如何生成demo程序
demo:   demo.o $(LIBS)
    $(CC) $(CFLAGS) -o $@ demo.o $(LIBS)
clean:
    rm -rf *.o ${PROGS}

然后make一下,程序便生成成功。
我们运行demo一下:

这里写图片描述

程序没有问题。

差不多这就是我从unp的源代码中学到的如何在一个很大型的工程中应用makefile文件的例子啦,高手莫见笑,这么干有什么优点呢?

  • lib文件夹下的文件出现了变动,我们只需要在lib文件下下make一下,这样,上级目录下的lib.a文件就会更新,也就导致了依赖于该文件的的代码也更新。

  • makefile并非写在一个文件里面,而是分文件夹书写,更加有序,更加简洁。

  • 一些共用的变量可以放在一个类似Make.defines的文件里面,像c语言调用库一样调用,这样大大减少了书写量。

暂时能想到的就这么多吧。


脑洞大开

如果我们在bin目录下新建一个new_lib.c:

/*
 * /demo/bin/new_lib.c
 */
#include <stdio.h>

int add()
{
    printf("我正在新的lib中调用add函数\n");
    return 0;
}

然后修改一下Makefile文件:

include ../Make.defines

PROGS=demo

all:$(PROGS)

%.o:    %.c
    $(CC) $(CFLAGS) -c $< -o $@

demo:   demo.o new_lib.o $(LIBS)
    $(CC) $(CFLAGS) -o $@ demo.o new_lib.o $(LIBS)
clean:
    rm -rf *.o ${PROGS}

需要注意的一点是:lib.o中有int add()函数,new_lib.o中也有int add()函数,那么gcc究竟会链接哪一个文件中的add程序呢?

这里写图片描述

很有趣是吧,居然先链接在前面的,其实这与gcc的编译方式有关,感兴趣的可以去看一看csapp,这一点在unpmakefile文件中用的很多。


如何加强?

我们来看一看lib目录下的makefile:

include ../Make.defines
LIB_OBJS=lib.o lib1.o

${LIBS}:    ${LIB_OBJS}
    ar rcs ${LIBS} $?

# all:  ${LIB_OBJS}
#   ar rcs ${LIBS} $?
# 如果将上面的两句换成注释里的两句,效果是相同的,但是效率是不同的
# all是伪目标,这意味着,all是一定会被执行的,这就导致效率底下,不论变没变,都会被更新
# 但是改用${LIBS}之后,效率绝对变高了,因为LIB_OBJS里面的文件没有变化的话,LIBS是不会被创建的

# 即使没有下面的语句,依然会有从.c文件生成.o文件,这是因为隐含规则的缘故
# make的隐含规则是,将.o的目标依赖文件置成.c文件,并使用 ${CC} -c ${CFLAGS} [.c]来生成.o文件
# %.o:%.c
#   $(CC) $(CFLAGS) -c $< -o $@

为了方便,我们在demo目录下加一个总控的makefile,只要执行这一个makefile,就可以实现整个项目的编译,很方便。

SUBDIRS =bin lib # 两个子目录,一个bin,一个lib
.PHONY: subdirs ${SUBDIRS} # 两个目标都是伪目标
subdirs:    ${SUBDIRS}
${SUBDIRS}:
    ${MAKE} -C $@ # 进入子目录下执行make命令
bin:    lib # 依赖,表示在进入bin之前应该先进入lib目录

此时文件的结构如下:

---demo----lib----lib.h
       |      |---lib.c
       |      |---Makefile
       |---bin----demo.c
       |      |---Makefile
       |---Make.defines
       |---lib.a
       |---Makefile

差不多就是这样啦,以后有新的发现再来补坑。

一个makefile模版

最近自己写了一个makefile模版,以后要编译很小程序的话,直接调用这个模版就可以了.

CC  := g++
CXXFLAGS:= -w -std=c++11 -c # 编译的一些参数
LFLAGS  := -lpthread  # 这里放入要链接的库的名称
BINS    := web_regular # 程序名,是main函数所在文件的名称(不要后缀)
SRCS    := $(wildcard *.cpp) # 当前目录下的所有的.cpp文件 
OBJS    := $(SRCS:.cpp=.o) # 将所有的.cc文件名替换为.o

.PHONY: all clean  # 表示all和clean是两个伪目标

all:$(BINS) # make每次编译的时候总是认为伪目标改变了,会重新编译

BINOS   = $(addsuffix .o, $(BINS))
TEMP_OBJ= $(filter-out $(BINOS), $^)

$(BINS):$(OBJS) 
    @echo "正在链接程序......"; \
    $(foreach BIN, $@, $(CC) $(TEMP_OBJ) $(BIN).o $(LFLAGS) -o $(BIN));   

%.d:%.cpp
    @echo "正在生成依赖中......"; \
    rm -f $@; \
    $(CC) -MM $< > $@.$$$$; \
    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
    rm -f $@.$$$$

-include $(SRCS:.cpp=.d)

clean:
    rm -f *.o *.d
    rm -f $(BINS)

# makefile说白了就是拼凑字符串

Makefile基础

跟我一起写makefile!
Makefile伪目标
深入学习Make命令和Makefile(上)
深入学习Make命令和Makefile(下)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容