文档章节

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

临峰不畏
 临峰不畏
发布于 2016/08/10 22:22
字数 565
阅读 838
收藏 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

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

© 著作权归作者所有

共有 人打赏支持
临峰不畏
粉丝 213
博文 186
码字总数 98141
作品 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
makefile(04)_函数

9.函数定义及调用 Makefile中支持函数的概念,make解析器提供了一系列函数供Makefile使用。同时可以自定义函数。 9.1.自定义函数 在Makefile中支持自定义函数的实现,并调用执行,通过defin...

三九感冒灵
04/26
0
0
内核模块编译 makefile入门

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

u012142460
2017/12/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Bash重定向详解

Bash重定向详解 Bash的重定向指的是将命令的输入和输出导向不同地方,而不是默认的标准输入、标准输出和标准错误。Bash的重定向实际上是对标准输入、标准输出和标准错误的重置,进而将所需输...

小陶小陶
今天
3
0
EventBus原理深度解析

一、问题描述 在工作中,经常会遇见使用异步的方式来发送事件,或者触发另外一个动作:经常用到的框架是MQ(分布式方式通知)。如果是同一个jvm里面通知的话,就可以使用EventBus。由于Event...

yangjianzhou
今天
13
0
OpenCV图像处理实例:libuv+cvui显示摄像头视频

#include <iostream>#include <opencv2/opencv.hpp>#define CVUI_IMPLEMENTATION#include <cvui.h>extern "C"{#include <uv.h>}using namespace std;#define WINDOW_NAM......

IOTService
今天
3
0
openJDK之JDK9的String

1.openJDK8的String 先来看下openJDK8的String的底层,如下图1.1所示: 图1.1 底层上使用的是char[],即char数组 每个char占16个bit,Character.SIZE的值是16。 2.openJDK9中的String 图2.1...

克虏伯
今天
4
0
UEFI 模式下如何安装 Ubuntu 16.04

作者:知乎用户 链接:https://www.zhihu.com/question/52092661/answer/259583475 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 针对UEFI模式下安装U...

寻知者
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部