如何使用makefile编译不同平台的目标文件(makefile的参数传递)
最近在研究一個(gè)嵌入式開發(fā)項(xiàng)目,在編寫實(shí)際的項(xiàng)目代碼時(shí),需要臨時(shí)寫一些測(cè)試代碼對(duì)部分功能進(jìn)行預(yù)測(cè)試。編寫的這些代碼,有時(shí)候需要在PC機(jī)(x86)的平臺(tái)上運(yùn)行,有時(shí)候則需要在A嵌入式平臺(tái)(arm端)i.mx6的平臺(tái)上運(yùn)行,而還有時(shí)候則需要在B嵌入式平臺(tái)(arm端)mini2440的平臺(tái)上運(yùn)行,需要能隨時(shí)進(jìn)行切換,編譯出對(duì)應(yīng)平臺(tái)所需要的可執(zhí)行文件。
為了解決這個(gè)問題,最土的辦法自然就是寫三份makefile,需要編譯某一個(gè)平臺(tái)時(shí),拷貝對(duì)應(yīng)的makefile,然后再make。可是這樣效率很低,而且很low,自然不予考慮。稍微好一點(diǎn)的辦法,則是在makefile中,定義三套編譯規(guī)則,通過輸入make x86,以及make imx6,以及make mini2440這樣的目標(biāo)選擇命令,來指示編譯器選擇某一套編譯規(guī)則并運(yùn)行。但是,這樣的方法,會(huì)導(dǎo)致makefile的文件很冗余,存在多套幾乎一模一樣的編譯規(guī)則。如下所示:
# 強(qiáng)制用bash,有的系統(tǒng)/bin/sh默認(rèn)是用dash的,用dash會(huì)導(dǎo)致echo -e顯示時(shí)多出一個(gè)-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 ************************"為了簡(jiǎn)單起見,上述makefile中,只列舉了其中兩套編譯規(guī)則,第三套并沒有寫上。盡管如此,仍然可以看出整個(gè)文件很冗長,雖然整個(gè)make的過程很簡(jiǎn)單,但是makefile的可讀性卻不怎么高,代碼看上去不舒服。而且,最大的問題是,可擴(kuò)展性很差,當(dāng)我要再增加第三個(gè)平臺(tái)甚至第四個(gè)平臺(tái)時(shí),代碼量是呈倍數(shù)增長的,顯然不適合。
那么,有沒有更好的辦法呢?答案顯然是有的。
通過一番搜索,我找到了以下的思路:
在makefile中可以預(yù)先使用一個(gè)未定義的變量, 這個(gè)變量可以在make執(zhí)行時(shí)傳遞給它。換句話說,就是可以向make命令傳遞參數(shù),告訴它怎么去解釋makefile這個(gè)文件。
網(wǎng)上關(guān)于這個(gè)思路最多的例子,就是如何使用同一份代碼、同一份makefile,卻通過給make命令傳入不同的參數(shù)來編譯出debug版本和release版本,直接去百度一抓一大把【可參見其他博主的博文:如何給Make命令來傳遞參數(shù),如何給Makefile 傳入?yún)?shù),make傳遞給Makefile參數(shù),等等】,這里就不再贅述。
于是,根據(jù)這個(gè)思路,我對(duì)上述的makefile文件進(jìn)行了精簡(jiǎn)和修改,最終的效果如下所示:
# 強(qiáng)制用bash,有的系統(tǒng)/bin/sh默認(rèn)是用dash的,用dash會(huì)導(dǎo)致echo -e顯示時(shí)多出一個(gè)-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,代碼明顯精簡(jiǎn)了,可讀性也提高了,最關(guān)鍵的是,擴(kuò)展性大大提升,日后如果我再需要更換或者增加目標(biāo)平臺(tái)時(shí),只需要在文件頭處加以修改就搞定!
使用起來的話,只需要輸入“make target=x86”命令,或者“make target=imx6”命令,或者“make target=2440”命令,系統(tǒng)就會(huì)自動(dòng)編譯出對(duì)應(yīng)平臺(tái)下的可執(zhí)行目標(biāo)文件,而無需對(duì)makefile文件本身進(jìn)行其他多余的操作,大大提升了調(diào)試和修改的效率。
2019.01.31,補(bǔ)充以下內(nèi)容:
經(jīng)過實(shí)際項(xiàng)目的研究,最終寫出了以下makefile,可完美搞定本問題:
# 強(qiáng)制用bash,有的系統(tǒng)/bin/sh默認(rèn)是用dash的,用dash會(huì)導(dǎo)致echo -e顯示時(shí)多出一個(gè)-e SHELL = /bin/bash# 這里先根據(jù)用戶輸入的編譯目標(biāo)選擇好相應(yīng)的編譯器,加入-include $(DEPENDS)的目的是為了能夠自動(dòng)識(shí)別出頭文件的修改并進(jìn)行跟隨編譯 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# 這里定義出所編譯的目標(biāo)架構(gòu)及最終的可執(zhí)行文件名 TARGET_ARCH = $(MAKECMDGOALS) TARGET_OBJT := test_$(MAKECMDGOALS)# 這里定義出編譯的選項(xiàng)及配置 CFLAGS += $(INCLUDES) -rdynamic -Wall -O2 -Wno-uninitialized LDFLAGS += -lpthread# 這里指定編譯過程需要包含的頭文件路徑,以及要編譯的源文件(下面的inc目錄和src目錄分別存放頭文件和源文件,可自定義修改和添加) INCLUDES += -Iinc/h SOURCES += ${wildcard *.c} SOURCES += ${wildcard src/*.c}# 這里設(shè)置好編譯過程中的臨時(shí)目錄名稱 BUILDDIR ?= _build OBJCTDIR ?= $(BUILDDIR)/$(TARGET_ARCH)# 這里定義好編譯的規(guī)則:即根據(jù).c文件編譯出同名的.d和.o文件 OBJECTS := $(patsubst %.c, $(OBJCTDIR)/%.o, $(filter %.c, $(SOURCES))) DEPENDS := $(patsubst %.c, $(OBJCTDIR)/%.d, $(filter %.c, $(SOURCES)))# 這里定義出合法的編譯對(duì)象 .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!"編譯時(shí),只需輸入“make pc”或者“make imx6”或者“make 2440”即可自動(dòng)編譯出不同平臺(tái)下的目標(biāo)文件,輸入“make clean”便可一次性清理掉全部的臨時(shí)文件,輸入“make help”或者“make usage”便可查看本makefile的使用幫助,整個(gè)過程輕松愉快!
總結(jié)
以上是生活随笔為你收集整理的如何使用makefile编译不同平台的目标文件(makefile的参数传递)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是UE4_unity3d和ue4区别
- 下一篇: 盖茨炮轰马斯克殖民火星雄心:这是在浪费钱