Makefile的在工程中的一般性应用
来源:互联网 发布:yum install redis 编辑:程序博客网 时间:2024/05/16 18:15
这几天查看了一下unp
的源代码,发现makefile
的书写真是一门学问,通过查看unp
的makefile
如何书写,本人从中间学到了很多东西。
一般的做法
这里,我已自己的一个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.definesLIB_OBJS=lib.oall: ${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.definesPROGS=demoall:$(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
,这一点在unp
的makefile
文件中用的很多。
如何加强?
我们来看一看lib
目录下的makefile
:
include ../Make.definesLIB_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(下)
- Makefile的在工程中的一般性应用
- Makefile在大型工程文件中的应用简析
- iOS_11_XMPP在工程中的应用
- 细胞工程在植物组织培养中的应用
- 选项卡在工程中的应用
- 时频分析在工程中的应用
- Kotlin在Android工程中的应用
- Kotlin在Android工程中的应用
- IOS 文件路径 在工程中的应用
- Kotlin在Android工程中的应用
- Ehcache在工程实践中的应用
- makefile--工程管应用理器的简单
- Vs2012在Linux开发中的应用(6):改写Makefile项目的Build过程
- Makefile定义工程中的宏
- VS 的makefile工程
- VS 的makefile工程
- VS 的makefile工程
- VS 的makefile工程
- c++中的隐藏、重载、覆盖(重写)
- 用JS编写日历的简单思路
- 列名无效
- 每日一Vim(5)—— c命令
- JUnit的jar包和hamcrest的jar包关系
- Makefile的在工程中的一般性应用
- java中equals与==
- 使用QtSingleApplication,实现应用只启动一个实例
- Unity 鼠标事件 GUI GUILayerOut Input Application(截屏,getMouseDown,getKeyCode) 射线
- ubuntu下中文输入法安装
- dell工作电脑配置
- 黑马程序员---IO流1(其他对象、FileWriter、FileReader)
- Sass入门-简介
- map小结[2015-11-03]