終於將C++代碼porting到了bootloader中,唯一的收穫就是熟悉了Makefile,有工廠的公司傷不起啊,每次都得先做一些東西滿足工廠端測試的需求,為了能夠做到工廠在boot中測試的要求,經過與晶片公司討論,只有將C++弄到了boot中,真是一個很二的決定boot最終做到了2M比有些kernel還要大。不過老闆要這麼做就硬著頭皮做了現在做成了心中還蠻高興的,原來被逼之後人的潛能還是蠻大的。
對於Makefile中所用的函數還在研究中,之後會寫一寫主要函數的用法。
因為從事著android驅動開發所以天天要接觸Android.mk。
1、在運行 . build/envsetup.sh 會產生一些操作例如:chooseproduct mmm
2、運行 chooseproduct project 選擇所要編譯的工程
3、運行make,回去編譯整個android source
怎麼說到了編譯Android Source的方法呢
切入主題 先寫一個簡單的Android.mk
[python]
view plaincopyprint?
- LOCAL_PATH := $(call my-dir) #指定目前的目錄
-
- include $(CLEAR_VARS)
#引入編譯變數
-
- LOCAL_MODULE_TAGS := optional
#編譯選項便是在何種情況下編譯
-
- LOCAL_SRC_FILES := hello.c
#源檔案(可以指定多個)
-
- LOCAL_MODULE := hello
#編譯出來的模組名
-
- LOCAL_MODULE_CLASS := EXECUTABLES
#指定編譯之後放置的位置(此處指示放在system/bin下)
-
- include $(BUILD_EXECUTABLE)
#引入編譯成可執行檔的規則
LOCAL_PATH := $(call my-dir) #指定目前的目錄 include $(CLEAR_VARS) #引入編譯變數LOCAL_MODULE_TAGS := optional #編譯選項便是在何種情況下編譯LOCAL_SRC_FILES := hello.c #源檔案(可以指定多個) LOCAL_MODULE := hello #編譯出來的模組名LOCAL_MODULE_CLASS := EXECUTABLES #指定編譯之後放置的位置(此處指示放在system/bin下)include $(BUILD_EXECUTABLE) #引入編譯成可執行檔的規則
以上的Android.mk 會編譯出一個hello的可執行檔,並放入system/bin
LOCAL_PATH : 指定目錄,以上是一般用法指示目前的目錄(my-dir函數是Android編譯時間. build/envsetup.sh命令產生的 能夠擷取目前的目錄的路徑)
CLEAR_VARS: android有自己的一套代碼編譯規則跟編譯選項等變數的定義,此變數會引入,實際是android/build/core下的clear_vas.mk,
clear_vas.mk
[plain]
view plaincopyprint?
- ##########################################################
- ## Clear out values of all variables used by rule templates.
- ###########################################################
-
- LOCAL_MODULE:=
- LOCAL_MODULE_PATH:=
- LOCAL_MODULE_STEM:=
- LOCAL_DONT_CHECK_MODULE:=
- LOCAL_CHECKED_MODULE:=
- .
- .
- .
- LOCAL_CERTIFICATE:=
- LOCAL_SDK_VERSION:=
- LOCAL_NDK_VERSION:=
- LOCAL_NO_EMMA_INSTRUMENT:=
- LOCAL_NO_EMMA_COMPILE:=
- LOCAL_PROGUARD_ENABLED:= # '',optonly,full,custom
- LOCAL_PROGUARD_FLAGS:=
- LOCAL_PROGUARD_FLAG_FILES:=
- LOCAL_EMMA_COVERAGE_FILTER:=
- LOCAL_MANIFEST_FILE:=
- LOCAL_BUILD_HOST_DEX:=
- LOCAL_DEX_PREOPT:=
- LOCAL_DEX_PREOPT:=
-
- # Trim MAKEFILE_LIST so that $(call my-dir) doesn't need to
- # iterate over thousands of entries every time.
- # Leave the current makefile to make sure we don't break anything
- # that expects to be able to find the name of the current makefile.
- MAKEFILE_LIST := $(lastword $(MAKEFILE_LIST))
############################################################ Clear out values of all variables used by rule templates.###########################################################LOCAL_MODULE:= LOCAL_MODULE_PATH:=LOCAL_MODULE_STEM:=LOCAL_DONT_CHECK_MODULE:=LOCAL_CHECKED_MODULE:= ...LOCAL_CERTIFICATE:=LOCAL_SDK_VERSION:=LOCAL_NDK_VERSION:=LOCAL_NO_EMMA_INSTRUMENT:=LOCAL_NO_EMMA_COMPILE:=LOCAL_PROGUARD_ENABLED:= # '',optonly,full,customLOCAL_PROGUARD_FLAGS:=LOCAL_PROGUARD_FLAG_FILES:=LOCAL_EMMA_COVERAGE_FILTER:=LOCAL_MANIFEST_FILE:=LOCAL_BUILD_HOST_DEX:=LOCAL_DEX_PREOPT:=LOCAL_DEX_PREOPT:=# Trim MAKEFILE_LIST so that $(call my-dir) doesn't need to# iterate over thousands of entries every time.# Leave the current makefile to make sure we don't break anything# that expects to be able to find the name of the current makefile.MAKEFILE_LIST := $(lastword $(MAKEFILE_LIST))
在編譯C/C++代碼時候常用的變數定義
LOCAL_MODULE 指示當前編譯出來的模組名
LOCAL_MODULE_TAGS 標識在什麼情況下去編譯起模組
有幾個選項
user |
模組只在user下編譯 |
eng |
模組在eng模式下編譯 |
tests |
test狀態下編譯 |
optional |
此模組在所有版本下都編譯 |
即 TARGET_BUILD_VARIANT=eng 編譯TAGS為eng和optional的模組
LOCAL_SRC_FILES 表示編譯出此模組需要的來源程式 可以有多個
LOCAL_C_INCLUDE 如果不去調用標準庫標頭檔,跟目前的目錄的標頭檔,則需要在此指定標頭檔的位置,在此指定標頭檔的目錄。
LOCAL_STATIC_LIBRARIES: 指定需要串連的靜態庫像一些比較通用的標準庫就無需指定了
LOCAL_SHARED_LIBRARIES: 指定需要串連的動態庫
最後include $(BUILD_XXX) 表示編譯出來的模組類型,有三種
BUILD_EXECUTABLE |
編譯成可執行檔模組 |
build/core/host_executable.mk |
BUILD_STATIC_LIBRARY |
編譯成靜態庫 |
build/core/host_static_library.mk |
BUILD_SHARED_LIBRARY |
編譯成動態庫 |
build/core/host_shared_library.mk |
LOCAL_MODULE_CLASS 標識了所編譯模組最後放置的位置,如果不指定,不會放到系統中,之後放在最後的obj目錄下的對應目錄中。
LOCAL_MODULE_CLASS := ETC #表示放於system/etc目錄
LOCAL_MODULE_CLASS := EXECUTABLES #放於/system/bin
LOCAL_MODULE_CLASS := SHARED_LIBRARIES #放在/system/lib下
build/core下有很多編譯的全域的mk,如編譯C/C++規則definitions.mk ......
再說一下編譯核心模組的Makefile
[plain]
view plaincopyprint?
- ifneq ($(KERNELRELEASE),) #查看是都已定義kernel版本
-
- obj-m := gps_onoff.o #如果已定義則編譯出得模組名是gps_onoff.o
- #(在linux2.6編譯模組後會產生module_name.ko module_name.o
- #使用insmod module_name.ko來裝載模組moudule_name.o已經棄用
- #即moudule_name.ko 是最終產物)
-
- else #第一次運行時候會走此分支
-
- PWD := $(shell pwd) #指定源檔案目錄
-
- KDIR ?= /home/zk/POP_TD/marvell-pxa920-kernel #指定到已經編譯的核心的目錄
- #如果編譯PC機上的模組則指定到當前啟動並執行核心
- #(uname -r 查看當前的核心版本)
- #(此時核心版本也被定義KERNELRELEASE非空)
-
- #核心編譯命令 此處可以指定硬體體系與交叉編譯工具
- all:
- $(MAKE) -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-eabi-
-
- #重新編譯核心前需要先make clean 清空編譯產生的檔案 否則編譯會出錯
- clean:
- rm -rf .* *.ko *.o *.cmd *.tmp_version *.mod.c *.order Module.*endif
ifneq ($(KERNELRELEASE),) #查看是都已定義kernel版本obj-m := gps_onoff.o #如果已定義則編譯出得模組名是gps_onoff.o #(在linux2.6編譯模組後會產生module_name.ko module_name.o #使用insmod module_name.ko來裝載模組moudule_name.o已經棄用 #即moudule_name.ko 是最終產物)else #第一次運行時候會走此分支PWD := $(shell pwd) #指定源檔案目錄 KDIR ?= /home/zk/POP_TD/marvell-pxa920-kernel #指定到已經編譯的核心的目錄 #如果編譯PC機上的模組則指定到當前啟動並執行核心 #(uname -r 查看當前的核心版本) #(此時核心版本也被定義KERNELRELEASE非空) #核心編譯命令 此處可以指定硬體體系與交叉編譯工具all: $(MAKE) -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-eabi- #重新編譯核心前需要先make clean 清空編譯產生的檔案 否則編譯會出錯clean: rm -rf .* *.ko *.o *.cmd *.tmp_version *.mod.c *.order Module.*endif
編譯模組的Mkefile會被讀取兩次,Makefile從命令列調用時候KERNELRELEASE尚未設定,
在運行到KDIR時即會指向一個核心構造樹,
在運行$(MAKE)時 會會第二次運行make命令,此時設定obj-m 構造真正的核心模組