最近在研究一个嵌入式开发项目,在编写实际的项目代码时,需要临时写一些测试代码对部分功能进行预测试。编写的这些代码,有时候需要在PC机(x86)的平台上运行,有时候则需要在A嵌入式平台(arm端)i.mx6的平台上运行,而还有时候则需要在B嵌入式平台(arm端)mini2440的平台上运行,需要能随时进行切换,编译出对应平台所需要的可执行文件。

为了解决这个问题,最土的办法自然就是写三份makefile,需要编译某一个平台时,拷贝对应的makefile,然后再make。可是这样效率很低,而且很low,自然不予考虑。稍微好一点的办法,则是在makefile中,定义三套编译规则,通过输入make x86,以及make imx6,以及make mini2440这样的目标选择命令,来指示编译器选择某一套编译规则并运行。但是,这样的方法,会导致makefile的文件很冗余,存在多套几乎一模一样的编译规则。如下所示:

# 强制用bash,有的系统/bin/sh默认是用dash的,用dash会导致echo -e显示时多出一个-e
SHELL = /bin/bash# syspath & tools
COMPILE_x86      = gcc
COMPILE_arm      = arm-poky-linux-gnueabi-gcc# build target
TARGET_x86      := test_x86
TARGET_arm      := test_arm# compile option
LIBS            += -lpthread
CFLAGS          += -rdynamic -Wall -O2 -Wno-uninitialized
LDFLAGS         += $(LIBS)# sources path
SOURCES         += ${wildcard *.c}# build dir
BUILDDIR_x86    ?= _build_x86
BUILDDIR_arm    ?= _build_armTEMPDIR_x86       ?= $(BUILDDIR_x86)/temp
TEMPDIR_arm     ?= $(BUILDDIR_arm)/temp# object files
OBJECTS_x86     := $(patsubst %.c,$(TEMPDIR_x86)/%.o,$(filter %.c, $(SOURCES)))
DEPENDS_x86     := $(patsubst %.c,$(TEMPDIR_x86)/%.d,$(filter %.c, $(SOURCES)))OBJECTS_arm     := $(patsubst %.c,$(TEMPDIR_arm)/%.o,$(filter %.c, $(SOURCES)))
DEPENDS_arm     := $(patsubst %.c,$(TEMPDIR_arm)/%.d,$(filter %.c, $(SOURCES)))# build command
.PHONY: x86 arm cleanx86: mngdir_x86 $(TARGET_x86)mngdir_x86:@mkdir -pv $(TEMPDIR_x86)@mkdir -pv $(BUILDDIR_x86)$(TEMPDIR_x86)/%.o: %.c@mkdir -pv $(@D)$(COMPILE_x86) $(CFLAGS) -c -o $@ $<$(TEMPDIR_x86)/%.d: %.c@echo "$@: $<:$(notdir $*)"@mkdir -pv $(@D)@set -e; rm -f $@; \$(COMPILE_x86) -MM $(CFLAGS) $< > $@.$$$$; \sed 's,$(notdir $*)\.o[ :]*,$(TEMPDIR_x86)/$*\.o $@ : ,g' < $@.$$$$ > $@; \rm -f $@.$$$$$(TARGET_x86): $(OBJECTS_x86) $(DEPENDS_x86)$(COMPILE_x86) $(CFLAGS) -o $(BUILDDIR_x86)/$@ $(OBJECTS_x86) $(LDFLAGS)@echo "*********************  Bulid $(TARGET_x86)  complete   ************************"arm: mngdir_arm $(TARGET_arm)mngdir_arm:@mkdir -pv $(TEMPDIR_arm)@mkdir -pv $(BUILDDIR_arm)$(TEMPDIR_arm)/%.o: %.c@mkdir -pv $(@D)$(COMPILE_arm) $(CFLAGS) -c -o $@ $<$(TEMPDIR_arm)/%.d: %.c@echo "$@: $<:$(notdir $*)"@mkdir -pv $(@D)@set -e; rm -f $@; \$(COMPILE_arm) -MM $(CFLAGS) $< > $@.$$$$; \sed 's,$(notdir $*)\.o[ :]*,$(TEMPDIR)/$*\.o $@ : ,g' < $@.$$$$ > $@; \rm -f $@.$$$$$(TARGET_arm): $(OBJECTS_arm) $(DEPENDS)$(COMPILE_arm) $(CFLAGS) -o $(BUILDDIR_arm)/$@ $(OBJECTS_arm) $(LDFLAGS)@echo "********************* Bulid $(TARGET_arm) complete    ************************"clean:-@rm -fv $(TARGET_x86)-@rm -fv $(OBJECTS_x86)-@rm -fv $(DEPENDS_x86)-@rm -rfv $(TEMPDIR_x86)-@rm -rfv $(BUILDDIR_x86)-@rm -fv $(TARGET_arm)-@rm -fv $(OBJECTS_arm)-@rm -fv $(DEPENDS_arm)-@rm -rfv $(TEMPDIR_arm)-@rm -rfv $(BUILDDIR_arm)@echo "*********************  clean all targets complete  ************************"

为了简单起见,上述makefile中,只列举了其中两套编译规则,第三套并没有写上。尽管如此,仍然可以看出整个文件很冗长,虽然整个make的过程很简单,但是makefile的可读性却不怎么高,代码看上去不舒服。而且,最大的问题是,可扩展性很差,当我要再增加第三个平台甚至第四个平台时,代码量是呈倍数增长的,显然不适合。

那么,有没有更好的办法呢?答案显然是有的。

通过一番搜索,我找到了以下的思路:

在makefile中可以预先使用一个未定义的变量, 这个变量可以在make执行时传递给它。换句话说,就是可以向make命令传递参数,告诉它怎么去解释makefile这个文件。

网上关于这个思路最多的例子,就是如何使用同一份代码、同一份makefile,却通过给make命令传入不同的参数来编译出debug版本和release版本,直接去百度一抓一大把【可参见其他博主的博文:如何给Make命令来传递参数,如何给Makefile 传入参数,make传递给Makefile参数,等等】,这里就不再赘述。

于是,根据这个思路,我对上述的makefile文件进行了精简和修改,最终的效果如下所示:

# 强制用bash,有的系统/bin/sh默认是用dash的,用dash会导致echo -e显示时多出一个-e
SHELL = /bin/bash# avalible targets
target_x86       = x86
target_imx6      = imx6
target_2440      = 2440# build target
TARGET_ARCH      = $(target)
TARGET_OBJT     := temptest_$(TARGET_ARCH)# syspath & tools
ifeq ($(TARGET_ARCH), $(target_x86))COMPILE      = gcc
else ifeq ($(TARGET_ARCH), $(target_imx6))COMPILE    = arm-poky-linux-gnueabi-gcc
else ifeq ($(TARGET_ARCH), $(target_2440))COMPILE        = arm-linux-gcc
endif# compile option
LIBS            += -lpthread
CFLAGS          += -rdynamic -Wall -O2 -Wno-uninitialized
LDFLAGS         += $(LIBS)# sources path
SOURCES         += ${wildcard *.c}# build dir
BUILDDIR        ?= _build
OBJCTDIR        ?= $(BUILDDIR)/object_$(TARGET_ARCH)# object files
OBJECTS         := $(patsubst %.c,$(OBJCTDIR)/%.o,$(filter %.c, $(SOURCES)))
DEPENDS         := $(patsubst %.c,$(OBJCTDIR)/%.d,$(filter %.c, $(SOURCES)))# build command
.PHONY: all useage help cleanall: mngdir $(TARGET_OBJT)mngdir:@mkdir -pv $(OBJCTDIR)@mkdir -pv $(BUILDDIR)$(OBJCTDIR)/%.o: %.c@mkdir -pv $(@D)$(COMPILE) $(CFLAGS) -c -o $@ $<$(OBJCTDIR)/%.d: %.c@echo "$@: $<:$(notdir $*)"@mkdir -pv $(@D)@set -e; rm -f $@; \$(COMPILE) -MM $(CFLAGS) $< > $@.$$$$; \sed 's,$(notdir $*)\.o[ :]*,$(TEMPDIR_x86)/$*\.o $@ : ,g' < $@.$$$$ > $@; \rm -f $@.$$$$$(TARGET_OBJT): $(OBJECTS) $(DEPENDS)$(COMPILE) $(CFLAGS) -o $(BUILDDIR)/$@ $(OBJECTS) $(LDFLAGS)@echo "********************* Bulid $(TARGET_OBJT) complete   ************************"useage help:@echo "Build Help Info"@echo "    make target=$(target_x86)         -- build $(target_x86) arch target"@echo "    make target=$(target_imx6)        -- build $(target_imx6) arch target"@echo "    make target=$(target_2440)       -- build $(target_2440) arch target"clean:-@rm -rfv $(BUILDDIR)@echo "********************* clean all targets complete  ************************"

可以看出,修改后的makefile,代码明显精简了,可读性也提高了,最关键的是,扩展性大大提升,日后如果我再需要更换或者增加目标平台时,只需要在文件头处加以修改就搞定!

使用起来的话,只需要输入“make target=x86”命令,或者“make target=imx6”命令,或者“make target=2440”命令,系统就会自动编译出对应平台下的可执行目标文件,而无需对makefile文件本身进行其他多余的操作,大大提升了调试和修改的效率。


2019.01.31,补充以下内容

经过实际项目的研究,最终写出了以下makefile,可完美搞定本问题:

# 强制用bash,有的系统/bin/sh默认是用dash的,用dash会导致echo -e显示时多出一个-e
SHELL = /bin/bash# 这里先根据用户输入的编译目标选择好相应的编译器,加入-include $(DEPENDS)的目的是为了能够自动识别出头文件的修改并进行跟随编译
ifeq ($(MAKECMDGOALS),pc)COMPILE    = gcc-include $(DEPENDS)
else ifeq ($(MAKECMDGOALS),imx6)COMPILE = /opt/poky/1.7/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-gcc -march=armv7-a -mthumb-interwork -mfloat-abi=hard -mfpu=neon -mtune=cortex-a7-include $(DEPENDS)
else ifeq ($(MAKECMDGOALS),2440)COMPILE = arm-linux-gcc-include $(DEPENDS)
endif# 这里定义出所编译的目标架构及最终的可执行文件名
TARGET_ARCH      = $(MAKECMDGOALS)
TARGET_OBJT     := test_$(MAKECMDGOALS)# 这里定义出编译的选项及配置
CFLAGS          += $(INCLUDES) -rdynamic -Wall -O2 -Wno-uninitialized
LDFLAGS         += -lpthread# 这里指定编译过程需要包含的头文件路径,以及要编译的源文件(下面的inc目录和src目录分别存放头文件和源文件,可自定义修改和添加)
INCLUDES        += -Iinc/h
SOURCES         += ${wildcard *.c}
SOURCES         += ${wildcard src/*.c}# 这里设置好编译过程中的临时目录名称
BUILDDIR        ?= _build
OBJCTDIR        ?= $(BUILDDIR)/$(TARGET_ARCH)# 这里定义好编译的规则:即根据.c文件编译出同名的.d和.o文件
OBJECTS         := $(patsubst %.c, $(OBJCTDIR)/%.o, $(filter %.c, $(SOURCES)))
DEPENDS         := $(patsubst %.c, $(OBJCTDIR)/%.d, $(filter %.c, $(SOURCES)))# 这里定义出合法的编译对象
.PHONY: pc imx6 2440 useage help cleanpc imx6 2440: mngdir $(TARGET_OBJT)mngdir:@echo "-------------------------------------------------- Begin to bulid $(TARGET_OBJT)"@mkdir -pv $(OBJCTDIR)@mkdir -pv $(BUILDDIR)$(OBJCTDIR)/%.o: %.c@mkdir -pv $(@D)$(COMPILE) $(CFLAGS) -c -o $@ $<$(OBJCTDIR)/%.d: %.c@echo "$@: $<:$(notdir $*)"@mkdir -pv $(@D)@set -e; rm -f $@; \$(COMPILE) -MM $(CFLAGS) $< > $@.$$$$; \sed 's,$(notdir $*)\.o[ :]*,$(OBJCTDIR)/$*\.o $@ : ,g' < $@.$$$$ > $@; \rm -f $@.$$$$$(TARGET_OBJT): $(OBJECTS) $(DEPENDS)$(COMPILE) $(CFLAGS) -o $(BUILDDIR)/$@ $(OBJECTS) $(LDFLAGS)@echo "-------------------------------------------------- Bulid $(TARGET_OBJT) complete!"useage help:@echo "How to build"@echo "    make pc      -- build target for pc"@echo "    make imx6      -- build target for imx6"@echo "    make 2440        -- build target for mini2440"clean:@echo "-------------------------------------------------- Begin to clean bulid files"-@rm -rfv $(BUILDDIR)@echo "-------------------------------------------------- clean all files complete!"

编译时,只需输入“make pc”或者“make imx6”或者“make 2440”即可自动编译出不同平台下的目标文件,输入“make clean”便可一次性清理掉全部的临时文件,输入“make help”或者“make usage”便可查看本makefile的使用帮助,整个过程轻松愉快!

如何使用makefile编译不同平台的目标文件(makefile的参数传递)相关推荐

  1. 浅显易懂 Makefile 入门 (03)— 目标文件搜索(VPATH 和 vpath 的区别和使用)、隐含规则

    1. 目标文件搜索(VPATH和vpath) 如果需要的文件是存在于不同的路径下(即源文件与 Makefile 文件不在同一个路径下),在编译的时候就用到了 Makefile 中为我们提供的目录搜索文 ...

  2. make *** 没有指明目标并且找不到 makefile。 停止。_Makefile目标文件搜索(VPATH和vpath)...

    我们都知道一个工程文件中的源文件有很多,并且存放的位置可能不相同(工程中的文件会被放到不同的目录下),所以按照之前的方式去编写 Makefile 会有问题.我们之前列举的例子,所有的源文件基本上都是存 ...

  3. build文件_把编译时间加入到目标文件

    出处:https://www.cnblogs.com/pingwen/p/8183728.html 1.问题背景:如何保证发布出去的bin文件是最终测试通过的版本? 一般的来讲,代码到了测试后期,ma ...

  4. 把编译时间加入到目标文件

    原文:https://www.cnblogs.com/pingwen/p/8183728.html 1.问题背景:如何保证发布出去的bin文件是最终测试通过的版本? 一般的来讲,代码到了测试后期,ma ...

  5. GCC编译器原理(二)------编译原理一:目标文件

    一.目标文件 在 UNIX® 和 Linux® 中,任何事物都是文件.UNIX 和 Linux 编程实际上是编写处理各种文件的代码.系统由许多类型的文件组成,但目标文件具有一种特殊的设计,提供了灵活和 ...

  6. 安卓SO层开发 -- 编译指定平台的SO文件

    0x01 四种SO文件 1.一个apk中的lib文件夹里面可能有四个子文件夹 2.里面是运行在不同平台的SO文件,SO文件内容不一样,但运行效果是一样 armeabi-v7a 运行在32位的手机上 a ...

  7. c语言编译生成的目标文件拓展名,系统默认的C语言源程序文件的扩展名是(),经过编译后生成的目标文件的扩展名是(),经过连接后生成的可执行文件的扩展名是()。...

    系统序文常用的密钥分发技术有 CA 技术和[] 技术. 默认名名探究精神的重要性体现在以下哪些方面?() 如果采用偶校验,的目的可的扩0101010的校验位是(),0011011的校验位是(). 语言 ...

  8. c语言目标文件作用,关于编译:C语言中的目标文件是什么?

    我正在阅读有关C语言中的库的信息,但尚未找到关于什么是目标文件的解释. 其他任何编译文件和目标文件之间的真正区别是什么? 如果有人能够用人类语言进行解释,我将感到非常高兴. 一个更活跃的版本:stac ...

  9. Linux内核中makefile有什么作用?深入解析makefile工作过程和原理

    Table of Contents Makefile 中的变量 常用的变量有以下几类: 1) 版本信息 2) CPU 体系结构:ARCH 3) 路径信息:TOPDIR, SUBDIRS 4) 内核组成 ...

最新文章

  1. c3p0连接池配置_Maven+JSP+Servlet+C3P0+Mysql实现的音乐库管理系统
  2. 深入理解SpringBoot之装配条件
  3. 031_yml配置文件
  4. 给基于SAP Spartacus 3.4.1 版本的 Storefront 添加对服务器端渲染的支持
  5. JAX-RS 2.x与Spring MVC:返回对象列表的XML表示
  6. 关于java结构中描述正确的是_下列关于Java中类的构造方法的描述,正确的是()...
  7. Oracle 存储过程调用语句
  8. 麦克纳姆轮全向移动机器人速度空间分析
  9. miniMobile(手机)
  10. 零基础必看的Html5+Css3+移动端前端教程(一)
  11. 关于word使用之三线表制作
  12. 招商银行笔试题之解码方法
  13. 提高iOS开发效率的方法和工具
  14. 爬虫--电影天堂案例(二级页面抓取)
  15. InkScape:制作简易LOGO
  16. 搜狗老域名作用之快速大量搜狗收录
  17. 开源Api后台服务/管理系统 HoServer
  18. datanlysis
  19. 正则表达式:检测密码由6-21字母和数字组成
  20. JavaScript限时秒杀

热门文章

  1. AbsListView.LayoutParams
  2. 机器学习入门-Knn算法
  3. wordpress的手动更新
  4. Java线程:创建与启动
  5. [linux] 查看网络丢包信息
  6. PowerDesigner 手记
  7. Mocha BSM产品亮点——以Portal为展现中心的监控管理平台
  8. php qcloud sdk weapp_微信小程序源码+PHP后台
  9. oracle 共享硬盘主从,oracle dataguard主从切换
  10. php 标点符号反转,PHP删除标点符号(无破折号)