2014年11月25日 星期二

[轉] kernel build system探索

vmlinux是如何煉成的-- kernel makefile

引子
kernelmakefile包含的內容還真是多,我就是想看看要是我自己添加一個目錄編譯到內核裡,要怎麼做
就是這麼個不起眼的實驗,引發了一堆的故事

最簡單的例子
添加 一個目錄,叫test, 添加了test.c 和 Makefile
文件內容很簡單,如下。
cat Makefile
#
# Makefile for the linux kernel makefile experiment.
#
obj-y := test.o
cat test.c
#include <linux/export.h>
int test_global = 0;
然後在主 Makefile中 添加
-core-y         += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
+core-y         += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ test/
最後 make test
make[1]: Nothing to be done for `all'.
  HOSTCC arch/x86/tools/relocs
  CHK include/linux/version.h
  CHK include/generated/utsrelease.h
  CC kernel/bounds.s
  GEN include/generated/bounds.h
  CC arch/x86/kernel/asm-offsets.s
  GEN     include/generated/asm-offsets.h
  CALL    scripts/checksyscalls.sh
  CC      test/test.o
  LD      test/built-in.o
恩,不錯,可以了。

vmlinux是如何煉成的-- kernel makefile
人總是不知足的,我又開始好奇,這build的過程究竟是怎麼個回事
好吧,我們知make後,最終的結果vmlinux,那我們就找找這個神奇的東西是
產生的吧。 
vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)
$(sort $(vmlinux-deps)): $(vmlinux-dirs) ;
vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) FORCE
ifdef CONFIG_HEADERS_CHECK
    $(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
ifdef CONFIG_SAMPLES
    $(Q)$(MAKE) $(build)=samples
endif
ifdef CONFIG_BUILD_DOCSRC
    $(Q)$(MAKE) $(build)=Documentation
endif
    +$(call if_changed,link-vmlinux)

vmlinx 基於上面三個目標, 而vmlinux-deps又基於 $(vmlinux-dirs)。 恩,好複雜。
那來看vmlinux-dirs都包含什麼吧。
在主Makefile中看到下面的內容。
core-y        += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ test/

vmlinux-dirs    := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
             $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
             $(net-y) $(net-m) $(libs-y) $(libs-m)))
$(vmlinux-dirs): prepare scripts
    $(Q)$(MAKE) $(build)=$@
恩, 我們vmlinux-dirs的東東打印出來看看。
vmlinux-dris: init usr arch/x86 kernel mm fs ipc security crypto block test drivers sound firmware arch/x86/pci arch/x86/power arch/x86/video arch/x86/oprofile net lib arch/x86/lib
這樣,你是不是明白點了呢。 這些都kernel源代碼中子目錄。也就kernel將要挨
進入每個子目錄,編譯~。
那最後這vmlinux是怎麼生成的呢? 怎麼樣將每個目錄下生成的模塊鏈接成一vmlinux的文件的呢
看到上vmlinux目標中,最後一個命令
+$(call if_changed,link-vmlinux)
哦,原來是調用cmd_link-vmlinux。這個命令就定義在Makefile
      cmd_link-vmlinux = $(CONFIG_SHELL) $< $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux)
打出來看看,長這樣。
      /bin/bash $<  ld -m elf_i386 --emit-relocs --build-id
$< 表示第一個以來目標,那麼vmlinux目標中,第一個目標是 scripts/link-vmlinux.sh, 展開後就成為。
/bin/bash scripts/link-vmlinux.sh ld -m elf_i386 --emit-relocs --build-id
額,原來是又調用了一個腳本。。。 好吧, 再進去看看。  發現這麼個東東
info LD vmlinux
vmlinux_link "${kallsymso}" vmlinux
vmlinux_link()
{
    local lds="${objtree}/${KBUILD_LDS}"

    if [ "${SRCARCH}" != "um" ]; then
        ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2}                  \
            -T ${lds} ${KBUILD_VMLINUX_INIT}                     \
            --start-group ${KBUILD_VMLINUX_MAIN} --end-group ${1}
    else
        ${CC} ${CFLAGS_vmlinux} -o ${2}                              \
            -Wl,-T,${lds} ${KBUILD_VMLINUX_INIT}                 \
            -Wl,--start-group                                    \
                 ${KBUILD_VMLINUX_MAIN}                      \
            -Wl,--end-group                                      \
            -lutil ${1}
        rm -f linux
    fi
}
好吧,原來是調用了這個函數。。。 打出來看看吧。
ld -m elf_i386 --emit-relocs --build-id -o vmlinux -T arch/x86/kernel/head_32.o arch/x86/kernel/head32.o arch/x86/kernel/head.o init/built-in.o --start-group usr/built-in.o arch/x86/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o test/built-in.o lib/lib.a arch/x86/lib/lib.a lib/built-in.o arch/x86/lib/built-in.o drivers/built-in.o sound/built-in.o firmware/built-in.o arch/x86/pci/built-in.o arch/x86/power/built-in.o arch/x86/video/built-in.o net/built-in.o --end-group .tmp_kallsyms2.o
恩,原來真相是這樣的。 最後把這麼多東西鏈接起來vmlinux。 看到我們添加test目錄了麼,它也生成了一built-in.o,最後鏈接到vmlinux
$ nm vmlinux | grep test_global
c198d284 B test_global

啊哦,還真有這個symbol

神秘的built-in.o
在最後的鏈接過程中,我們可以看到,幾乎所有的依賴條件中,都會生成built-in.o的文件。 那這個文件,是怎麼生成的呢?
$(vmlinux-dirs): prepare scripts
    $(Q)$(MAKE) $(build)=$@
從這個規則中可以看到vmlinux-dir目標是通過下面make來生成的。展開一下看看。 這buildscripts/Kbuild.include
make -f scripts/Makefile.build obj=$@
對應到test目錄 那就是
make -f scripts/Makefile.build obj=test
這麼看來,就要進scripts/Makefile.build文件了
PHONY := __build
__build:
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
     $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
     $(subdir-ym) $(always)
    @:
__build是這makefile的第一個目標,也是默認的目標。 這裡面藏著一builtin-target,看著很像,再搜搜
ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(subdir-m) $(lib-target)),)
builtin-target := $(obj)/built-in.o
endif
恩 原來這個就是這麼built-in.o的原因。但是要buit-in.o,必須要以上的這些變量不能全部為空
那再來看看編譯這built-in.o的規則是什
quiet_cmd_link_o_target = LD      $@
# If the list of objects to link is empty, just create an empty built-in.o
cmd_link_o_target = $(if $(strip $(obj-y)),\
              $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
              $(cmd_secanalysis),\
              rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@)

$(builtin-target): $(obj-y) FORCE
    $(call if_changed,link_o_target)

targets += $(builtin-target)
恩,基本明白了,就是obj-y的內容不為空,那麼就ld來鏈接成一built-in.o
但是我試了一下,如果沒obj-y那麼,也會生成built-in.o,但是用的是別的命令
如在i386下,用的是
rm -f test/built-in.o; ar rcsD test/built-in.o
不知道這個是什麼高級玩意。
好了,到此為止,基本上一個最上層的框架有了一個概念。 那就先休息一下~

一切盡在掌握 -- kconfig 配置系統

kconfig是個強大的工具,如果makefile制定了完美的編譯依賴關系,那kconfig制定了完美的模塊的依賴關係
源頭
在根目錄下有Kconfig文件,這就是一切故事的起源
整個文件就沒幾行,打出來看一眼。
#
# For a description of the syntax of this configuration file,
# see Documentation/kbuild/kconfig-language.txt.
#
mainmenu "Linux/$ARCH $KERNELVERSION Kernel Configuration"

config SRCARCH
    string
    option env="SRCARCH"
source "arch/$SRCARCH/Kconfig"
第一行就是輸出個內核版本號。
第二行應該是配置一個環境變量? 不知道,以後再來看。
第三行很重要,這個是包含了一arch目錄下Kconfig文件

當你打開這個文件的時候,你就發現這是一切的開始
我們運行make menuconfig, 你可以看到,這個文件就是make menuconfig中顯示的東西。
一切都變得明朗起來,你是否有種太極生兩儀,兩儀生四象,四象生八卦的神奇感

剪不斷,理還亂
kernel中這麼多的模塊之間的依賴關係,簡直就是 剪不斷,理還亂。
幸好Kconfig文件中,我們可以找到一點蛛絲馬
依賴 depends on
這個關鍵字表示了在某些配置選中後,本配置項才會顯
在 driver/pci/Kconfig文件中
config PCI_MSI
    bool "Message Signaled Interrupts (MSI and MSI-X)"
    depends on PCI
    depends on ARCH_SUPPORTS_MSI

可以發現,要配MSI必須要先支PCI。 恩這個道理咱都懂, 連PCI都沒有,哪裡來的MSI啊。
反向依賴 select
這個關鍵字表示了當本配置項選中後,其他的配置項也需要選中
在 arch/x86/Kconfig文件中
config HIGHMEM64G
    bool "64GB"
    depends on !M386 && !M486
    select X86_PAE
    ---help---
      Select this if you have a 32-bit processor and more than 4
      gigabytes of physical RAM.

其實這個我也不懂,看上去就是說要支持更多的物理內存,那麼x86的平台上,就要X86_PAE
看上去是這麼回事兒。

革命尚未成功,同志仍需努力
好了,我要記錄的東西就到這裡了。突然這麼嘎然而止,估計大家一定意猶未盡
但是事實就是這樣,基本kconfig語法大家可以在 Document/kbuild/kconfig-language.txt中找到
就不用我在這裡搬出來照抄了。

kernel模塊之間的關聯又怎能是我這樣的初學者所能理解,不能理解又豈能講得清楚
這裡只是給大家一個入口,讓大家能夠進一步kernel的海洋中探索。話說,授之以魚不如授之以漁嘛
要讓linux kernel更好的發揮作用,讓更多的人參與這個項目,幫助更多的人,還有很長的路要走
革命尚未成功,同志仍需努力。

[轉] MTK6577+Android編譯之preloader

http://blog.csdn.net/loongembedded/article/details/38706537

[轉] MTK6577+Android編譯之kernel

http://blog.csdn.net/loongembedded/article/details/38778731

MTK代碼目錄結構

1、android
|-- a、bionic - bionic C庫
|-- b、bootable - 啟動引導相關代碼
|-- c、build - 存放系統編譯規則及generic等基礎開發包配置
|-- d、cts - Android兼容性測試套件標準
|-- e、dalvik - dalvik JAVA虛擬機
|-- f、development - 應用程序開發相關
|-- g、external - android使用的一些開源的模組
|-- h、frameworks - 核心框架——java及C++語言
|-- i、hardware - 主要保護硬解適配層HAL代碼
|-- j、out - 編譯完成後的代碼輸出於此目錄
|-- k、packages - 應用程序包
|-- l、prebuilt - x86和arm框架下預編譯的一些資源
|-- m、sdk - sdk及模擬器
|-- n、system - 文件系統庫,應用及組件——C語言
|-- o、vendor - 廠家定製代碼



2、bionic目錄
|-- (1)、libc - C庫
|       |-- a、arch-arm - ARM框架,包含系統調用彙編實現
|       |-- b、arch-sh -
|       |-- c、arch-x86 - x86框架,包含系統調用彙編實現
|       |-- d、bionic - 由C實現的功能,框架無關
|       |-- e、docs - 文檔
|       |-- f、include - 頭文件
|       |-- g、inet -
|       |-- h、kernel - Linux內核中的一些頭文件
|       |-- i、netbsd -
|       |-- j、private - 一些私有的頭文件
|       |-- k、regex -
|       |-- l、stdio - stdio實現
|       |-- m、stdlib - stdlib實現
|       |-- n、string - string函數實現
|       |-- o、tools - 幾個工具
|       |-- p、tzcode - 區時相關代碼
|       |-- q、unistd - unistd 實現
|       |-- r、wchar -
|       |-- s、zoneinfo - 區時信息
|-- (2)、libdl - libdl實現,dl是動態鏈接,提供訪問動態鏈接庫的功能
|       |-- a、arch-sh -
|-- (3)、libm - libm數學庫的實現
|       |-- a、alpha - alpha框架
|       |-- b、amd64 - amd64框架
|       |-- c、arm - arm框架
|       |-- d、bsdsrc - bsd的源碼
|       |-- e、i386 - i386框架
|       |-- f、i387 - i387框架
|       |-- g、ia64 - ia64框架
|       |-- h、include - 頭文件
|       |-- i、man - 數學函數,後綴名為.3,一些為freeBSD的庫文件
|       |-- j、powerpc - powerpc框架
|       |-- k、sh -
|       |-- l、sparc64 - spare64框架
|       |-- m、src - 源代碼
|-- (4)、libstdc++ - libstdc++ C++實現庫
|       |-- a、include - 頭文件
|       |-- b、src - 源代碼
|-- (5)、libthread_db - 多線程程序的調試器庫
|       |-- a、inckude - 頭文件
|-- (5)、linker- 動態連接器
|       |-- a、arch - 支持arm和x86兩種框架



3、bootable目錄
|-- (1)、bootloader - 適合各種bootlader的通用代碼
|       |-- a、legacy - 估計不能直接使用,可以參考
|               |-- arch_armv6 - V6框架,幾個簡單的彙編文件
|               |-- arch_msm7k - 高通7k處理器框架的幾個基本驅動
|               |-- include - 通用頭文件和高通7k框架頭文件
|               |-- libboot - 奇洞窟,都寫得很簡單
|               |-- libc - 一些常用的C函數
|               |-- nandwrite - nandwrite函數實現
|               |-- usbloader - usbloader實現
|       |-- b、uboot -
|-- (2)、diskinstaller - android鏡像打包器,x86可生產iso
|       |-- a、deitdisklbl -
|       |-- b、libdiskconfig -
|-- (3)、recovery - 系統恢複相關
|       |-- a、applypatch -
|       |-- b、edify - 升級腳本使用的edify腳本語言
|       |-- c、etc - init.rc回覆腳本
|       |-- d、minui - 一個簡單的UI
|       |-- e、minzip - 一個簡單的壓縮工具
|       |-- f、mtdutils - mtd工具
|       |-- g、res - 資源
|               |-- images - 一些圖片
|       |-- h、sec -
|       |-- i、testdata -
|       |-- j、tools - 工具
|               |-- ota - OTA Over The Air Updates升級工具
|       |-- k、updater - 升級器



4、build目錄
|-- (1)、core - 核心編譯規則
|-- (2)、libs -
|       |-- a、host - 主機端庫,有android「cp」功能替換
|-- (3)、target - 目標機編譯對象
|       |-- a、board - 開發平台
|               |-- generic_x86 - 通用
|               |-- mt6516_evb[QVGA] -
|               |-- sim -
|       |-- b、product - 開發平台對應的編譯規則
|               |-- security - 密鑰相關
|-- (4)、toools - 編譯中主機使用的工具及腳本
|       |-- a、acp - Acdroid「acp」Command
|       |-- b、apicheck - api檢查工具
|       |-- c、apriori - 預鏈接工具
|       |-- d、atree - tree工具
|       |-- e、bin2asm - bin轉換為asm工具
|       |-- f、check_prereq - 檢查編譯時間戳工具
|       |-- g、droiddoc -
|       |--h、fs_config -
|       |-- i、fs_get_stats - 獲取文件系統狀態
|       |-- j、iself - 判斷是否ELF格式
|       |-- k、isprelinked - 判斷是否prelinked
|       |-- l、kcm - 按鍵相關
|       |-- m、lsd - List symbol dependencies
|       |-- n、releasetools - 生成鏡像的工具及腳本
|       |-- o、rgb2565 - rgb轉換為565
|       |-- p、singapk - apk簽名工具
|       |-- q、soslim - strip工具
|       |-- r、zipalign - zip archibe alignment tool



5、dalvik目錄 dalvik虛擬機
|-- (1)、dalvikvm - main.c的目錄
|-- (2)、dexdump - dex反彙編
|-- (3)、dexlist - List all methods in all concrete classes in a DEX file
|-- (4)、dexopt - 預驗證與優化
|-- (5)、docs - 文檔
|-- (6)、dvz - 和zygote相關的一個命令
|-- (7)、dx - dx工具,將多個java轉換為dex
|-- (8)、hit - java語言寫成
|-- (9)、libdex - dex的庫
|-- (10)、libnativehelper -
|-- (11)、tests - 測試代碼
|-- (12)、tools - 工具
|-- (13)、vm -虛擬機實現



6、development目錄        (開發需要的一些例程及工具)
|-- (1)、apps - 一些核心應用程序
|       |-- a、BluetoothDebug - 藍牙調試程序
|       |-- b、BuildWidget -
|       |-- c、CustomLocale - 自定義區域設置
|       |-- d、Development - 開發
|       |-- e、Fallback - 和語言相關的一個程序
|       |-- f、FontLab - 字庫
|       |-- g、GestureBuilder - 手勢運動
|       |-- h、GraphicsLab -
|       |-- i、launchperf -
|       |-- j、NinePatchLab -
|       |-- k、OBJViewer - OBJ查看器
|       |-- l、SdkSetup - SDK安裝器
|       |-- m、SpareParts - 高級設置
|       |-- n、Term - 遠程登錄
|-- (2)、build - 編譯腳本模板
|-- (3)、cmds - 有個monkey工具
|-- (4)、data - 配置數據
|-- (5)、docs - 文檔
|-- (6)、host - 主機端SUB驅動等
|-- (7)、ide - 集成開發環境
|-- (8)、ndk - 本地開發套件 ——C語言開發套件
|-- (9)、pdk - Plug Development Kit
|-- (10)、samples - 例程
|       |-- a、AccelermoeterPlay -
|       |-- b、AccessibilityService -
|       |-- c、Alarm -
|       |-- d、AliasActivity -
|       |-- e、ApiDemos - API掩飾程序
|       |-- f、BackupRestore -
|       |-- g、BasicGLSurfaceView -
|       |-- h、BluetoothChat - 藍牙聊天
|       |-- i、BrowserPlugin - 瀏覽器插件
|       |-- j、BusinessCard - 商業卡
|       |-- k、Compass - 指南針
|       |-- l、ContactManager - 了聯繫人管理器
|       |-- m、CrossCompatibility -
|       |-- n、CubeLiveWallpaper - 動態壁紙的一個簡單例程
|       |-- o、FixedGridLayout - 佈局
|       |-- p、GlobalTime - 全球時間
|       |-- q、HeavyWeight -
|       |-- r、HelloActivity - hello
|       |-- s、Home - Home
|       |-- t、JetBoy - jetBoy遊戲
|       |-- u、LunarLander -
|       |-- v、MailSync - 右鍵同步
|       |-- w、MultiResolution -多分辨路
|       |-- x、MySampleRss - RSS
|       |-- y、NFCDemo -
|       |-- z、Obb -
|       |-- aa、RSSReader - RSS閱讀器
|       |-- bb、SampleSyncAdapter -
|       |-- cc、SearchableDictionary - 目錄搜索
|       |-- dd、SimpleJNI - JNI例程
|       |-- ee、SipDemo -
|       |-- ff、SkeletonApp - 空殼APP
|       |-- gg、Snake - Snake程序
|       |-- hh、SoftKeyboard - 軟鍵盤
|       |-- ii、Spinner -
|       |-- jj、SpinnerTest -
|       |-- kk、TicTacToeLib -
|       |-- ll、TicTacToeMain -
|       |-- mm、VoiceRecognitionService -
|       |-- nn、Wiktionary -
|       |-- oo、WiktionarySimple -
|-- (11)、scripts - 腳本
|-- (12)、sdk - sdk配置
|-- (13)、sdk_overlay -
|-- (14)、simulator -
|-- (15)、testrunner -
|-- (16)、tools - 工具
|-- (17)、tutorials -



7、external目錄
|-- (1)、apache-http - 網頁服務器
|-- (1)、astl - a slimmed-down vesion of the regular C++ STL
|-- (1)、bison - 自動生成語法分析器
|-- (2)、blisrc -
|-- (3)、blktrace -
|-- (4)、bluetooth - 藍牙相關,協議棧
|-- (5)、bouncycastle -
|-- (6)、bsdiff - diff工具
|-- (7)、bzip2 - 壓縮工具
|-- (8)、chromium -
|-- (9)、clearsilver - html模板系統
|-- (10)、dbus - 低延時,低開銷,高可用性的IPC機制
|-- (11)、dhcpcd -DHCP服務
|-- (12)、dnsmasq -
|-- (13)、e2fsprogs - EXT2文件系統工具
|-- (14)、easymock -
|-- (15)、elfcopy - 複製ELF的工具
|-- (16)、elfutils - ELF工具
|-- (17)、embunit - Embedded Unit Project
|-- (18)、emma - java代碼覆蓋統計工具
|-- (19)、esd - Enlightended Sound Daemon,將多種音頻流混合在一個設備上播放
|-- (20)、expat -
|-- (21)、fdlibm - Freely Distributable LIBM
|-- (22)、freetype - 字體
|-- (23)、fsck_msdos - dos文件系統檢查工具
|-- (24)、genext2fs -
|-- (25)、giflib - gif庫
|-- (26)、grub - GNU GRUB,the GRand Unified Bootloader
|-- (27)、gtest - Google C++ Testing Framework
|-- (28)、guava -
|-- (29)、icu4c - ICU(International Component for )
|-- (30)、iproute2 -
|-- (31)、ipsec-tools - this package provides a way to use the native IPsec functionality
|-- (32)、iptables - 防火牆
|-- (33)、jdiff - generate a re[ort describing the difference between two public Java APIs
|-- (34)、jhead - jpeg頭部信息工具
|-- (35)、jpeg - jpeg庫
|-- (36)、jsr305 -
|-- (37)、junit - JUnit是一個java元以內的單元測試框架
|-- (38)、kernel-headers - 內核的一些頭文件
|-- (39)、libffi - a foreign function interface library
|-- (40)、libgsm -
|-- (41)、libnfc-nxp -
|-- (42)、libpcap - 網絡數據包獲取函數
|-- (43)、libpng - png庫
|-- (44)、libvpx -
|-- (45)、libxml2 - xml解析庫
|-- (46)、mtpd - 命令
|-- (47)、netcat - simple Unix utility which reads and writes dataacross network connections
|-- (48)、netperf - 網絡性能測試工具
|-- (49)、nenen - 看代碼和JNI相關
|-- (50)、nist-sip -
|-- (1)、oauth -
|-- (1)、opencore - 多媒體框架
|-- (51)、openssl - SSL加密相關
|-- (52)、oprofile - Linux內核支持的一種性能分析機制
|-- (53)、ping - ping命令
|-- (54)、ppp - ppps撥號命令
|-- (55)、proguard - Java class fileshrinker,optimizer,obfuscator,and preverfier
|-- (56)、protobuf - a flexible,efficient,automated mechanism for serializing structured data
|-- (57)、qemu - arm模擬器
|-- (58)、quake -
|-- (59)、safe-iop - functions for performing sage integer operations
|-- (60)、skia - skia圖形引擎
|-- (61)、skia_asm -
|-- (62)、sonivox - sole MIDI solution for Google Android Mobile Phone Platform
|-- (63)、speex - Speex編/解碼API的使用(libspeex)
|-- (64)、srec - Nuance公司提供的開源連續非特定人語音識別
|-- (65)、stlport -
|-- (66)、strace - trace工具
|-- (67)、svox - Embedded Text-to-Speech
|-- (68)、tagsoup - 一個Java開發符合SAX的HTML解析器
|-- (69)、tcpdump - 抓TCP包的軟件
|-- (70)、tinyxml - a simple,small,C++ XML parser
|-- (71)、v8 -
|-- (72)、webkit - 瀏覽器核心
|-- (73)、wpa_supplicant - 無限網卡管理
|-- (74)、wpa_supplicant_6 -
|-- (75)、xmlwriter - XML編輯工具
|-- (76)、yaffs2 - yaffs文件系統
|-- (77)、zlib - a general purpose data compression library

2014年11月10日 星期一

[轉] 使用 /proc 文件系統來訪問 Linux 內核的內容

http://www.ibm.com/developerworks/cn/linux/l-proc.html

[轉] android 編譯C程序 在android下可執行

Android編譯環境本身比較複雜,且不像普通的編譯環境:只有頂層目錄下才有Makefile文件,而其他的每個component都使用統一標準Android.mk. Android.mk文件本身是比較簡單的,不過它並不是我們熟悉的Makefile,而是經過了Android自身編譯系統的很多處理,因此要真正理清楚其中的聯繫還比較複雜,不過這種方式的好處在於,編寫一個新的Android.mk來給Android增加一個新的Component會比較簡單。 編譯Java程序可以直接採用Eclipse的集成環境來完成,這裡就不重複了。我們主要針對C/C++來說明,下面通過一個小例子來說明,如何在Android 中增加一個C程序的Hello World:
1. 在$(YOUR_ANDROID)/ development 目錄下創建hello目錄,其中$(YOUR_ANDROID)指Android源代碼所在的目錄。
- # mkdir $(YOUR_ANDROID)/development/hello
2. 在$(YOUR_ANDROID)/external/hello/目錄編寫hello.c文件,hello.c的內容當然就是經典的HelloWorld程序:
#include <stdio.h>
int main(int argc, char **argv)
{
    printf("Hello World!\n");
return 0;
}


3. 在$(YOUR_ANDROID)/external/hello/目錄編寫Android.mk文件。這是Android Makefile的標準命名,不要更改。Android.mk文件的格式和內容可以參考其他已有的Android.mk文件的寫法,針對helloworld程序的Android.mk文件內容如下
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES:= \
    hello.c
LOCAL_MODULE := helloworld
include $(BUILD_EXECUTABLE)

 Android.mk的例外一種寫法也可以
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_STATIC_LIBRARIES := libcutils libc
LOCAL_MODULE := helloworld
LOCAL_MODULE_TAGS := eng

LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_SRC_FILES:= \
        hello.c

LOCAL_C_INCLUDES := bionic/libc/bionic

ifeq ($(HAVE_SELINUX),true)
LOCAL_CFLAGS += -DHAVE_SELINUX
LOCAL_SHARED_LIBRARIES += libselinux
LOCAL_C_INCLUDES += external/libselinux/include
endif

include $(BUILD_EXECUTABLE)


注意上面LOCAL_SRC_FILES用來指定源文件;,LOCAL_MODULE指定要編譯的模塊的名字,下一步驟編譯時就要用到;include $(BUILD_EXECUTABLE)表示要編譯成一個可執行文件,如果想編譯成動態庫則可用BUILD_SHARED_LIBRARY,這些可以在$(YOUR_ANDROID)/build/core/config.mk查到。
4. 回到Android源代碼頂層目錄進行編譯:
# cd $(YOUR_ANDROID) && make helloworld
注意make helloworld中的目標名helloworld就是上面Android.mk文件中由LOCAL_MODULE指定的模塊名。編譯結果如下:
target thumb C: helloworld <= development/hello/hello.c
target Executable: helloworld (out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/LINKED/helloworld)
target Non-prelinked: helloworld (out/target/product/generic/symbols/system/bin/helloworld)
target Strip: helloworld (out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/helloworld)
Install: out/target/product/generic/system/bin/helloworld


5.如上面的編譯結果所示,編譯後的可執行文件存放在out/target/product/generic/system/bin/helloworld目錄
啟動Android模擬器,用如下命令將文件push到Android模擬器上:
    注意:  要把SDK目錄裡的tools目錄放到PATH環境變量中.
adb shell mkdir /dev/sample
adb push hello /dev/sample/hello
adb shell chmod 777 /dev/sample/hello
先創建 /dev/sample目錄,再將編譯好的hello上傳上去,最後將hello改成可執行的。
再進入命令行模式,進入Android的shell環境:
adb shell
#cd /dev/sample
#./hello

2014年11月6日 星期四

[轉] 淺析Linux等待隊列

在Linux驅動程序中,可以使用等待隊列(wait queue)來實現阻塞進程的喚醒。等待很早就作為一個基本的功能單位出現在Linux內核中,它以隊列為基礎數據結構,與進程調度機制緊密結合,能夠用於實現內核中的異步事件通知機制。
我們從它的使用範例著手,看看等待隊列是如何實現異步信號功能的。以下代碼節選自kernel/printk.c。
DECLARE_WAIT_QUEUE_HEAD(log_wait); // 初始化等待隊列頭log_wait
static DEFINE_SPINLOCK(logbuf_lock); // 定義自旋鎖logbuf_lock
int do_syslog(int type, char __user *buf, int len)
{
        ... ... ...
        err = wait_event_interruptible(log_wait, (log_start - log_end)); // 等待
        /*
        // 我們先來看看linux/wait.h中定義的wait_event_interruptible()的原型
        #define wait_event_interruptible(wq, condition)
        ({
               int __ret = 0;
                if ( (!condition) )
                        __wait_event_interruptible(wq, condition, __ret);
                __ret;
        })
        // wait_event_interruptible()將等待隊列加入第一個參數wq為等待隊列頭的等待隊列鏈表中,
        // 當condition滿足時,wait_event_interruptible()會立即返回,否則,阻塞等待condition滿足。
        // 與之類似的還有wait_event(),不同點在於wait_event_interruptible()可以被信號喚醒。
        // __wait_event_interruptible()原型如下:
        #define __wait_event_interruptible(wq, condition, __ret)
        do {
                DEFINE_WAIT(__wait); // 定義等待隊列__wait
                for(;;) {
                        prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE);
                        // prepare_to_wait()的作用是:將等待隊列__wait加入以wq為等待隊列的等待隊列
                         // 鏈表中,並且將進程狀態設置為TASK_INTERRUPTIBLE
                        if (condition)
                                break; // 如果condition滿足則跳出
                       if (!signal_pending(current)) { // 如果不是被信號喚醒
                                ret = schedule_timeout(ret);
                                if (!ret)
                                        break;
                                continue;
                        }
                          ret = - ERESTARTSYS;
                          break;
                          schedule(); // 放棄CPU,調度其它進程執行
                }
                finish_wait(&wq, &__wait);
                // finish_wait()的作用是,將等待隊列__wait從等待隊列頭wq指向的等待隊列鏈表中移除,
                // 並且將進程狀態設置為TASK_RUNNING
        }while(0)
        */
        ... ... ...
        spin_lock_irq(&lock_wait); // 鎖定
        ... ... ...
        log_start++; // log_start自加,使得(log_start - log_end)這個等待隊列的condition滿足
        ... ... ...
         spin_unlock_irq(&lock_wait); // 解鎖
        ... ... ...
}
void wake_up_klogd(void)
{
        ... ... ...
        wake_up_interruptible(&lock_wait); //喚醒等待隊列
}
void release_console_sem(void)
{
        ... ... ...
        spin_lock_irqsave(&lock_wait); // 鎖定
        wake_klogd = log_start - log_end;
         ... ... ...
        spin_unlock_irqrestore(&lock_wait); // 解鎖
        ... ... ...
        if (wake_klogd)
                wake_up_klogd(); // 如果wake_klogd非負,則調用wake_up_klogd()來喚醒等待隊列
        ... ... ...
}
我們最後再總結一下等待隊列wait_event_interruptible():


在wait_event_interruptible()中首先判斷conditon是不是已經滿足,如果是則直接返回0,否則調用__wait_event_interruptible(),並用__ret來存放返回值。__wait_event_interruptible()首先將定義並初始化一個wait_queue_t變量__wait,其中數據為當前進程狀態current(struct task_struct),並把__wait加入等待隊列。在無限循環中,__wait_event_interruptible()將本進程置為可中斷的掛起狀態,反覆檢查condition是否成立,如果成立則退出,如果不成立則繼續休眠;條件滿足後,即把本進程運行狀態置為運行態,並把__wait從等待隊列中清除,從而進程能夠調度運行。

掛起的進程並不會自動轉入運行的,因此,還需要一個喚醒動作,這個動作由wake_up_interruptible()完成,它將遍歷作為參數傳入的lock_wait等待隊列,將其中所有的元素(通常都是task_struct)置為運行態,從而可被調度。