搜索
bottom↓
回复: 20

一个 Makefile 示例

  [复制链接]

出0入0汤圆

发表于 2019-3-24 17:49:59 | 显示全部楼层 |阅读模式
作为一个普通的搬砖码农来说,敲 make 的次数多,写 makefile 的机会却比较少,但掌握它是十分有必要的,毕竟读和改 makefile 的时候还是很多的嘛,特别是对于一个经常使用 c/c++ 的码农来说。

网上有一份关于 makefile 很好的资料叫做 《跟我一起写Makefile》,每每遇到不懂的地方我都会在里面找答案,非常的不错,需要的请到如下网盘路径下载:

链接https://pan.baidu.com/s/1OT-Hk3bzo070hjuWo39ASg
提取码:sjfy

资料的内容还是比较多的,对于新手来说非常有必要通读,但读完以后要自己来写一个的时候通常也是一头雾水,不知如何下手,本文则展示一个 makefile 示例,帮助大家运用和理解它,也可把它作为构建一个应用的 makfile 模板。

开始之前还是选简单说下 makefile,它是由一系列规则组成的文件,一条基本的规则结构如下:

  1. <target> : <prerequisites>
  2. [tab]  <commands>
复制代码


即 target 依赖于 prerequisites,那怎么由 prerequisites 生成 target 的,那就定义在 commands,那何时会更新 target 呢,则只要 prerequisites 最后一次更新的时间早已 target,则 target 会发生更新,即 commands 会执行。

现假设我们有如下一个工程目录,需要我们使用 makefile 来构建出 bin 档,那我们应该做呢?

  1. .
  2. ├── Makefile
  3. ├── README.md
  4. └── src
  5.     ├── inc
  6.     │   ├── test01.h
  7.     │   └── test02.h
  8.     ├── main.cpp
  9.     ├── src
  10.     │   └── test02.cpp
  11.     └── test01.cpp
复制代码


首先如果我们只需要构建 main.cpp 一个文件的时候我们可以这么做

  1. g++ main.cpp -o main
复制代码


这里其实是一步到位,把编译和链接放到了一起,直接生产 bin 档 main

通常的做法是我们先把源文件先编译成 .o 文件,然后再一起链接成 bin 档,如下:

  1. g++ -o main.o -c main.cpp

  2. g++ main.o -o main
复制代码


这是为什么呢?这是因为一步到位的做法,当源文件数量很多的时候非常的慢,它每次都要对所有文件进行编译,先编译生产中间文件的好处在于在一次全编译后,如果后续只更改一个文件的话,编译过程只会只编译更新过的文件,然后再一起链接输出可执行文件,速度比较快。

在编译链接过程有时往往还需要加入各种参数,如下两个常用的编译参数,则告诉编译器打开所有警告并遇到警告的地方也发出错误,这是十分好的习惯。

  1. -Wall -Werror
复制代码


除了编译选项,我们有时还会有链接选项,如下常用的指定链接线程库动态库

  1. -lpthread
复制代码


以上介绍的则是我们即将要用的 commands 啦,即怎么编译输出某文件,怎么链接生成某文件。

好的,那么我们再来理清楚一下我们的目标和依赖。

首先我们有一个终极目标就是生成可执行 bin 档,它依赖于源文件对应的 .o 文件,我们输入 .o 文件通过链接命令生成可执行文件,则这条规则可以这么写(伪代码):

  1. 可执行文件:所有源文件编译生成的 .o 文件
  2.     一条链接命令,输入是所有 .o 文件,输出是可执行文件
复制代码


那所有源文件编译生成的 .o 文件怎么生成呢,我们再写一条规则如下(伪代码):

  1. 所有源文件编译生成的 .o 文件:所有源文件
  2.     一条编译命令,输入是源文件,输出是 .o 文件
复制代码


那如果对于只有一个源文件的情况这个 makefile 文件就可以这么写了:

  1. main:main.o
  2.     g++ main.o -o main

  3. main.o:main.cpp
  4.     g++ -o main.o -c main.cpp
复制代码


对于如上我们给出的工程目录实例存在多个源文件还遍布在不同的目录下,那我们应该怎么办呢?

那这里需要再介绍一个 makefile 的知识,模式规则。

模式规则是用于说明生一类文件的另一类文件是什么,和是怎么生成的。假设我们要说明 .o 文件是由 .cpp 文件生成的,那么我们可以这么写:

  1. %.o:%.cpp
  2.     g++ -o $@ -c $<
复制代码


假设我们要生产 a.o b.o c.o 那它就会知道我们需要 a.cpp b.cpp c.cpp,其中 $@ 和 $< 是两个自动化变量。

其中 $@ 表示目标文件集,$< 表示这一模式规则中所有符合的文件,注意这里多是一一取出的。

了解了这些后,我们基本就能写出适用我们示例工程的 makefile 了。

首先第一件事情我们要先写出两个目标,终极目标好办,我们把它叫做 bin,则它依赖所有的 .o 文件,我们把所有 .o 文件存在一个变量 $(OBJ) 中的话,那么我们的第一条规则就是这么样的:

  1. bin: $(OBJ)
  2.     g++ $(OBJ) -o bin
复制代码


那我们所有的 .o 文件怎么生成呢,按上面的写出由所有 .cpp 文件生成所有 .o 文件的规则如下:

  1. $(OBJ): %.o : %.cpp
  2.     g++ -o $@ -c $<
复制代码


那这里 $(OBJ) 还是一个变量呢,我们应该对它进行赋值,我们可以这样做,如下:

  1. # 找到所有源文件
  2. SRC = $(shell find ./src -name '*.cpp')

  3. # 把所有源文件名字的 cpp 换成 o,同时去掉前面的路径,就得到所有 .o 文件了
  4. OBJ  = $(notdir $(patsubst %.cpp, %.o, $(SRC)))
复制代码


那这里还有最后一个问题是 make 过程中它怎么找到所有 cpp 文件呢?这里就还需要介绍 makefile 下的另一个变量了叫 VPATH,它指明了依赖文件的搜索路径,所以我们要指定它,如下:

  1. VPATH = ./src ./src/src
复制代码


注意它是要指定到每一级路径的。

那到这里关于怎么写用于构建这个示例工程的 makefile 文件,基本就完成了,剩下的就是把他们组织起来即可了。

下面是一个完整的组织起来后的示例,里面也有详细的注释,可以参考,

  1. # 输出标目名称
  2. BINNAME = test

  3. # 设置 .o 文件输出路径
  4. OBJDIR = ./obj

  5. # 配置工具链 CC
  6. CC = g++

  7. # 配置编译选项
  8. CC_OPTS := -Wall -Werror

  9. # 配置链接选项
  10. LD_OPTS :=

  11. # 指定编译时依赖的头文件目录,然后放进编译选项
  12. INC_DIR := ./src/inc

  13. CC_OPTS += -I$(INC_DIR)

  14. # 指出源文件存放路径
  15. SRC_DIR := ./src
  16. SRC_DIR += ./src/src

  17. # 指定依赖文件搜索路径,即我们的源文件路径
  18. VPATH = $(SRC_DIR)

  19. # 找出所有需要编译的 cpp 类型文件,注意 find 默认是会循环找子目录的,
  20. # 由于我们子目录的路径也需要写进 VPATH 所以这里把 find 的查找深度设置为了 1
  21. SRC = $(shell find $(SRC_DIR) -maxdepth 1 -name '*.cpp')

  22. # 生成需要输出的 .o 文件名
  23. OBJ_0  = $(notdir $(patsubst %.cpp, %.o, $(SRC)))

  24. # 加上 .o 文件存放路径前缀
  25. OBJ    = $(foreach file, $(OBJ_0), $(OBJDIR)/$(file))

  26. .PHONY: all setup bin clean

  27. all: setup bin

  28. setup:
  29.     @echo $(SRC)
  30.     @echo $(OBJ_0)
  31.     @echo $(OBJ)
  32.     mkdir -p $(OBJDIR)

  33. bin: $(OBJ)
  34.     $(CC) $(OBJ) $(LD_OPTS) -o $(BINNAME)

  35. $(OBJ): $(OBJDIR)/%.o : %.cpp
  36.     $(CC) $(CC_OPTS) -o $@ -c $<

  37. clean:
  38.     rm -rf $(OBJDIR)
  39.     rm -rf $(BINNAME)
复制代码


感觉写的不是不是特别好,希望解释清楚了,怎么从零开始生成这样一个示例工程的 makefile 文件。欢迎提出你的建议或疑问,谢谢大家阅读。

完整的示例工程和 makefile 文件可以到如下路径取:

点击获取

扫码关注我了解更多有趣编程实例



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2019-3-24 17:56:31 | 显示全部楼层
cmake 了解一下

出0入0汤圆

发表于 2019-3-24 18:12:48 | 显示全部楼层
广告不错!

出0入25汤圆

发表于 2019-3-24 18:21:28 | 显示全部楼层

很详细,,感谢

出0入0汤圆

发表于 2019-3-24 20:43:04 | 显示全部楼层
楼主公众号?

出0入0汤圆

 楼主| 发表于 2019-3-24 21:09:54 | 显示全部楼层

有机会写一篇 cmake 相关的

出0入0汤圆

 楼主| 发表于 2019-3-24 21:10:21 | 显示全部楼层

我公众号现在还没任何广告

出0入0汤圆

 楼主| 发表于 2019-3-24 21:10:41 | 显示全部楼层

是的,欢迎关注

出0入0汤圆

发表于 2019-3-25 12:54:01 | 显示全部楼层
很详细,,感谢

出0入296汤圆

发表于 2019-3-25 18:19:53 | 显示全部楼层
http://gnuwin32.sourceforge.net/packages/make.htm

安装windows版本的make,然后看里面的user guide。

文档写的很好,可以在这个目录下看到:C:\Program Files (x86)\GnuWin32\doc\make\3.81\make-3.81\make.pdf

出0入0汤圆

 楼主| 发表于 2019-3-25 18:54:23 | 显示全部楼层
Gorgon_Meducer 发表于 2019-3-25 18:19
http://gnuwin32.sourceforge.net/packages/make.htm

安装windows版本的make,然后看里面的user guide。

多谢指点,文档可以直接下载,下载看了下确实很好,多谢!

出0入0汤圆

发表于 2019-3-25 18:56:02 | 显示全部楼层
make 一下mark

出0入0汤圆

发表于 2019-3-25 20:26:36 | 显示全部楼层
前几天刚好需要为一个C++工程写makefile,一开始以为要一个文件一个写,后来从网上搜了一遍,也是跟楼主差不多这么写

出105入79汤圆

发表于 2019-3-25 20:31:16 | 显示全部楼层
上面提到的 GNU make 说明

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2019-3-25 22:13:26 来自手机 | 显示全部楼层
make 一下mark

出0入0汤圆

发表于 2019-3-26 07:13:52 | 显示全部楼层
用netbeans建立c工程就可以不用关注Makefile怎么写了

出0入0汤圆

发表于 2019-3-26 12:57:33 | 显示全部楼层
mark一下

出0入0汤圆

发表于 2019-5-8 19:59:50 | 显示全部楼层
上传一个别人翻译成中文的

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2019-5-9 09:51:22 | 显示全部楼层
不错、很好,学习了!谢谢。

出0入0汤圆

发表于 2019-11-29 09:18:11 | 显示全部楼层
有顶层Makefile调到底层Makefile的例程吗?

出0入0汤圆

发表于 2020-10-29 17:57:12 | 显示全部楼层
下个buildroot玩玩,收货会更多
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-20 06:25

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表