1. 程式人生 > >如何使用makefile編譯不同平臺的目標檔案(makefile的引數傳遞)

如何使用makefile編譯不同平臺的目標檔案(makefile的引數傳遞)

最近在研究一個嵌入式開發專案,在編寫實際的專案程式碼時,需要臨時寫一些測試程式碼對部分功能進行預測試。編寫的這些程式碼,有時候需要在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_arm TEMPDIR_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 clean x86: 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 [email protected] $< $(TEMPDIR_x86)/%.d: %.c @echo "[email protected]: $<:$(notdir $*)" @mkdir -pv $(@D) @set -e; rm -f [email protected]; \ $(COMPILE_x86) -MM $(CFLAGS) $< > [email protected].$$$$; \ sed 's,$(notdir $*)\.o[ :]*,$(TEMPDIR_x86)/$*\.o [email protected] : ,g' < [email protected].$$$$ > [email protected]; \ rm -f [email protected].$$$$ $(TARGET_x86): $(OBJECTS_x86) $(DEPENDS_x86) $(COMPILE_x86) $(CFLAGS) -o $(BUILDDIR_x86)/[email protected] $(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 [email protected] $< $(TEMPDIR_arm)/%.d: %.c @echo "[email protected]: $<:$(notdir $*)" @mkdir -pv $(@D) @set -e; rm -f [email protected]; \ $(COMPILE_arm) -MM $(CFLAGS) $< > [email protected].$$$$; \ sed 's,$(notdir $*)\.o[ :]*,$(TEMPDIR)/$*\.o [email protected] : ,g' < [email protected].$$$$ > [email protected]; \ rm -f [email protected].$$$$ $(TARGET_arm): $(OBJECTS_arm) $(DEPENDS) $(COMPILE_arm) $(CFLAGS) -o $(BUILDDIR_arm)/[email protected] $(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 clean

all: mngdir $(TARGET_OBJT)

mngdir:
    @mkdir -pv $(OBJCTDIR)
    @mkdir -pv $(BUILDDIR)

$(OBJCTDIR)/%.o: %.c
    @mkdir -pv $(@D)
    $(COMPILE) $(CFLAGS) -c -o [email protected] $<

$(OBJCTDIR)/%.d: %.c
    @echo "[email protected]: $<:$(notdir $*)"
    @mkdir -pv $(@D)
    @set -e; rm -f [email protected]; \
    $(COMPILE) -MM $(CFLAGS) $< > [email protected].$$$$; \
    sed 's,$(notdir $*)\.o[ :]*,$(TEMPDIR_x86)/$*\.o [email protected] : ,g' < [email protected].$$$$ > [email protected]; \
    rm -f [email protected].$$$$

$(TARGET_OBJT): $(OBJECTS) $(DEPENDS)
    $(COMPILE) $(CFLAGS) -o $(BUILDDIR)/[email protected] $(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檔案本身進行其他多餘的操作,大大提升了除錯和修改的效率。

相關推薦

如何使用makefile編譯不同平臺目標檔案makefile引數傳遞

最近在研究一個嵌入式開發專案,在編寫實際的專案程式碼時,需要臨時寫一些測試程式碼對部分功能進行預測試。編寫的這些程式碼,有時候需要在PC機(x86)的平臺上執行,有時候則需要在A嵌入式平臺(arm端)i.mx6的平臺上執行,而還有時候則需要在B嵌入式平臺(arm

android studio ndk-build 編譯C生成.so檔案ndk基礎篇

一、概要 最近專案需要,要把程式碼中加密的部分打包成so檔案,剛開始接觸的時候真是痛苦呀,網上好多資料,都不是很詳細,步驟也不清晰,所以我整理了一下,希望大家喜歡。 現在android studio打包so檔案有兩種方式,第一種是ndk-build編譯專案,還有一種用

使用java程式碼呼叫exe程式 包括引數傳遞

使用Java程式碼呼叫exe 1使用場景       我現在使用eclipse+tomcat的架構建立了web server, 在這個web project中我需要建立一個定時任務,在定時任務中執行本地的一個C#工程生成的exe。 2Java程式碼 public clas

makefile編譯生成.a檔案linux靜態庫,並編譯進可執行檔案

檔案列表: 程式碼檔案 /* 下列程式碼儲存到 plus.cpp */ int my_plus(int x,int y) { return x + y; }

Makefile中使用 for 控制結構編譯多個目標檔案

假如,有很多檔案,每個檔案都要變成一個單獨的目標檔案,如果使用makefile的話,最好能用一個 for 迴圈來做。 makefile是支援使用 for的。 先假定有下面幾個檔案: a.h b.h test1.cpp test2.cpp $ cat a.h #if

Makefile生成多個目標檔案

有目錄結構如下:  mmap ├── Makefile ├── read │   ├── Makefile │   └── mmap_read.c └── write     ├── Makefile     └── mmap_write.c mmap 目錄下面有 wri

Linux下如何編譯有多個檔案包括不同目錄下的.c/.h檔案的C/C++程式

在Linux下要編譯一個C/C++程式,首先要知道包含目錄的作用,對C/C++有了解的就會知道,#include是包含標頭檔案所用的,也就說說部分類、函式、或者變數宣告就在其中。而#include巨集定義又有兩種: #include""和#include <>

makefile編譯多個目標

即然make可以指定所有makefile中的目標,那麼也包括“偽目標”,於是我們可以根據這種性質來讓我們的makefile根據指定的不同的目標來完成不同的事。在Unix世界中,軟體釋出時,特別是GNU這種開源軟體的釋出時,其makefile都包含了編譯、安裝、打包等功能。我們可以參照這種規則來書寫我們的mak

Servlet | 訪問不同格式檔案PDF、doc

   核心程式碼 //設定響應內容型別為PDF型別 response.setContentType("application/pdf"); request.getRequestDispatcher("/WEB-INF/搜尋框架.pdf").

[PYTHON]_ELVE_Python原始碼檔案編譯成可執行檔案支援macOS High Sierra和window 10

#0x01 背景 這兩天寫了一個抽獎的Python指令碼,要生成可執行檔案,總不能一直在sublime上執行吧,或者執行前先安裝Python,所以就查了一下怎麼生成可執行檔案,本篇包括mac下和win下,經本人測試,mac下生成.app(mac下的可執行檔案為.app字尾)較win下容易一些。 我用的Py

Androidy打jar包後找不到目標檔案找不到bundles目錄和jar包解決

1、說明 以前我們打包會在LibModule下的build.gradle中新增以下命令: task clearJar(type: Delete) { delete 'build/outputs/' } task makeJar(type: Copy) {

logback日誌輸出不同級別到不同檔案開發例項配置

<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- 控制檯 appender --> <appender name="STDOUT" class="

golang 跨平臺編譯——go 在windows上編譯Linux平臺的程式Cross Compilation from Windows to Linux/Ubuntu

Go Cross Compilation from Windows to Linux/Ubuntu  I have GO 1.7 installed on my Windows 10. I created test program and it works perfectly

.NET MVC同頁面顯示從不同數據庫mssql、mysql的數據

dex datatable 引用 填充 scrip 電話 action eat str    控制器:     private readonly VipViewModel _model = new VipViewModel(); public stati

不同的繼承方式三十八

C++ protected 繼承 private 繼承 三種繼承方式 我們之前在學習繼承的時候,冒號(:)表示繼承關系,Parent 表示被繼承的類,而 public 的意義又是什麽呢?我們知道,C++ 中的跟 public 對應的關鍵字還有 protected 和 priva

源碼編譯方式安裝mysql服務 Centos 6.X

app pri root conf make 系統用戶 script ext mysq root 用戶執行 $ yum install -y autoconf automake imake libxml2-devel expat-devel cmake gcc gc

Servlet | 訪問不同格式文件PDF、doc

ssr post 格式 tdi study ted sdn 類型 bsp 核心代碼 //設置響應內容類型為PDF類型 response.setContentType("application/pdf"); request.ge

實現從oss阿里雲伺服器以附件形式下載檔案含批量下載

轉載自:https://blog.csdn.net/sinat_28771747/article/details/53520253 筆者在專案中寫一個從阿里雲伺服器上面以附件形式下載檔案的介面時,遇到了問題,網上搜索無任何相關的解決方案,最後通過通過自己查閱API文件,再結合自己的經驗,實現了下

P檔案混合星曆中各衛星更新時間和衛星總數統計

PS:粗略估計,沒有精確考慮備份星和異常衛星等特殊情況。 以前整理的內容,個別地方現在未必有時效性。 BDS:27MEO+5GEO+3IGSO,35顆衛星,每1小時更新一次。 GPS:32MEO,每2小時更新一次。 GLONASS:目前26顆在軌,每半小時更新一次

Ajax 上傳檔案input file FormData

FormData物件用以將資料編譯成鍵值對,以便用XMLHttpRequest來發送資料。其主要用於傳送表單資料,但亦可用於傳送帶鍵資料(keyed data),而獨立於表單使用。 jQuery Ajax 上傳檔案 通過 Ajax 向後臺傳送檔案(包括圖片)時,其引數型別屬於物件。可以建立一個 FormD