文档章节

Makefile中用foreach,eval,call实现将目标文件编译到指定目录

临峰不畏
 临峰不畏
发布于 2016/08/10 22:22
字数 565
阅读 936
收藏 3

博主要创建一个工程目录,希望将所有的.c文件都编译成.o并存放到out/目录下。如下:

.
├── d1
│   ├── aa.c
│   └── dd.c
├── main.c
├── Makefile
└── out

经过一晚上的尝试,最终使用了foreach函数实现了这个目标:

TARGET=test
ALL_SOURCES=$(shell find -name "*.c")

SOURCE_TO_OBJECT = ./out/$(subst .c,.o,$(notdir $(1)))
ALL_OBJECTS=$(foreach src,$(ALL_SOURCES),$(call SOURCE_TO_OBJECT,$(src)))

define CREATE_OBJECT_TARGET
$(call SOURCE_TO_OBJECT,$(1)) : $(1)
	gcc -c -o $$@ $$^
endef

all: $(TARGET)

clean:
	-rm $(ALL_OBJECTS)
	-rm $(TARGET)

$(TARGET):$(ALL_OBJECTS)
	gcc -o $@ $^

$(foreach src,$(ALL_SOURCES),$(eval $(call CREATE_OBJECT_TARGET,$(src))))

大概思路是这样的:
首先,ALL_SOURCES=$(shell find -name "*.c"),我将当前目录下的所有.c文件找到并赋值给ALL_SOURCE变量。
然后,ALL_OBJECTS=$(foreach src,$(ALL_SOURCES),$(call SOURCE_TO_OBJECT,$(src))),对每个一ALL_SOURCE中的源文件进行处理,将每个文件名去除路径,并将后缀.c替换成.o,再加上./out前缀就成了目标文件名。注意:函数调用中不能随意地加空格!!
SOURCE_TO_OBJECT是一个将源文件名转换成目标文件名的函数。上面用$(call ...) 对它进行调用。

然后,我想为每个目标文件建立依赖关系,如下:

./obj/main.o : main.c
    gcc -c -o $@ $^

./obj/aa.o : d1/aa.c
    gcc -c -o $@ $^

./obj/bb.o : d1/bb.c
    gcc -c -o $@ $^

文件个数少还好说,如果工程大了,上百个文件维护起来很吃力。于是想到要用 $(foreach ...) 函数来实现。创建这么一个函数,用于生成目标与文件依赖关系:

define CREATE_OBJECT_TARGET
$(call SOURCE_TO_OBJECT,$(1)) : $(1)
	gcc -c -o $$@ $$^
endef

转入的一个参数$(1)是源文件全路径。
注意:其中的 gcc -c -o $$@ $$^,是双 $ 符号。

再用如下的$(foreach ...)函数达到对每一个源文件都建立一个目标的目的:
$(foreach src,$(ALL_SOURCES),$(eval $(call CREATE_OBJECT_TARGET,$(src))))

其中用到的命令有:

  • notdir,从全路径的文件名,提取出文件名称。相当于shell的basename
  • subst,字符串替换
  • foreach,对数组中的每一个元数做处理
  • call,调用自定义宏
  • eval,将字串应用到Makefile上下文
  • shell,执行shell脚本

其它常用的函数还有:

  • dir
  • addprefix
  • patsubst
  • strip
  • sort
  • wildcard

如果大家还有别的什么更好的方法,欢迎留言。

© 著作权归作者所有

共有 人打赏支持
临峰不畏
粉丝 214
博文 187
码字总数 98583
作品 0
深圳
架构师
私信 提问
[转]Makefile 使用总结

Makefile 简介 Makefile 是和 make 命令一起配合使用的. 很多大型项目的编译都是通过 Makefile 来组织的, 如果没有 Makefile, 那很多项目中各种库和代码之间的依赖关系不知会多复杂. Makefil...

四彩
2016/02/28
119
0
一个通用的makefile写法,自动推导文件的依赖关系

今天看了一天的makefile的写法,东拼西凑,好不容易写出了一个makefile,颇有成就感,记录下来,以备温习之用。 假设有两个头文件目录 header1,header2;两个cpp文件目录,src1,src2,一个lib目...

AlphaJay
2010/11/23
0
0
makefile 一看就懂了

前言:没接触Linux下编译之前,觉得很神秘,特别是makefile,一个简单的make命令就能编译一个大型项目生成一个可执行文件,接下来跟大家分享下学习的makefile的知识。 目录: 1.makefile简介...

小小实习生
2016/10/22
39
0
Android系统镜像文件的打包过程分析

在前面一篇文章中,我们分析了Android模块的编译过程。当Android系统的所有模块都编译好之后,我们就可以对编译出来的模块文件进行打包了。打包结果是获得一系列的镜像文件,例如system.img、...

sflfqx
2015/02/09
0
0
内核模块编译 makefile入门

转自http://blog.csdn.net/zqixiao_09/article/details/50838043 一、模块的编译 我们在前面内核编译中驱动移植那块,讲到驱动编译分为静态编译和动态编译;静态编译即为将驱动直接编译进内核...

u012142460
2017/12/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

css hack

浏览器的兼容性一直是个头疼的问题,使用“欺骗”技术可使各个浏览器效果一致,花了些时间整理了各个浏览器的HACK,主要包括IE系列和最新版本的Chrome、Safari、Firefox、 Opera,比较全面的...

kitty1116
29分钟前
1
0
zookeeper脑裂问题

一、为什么zookeeper要部署基数台服务器? 二、zookeeper脑裂(Split-Brain)问题 2.1、什么是脑裂? 2.2、什么原因导致的? 2.2、zookeeper是如何解决的? 一、为什么zookeeper要部署基数台...

tantexian
34分钟前
2
0
Spring事务传播行为详解

前言 Spring在TransactionDefinition接口中规定了7种类型的事务传播行为。事务传播行为是Spring框架独有的事务增强特性,他不属于的事务实际提供方数据库行为。这是Spring为我们提供的强大的...

码代码的小司机
45分钟前
3
0
Android设备通过fastboot刷入TWRP

方法一:通过fastboot刷入TWRP的方式 首先去TWRP官网下载TWRP安装文件https://twrp.me/Devices/ 1.进入bootloader adb reboot bootloader 也可在开机时,同时按住电源键+音量减,进入bootloa...

robslove
49分钟前
1
0
为何译为“东家机”和“宾客机”

学习过虚拟化、云计算的人大概都知道,并且都在自己的电脑上安装KVM,如下图所示: 什么情况?不过是在物理机的Windows 10上安装了VMware;在VMware上安装了Linux CentOS 7操作系统;又在其上...

大别阿郎
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部