uClinux 上的應用程序設計

admin @ 2014-03-25 , reply:0

     uClinux以其優異的性能、免費開放的代碼等優點,博得眾多嵌入式開發者的青睞。和過去基於簡單RTOS甚至沒有使用任何操作系統的嵌入式程序設計相比,基於Linux這樣的成熟的、高效的、健壯的、可靠的、模塊化的、易於配置的操作系統來開發自己的應用程序,無疑能進一步提高效率,並具有很好的可移植性。

      在前面的章節中,我們已介紹了硬體平台、內核編譯、開發環境等內容。如果僅僅有Hardware和OS,這個系統所能做的事情還非常有限。對於一個實際的嵌入式產品而言,所提供的功能和應用是關係到產品成敗的重要因素。

     我們知道,在主流的Linux平台上,已經有了非常豐富的、開源的應用程序,使得開發者很容易獲得前人的成果作為參考,編寫更適合自己的程序。然而,對於很多已經在標準Linux環境中工作得很好的程序,並不能直接在uCLinux環境上運行。一方面,是由於嵌入式的uCLinux所使用的處理器和普通PC不同,指令集、CPU結構上的差異導致uClinux上運行的程序需要專門為該類型處理器交叉編譯產生;另一方面,uCLinux是為了沒有內存管理單元(MMU)的處理器、控制器設計,並做了較大幅度的精簡,所以,在標準Linux上可以使用的一些函數和系統調用在uCLinux上有可能就行不通了。

     因此,我們有必要了解,在uCLinux上的應用程序設計和標準Linux程序設計存在哪些不同之處?應該如何修改,才能讓標準Linux程序可以移植到uCLinux上並正常工作呢?如何才能高效地開發uclinux上的應用程序呢?本文旨在對這些問題進行初步的探討。

1 uClinux和Linux的異同
    uClinux是針對控制領域的嵌入式linux操作系統,它從Linux 2.0/2.4內核派生而來,沿襲了主流Linux的絕大部分特性。適合不具備內存管理單元(MMU)的微處理器/微控制器。沒有MMU支持是uClinux與主流Linux的基本差異。
    標準Linux是針對有MMU的處理器設計的。在這種處理器上,虛擬地址被送到MMU,把虛擬地址映射為物理地址。通過賦予每個任務不同的虛擬-物理地址轉換映射,支持不同任務之間的保護。
對uCLinux 來說,其設計針對沒有MMU的處理器,不能使用處理器的虛擬內存管理技術。uCLinux仍然採用存儲器的分頁管理,系統在啟動時把實際存儲器進行分頁。在載入應用程序時程序分頁載入。但是由於沒有MMU管理,所以實際上uCLinux採用實存儲器管理策略。uCLinux系統對於內存的訪問是直接的,所有程序中訪問的地址都是實際的物理地址。操作系統對內存空間沒有保護,各個進程實際上共享一個運行空間。一個進程在執行前,系統必須為進程分配足夠的連續地址空間,然後全部載入主存儲器的連續空間中。
    同時,uClinux有著特別小的內核和用戶軟體空間。熟悉主流Linux的開發者會注意到在uClinux下工作的微小差異,但同樣也可以很快熟悉uclinux的一些特性。對於設計內核或系統空間的應用程序的開發者,要特別注意 uClinux既沒有內存保護,也沒有虛擬內存模型,另外,有些內核系統調用也有差異。

1.1 內存保護
    沒有內存保護(Memory Protection)的操作會導致這樣的結果:即使由無特權的進程來調用一個無效指針,也會觸發一個地址錯誤,並潛在地引起程序崩潰,甚至導致系統的掛起。顯然,在這樣的系統上運行的代碼必須仔細編程,並深入測試來確保健壯性和安全。
對於普通的Linux來說,需要運行不同的用戶程序,如果沒有內存保護將大大降低系統的安全性和可靠性;然而對於嵌入式uClinux系統而言,由於所運行的程序往往是在出廠前已經固化的,不存在危害系統安全的程序侵入的隱患,因此只要應用程序經過較完整的測試,出現問題的概率就可以控制在有限的範圍內。

1.2 虛擬內存
    沒有虛擬內存(Virtual Memory)主要導致下面幾個後果:
     首先,由內核所載入的進程必須能夠獨立運行,與它們在內存中的位置無關。實現這一目標的第一種辦法是一旦程序被載入到RAM中,那麼程序的基準地址就“固定”下來;另一種辦法是產生只使用相對定址的代碼(稱為“位置無關代碼”,Position Independent Code,簡稱PIC)。uClinux對這兩種模式都支持。
   其次,要解決在扁平(flat)的內存模型中的內存分配和釋放問題。非常動態的內存分配會造成內存碎片,並可能耗盡系統的資源。對於使用了動態內存分配的那些應用程序來說,增強健壯性的一種辦法是用預分配緩衝區池(Preallocated buffer pool)的辦法來取代malloc()調用。由於uclinux中不使用虛擬內存,進出內存的頁面交換也沒有實現,因為不能保證頁面會被載入到RAM中的同樣位置。在普通計算機上,操作系統允許應用程序使用比物理內存(RAM)更大的內存空間,這往往是通過在硬碟上設立交換分區來實現的。但是,在嵌入式系統中,通常都用FLASH存儲器來代替硬碟,很難高效地實現內存頁面交換的存取,因此,對運行的應用程序都限制其可分配空間不大於系統的RAM空間。
     最後,uClinux目標板處理器缺乏內存管理的硬體單元,使得Linux的系統介面需要作些改變。有可能最大的不同就是沒有fork()和brk()系統調用。調用fork()將複製出進程來創建一個子進程。在Linux下,fork()是使用copy-on-write頁面來實現的。由於沒有MMU, uclinux不能完整、可靠地複製一個進程,也沒有對copy-on-write的存取。為了彌補這一缺陷,uClinux實現了vfork(),當父進程調用vfork()來創建子進程時,兩個進程共享它們的全部內存空間,包括堆棧。子進程要麼代替父進程執行(此時父進程已經sleep)直到子進程調用exitI()退出,要麼調用exec()執行一個新的進程,這個時候將產生可執行文件的載入。即使這個進程只是父進程的拷貝,這個過程也不能避免。當子進程執行exit()或exec()后,子進程使用wakeup把父進程喚醒,父進程繼續往下執行。
    注意,多任務並沒有受影響。哪些舊式的、廣泛使用fork()的網路後台程序(daemon)的確是需要修改的。由於子進程運行在和父進程同樣的地址空間內,在一些情況下,也需要修改兩個進程的行為。
很多現代的程序依賴子進程來執行基本任務,使得即時在進程負載很重時,系統仍可以保持一種“可交互”的狀態,這些程序可能需要實質上的修改來在uClinux下完成同樣的任務。如果一個關鍵的應用程序非常依賴這樣的結構,那就不得不對它重新編寫了。
     假設有一個簡單的網路後台程序(daemon),大量使用了fork()。這個daemon總監?一個知名埠(或套接字)等待網路客戶端來連接。當客戶端連接時,這個daemon給它一個新的連接信息(新的socket編號),並調用fork()。子進程接下來就會和客戶端在新的socket上進行連接,而父進程被釋放,可以繼續監?新的連接。
uClinux 既沒有自動生長的堆棧,也沒有brk()函數,這樣,用戶空間的程序必須使用mmap() 命令來分配內存。為了方便,在uclinux的C語言庫中所實現的malloc()實質上就是一個mmap()。在編譯時,可以指定程序的堆棧大小。

1.3 通用架構的內核變化
    在uClinux的發布中,/linux/mmnommu目錄取代了/linux/mm目錄。前者就是修改後的內存管理子系統被修改,去除了MMU硬體的依賴,並在內核軟體自身提供基本的內存管理函數。
很多子系統需要被重新修改、添加或者重寫。內核和用戶內存分配和釋放進程必須重新實現。對透明交互/頁面調度的支持也被去除。
    內核中,加入了支持“位置無關代碼(PIC)”的程序載入模塊,並使用了新的二進位目標碼格式,稱為“扁平”格式(flat),用來支持PIC(有非常緊湊的頭部)。內核也提供了支持ELF格式的程序載入模塊,用來支持使用固定基準地址的可執行程序。兩種模式各有利弊,傳統的PIC運行快,代碼緊湊,但是有代碼大小限制。例如Motorola 68K架構的16位相對跳轉限制了PIC程序不能超過32kbyte大小。而採用運行期固定基址的方法使得沒有了代碼大小限制,不過當程序被內核載入后招致了較多的系統開銷。

1.4 uCLinux的內核載入方式
    uCLinux的內核有兩種可選的運行方式:可以在flash上直接運行,也可以載入到RAM中運行。
    Flash運行方式:把內核的可執行映像文件燒到flash上,系統啟動時從flash的某個地址開始逐句執行。這種方法實際上是很多嵌入式系統採用的方法。
    內核載入RAM方式:把內核的壓縮文件存放在flash上,系統啟動時讀取壓縮文件在內存里解壓,然後開始執行,這種方式相對複雜一些,但是運行速度可能更快。同時這也是標準Linux系統採用的啟動方式。

1.5 uCLinux的文件系統
    uCLinux系統採用ROMFS文件系統,這種文件系統相對於一般的ext2文件系統要求更少的空間。空間的節約來自於兩個方面:首先內核支持ROMFS文件系統比支持ext2文件系統需要更少的代碼;其次 ROMFS文件系統相對簡單,在建立文件系統超級塊(superblock)需要更少的存儲空間。ROMFS文件系統不支持動態擦寫保存,對於系統需要動態保存的數據採用虛擬RAM盤的方法進行處理(RAM盤將採用ext2文件系統)。
應用程序如果需要以文件方式交換數據,可以將它存儲在/tmp目錄下。這一目錄實質上就是虛擬的RAM盤。不過在掉電時,這些數據就會丟失。
   如果希望在掉電時,信息仍然可以保持,那麼就要把它寫到FLASH中。這時,就可以使用JFFS這一文件系統,在uClinux的發布中,文件“/linux/drivers/block/flash.c”中提供的JFFS代碼可以參考。
另外,還需要修改/linux/.config和include/linux/autoconf.h中的有關內容,增加對FLASH和JFFS的編譯。

2 uClinux程序設計要點

2.1 軟體開發工具
    可以免費獲得的GCC(GNU C Compiler)無疑是uClinux上最佳的開發工具。
uClinux系統的軟體開發需要在標準Linux平台上用交叉編譯工具來完成。除了前面所提到的一些涉及內存和系統調用的程序之外,在x86版本的gcc編譯器下編譯通過的軟體通常不需要做大的改動就可以用交叉編譯工具編譯到uClinux上運行。
    交叉編譯器可以從下面網址獲得:
    http:/www.uclinux.org/pub/uClinux/m68k-elf-tools/
    目前最新的版本是2.95.3:m68k-elf-tools-20020410.tar.gz
交叉編譯器直接解在根目錄(/)下就行了:(注意當前目錄是/,而且m68k-elf-tools-20020218.tar.gz要在/下)
    tar xzf m68k-elf-tools-20020218.tar.gz
它會自動在/usr/local/下建立起整套m68k的ELF交叉編譯器,要編譯自己的簡單C程序就可以用/usr/local/bin/m68k-elf-gcc,例如,源代碼為test.c,那麼可以這樣編譯:
/usr/local/bin/m68k-elf-gcc –Wall -elf2flt -m5307 test.c –lc –o test.out
參數“-Wall”指定產生全部的警告;-elf2flt指定自動調用elf轉換flat格式的工具;-m5307指定了處理器的指令集;-lc指定了鏈接信息(ld);-o指定輸出文件的名字。
編譯成功后得到的test.out就可以在uClinux環境上運行(通過nfsmount、smbmount,或者直接放到內核映像中都可以)。
    也可以建立一個簡單的Makefile來做這件事情:
    CC = /usr/local/bin/m68k-elf-gcc
    all:
    $(CC) -Wall -elf2flt -m5307 test.c -lc -o test.out

    通過GDB可以調試目標板,Coldfire處理器可以通過Motorola的BDM作為調試介面,可以在不干擾程序正常運行的情況下調試目標板上的內核。如果處理器不支持,那麼在內核中需要插樁(stub),GDB和stub通過串列口或者乙太網通訊。

2.2 可執行文件格式
    先解釋幾種可執行文件格式。
     coff(common object file format):一種通用的對象文件格式;
     elf(excutive linked file):一種為Linux系統所採用的通用文件格式,支持動態連接和重定位;
     flat:扁平格式。elf格式有很大的文件頭,flat格式對文件頭和一些段信息做了簡化,可執行程序小。
     uCLinux系統目前支持flat和elf兩種可執行文件格式。

2.3 uCLinux的應用程序庫
    uCLinux小型化的另一個做法是重寫了應用程序庫,相對於越來越大且越來越全的glibc庫,uClibc對libc做了精簡。
    最新版本的程序庫可以從這個網址獲得:
    http:/uclibc.org/download/uClibc-0.9.10.tar.gz
    uCLinux對用戶程序採用靜態鏈接的形式,這種做法會使應用程序變大,但是基於內存管理的問題,也就是基於沒有MMU的特性,只能這樣做,同時這種做法也更接近於通常嵌入式系統的做法。
    uClibc提供大多數的類UNIX的C程序調用。如果應用程序需要用到uClibc中沒有提供的函數,這些函數可以加到uClibc中、或者作為一個獨立的庫、或者加到應用程序上面來進行鏈接。

2.4 裁減uCLinux以適合自己的應用
    不同的嵌入式系統之間的根文件系統內容差異很大。uClinux的發布包括一個根文件系統,實現了一個小型的類UNIX伺服器,在串口上有控制台,telnet daemon,web server,NFS客戶端支持和一些可選的常用工具。
但是,有的系統設計可能不需要控制台,例如,如果設計一個可以播放MP3的隨身CD機,內核只需要支持CD驅動、并行I/O和音頻DAC。而在用戶空間可能只包括一個介面程序來驅動按鈕、LED、來控制CD播放,並調用MP3的解碼程序。

2.5 關於uClinux 2.4內核
    2001年發布了uClinux 2.4,支持龍珠和coldfire處理器,基於2.4內核的一些增強特性同樣做到了uclinux 2.0系列上。目前一些應用仍然基於2.0.x空間的。然而2.4內核使得開發者可以訪問很多新的特性,例如支持USB、IEEE火線、IrDA和新的網路特點,例如帶寬分配、QoS、IPv6等等。
    如果在應用程序中需要使用2.4的新特性,可以在編譯uClinux內核時,選擇2.4的版本。不過,2.4畢竟是較新的內核,有可能不穩定的風險。

3 高效的程序開發
    總的來說,在uClinux上的開發和標準Linux還是很類似的。通常可以按照下面的步驟去設計和調試:
    1. 建立基於乙太網的開發環境;
    2. 如果所設計的程序和硬體的關聯不大,那麼一定要在標準Linux上先編譯和調試通過。靈活地使用gcc和gdb將大大節省時間;
    3. 將x86上的GCC編譯好的應用程序用交叉編譯工具來編譯;如果編譯時發現錯誤,那麼很可能存在以下問題:
    n 交叉編譯器或庫文件的路徑不正確;最徹底的解決辦法是重新裝一次編譯器;
    n 遇到庫不支持的函數;此時需要自己把函數的實現做成另外一個庫供應用程序使用。如果是uClinux本身不支持的調用,那麼就需要改寫代碼了。
    n C++的一些寫法不太標準,需要修改;
    4. 通過網路(nfsmount)運行交叉編譯成功的應用程序;
    5. 如果程序工作初步正常,那麼就可以進一步在板子上測試了;否則,需做修改重新編譯,尤其要檢查與uClinux的內存特性有關的代碼。

    如果程序較小,設計時就可以比較靈活。如果是一個比較龐大的工程,那麼,建立一個好的編譯環境非常重要。下面,給出一個較為複雜的工程中所建立的一系列編譯文件例子,用好它們可以提高效率。
    例如,在編譯x86平台上的程序時,可以這樣輸入:
    >make config
    出現提示:
    Target Platform Selection
    Choose a Vendor/Product combination.
    Vendor/Product [Intel/i386| Motorola/M5307C3]
    如果我們輸入i386,那麼就可以編譯出PC上運行的程序;而輸入M5307C3,就可以編譯出uClinux上運行的程序。這對於經常需要在標準Linux和uClinux之間進行交叉編譯和查找錯誤的程序來說非常方便。

   首先,建立圖 2所示的整個工程目錄結構。

 

圖 2 整個工程的目錄結構

    在config中,存放一些編譯有關的配置文件;src目錄下,按照各個程序模塊分別創建一個目錄。
    在Project目錄下,是整個工程的Makefile文件,如下:
###########################################################
#
# Makefile – Whole Project makefile.
#
# Copyright (c) 2001-2002, Tsinghua MAC
#
###########################################################
#
# Get the core stuff worked out
#

ROOT_DIR = $(shell pwd)
SRC_DIR = $(ROOT_DIR)/src
CONFIG_DIR = $(ROOT_DIR)/config
SCRIPTS_DIR = $(ROOT_DIR)/scripts

CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
else if [ -x /bin/bash ]; then echo /bin/bash; \
else echo sh; fi ; fi)
TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)

HPATH = $(TOPDIR)/include
FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net

export ROOT_DIR SRC_DIR CONFIG_DIR SCRIPTS_DIR HPATH FINDHPATH

###########################################################
# normal make targets
#
#
.PHONY: all
all:
$(MAKE) -C $(SRC_DIR) all
###########################################################

#
# Config stuff, we recall ourselves to load the new config.arch before
# running the kernel and other config scripts
#
.PHONY: config
config: $(CONFIG_DIR)/config.in
cd $(CONFIG_DIR); $(CONFIG_SHELL) $(SCRIPTS_DIR)/Configure $(CONFIG_DIR)/config.in
@rm -f $(SRC_DIR)/arch.config
@if egrep "^CONFIG_DEFAULTS_INTEL_I386" $(CONFIG_DIR)/.config > /dev/null; then \
ln -s "$(CONFIG_DIR)/arch.i386" $(SRC_DIR)/arch.config; \
fi
@if egrep "^CONFIG_DEFAULTS_MOTOROLA_M5272C3" $(CONFIG_DIR)/.config > /dev/null; then \
ln -s "$(CONFIG_DIR)/arch.m68k" $(SRC_DIR)/arch.config; \
fi
@echo "#This dir.config file is automaticly generated by make config!" > $(SRC_DIR)/dir.config
@echo "ROOT_DIR="$(ROOT_DIR) >> $(SRC_DIR)/dir.config
@echo "CONFIG_DIR="$(CONFIG_DIR) >> $(SRC_DIR)/dir.config
@echo "SRC_DIR="$(SRC_DIR) >> $(SRC_DIR)/dir.config
@echo "SCRIPTS_DIR="$(SCRIPTS_DIR) >> $(SRC_DIR)/dir.config
@echo "HPATH="$(HPATH) >> $(SRC_DIR)/dir.config
@echo "FINDPATH="$(FINDPATH) >> $(SRC_DIR)/dir.config

###########################################################
#
# normal make dependancy
#
#
.PHONY: dep
dep:
$(MAKE) -C $(SRC_DIR) dep

# This one removes all executables from the tree and forces their relinking
clean:
$(MAKE) -C $(SRC_DIR) clean

test:
$(MAKE) -C $(SRC_DIR) test

run:
$(MAKE) -C $(SRC_DIR) run

config_error:
@echo "*************************************************"
@echo "You have not run make config."
@echo "The build sequence for this source tree is:"
@echo "1. 'make config' or 'make xconfig'"
@echo "2. 'make dep'"
@echo "3. 'make'"
@echo "*************************************************"
@exit 1
###########################################################

src目錄下的Makefile文件,如下:

VERSION = 2
PATCHLEVEL = 0
SUBLEVEL = 39
UCRELEASE = uc2

.EXPORT_ALL_VARIABLES:

CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
else if [ -x /bin/bash ]; then echo /bin/bash; \
else echo sh; fi ; fi)
TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)

TARGET = ESGateway

all: $(TARGET)

# Include the make variables (CC, etc...)
#

SUBDIRS = public serial packet cal xml fifo main interface

$(TARGET):
@set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i all_targets; done

linuxsubdirs: dummy
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done

clean:
@set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i clean; done

dep:
@set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i fastdep; done

.PHONY: test
test:
@set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i test; done

run:
# @set -e; for i in $(SUBDIRS); do $(MAKE) -i -C $$i run; read junk; done
make -C main run

src目錄下的Rules.make文件給出了編譯的一些規則,如下:
#
# This file contains rules which are shared between multiple Makefiles.
#

#
# False targets.
#
.PHONY: dummy

#
# Special variables which should not be exported
#
unexport EXTRA_ASFLAGS
unexport EXTRA_CFLAGS
ifneq "$(ARCH)" "h8300"
unexport EXTRA_LDFLAGS
endif
unexport EXTRA_ARFLAGS
unexport SUBDIRS
unexport SUB_DIRS
unexport ALL_SUB_DIRS
unexport MOD_SUB_DIRS
unexport O_TARGET
unexport O_OBJS
unexport L_OBJS
unexport M_OBJS
unexport MI_OBJS
unexport ALL_MOBJS
# objects that export symbol tables
unexport OX_OBJS
unexport LX_OBJS
unexport MX_OBJS
unexport MIX_OBJS
unexport SYMTAB_OBJS

unexport MOD_LIST_NAME

include ../dir.config
include $(SRC_DIR)/arch.config

#
# Get things started.
#
first_rule: sub_dirs
$(MAKE) all_targets

#
# Common rules
#
INC_DIR = -I$(SRC_DIR)/cal -I$(SRC_DIR)/xml -I$(SRC_DIR)/serial -I$(SRC_DIR)/packet -I$(SRC_DIR)/fifo -I$(SRC_DIR)/ping -I$(SRC_DIR)/interface -I$(SRC_DIR)/public

%.o: %.c
@echo "Compiling..."
@echo "$<"
$(CXX) $(INC_DIR) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<

%.o: %.cpp
@echo "Compiling..."
@echo "$<"
$(CXX) $(INC_DIR) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<

# Rule to compile a set of .o files into one .o file
#

ifeq (.depend,$(wildcard .depend))
include .depend
else
.depend: fastdep
endif

ifneq ($(O_TARGET),$(O_OBJS))
$(O_TARGET): .depend $(O_OBJS)
@echo "Linking..."
@echo $(O_OBJS) " --> " $@
@$(LD) $(EXTRA_LDFLAGS) -r -o $@ $(O_OBJS)
else
$(O_TARGET): .depend
endif
#
#
#

all: $(O_OBJS)
echo all

all_targets: $(O_OBJS) $(O_TARGET)

#

#
# Rule to compile a set of .o files into one .a file
#
ifdef L_TARGET
$(L_TARGET): $(LX_OBJS) $(L_OBJS)
rm -f $@
$(AR) $(EXTRA_ARFLAGS) rcs $@ $(LX_OBJS) $(L_OBJS)
endif

#
# This make dependencies quickly
#
fastdep: dummy
@echo "make fastdep"
if [ -n "$(wildcard *.[chS])" ]; then \
$(SCRIPTS_DIR)/mkdep *.[chS] > .depend; fi
if [ -n "$(wildcard *.cpp)" ]; then \
$(SCRIPTS_DIR)/mkdep *.cpp >> .depend; fi

#
# A rule to make subdirectories
#
sub_dirs: dummy
ifdef SUB_DIRS
set -e; for i in $(SUB_DIRS); do $(MAKE) -C $$i; done
endif
#
# A rule to do nothing
#
dummy:

config:
cd $(ROOT_DIR); make config

c clean:
rm -f *.o
rm -f *.gdb
rm -f .depend
rm -f test
rm -f core
rm -f *.elf
rm -f *.elf2flt

#
# This is useful for testing
#
script:
$(SCRIPT)

run: test
@echo ... running ...
@echo `pwd`/test
@./test

#
# This sets version suffixes on exported symbols
# Uses SYMTAB_OBJS
# Separate the object into "normal" objects and "exporting" objects
# Exporting objects are: all objects that define symbol tables
#


$(MX_OBJS):
$(CC) $(CFLAGS) -DEXPORT_SYMTAB -c $(@:.o=.c)

$(LX_OBJS) $(OX_OBJS):
$(CC) $(CFLAGS) -DMODVERSIONS -DEXPORT_SYMTAB -c $(@:.o=.c)

$(M_OBJS):
ifdef MAKING_MODULES
$(O_OBJS) $(L_OBJS):
endif


在config 目錄下,編寫兩個和架構有關的文件,對於x86平台,是arch.i386,如下:
.EXPORT_ALL_VARIABLES:
###################################################################
#
# Vendor specific settings
#

CONSOLE_BAUD_RATE = 19200

###################################################################
#
# The makefiles need to know how to do things in different contexts
# To save some pain we put it all here
#
# First settings we always want for all build
#

# ARCH = kernel, TARGET_ARCH = uClibc

MACHINE = i386
ARCH = i386
CROSS_COMPILE =
CROSS = $(CROSS_COMPILE)

# We've used -m5307 here because the bulk of the 5272 instruction timings
# happen to be closer to the 5307 than the 5200 series. Luckily, the
# actual instructions on the two processors are essentially identical.
# This should be fixed at some stage.
CPUFLAGS =
CC = $(CROSS_COMPILE)gcc
AS = $(CROSS_COMPILE)as
CXX = $(CROSS_COMPILE)g++
AR = $(CROSS_COMPILE)ar
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
RANLIB = $(CROSS_COMPILE)ranlib

STRIPTOOL = $(CROSS_COMPILE)strip
STRIP = $(STRIPTOOL)

UCLINUX_BUILD_SET = 0 # have we set a special config below

###################################################################
#
# General purpose lib building rules, uClibc.config uses these when
# possible
#


###################################################################
# Settings for building user apps
#
CFLAGS = -Wall -Wstrict-prototypes -O2 -g
#CFLAGS = -Wstrict-prototypes -g
LDFLAGS = -m elf_i386
###################################################################
# fall through, do other config options perhaps
#
ifeq ($(UCLINUX_BUILD_SET),1)
endif
###################################################################

在config 目錄下,對於嵌入式平台,是arch.m68k,如下:

.EXPORT_ALL_VARIABLES:
###################################################################
#
# Vendor specific settings
#
CONSOLE_BAUD_RATE = 19200
###################################################################
#
# The makefiles need to know how to do things in different contexts
# To save some pain we put it all here
#
# First settings we always want for all build
#
# ARCH = kernel, TARGET_ARCH = uClibc

MACHINE = m68k
ARCH = m68knommu
CROSS_COMPILE = m68k-elf-
CROSS = $(CROSS_COMPILE)

# We've used -m5307 here because the bulk of the 5272 instruction timings
# happen to be closer to the 5307 than the 5200 series. Luckily, the
# actual instructions on the two processors are essentially identical.
# This should be fixed at some stage.
CPUFLAGS = -m5200
CC = $(CROSS_COMPILE)gcc
AS = $(CROSS_COMPILE)as
CXX = $(CROSS_COMPILE)g++
AR = $(CROSS_COMPILE)ar
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
RANLIB = $(CROSS_COMPILE)ranlib
ELF2FLT = elf2flt
STRIPTOOL = $(CROSS_COMPILE)strip
STRIP = $(STRIPTOOL)

UCLINUX_BUILD_SET = 0 # have we set a special config below


###################################################################
#
# Settings for building user apps
#
#CFLAGS = -m5200 -msep-data -g
CFLAGS = -m5200 -msep-data
LDFLAGS = -Wl,-elf2flt
SYSLIBS = -lc -lstdc++ -lgcc
###################################################################
#
# fall through, do other config options perhaps
#

ifeq ($(UCLINUX_BUILD_SET),1)
endif
###################################################################

在config 目錄下的config.in文件如下:

mainmenu_name 'uClinux Configuration'
mainmenu_option next_comment
comment 'Target Platform Selection'
comment 'Choose a Vendor/Product combination.'
choice 'Vendor/Product [Intel/i386 | Motorola/M5307C3] ' "1 CONFIG_DEFAULTS_INTEL_I386 \
2 CONFIG_DEFAULTS_MOTOROLA_M5307C3 \
" Intel/i386
endmenu

4 結語
    本文討論了uClinux平台上程序設計必須關注的一些特點,並對在uClinux進行高效程序開發做了一些討論。
    由於uClinux是開源的,在uClinux上的開發努力永遠不會停止。世界範圍的技術專家在使用uClinux來構造商業化的產品,他們的工作的重要部分反過來對開源的社區作出了貢獻。每當我們訪問uClinux的網站,看到又出現了更新的源碼發布或者更好的工具時,就會感覺到這個開發團體的熱情和能力,並鞭策自己努力工作,爭取為這個自由軟體的發展作出自己的創造性貢獻。




[admin via 研發互助社區 ] uClinux 上的應用程序設計已經有1453次圍觀

http://cocdig.com/docs/show-post-42584.html