OpenWRT基本知識整理

轉載自:http://www.liwangmeng.com/openwrt%E5%9F%BA%E6%9C%AC%E7%9F%A5%E8%AF%86%E5%BD%92%E7%BA%B3/

目錄:

1.OpenWRT虛擬系統準備… 3

1.1.編譯openwrt虛擬機系統… 3

1.1.1 準備源碼… 3

1.1.2 準備源碼包… 3

1.1.3 編譯配置… 4

1.1.4 編譯… 4

1.2.安裝虛擬機… 5

1.2.1.新建虛擬機… 5

1.2.2.修改虛擬機配置文件:… 11

2.配置使用… 12

2.1.設置root密碼… 12

2.2.網絡配置… 12

2.3.關於ssh. 13

3.軟件安裝方法… 13

3.1.本地安裝ipk軟件包… 13

3.2.在線安裝軟件及設置… 13

3.2.1.設置軟件源… 13

3.2.2.安裝軟件… 14

3.2.3.直接安裝… 14

3.3.使用本地服務器做軟件源以安裝自定義軟件… 14

3.3.1.在編譯服務器上配置vsftp服務器… 14

3.3.2.修改openwrt在線安裝軟件源… 15

3.3.3更新opkg. 16

3.3.3.通過命令安裝ipk軟件… 16

4.模塊開發方法… 16

4.1.SDK準備… 16

4.2.添加模塊代碼… 16

4.3.模塊程序源代碼… 16

4.4.源碼編譯Makefile. 16

4.5.ipK包製作規則Makefile. 17

4.6.編譯模塊… 18

4.7.ipk包製作… 18

4.8.安裝測試… 18

5.openwrt SDK源碼目錄結構… 18

5.1.源碼下載… 18

5.2.OpenWRT的feeds. 19

5.3.OpenWrt源碼目錄結構… 19

6.Openwrt模塊驅動開發… 20

6.1.建立工作目錄… 20

6.2.進入example目錄,創建Makefile文件和代碼路徑… 20

6.3.進入src目錄,創建代碼路徑和相關源文件… 21

6.4.回到OpenWrt源碼根目錄下… 21

6.5.在OpenWrt系統裏面就可以用opkg下載使用了。… 22

7.openwrt Makefile框架分析… 22

7.1.openwrt目錄結構… 22

7.2.main Makefile. 23

第一個邏輯… 24

第二邏輯… 24

stampfile. 25

目錄變量… 26

7.3.kernel 編譯:… 26

7.4.生成firmware. 27

處理vmlinux: Image/BuildKernel 28

lzma壓縮內核… 28

MkImage. 29

copy. 29

7.5.製作squashfs,生成.bin: $(call Image/mkfs/squashfs). 29

7.6.Openwrt_SDK中Makefile相關總結… 31

7.6.1CURDIR變量… 31

7.6.2空格的表示方法:… 31

7.6.3調用makefile中的函數… 31

7.6.4.其他相關內容… 32

8.軟件包Makefile解析… 35

include $(TOPDIR)/rules.mk. 36

自定義 PKG_XXXX 變量… 37

include $(INCLUDE_DIR)/package.mk. 38

(1)它會配置默認的變量… 38

(2)推導其它變量… 39

(3)包含其它mk文件… 40

(4)定義默認宏… 40

(5)BuildPackage宏… 41

自定義宏… 42

必須定義的宏… 42

可選定義的宏… 43

使之生效… 46

參考資料… 46

 

 

 

 

 

 

1.OpenWRT虛擬系統準備

環境:

編譯服務器:Ubuntu-14.04-desktop

虛擬機軟件:VMWare-10.0

編譯環境準備:apt-get install subversion build-essential libncurses5-dev zlib1g-dev gawk git ccache gettext libssl-dev xsltproc flex gcc-multilib

 

1.1.編譯openwrt虛擬機系統

1.1.1 準備源碼

#cd /home/nickli/

#mkdir openwrt_SDK

#cd openwrt_SDK

#svn checkout

svn://svn.openwrt.org/openwrt/branches/barrier_breaker

1.1.2 準備源碼包

#cd barrier_breaker

#mkdir dl

#cp -r /home/public/openwrt_dl/* ./dl/

 

之前已經將幾乎所有的編譯時需要下載的源碼包下載到了/home/public/openwrt_dl 目錄下,所以爲減少編譯時間直接將該目錄鏈接到新的SDK中。

1.1.3 編譯配置

#make defconfig

#make prereq

#make menuconfig   //配置系統編譯選單時需注意以下幾點:

  • 系統目標平臺選擇爲x86
  • 目標文件爲虛擬機文件***.vmdk
  • 選擇c庫(uClibc/eglibc/glibc……)
  • 配置系統所需的基本配置比如adduser/addgroup/su等命令(basesystem/busybox)

退出配置單並保存。

1.1.4 編譯

#make V=99

完成以後鏡像文件“openwrt-x86-generic-combined-squashfs.vmdk”存在於bin/x86/目錄下,將該文件拷貝到windows下如F:/template/下。

 

1.2.安裝虛擬機

1.2.1.新建虛擬機

 

下一步

選擇稍後安裝操作系統

客戶及操作系統選擇Linux,版本選擇“其他Linux 2.6.x內核”

爲虛擬機命名,並選擇之前鏡像存放的路徑作爲虛擬機存放路徑

點擊繼續

Cpu/memory等信息保持默認,點擊下一步即可:

內存選擇512足夠了:

選擇橋接:

保持默認,點擊下一步

選擇硬盤類型爲IDE:

創建新磁盤:

設置磁盤大小10G:

 

然後一路默認,點擊“下一步”直到結束。

 

1.2.2.修改虛擬機配置文件:

進入以上放置虛擬機的目錄,並找後綴爲vmx的文件,使用記事本打開,將以下途中表示的虛擬機名字修改成第一步中編譯出來,保存在本地的那個系統鏡像名稱:

修改完成後保存退出。

在vmware中啓動剛剛新建的虛擬機“smartRouter_4x4”

 

2.配置使用

2.1.設置root密碼

#passwd

兩次輸入密碼即可

重啓系統即可

2.2.網絡配置

#vi /etc/config/network

 

保存退出,後重啓網絡:

#/etc/init.d/network restart

#ifconfig  br-lan

以上紅色標註處顯示修改成功。

 

2.3.關於ssh

OpenWrt 中默認自帶的 SSH 服務端和客戶端是 Dropbear

使用ssh代理方法,實現自動登錄ssh,類似於convirt節點管理方法:

http://talk.withme.me/?p=210#codesyntax_1

 

3.軟件安裝方法

3.1.本地安裝ipk軟件包

使用命令:opkg install softwall.ipk

例如:安裝sftp

首先下載軟件:

#cd /root

#wget http://downloads.openwrt.org/backfire/10.03.1/x86_generic/packages/openssh-sftp-server_5.8p2-2_x86.ipk

# opkg install openssh-sftp-server_5.8p2-2_x86.ipk

Installing openssh-sftp-server (5.8p2-2) to root…

Configuring openssh-sftp-server.

 

3.2.在線安裝軟件及設置

3.2.1.設置軟件源

#vim /etc/opkg.conf

內容如下:

dest root /

dest ram /tmp

lists_dir ext /var/opkg-lists

option overlay_root /overlay

src/gz barrier_breaker_basehttp://downloads.openwrt.org/barrier_breaker/14.07/x86/generic/packages/base

最後一行url爲實際可以下載到ipk的地址,配置好後才能使用在線安裝功能。

 

3.2.2.安裝軟件

更新可用ipk軟件包列表:

#opkg update

查看所有ipk包列表:

#opkg list

#opkg install software.ipkg

安裝軟件:

#opkg install software.ipk

3.2.3.直接安裝

在3.1節中,描述的安裝本地軟件,實際上是先wget下載一個軟件到本地,然後再執行本地安裝,實際上可以直接使用opkg install URL的方式在線安裝。如下:

#opkg install http://downloads.openwrt.org/backfire/10.03.1/x86_generic/packages/openssh-sftp-server_5.8p2-2_x86.ipk

 

 

3.3.使用本地服務器做軟件源以安裝自定義軟件

安裝本地軟件有兩種方法:一種是將本地軟件scp到openwrt系統中,通過opkg安裝即可;第二種就是在本地服務器上搭建一個ftp服務器,然後在openwrt系統軟件源中添加該服務器的url,然後通過在線安裝的方式安裝本地服務器上製作的Ipk包。現就第二種方式做介紹。

3.3.1.在編譯服務器上配置vsftp服務器

2.11安裝ftp服務器

 

#sudo apt-get install vsftpd

# sudo gedit /etc/vsftpd.conf

原文件中不少指令被註釋,只要啓用部分即可,一下是啓用的命令(配置文件中對每一條都有具體說明)

listen=YES       # 服務器監聽

anonymous_enable=YES       # 匿名訪問允許

local_enable=YES    # 本地主機訪問允許

write_enable=YES    # 寫允許

anon_upload_enable=YES

# 匿名上傳允許,默認是NO,嫌麻煩的可以開起來。出了問題我不負責~

anon_mkdir_write_enable=YES  # 匿名創建文件夾允許

dirmessage_enable=YES  # 進入文件夾允許

xferlog_enable=YES   #  ftp 日誌記錄允許

connect_from_port_20=YES     # 允許使用20號端口作爲數據傳送的端口

secure_chroot_dir=/var/run/vsftpd/empty

pam_service_name=vsftpd

rsa_cert_file=/etc/ssl/private/vsftpd.pem

保存。

 

創建匿名訪問目錄以供openwrt訪問

#mkdir /srv/ftp

修改ftp目錄權限:

#chmod 755 /srv/ftp

創建upload download目錄

#mkdir –p –m 777 /srv/ftp/upload

#mkdir –p –m 755 /srv/ftp/download

重啓vsftpd

#service vsftpd restart

然後將/home/nickli/openwrt_SDK/barrier_breaker/bin/x86/packages 目錄下所有的內容都拷貝到/srv/ftp/download目錄下:

#scp -r /home/nickli/openwrt_SDK/barrier_breaker/bin/x86/packages /srv/ftp/download/

 

默認情況下,每個用戶的家目錄會自動做爲vsftp服務的根目錄。也就是說使用用戶A的權限來訪問該ftp服務器時,其登錄到的ftp根目錄就是該用戶A在該ftp服務器寄存的這臺主機上自己的home目錄。

本文檔製作時服務器IP爲10.8.3.50的ubuntu-14.04系統,OpenWRT的SDK在/home/nickli/openwrt_SDK/barrier_breaker目錄下。編譯出來的所有成果在該目錄的bin目錄下。我們將使用編譯出的packages作爲最終的軟件源。

3.3.2.修改openwrt在線安裝軟件源

openwrt端修改opkg.conf,添加ftp服務器ipk包存在地址,註釋掉系統默認的url地址如下紅色標註,並添加綠色標註的文字:

src/gz barrier_breaker_base ftp://10.8.3.50/download/packages/base

(或者src/gz packages ftp://10.8.3.50/download/packages/base)

dest root /

dest ram /tmp

lists_dir ext /var/opkg-lists

option overlay_root /overlay

#src/gz barrier_breaker_base http://downloads.openwrt.org/barrier_breaker/14.07/x86/generic/packages/base

3.3.3更新opkg

#opkg update

若無錯誤提示,則表示可以正常使用opkg從ftp下載ipk包了。

 

3.3.3.通過命令安裝ipk軟件

#opkg install software.ipk

 

 

4.openwrt SDK源碼目錄結構

4.1.源碼下載

OpenWrt的源代碼管理默認用的是SVN下載:

svn co svn://svn.openwrt.org/openwrt/trunk/ .

還可以用Git下載:

git clone git://git.openwrt.org/openwrt.git

git clone git://git.openwrt.org/packages.git

參考方法:https://dev.openwrt.org/wiki/GetSource

 

4.2.OpenWRT的feeds

包括:

packages – 提供衆多庫, 工具等基本功能. 也是其他feed所依賴的軟件源, 因此在安裝其他feed前一定要先安裝packages!

luci – OpenWrt默認的GUI(WEB管理界面).

xwrt – 另一種可替換LuCI的GUI

qpe – DreamBox維護的基於Qt的圖形界面, 包含Qt2, Qt4, Qtopia, OPIE, SMPlayer等衆多圖形界面.

device – DreamBox維護與硬件密切相關的軟件, 如uboot, qemu等.

dreambox_packages – DreamBox維護的國內常用網絡工具, 如oh3c, njit8021xclient等.

desktop – OpenWrt用於桌面的一些軟件包.

xfce – 基於Xorg的著名輕量級桌面環境. Xfce建基在GTK+2.x之上, 它使用Xfwm作爲窗口管理器.

efl – 針對enlightenment.

phone -針對fso, paroli.

 

trunk中默認的feeds下載有packages、xwrt、luci、routing、telephony。如要下載其他的軟件包,需打開源碼根目錄下面的feeds.conf.default文件,去掉相應軟件包前面的#號,然後更新源:

./scripts/feeds update -a

安裝下載好的包:

./scripts/feeds install -a

4.3.OpenWrt源碼目錄結構

 

toolstoolchain目錄:包含了一些通用命令, 用來生成固件, 編譯器, 和C庫.

build dir/host目錄:是一個臨時目錄, 用來儲存不依賴於目標平臺的工具.

build dir/toolchain-目錄:用來儲存依賴於指定平臺的編譯鏈. 只是編譯文件存放目錄無需修改.

build dir/target-目錄:用來儲存依賴於指定平臺的軟件包的編譯文件, 其中包括linux內核, u-boot, packages, 只是編譯文件存放目錄無需修改.

staging_dir目錄:是編譯目標的最終安裝位置, 其中包括rootfs, package, toolchain.

package目錄:軟件包的下載編譯規則, 在OpenWrt固件中, 幾乎所有東西都是.ipk, 這樣就可以很方便的安裝和卸載.

target目錄:目標系統指嵌入式設備, 針對不同的平臺有不同的特性, 針對這些特性, “target/linux”目錄下按照平臺進行目錄劃分, 裏面包括了針對標準內核的補丁, 特殊配置等.

bin目錄:編譯完OpenWrt的二進制文件生成目錄, 其中包括sdk, uImage, u-boot, dts, rootfs構建一個嵌入式系統完整的二進制文件.

config目錄:存放着整個系統的的配置文件.

docs目錄:裏面不斷包含了整個宿主機的文件源碼的介紹, 裏面還有Makefile爲目標系統生成docs.

include目錄:裏面包括了整個系統的編譯需要的頭文件, 但是是以Make進行連接的.

feeds目錄:擴展軟件包索引目錄.

scripts目錄:組織編譯整個OpenWrt的規則.

tmp目錄:編譯文件夾, 一般情況爲空.

dl目錄:所有軟件的下載目錄, 包括u-boot, kernel.

logs目錄:如果編譯出錯, 可以在這裏找到編譯出錯的log.

4.4.基本命令介紹

#./scripts/feeds update -a

#./scripts/feeds install -a

#make prereq //該命令可以檢查SDK中target內是否有存在錯誤的Makefile。

#make defconfig

#make menuconfig

#make kernel_config

#make V=99

#make package/pacakge_name/{clean,prepare,compile,install} V=99

 

5.用戶層模塊開發方法

5.1.SDK準備

請參考:4.1小節內容。

5.2.添加模塊代碼

例如添加模塊名字加hello,其目錄樹如下:

hello

├── files     ———————–文件夾:存放文件如:服務配置文件/啓動腳本等

├── Makefile ————————文件:打包相關的Makefile

└── src      ———————–文件夾:存放模塊源碼文件

├── hello.c ———————文件:源代碼

└── Makefile ——————文件:源碼編譯用的Makefile

5.3.模塊程序源代碼

#include<stdio.h>

int main ()

{

printf(“hello world!\n”);

return 0;

}

5.4.源碼編譯Makefile

hello:hello.o

$(CC) -o $@ $^

hello.o:hello.c

$(CC) -c $<

clean:

rm -rf *.o hello

5.5.ipK包製作規則Makefile

 

#

# Copyright (C) 2006-2010 OpenWrt.org

#

# This is free software, licensed under the GNU General Public License v2.

# See /LICENSE for more information.

#

include $(TOPDIR)/rules.mk

PKG_NAME:=hello

PKG_VERSION:=1.0

PKG_RELEASE:=1.0

 

PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)

 

include $(INCLUDE_DIR)/package.mk

define Package/hello

SECTION:=libs

CATEGORY:=Libraries

TITLE:=hello

endef

define Build/Prepare

mkdir -p $(PKG_BUILD_DIR)

$(CP) ./src/* $(PKG_BUILD_DIR)/

endef

define Package/hello/description

the hello is the base utils of the skysoft’s smartrouter

endef

define Package/hello/install

$(INSTALL_DIR)  $(1)/usr/lib/

$(CP) $(PKG_BUILD_DIR)/hello.so* $(1)/usr/lib/

endef

$(eval $(call BuildPackage,hello))

注意以上紅色標註部分文字須保持一致。

 

5.6.編譯模塊

$ make package/libs/hello/compile V=99

$ make package/libs/hello/clean

$ make package/skysoft_web_admin/{clean,prepare,compile} V=99

5.7.ipk包製作

加入install後會將編譯結果打包安裝到SDK目錄下bin目錄下相應位置。

$ make package/skysoft_web_admin/{clean,prepare,compile,install} V=99

 

 

5.8.安裝測試

編譯完成後在SDK目錄下的/bin/x86/package/base文件夾下回有hello*.ipk文件,將bin/x86/package整個目錄拷貝到ftp下載目錄/srv/ftp/download/下,採用在openwrt在線安裝的方式,或者直接遠程拷貝到目標openwrt系統中安裝。

 

 

 

 

 

 

 

6.內核模塊開發方法

OpenWrt開發內核驅動有多種方式,前面講到的製作內核補丁也是一種開發方法。這裏介紹直接在OpenWrt系統上開發內核驅動,把內核驅動做成ipk軟件包的形式。

6.1.建立工作目錄

$cd  openwrt/trunk/package

$mkdir example

 

6.2.進入example目錄,創建Makefile文件和代碼路徑

$cd example

$mkdir src

$vim Makefile

文件內容如下:

# Kernel module example

include $(TOPDIR)/rules.mk

include $(INCLUDE_DIR)/kernel.mk

PKG_NAME:=example

PKG_RELEASE:=1

include $(INCLUDE_DIR)/package.mk

define KernelPackage/example

  SUBMENU:=Other modules

  DEPENDS:=@TARGET_octeon

  TITLE:=Support Module for example

  AUTOLOAD:=$(call AutoLoad,81,example)

  FILES:=$(PKG_BUILD_DIR)/example/example.$(LINUX_KMOD_SUFFIX)

endef

define Build/Prepare

  mkdir -p $(PKG_BUILD_DIR)

  $(CP) -R ./src/* $(PKG_BUILD_DIR)/

endef

define Build/Compile

  $(MAKE) -C “$(LINUX_DIR)” \

    CROSS_COMPILE=”$(TARGET_CROSS)” \

    ARCH=”$(LINUX_KARCH)” \

    SUBDIRS=”$(PKG_BUILD_DIR)/example” \

    EXTRA_CFLAGS=”-g $(BUILDFLAGS)” \

    modules

endef

$(eval $(call KernelPackage,example))

 

註釋:AUTOLOAD:定義了內核模塊開機自動掛載的動作,$(call AutoLoad,81,example),表示當系統啓動時名叫“example”的內核模塊會在順序爲第81的位置加載到系統中,不必每次啓動系統後手動的去insmod加載模塊。如果正常,本模塊ipk包製作好並安裝到目標系統中後,會在目標系統的/etc/modules.d/目錄下創建一份名叫81-example的加載序列文件,其內容爲example。而本ipk安裝後會在/lib/moudules/$(KERNEL-VERSION)/目錄下放置example.ko文件。而如果本軟件包包含了多個內核模塊文件,比如多個“.ko”文件,那麼在這個位置就要加入多個模塊名,模塊名之間以“空格”隔開,如下例: 

define KernelPackage/exfat

  SUBMENU:=Other modules

  TITLE:=exfat driver

  DEPENDS:=+kmod-nls-base @BUILD_PATENTED

  FILES:=$(PKG_BUILD_DIR)/*.$(LINUX_KMOD_SUFFIX)

  AUTOLOAD:=$(call AutoLoad,82,exfat_core exfat_fs)

  KCONFIG:=

endef

定義的模塊名稱爲exfat,其內部有兩個內核文件需要添加,分別爲exfat_core.ko,exfat_fs.ko。

 

6.3.進入src目錄,創建代碼路徑和相關源文件

$cd src

$mkdir example

$cd example

$vim example.c

編輯內容如下:

#include <linux/init.h>

#include <linux/module.h>

#include <linux/kernel.h>

/* hello_init —- 初始化函數,當模塊裝載時被調用,如果成功裝載返回0 否則返回非0值 */

static int __init hello_init(void)

{

   printk(“I bear a charmed life.\n”);

   return 0;

}

/ * hello_exit —- 退出函數,當模塊卸載時被調用 */

static void __exit hello_exit(void)

{

   printk(“Out, out, brief candle\n”);

}

module_init(hello_init);

module_exit(hello_exit);

MODULE_LICENSE(“GPL”);

MODULE_AUTHOR(“Pillar_zuo”);

vim Kconfig

config EXAMPLE

  tristate “Just a example”

  default n

  help

   This is a example, for debugging kernel model.

   If unsure, say N.

保存並退出。

增加源碼編譯Makefile:

$vim Makefile

內容如下:

obj-m := example.o

 

6.4.回到OpenWrt源碼根目錄下

$make menuconfig

  Kernel modules —>

    Other modules —>

      kmod-example

選項設置爲M,保存退出

然後編譯該模塊:

$make package/example/compile

$make package/index

 

6.5.在OpenWrt系統裏面就可以用opkg下載使用了。

方法參考第三節內容。

7.openwrt Makefile框架分析

本節原文地址:http://www.cnblogs.com/sammei/p/3968916.html

本篇的主要目的是想通過分析Makefile,瞭解openwrt編譯過程。着重關注以下幾點:

  • openwrt目錄結構
  • 主Makefile的解析過程,各子目錄的目標生成
  • kernel編譯過程
  • firmware的生成過程
  • 軟件包的編譯過程

7.1.openwrt目錄結構

官方源下載速度太慢,我從github上clone了openwrt的代碼倉庫。

git clone https://github.com/openwrt-mirror/openwrt.git

openwrt目錄結構

 

上圖是openwrt目錄結構,其中第一行是原始目錄,第二行是編譯過程中生成的目錄。各目錄的作用是:

 

tools – 編譯時需要一些工具, tools裏包含了獲取和編譯這些工具的命令。裏面是一些Makefile,有的可能還有patch。每個Makefile裏都有一句 $(eval $(call HostBuild)),表示編譯這個工具是爲了在主機上使用的。

toolchain – 包含一些命令去獲取kernel headers, C library, bin-utils, compiler, debugger

target – 各平臺在這個目錄裏定義了firmware和kernel的編譯過程。

package – 包含針對各個軟件包的Makefile。openwrt定義了一套Makefile模板,各軟件參照這個模板定義了自己的信息,如軟件包的版本、下載地址、編譯方式、安裝地址等。

include – openwrt的Makefile都存放在這裏。

scripts – 一些perl腳本,用於軟件包管理。

dl – 軟件包下載後都放到這個目錄裏

build_dir – 軟件包都解壓到build_dir/裏,然後在此編譯

staging_dir – 最終安裝目錄。tools, toolchain被安裝到這裏,rootfs也會放到這裏。例如puma_SDK中文件系統目錄爲:

/home/nickli/2015-Router_N01-PUMA_4x4/trunk/02.DevelopementRepository/04.Coding/qualcomm_sdk/qsdk/staging_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/root-ipq806x

feeds – 擴展軟件包索引目錄。

bin – 編譯完成之後,firmware和各ipk會放到此目錄下。

 

推薦閱讀官方資料OpenWrt Development Guide

OpenWrt_Dev_Tutorial

 

7.2.main Makefile

openwrt根目錄下的Makefile是執行make命令時的入口。從這裏開始分析。

 

world:

 

ifndef ($(OPENWRT_BUILD),1)

# 第一個邏輯

else

# 第二個邏輯

endif

上面這段是主Makefile的結構,可以得知:

 

執行make時,若無任何目標指定,則默認目標是world

執行make時,無參數指定,則會進入第一個邏輯。如果執行命令make OPENWRT_BUILD=1,則直接進入第二個邏輯。

編譯時一般直接使用make V=s -j5這樣的命令,不會指定OPENWRT_BUILD變量

 

第一個邏輯

override OPENWRT_BUILD=1

export OPENWRT_BUILD

更改了OPENWRT_BUILD變量的值。這裏起到的作用是下次執行make時,會進入到第二邏輯中。

 

toplevel.mk中的 %:: 解釋world目標的規則。

 

prereq:: prepare-tmpinfo .config

@+$(MAKE) -r -s tmp/.prereq-build $(PREP_MK)

@+$(NO_TRACE_MAKE) -r -s $@

%::

@+$(PREP_MK) $(NO_TRACE_MAKE) -r -s prereq

@( \

cp .config tmp/.config; \

./scripts/config/conf –defconfig=tmp/.config -w tmp/.config Config.in > /dev/null 2>&1; \

if ./scripts/kconfig.pl ‘>’ .config tmp/.config | grep -q CONFIG; then \

printf “$(_R)WARNING: your configuration is out of sync. Please run make menuconfig, oldconfig or defconfig!$(_N)\n” >&2; \

fi \

)

@+$(ULIMIT_FIX) $(SUBMAKE) -r $@

 

執行 make V=s 時,上面這段規則簡化爲:

 

prereq:: prepare-tmpinfo .config

@make -r -s tmp/.prereq-build

@make V=ss -r -s prereq

 

%::

@make V=s -r -s prereq

@make -w -r world

可見其中最終又執行了prereq和world目標,這兩個目標都會進入到第二邏輯中。

 

第二邏輯

首先就引入了target, package, tools, toolchain這四個關鍵目錄裏的Makefile文件

 

include target/Makefile

include package/Makefile

include tools/Makefile

include toolchain/Makefile

這些子目錄裏的Makefile使用include/subdir.mk裏定義的兩個函數來動態生成規則,這兩個函數是subdir和stampfile

 

stampfile

拿target/Makefile舉例:

 

(eval(call stampfile,$(curdir),target,prereq,.config))

 

會生成規則:

 

target/stamp-prereq:=$(STAGING_DIR)/stamp/.target_prereq

 

$$(target/stamp-prereq): $(TMP_DIR)/.build .config

@+$(SCRIPT_DIR)/timestamp.pl -n $$(target/stamp-prereq) target .config || \

make $$(target/flags-prereq) target/prereq

@mkdir -p $$$$(dirname $$(target/stamp-prereq))

@touch $$(target/stamp-prereq)

 

$$(if $(call debug,target,v),,.SILENT: $$(target/stamp-prereq))

 

.PRECIOUS: $$(target/stamp-prereq) # work around a make bug

 

target//clean:=target/stamp-prereq/clean

target/stamp-prereq/clean: FORCE

@rm -f $$(target/stamp-prereq)

所以可以簡單的看作: (eval(call stampfile,(curdir),target,prereq,.config))生成了目標(target/stamp-prereq)

 

對於target分別生成了:(target/stamp−preq),(target/stamp-copile), $(target/stamp-install)

toolchain : $(toolchain/stamp-install)

package : (package/stamp−preq),(package/stamp-cleanup), (package/stamp−compile),(package/stamp-install)

tools : $(tools/stamp-install)

OpenWrt的主Makefile工作過程

 

subdir

subdir這個函數寫了一大堆東西,看起來很複雜 。

 

$(call subdir, target) 會遍歷下的子目錄,執行 make -C 操作。這樣就切入子目錄中去了。

 

目錄變量

幾個重要的目錄路徑:

 

KERNEL_BUILD_DIR

build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7620a/linux-3.14.18

 

LINUX_DIR

build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7620a/linux-3.14.18

 

KDIR

build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7620a

 

BIN_DIR

bin/ramips

 

Makefile中包含了rules.mk, target.mk等.mk文件,這些文件中定義了許多變量,有些是路徑相關的,有些是軟件相關的。這些變量在整個Makefile工程中經常被用到,

 

TARGET_ROOTFS_DIR

build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2

 

BUILD_DIR

build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2

 

STAGING_DIR_HOST

staging_dir/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2

 

TARGET_DIR

build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/root-ramips

 

7.3.kernel 編譯:

target/linux/ramips/Makefile: $(eval $(call BuildTarget))

target/linux/Makefile : export TARGET_BUILD=1

include/target.mk:

 

ifeq ($(TARGET_BUILD),1)

include $(INCLUDE_DIR)/kernel-build.mk

BuildTarget?=$(BuildKernel)

endif

BuildKernel是include/kernel-build.mk定義的一個多行變量,其中描述瞭如何編譯內核, 主要關注其中install規則的依賴鏈:

 

$(KERNEL_BUILD_DIR)/symtab.h: FORCE

rm -f $(KERNEL_BUILD_DIR)/symtab.h

touch $(KERNEL_BUILD_DIR)/symtab.h

+$(MAKE) $(KERNEL_MAKEOPTS) vmlinux

 

$(LINUX_DIR)/.image: $(STAMP_CONFIGURED) $(if $(CONFIG_STRIP_KERNEL_EXPORTS),$(KERNEL_BUILD_DIR)/symtab.h) FORCE

$(Kernel/CompileImage)

$(Kernel/CollectDebug)

touch $$@

 

 

install: $(LINUX_DIR)/.image

+$(MAKE) -C image compile install TARGET_BUILD=

  1. 觸發make vmlinux命令生成vmlinux: install –> $(LINUX_DIR)/.image –> $(KERNEL_BUILD_DIR)/symtab.h –> `$(MAKE) $(KERNEL_MAKEOPTS) vmlinux`

 

  1. 對vmlinux做objcopy, strip操作: $(LINUX_DIR)/.image –> $(Kernel/CompileImage) –> $(call Kernel/CompileImage/Default) –> $(call Kernel/CompileImage/Default)

 

$(KERNEL_CROSS)objcopy -O binary $(OBJCOPY_STRIP) -S $(LINUX_DIR)/vmlinux $(LINUX_KERNEL)$(1)

–> build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7620a/vmlinux

 

$(KERNEL_CROSS)objcopy $(OBJCOPY_STRIP) -S $(LINUX_DIR)/vmlinux $(KERNEL_BUILD_DIR)/vmlinux$(1).elf

–> build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7620a/vmlinux.elf

 

$(CP) $(LINUX_DIR)/vmlinux $(KERNEL_BUILD_DIR)/vmlinux.debug

–> build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7620a/vmlinux.debug

7.4.生成firmware

firmware由kernel和rootfs兩個部分組成,要對兩個部分先分別處理,然後再合併成一個.bin文件。先看一下這個流程。

 

“target/linux/ramips/image/Makefile” 文件中的最後一句:$(eval $(call BuildImage)),將BuildImage展開在這裏。BuildImage定義在 include/image.mk 文件中,其中定義了數個目標的規則。

 

define BuildImage

 

compile: compile-targets FORCE

**$(call Build/Compile)**

 

install: compile install-targets FORCE

$(call Image/BuildKernel) ## 處理vmlinux

$(call Image/mkfs/squashfs) ## 生成squashfs,並與vmlinux合併成一個.bin文件

 

endef

處理vmlinux: Image/BuildKernel

target/linux/ramips/image/Makefile:

 

define Image/BuildKernel

cp $(KDIR)/vmlinux.elf $(BIN_DIR)/$(VMLINUX).elf

cp $(KDIR)/vmlinux $(BIN_DIR)/$(VMLINUX).bin

$(call CompressLzma,$(KDIR)/vmlinux,$(KDIR)/vmlinux.bin.lzma)

$(call MkImage,lzma,$(KDIR)/vmlinux.bin.lzma,$(KDIR)/uImage.lzma)

cp $(KDIR)/uImage.lzma $(BIN_DIR)/$(UIMAGE).bin

ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),)

cp $(KDIR)/vmlinux-initramfs.elf $(BIN_DIR)/$(VMLINUX)-initramfs.elf

cp $(KDIR)/vmlinux-initramfs $(BIN_DIR)/$(VMLINUX)-initramfs.bin

$(call CompressLzma,$(KDIR)/vmlinux-initramfs,$(KDIR)/vmlinux-initramfs.bin.lzma)

$(call MkImage,lzma,$(KDIR)/vmlinux-initramfs.bin.lzma,$(KDIR)/uImage-initramfs.lzma)

cp $(KDIR)/uImage-initramfs.lzma $(BIN_DIR)/$(UIMAGE)-initramfs.bin

endif

$(call Image/Build/Initramfs)

endef

lzma壓縮內核

build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7620a/ 目錄中:

 

lzma e vmlinux -lc1 -lp2 -pb2 vmlinux.bin.lzma

MkImage

build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7620a/ 目錄中:

 

mkimage -A mips -O linux -T  kernel -C lzma -a 0x80000000 -e 0x80000000 -n “MIPS OpenWrt Linux-3.14.18” -d vmlinux.bin.lzma uImage.lzma

copy

VMLINUX:=$(IMG_PREFIX)-vmlinux –> openwrt-ramips-mt7620a-vmlinux

UIMAGE:=$(IMG_PREFIX)-uImage –> openwrt-ramips-mt7620a-uImage

cp $(KDIR)/uImage.lzma $(BIN_DIR)/$(UIMAGE).bin

把uImage.lzma複製到bin/ramips/目錄下:

cp $(KDIR)/uImage.lzma bin/ramips/openwrt-ramips-mt7620a-uImage

 

7.5.製作squashfs,生成.bin: $(call Image/mkfs/squashfs)

define Image/mkfs/squashfs

@mkdir -p $(TARGET_DIR)/overlay

$(STAGING_DIR_HOST)/bin/mksquashfs4 $(TARGET_DIR) $(KDIR)/root.squashfs -nopad -noappend -root-owned -comp $(SQUASHFSCOMP) $(SQUASHFSOPT) -processors $(if $(CONFIG_PKG_BUILD_JOBS),$(CONFIG_PKG_BUILD_JOBS),1)

$(call Image/Build,squashfs)

endif

mkdir -p $(TARGET_DIR)/overlay

mkdir -p build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/root-ramips/overlay

 

mksquashfs4

$(STAGING_DIR_HOST)/bin/mksquashfs4 $(TARGET_DIR) $(KDIR)/root.squashfs -nopad -noappend -root-owned -comp $(SQUASHFSCOMP) $(SQUASHFSOPT) -processors $(if $(CONFIG_PKG_BUILD_JOBS),$(CONFIG_PKG_BUILD_JOBS),1)

製作squashfs文件系統,生成root.squashfs:

 

mksquashfs4 root-ramips root.squashfs -nopad -noappend -root-owned -comp gzip -b 256k -p ‘/dev d 755 0 0’ -p ‘/dev/console c 600 0 0 5 1’ -processors 1

$(call Image/Build,squashfs)

在 target/linux/ramips/image/Makefile 中:

 

define Image/Build

$(call Image/Build/$(1))

dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) bs=128k conv=sync

$(call Image/Build/Profile/$(PROFILE),$(1))

endef

dd if=(KDIR)/root.squashfsof=(BIN_DIR)/$(IMG_PREFIX)-root.squashfs bs=128k conv=sync

dd if=build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7620a/root.squashfs of=bin/ramips/openwrt-ramips-mt7620-root.squashfs bs=128k conv=sync

 

(callImage/Build/Profile/(PROFILE),squashfs)

target/linux/ramips/mt7620a/profiles/00-default.mk, 中調用 Profile 函數:$(eval $(call Profile,Default))

 

include/target.mk 中定義了 Profile 函數, 其中令 PROFILE=Default

 

define Image/Build/Profile/Default

$(call Image/Build/Profile/MT7620a,$(1))

endef

規則依賴序列如下:

 

$(call Image/Build/Profile/$(PROFILE),squashfs)

–> $(call BuildFirmware/Default8M/squashfs,squashfs,mt7620a,MT7620a)

–> $(call BuildFirmware/OF,squashfs,mt7620a,MT7620a,8060928)

–> $(call MkImageLzmaDtb,mt7620a,MT7620a)

–> $(call PatchKernelLzmaDtb,mt7620a,MT7620a)

–> $(call MkImage,lzma,$(KDIR)/vmlinux-mt7620a.bin.lzma,$(KDIR)/vmlinux-mt7620a.uImage)

–> $(call MkImageSysupgrade/squashfs,squashfs,mt7620a,8060928)

其中的主要步驟:

 

複製: cp (KDIR)/vmlinux(KDIR)/vmlinux-mt7620a

生成dtb文件: (LINUXDIR)/scripts/dtc/dtc−Odtb−o(KDIR)/MT7620a.dtb ../dts/MT7620a.dts

將內核與dtb文件合併:(STAGINGDIRHOST)/bin/patch−dtb(KDIR)/vmlinux-mt7620a $(KDIR)/MT7620a.dtb

使用lzma壓縮:(callCompressLzma,(KDIR)/vmlinux-mt7620a,$(KDIR)/vmlinux-mt7620a.bin.lzma)

將lzma壓縮後的文件經過mkimage工具處理,即在頭部添加uboot可識別的信息。

接下來就是合併生成firmware固件了:

 

MkImageSysupgrade/squashfs, squashfs, mt7620a,8060928

 

cat vmlinux-mt7620a.uImage root.squashfs > openwrt-ramips-mt7620-mt7620a-squashfs-sysupgrade.bin

–> 製作squashfs bin文檔, 並確認它的大小 < 8060928 纔是有效的,否則報錯。

 

總結: 整個流程下來,其實最煩索的還是對內核生成文件vmlinux的操作,經過了objcopy, patch-dtb, lzma, mkimage 等過程生成一個uImage,再與mksquashfs工具製作的文件系統rootfs.squashfs合併。

 

 

 

 

7.6.Openwrt_SDK中Makefile相關總結

7.6.1CURDIR變量

在makefile中表示當前目錄,效果等同於shell命令pwd.

7.6.2空格的表示方法:

empty:=

space:=$(empty) $(empty)

在openwrtSDK中該變量用以檢查SDK目錄是否含有空格,要求所有路徑中不得有含空格的文件夾

7.6.3調用makefile中的函數

if判斷函數,用法:

$(if <condition>,<then-part>)

或者:

$(if <condition>,<then-part>,<else-part>)

findstring查找字符串函數,用法:

$(findstring <find>,<in>)在字串<in>中查找<find>字串

 

error控制makefile運行的函數,用法:

7.6.4.其他相關內容

2.1make 的參數

-i 或者”–ignore-errors”:忽略Makefile中所有的命令錯誤;

-k或者“–keep-going“:終止出錯命令,但繼續執行其他命令;

-w或者”–print-directory“:嵌套執行make時,會輸出當前工作目錄信息,該選項的反作用項是”-s“;

2.2嵌套執行make

我們有一個子目錄叫 subdir,這個目錄下有個 Makefile 文件,來指明瞭這個目錄下文件的編譯規則。那麼我們總控的 Makefile 可以這樣書寫:

subsystem:

cd subdir && $(MAKE)

其等價於:

subsystem:

$(MAKE) -C subdir

定義$(MAKE)宏變量的意思是,也許我們的 make 需要一些參數,所以定義成一個變量比較利於維護。這兩個例子的意思都是先進入“subdir”目錄,然後執行 make 命令。

我們把這個 Makefile 叫做“總控 Makefile”,總控 Makefile 的變量可以傳遞到下級的 Makefile 中(如果你顯示的聲明),但是不會覆蓋下層的 Makefile 中所定義的變量,除非指定了“-e”參數。

如果你要傳遞變量到下級 Makefile 中,那麼你可以使用這樣的聲明:

export <variable …>

如果你不想讓某些變量傳遞到下級 Makefile 中,那麼你可以這樣聲明:

unexport <variable …>

2.在package目錄中的Makefile:

    2.1.call函數

call 函數是唯一一個可以用來創建新的參數化的函數。你可以寫一個非常複雜的表達式,這個表達式中,你可以定義許多參數,然後你可以用 call 函數來向這個表達式傳遞參數。其語法是:

 

$(call <expression>,<parm1>,<parm2>,<parm3>…)

 

當 make 執行這個函數時,<expression>參數中的變量,如$(1),$(2),$(3)等,會被參數<parm1>,<parm2>,<parm3>依次取代。而<expression>的返回值就是 call 函數的返回值。

    2.2.eval函數

函數“eval”是一個比較特殊的函數。使用它可以在Makefile中構造一個可變的規則結構關係(依賴關係鏈),其中可以使用其它變量和函數。

函數“eval”對它的參數進行展開,展開的結果作爲Makefile的一部分,make可以對展開內容進行語法解析。展開的結果可以包含一個新變量、目標、隱含規則或者是明確規則等。也就是說此函數的功能主要是:根據其參數的關係、結構,對它們進行替換展開。

Ø        返回值:函數“eval”的返回值是空,也可以說沒有返回值。

Ø        函數說明:“eval”函數執行時會對它的參數進行兩次展開。第一次展開過程發是由函數本身完成的,第二次是函數展開後的結果被作爲Makefile內容時由make解析時展開的。明確這一過程對於使用“eval”函數非常重要。理解了函數“eval”二次展開的過程後。實際使用時,如果在函數的展開結果中存在引用(格式爲:$(x)),那麼在函數的參數中應該使用“$$”來代替“$”。因爲這一點,所以通常它的參數中會使用函數“value”來取一個變量的文本值。

我們看一個例子。例子看起來似乎非常複雜,因爲它綜合了其它的一些概念和函數。不過我們可以考慮兩點:其一,通常實際一個模板的定義可能比例子中的更爲複雜;其二,我們可以實現一個複雜通用的模板,在所有Makefile中包含它,亦可作到一勞永逸。相信這一點可能是大多數程序員所推崇的。

示例:

 

# sample Makefile

 

PROGRAMS    = server client

    

 server_OBJS = server.o server_priv.o server_access.o

server_LIBS = priv protocol

    

client_OBJS = client.o client_api.o client_mem.o

client_LIBS = protocol

    

 # Everything after this is generic

.PHONY: all

all: $(PROGRAMS)

    

 define PROGRAM_template

$(1): $$($(1)_OBJ) $$($(1)_LIBS:%=-l%)

   ALL_OBJS   += $$($(1)_OBJS)

endef

    

                $(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))

    

                $(PROGRAMS):

                $(LINK.o) $^ $(LDLIBS) -o $@

    

                clean:

                rm -f $(ALL_OBJS) $(PROGRAMS)

 

來看一下這個例子:它實現的功能是完成“PROGRAMS”的編譯鏈接。例子中“$(LINK.o)”爲“$(CC) $(LDFLAGS)”,意思是對所有的.o文件和指定的庫文件進行鏈接。

                “$(foreach prog,$(PROGRAM),$(eval $(call PROGRAM_template,$(prog))))”展開爲:

                server : $(server_OBJS) –l$(server_LIBS)

                client : $(client_OBJS) –l$(client_LIBS)

 

8.軟件包Makefile解析

上面一篇博文中,博主嘗試創建一個非常簡單的helloworld包,過程詳見博文:http://my.oschina.net/hevakelcj/blog/410633

本文將帶大家一起深入地學習一下OpenWrt包的 Makefile。我們不僅要知其然,還要知其所以然。在上篇博文裏,包裏的 Makefile 內容如下:

 

include $(TOPDIR)/rules.mk

 

PKG_NAME:=helloworld

PKG_RELEASE:=1

PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)

 

include $(INCLUDE_DIR)/package.mk

 

define Package/helloworld

SECTION:=utils

CATEGORY:=Utilities

TITLE:=Helloworld — prints a snarky message

endef

 

define Package/helloworld/description

It’s my first package demo.

endef

 

define Build/Prepare

echo “Here is Package/Prepare”

mkdir -p $(PKG_BUILD_DIR)

$(CP) ./src/* $(PKG_BUILD_DIR)/

endef

 

define Package/helloworld/install

echo “Here is Package/install”

$(INSTALL_DIR) $(1)/bin

$(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/bin/

endef

 

$(eval $(call BuildPackage,helloworld))

大概我們可以將簡代爲如下的結構:

 

include $(TOPDIR)/rules.mk

 

# 這裏定義一系列的 PKG_XX

 

include $(INCLUDE_DIR)/package.mk

 

# 定義各種 Package, Build 宏

 

$(eval $(call BuildPackage,包名))

下面,我們來一一拆解。

 

8.1.include $(TOPDIR)/rules.mk

首先,include $(TOPDIR)/rules.mk,也就是將 SDK/rules.mk 文件中的內容導入進來。

TOPDIR就是SDK的路徑。

在 SDK/rules.mk 文件中,定義了許多變量。

我們可以看出,在Makefile中,賦值是用 := ,而不是等號。

比如上面的 BUILD_DIR, INCLUDE_DIR 等,都在這裏定義。還有:

還有關於 TARGET_CC, TARGET_CXX 等非常有用的變量定義。

還有 TAR, FIND, INSTALL_BIN, INSTALL_DIR, INSTALL_DATA等等非常重要的變量定義。

 

8.2.自定義 PKG_XXXX 變量

官網上指定有如下變量需要設置:

PKG_NAME        – The name of the package, as seen via menuconfig and ipkg

PKG_VERSION     – The upstream version number that we’re downloading

PKG_RELEASE     – The version of this package Makefile

PKG_LICENSE     – The license(s) the package is available under, SPDX form.

PKG_LICENSE_FILE- file containing the license text

PKG_BUILD_DIR   – Where to compile the package

PKG_SOURCE      – The filename of the original sources

PKG_SOURCE_URL- Where to download the sources from (directory)

PKG_MD5SUM      – A checksum to validate the download

PKG_CAT         – How to decompress the sources (zcat, bzcat, unzip)

PKG_BUILD_DEPENDS – Packages that need to be built before this package, but are not required at runtime. Uses the same syntax as DEPENDS below.

PKG_INSTALL     – Setting it to “1” will call the package’s original “make install” with prefix set to PKG_INSTALL_DIR

PKG_INSTALL_DIR – Where “make install” copies the compiled files

PKG_FIXUP       – ???

PKG_SOURCE_PROTO – the protocol to use for fetching the sources (git, svn)

PKG_REV         – the svn revision to use, must be specified if proto is “svn”

PKG_SOURCE_SUBDIR – must be specified if proto is “svn” or “git”, e.g. “PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)”

PKG_SOURCE_VERSION – must be specified if proto is “git”, the commit hash to check out

PKG_CONFIG_DEPENDS – specifies which config options depend on this package being selected

 

 

8.3.include $(INCLUDE_DIR)/package.mk

跟上面的 include $(TOPDIR)/rules.mk 是一樣的。就是把這個文件包含進來。

INCLUDE_DIR這個變量在 rules.mk 裏已經定義了:

那就是 SDK/include/package.mk 文件了,打開看看。

主要有以下幾個功能:

(1)它會配置默認的變量

如果某個變量我們沒有在上一部分裏定義,那裏在這個文件裏,它就會被指定爲默認值,比如:

上面的用 ?= 來表示給未定義的變量賦默認值。比如,如果沒有指定 PKG_MD5SUM,那麼就默認爲 unknow。

 

(2)推導其它變量

根據上部分用戶自定義的 PKG_XXXX 變量推導出更多相關的變量。

比如:

雖然我沒有看過相關的手冊,根據多年的從業經驗也能看出上面的意思來。

#如果定義了宏,就…

ifdef 宏名

endif

 

#如果宏相等

ifeq (宏1,宏2)

endif

 

strip $宏名     #將宏對應的值去除前後的空白字符

 

VAR += xxxx    #在變量 VAR 後面追加 xxxx

我猜大概就是這樣,如果不對請指正。

再比如如下:

就這樣,它爲我們提供了大量有價值的變量。

 

(3)包含其它mk文件

 

(4)定義默認宏

在 Makefile 中,宏的定義格式是:

define XXX/xxxx

<宏的實體…>

endef

 

package.mk會把大部分需要的宏都定義好。理想情況下,用戶只需要定義好了 PKG_XXX 之後,不需要再自定義宏,默認的宏就可以滿足需求。

比如Build/Prepare/Default的定義:

Build/Prepare宏是在編譯前進行的,是準備工作。

可以看出,它分了兩種情況:

A,定義了 USE_GIT_TREE,則按git的方式定義。

B,定義了 USB_SOURCE_DIR,則按源碼在本地的方案定義。

 

(5)BuildPackage宏

最重要的一個宏是 BuildPackage。它會在 Makefile 的最後一行被引用。它的實現也就是在 package.mk 文件裏。如下爲其源碼:

define BuildPackage

$(Build/IncludeOverlay)

$(eval $(Package/Default))    #定義在package-defaults.mk文件裏

$(eval $(Package/$(1)))       #調用用戶自定義的 Package/<包名> 宏

 

ifdef DESCRIPTION

$$(error DESCRIPTION:= is obsolete, use Package/PKG_NAME/description)

endif

 

#檢查有沒有定義 Package/<包名>/description宏,如果沒有定義,則以TITLE默認定義一個

ifndef Package/$(1)/description

define Package/$(1)/description

$(TITLE)

endef

endif

 

BUILD_PACKAGES += $(1)

$(STAMP_PREPARED): $$(if $(QUILT)$(DUMP),,$(call find_library_dependencies,$(DEPENDS)))

 

#檢查 TITLE, CATEGORY, SECTION, VERSION 是否定義,如果沒有定義則報錯

$(foreach FIELD, TITLE CATEGORY SECTION VERSION,

ifeq ($($(FIELD)),)

$$(error Package/$(1) is missing the $(FIELD) field)

endif

)

 

#如果有定義DUMP,那就引入Dumpinfo/Package宏的內部。

#如果沒有,那麼就引用 Packaget/<包名>/targets裏面的每一個target,如果沒有定義Packaget/<包名>/targets宏,那麼將PKG_TARGETS裏的每個target取出來,

#如果也沒有定義PKG_TARGETS,那就默認ipkg作爲target。將每一個target,引用 BuildTarget/$(target)。

$(if $(DUMP), \

$(Dumpinfo/Package), \

$(foreach target, \

$(if $(Package/$(1)/targets),$(Package/$(1)/targets), \

$(if $(PKG_TARGETS),$(PKG_TARGETS), ipkg) \

), $(BuildTarget/$(target)) \

) \

)

$(if $(PKG_HOST_ONLY)$(DUMP),,$(call Build/DefaultTargets,$(1)))

endef

總結一下語法:

$() 表示要執行的一條語句

$(if 條件, 成立執行, 失敗執行)        if條件分支

$(foreach 變量, 成員列表, 執行體)   成員遍歷語句

可以看出,語句是可以嵌套使用的。

$(N)  表示第N個參數

8.4.自定義宏

必須定義的宏

我定要爲我們的package定義特定的宏:

Package/<包名>    #包的參數

 

在 Package/<包名> 宏中定義與包相關的信息。

如Package/helloworld宏:

 

1

2

3

4

5

define Package/helloworld

SECTION:=utils

CATEGORY:=Utilities

TITLE:=Helloworld — prints a snarky message

endef

除了上面所列的 SECTION,CATEGORY,TITLE變量外,還可以定義:

SECTION     – 包的種類

CATEGORY    – 顯示在menuconfig的哪個目錄下

TITLE       –  簡單的介紹

DESCRIPTION – (deprecated) 對包詳細的介紹

URL – 源碼所在的網絡路徑

MAINTAINER  – (required for new packages) 維護者是誰(出錯了聯繫誰)

DEPENDS     – (optional) 需要依事的包,See below for the syntax.

USERID      – (optional) a username:groupname pair to create at package installation time.

 

【PKG_VERSION宏缺失時報錯】:

OpenWrt Developers Team <[email protected]>

@@

 

Makefile:53: *** Package/exfat is missing the VERSION field.  Stop.

可選定義的宏

其它的宏可以選擇性地定義,通常沒必要自己重寫。但有些情況,package.mk中默認的宏不能滿足我們的需求。這時,我們就需要自己重定義宏。

比如,我們在爲helloworld寫Makefile時,我們要求在編譯之前,將 SDK/package/helloworld/src/ 路徑下的文件複製到 PKG_BUILD_DIR 所指定的目錄下。

於是我們重新定義Build/Prepare宏:

?

1

2

3

4

define Build/Prepare

mkdir -p $(PKG_BUILD_DIR)

$(CP) ./src/* $(PKG_BUILD_DIR)/

endef

如此以來,在我們 make V=s 時,make工具會在編譯之前執行 Build/Prepare 宏裏的命令。

 

再比如,我們要指定包的安裝方法:

?

1

2

3

4

define Package/helloworld/install

$(INSTALL_DIR) $(1)/bin

$(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/bin/

endef

上面的這個宏就是指定了包的安裝過程。其中 INSTALL_DIR 定義在 rules.mk 文件裏。

INSTALL_DIR = install -d -m0755

INSTALL_BIN = install -m0755

$(1)爲第一個參數是./configure時的–prefix參數,通常爲””

展開之後就是:

define Package/helloworld/install

install -d -m0755 /bin

install -m0755 $(PKG_BUILD_DIR)/helloworld /bin/

endef

它的意思就一目瞭然了。

 

除了上面所列舉的這兩個宏外,在官網上也說明了其它可選的宏:

Package/conffiles (optional)

由該包安裝的配置文件的列表,一行一個文件。

 

Package/description

對包描述的純文本

 

Build/Prepare (optional)

A set of commands to unpack and patch the sources. You may safely leave this undefined.

 

Build/Configure (optional)

You can leave this undefined if the source doesn’t use configure or has a normal config script, otherwise you can put your own commands here or use “$(call Build/Configure/Default,)” as above to pass in additional arguments for a standard configure script.

 

Build/Compile (optional)

How to compile the source; in most cases you should leave this undefined, because then the default is used, which calls make. If you want to pass special arguments to make, use e.g. “$(call Build/Compile/Default,FOO=bar)

 

Build/Install (optional)

How to install the compiled source. The default is to call make install. Again, to pass special arguments or targets, use $(call Build/Install/Default,install install-foo) Note that you need put all the needed make arguments here. If you just need to add something to the “install” argument, don’t forget the ‘install’ itself.

 

Build/InstallDev (optional)

For things needed to compile packages against it (static libs, header files), but that are of no use on the target device.

 

Package/install

A set of commands to copy files into the ipkg which is represented by the $(1) directory. As source you can use relative paths which will install from the unpacked and compiled source, or $(PKG_INSTALL_DIR) which is where the files in the Build/Install step above end up.

 

Package/preinst

The actual text of the script which is to be executed before installation. Dont forget to include the #!/bin/sh. If you need to abort installation have the script return false.

 

Package/postinst

The actual text of the script which is to be executed after installation. Dont forget to include the #!/bin/sh.

 

Package/prerm

The actual text of the script which is to be executed before removal. Dont forget to include the #!/bin/sh. If you need to abort removal have the script return false.

 

Package/postrm

The actual text of the script which is to be executed after removal. Dont forget to include the #!/bin/sh.

 

之所以有些宏是以”Package/”開頭,有的又以”Build/”,是因爲在一個Makefile裏生成多個包。OpenWrt默認認爲一個Makefile裏定義一個包,但我們也可以根據需要將其拆分成多個。所以說,如果我們只希望編譯一次,那麼只要有一系列的”Build/”的宏定義就可以了。但是,我們也可以通過添加多個”Package/”宏定義,並調用 BuildPackage,來創建多個包。

 

8.5.使之生效

在Makefile的最後一行是:

$(eval $(call BuildPackage,helloworld))

最重要的 BuildPackage定義在 package.mk 文件裏。見上面 BuildPackage 宏定義。

8.6.添加新編譯選項

比如dibbler軟件包的編譯,需要編譯C++代碼,需要使用-Istdc++選項,可以在dibbler編譯Makefile中添加TAGET_CXXFLAGS +=-Istdc++ 即可。

 

9.openwrt主Makafile解析

其他相關參考:http://blog.csdn.net/suiyuan19840208/article/details/25737323/

原文地址:http://www.right.com.cn/forum/thread-73443-1-1.html

 

本文是本人對OpenWrt的Makefile的理解,並非轉載。
OpenWrt是一個典型的嵌入式Linux工程,瞭解OpenWrt的Makefile的工作過程對提高嵌入式Linux工程的開發能力有極其重要意義。
OpenWrt的主Makefile文件只有100行,可以簡單分爲三部分,1~17行爲前導部分,19~31爲首次執行部分,33~101爲再次執行部分。
前導部分
CURDIR爲make默認變量,默認值爲當前目錄。
前導部分主要把變量TOPDIR賦值爲當前目錄,把變量LC_ALL、LANG賦值爲C,並使用變量延伸指示符export,把上述三個變量延伸到下層Makefile。
使用文件使用指示符include引入$(TOPDIR)/include/host.mk。在OpenWrt的主Makefile文件使用了多次include指示符,說明主Makefile文件被拆分成多個文件,被拆分的文件放在不同的目錄。拆分的目的是明確各部分的功能,而且增加其靈活性。
在前導部分比較費解的是使用world目標,在makefile中基本規則爲:
TARGETS : PREREQUISITES
COMMAND

即makefile規則由目標、依賴、命令三部分組成,在OpenWrt的主Makefile文件的第一個目標world沒有依賴和命令。它主要起到指示當make命令不帶目標時所要執行的目標,沒有設定依賴和命令部分表明此目標在此後將會有其他依賴關係或命令。world目標的命令需要進一步參考$(TOPDIR)/include/toplevel.mk和主Makefile文件的再次執行部分。
首次執行部分
OPENWRT_BUILD是區分首次執行與再次執行的變量。在首次執行時使用強制賦值指示符override把OPENWRT_BUILD賦值爲1,並使用變量延伸指示符export把OPENWRT_BUILD延伸。在OPENWRT_BUILD使用強制賦值指示符override意味着make命令行可能引入OPENWRT_BUILD參數。
引入$(TOPDIR)/include/debug.mk、$(TOPDIR)/include/depends.mk、$(TOPDIR)/include/toplevel.mk三個文件,由於TOPDIR是固定的,所以三個文件也是固定的。其中$(TOPDIR)/include/toplevel.mk的135行%::有效解釋首次執行時world目標的規則。
再次執行部分
引入rules.mk、$(INCLUDE_DIR)/depends.mk、$(INCLUDE_DIR)/subdir.mk、target/Makefile、package/Makefile、tools/Makefile、toolchain/Makefile七個文件,rules.mk沒有目錄名,即引入與主Makefile文件目錄相同的rules.mk。在rules.mk定義了INCLUDE_DIR爲$(TOPDIR)/include,所以$(INCLUDE_DIR)/depends.mk實際上與首次執行時引入的$(TOPDIR)/include/depends.mk是同一個文件。
四個子目錄下的Makefile實際上是不能獨立執行。主要利用$(INCLUDE_DIR)/subdir.mk動態建立規則,諸如$(toolchain/stamp-install)目標是靠$(INCLUDE_DIR)/subdir.mk的stampfile函數動態建立。在package/Makefile動態建立了$(package/ stamp-prereq)、$(package/ stamp-cleanup)、$(package/ stamp-compile)、$(package/ stamp-install)、$(package/ stamp-rootfs-prepare)目標。
定義一些使用變量命名的目標,其變量的賦值位置在$(INCLUDE_DIR)/subdir.mk的stampfile函數中。目標只有依賴關係,可能說明其工作順序,在$(INCLUDE_DIR)/subdir.mk的stampfile函數中有進一步說明其目標執行的命令,併爲目標建立一個空文件,即使用變量命名的目標爲真實的文件。
定義一些使用固定的目標規則。
其中:clean是清除編譯結果的目標,清除$(BUILD_DIR) $(BIN_DIR) $(BUILD_LOG_DIR)三個目錄的用意是十分明確。暫時不知道爲什麼執行make target/linux/clean。
dirclean是刪除所有編譯過程產生的目錄和文件的目標,執行dirclean目標依賴於clean,因此將執行clean目標所執行的命令,然後刪除$(STAGING_DIR) $(STAGING_DIR_HOST) $(STAGING_DIR_TOOLCHAIN) $(TOOLCHAIN_DIR) $(BUILD_DIR_HOST) $(BUILD_DIR_TOOLCHAIN)目錄,以及刪除$(TMP_DIR)目錄。上述目錄的變量均在rules.mk定義。好像刪除staging_dir目錄就意味着刪除staging_dir目錄下的所有子目錄,不知道爲什麼要強調刪除$(STAGING_DIR_HOST) $(STAGING_DIR_TOOLCHAIN) $(TOOLCHAIN_DIR)目錄。同樣刪除builde_dir目錄就意味着刪除builde_dir目錄下的所有子目錄,不知道爲什麼要強調刪除$(BUILD_DIR_TOOLCHAIN)目錄。
tmp/.prereq_packages目標是對所需軟件包的預處理。目標依賴於.config,即執行make menuconfig後將會進行一次所需軟件包的預處理。不知什麼原因在編譯前刪除tmp目錄,執行時無法建立tmp/.prereq_packages文件。
prereq應該是預請求目標,在OpenWrt執行Makefile時好像都要先執行prereq目標。
prepare應該是準備目標,是world依賴的一個僞目標。依賴於文件.config和$(tools/stamp-install) $(toolchain/stamp-install)目標。
world就是編譯的目標。依賴於prepare爲目標和前面提到的變量命名目標。採用取消隱含規則方式執行package/index目標。package/index目標在package/Makefile的92行定義。
package/symlinks和package/symlinks-install是更新或安裝軟件包來源的目標,使用$(SCRIPT_DIR)/feeds腳本文件完成。
package/symlinks-clean是清除軟件包來源的目標,也是使用$(SCRIPT_DIR)/feeds腳本文件完成。
最後使用僞目標.PHONY說明clean dirclean prereq prepare world package/symlinks package/symlinks-install package/symlinks-clean屬於僞目標。通過僞目標說明可以知道可以執行的目標。

參考資料

Openwrt官網http://wiki.openwrt.org/start

軟件包相關:https://dev.openwrt.org/browser/branches/packages_10.03.2?order=name

關於包的依賴問題:http://wiki.openwrt.org/doc/devel/dependencies

 

 

 

問題記錄:

(1)【close】在移植exfat驅動到openwrt時遇到如下問題:

nickli@NewRouterDev:qsdk$ make package/exfat/{clean,prepare,compile,install} V=99

Collecting package info: done

make[1]: Entering directory `/home/nickli/puma_sdk/qualcomm_sdk/qsdk’

make[2]: Entering directory `/home/nickli/puma_sdk/qualcomm_sdk/qsdk/package/exfat’

Makefile:56: warning: overriding commands for target `/home/nickli/puma_sdk/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/exfat’

Makefile:56: warning: ignoring old commands for target `/home/nickli/puma_sdk/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/exfat’

Makefile:56: warning: overriding commands for target `/home/nickli/puma_sdk/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/exfat’

Makefile:56: warning: ignoring old commands for target `/home/nickli/puma_sdk/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/exfat’

rm -f /home/nickli/puma_sdk/qualcomm_sdk/qsdk/staging_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/stamp/.exfat _installed

bash: line 2: [: packages/exfat: binary operator expected

rm -f /home/nickli/puma_sdk/qualcomm_sdk/qsdk/bin/ipq806x/packages/exfat_*

rm -f /home/nickli/puma_sdk/qualcomm_sdk/qsdk/staging_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/packages/exfat .list /home/nickli/puma_sdk/qualcomm_sdk/qsdk/staging_dir/host/packages/exfat .list

rm -rf /home/nickli/puma_sdk/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/exfat

make[2]: Leaving directory `/home/nickli/puma_sdk/qualcomm_sdk/qsdk/package/exfat’

make[1]: Leaving directory `/home/nickli/puma_sdk/qualcomm_sdk/qsdk’

make[1]: Entering directory `/home/nickli/puma_sdk/qualcomm_sdk/qsdk’

make[2]: Entering directory `/home/nickli/puma_sdk/qualcomm_sdk/qsdk/package/exfat’

Makefile:56: *** target file `/home/nickli/puma_sdk/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/exfat’ has both : and :: entries.  Stop.

make[2]: Leaving directory `/home/nickli/puma_sdk/qualcomm_sdk/qsdk/package/exfat’

make[1]: *** [package/exfat/prepare] Error 2

make[1]: Leaving directory `/home/nickli/puma_sdk/qualcomm_sdk/qsdk’

make: *** [package/exfat/prepare] Error 2

問題原因:在Makefile中版本號變量後面多了個空格。

PKG_NAME:=exfat

PKG_VERSION:=0.9.5$space_char

PKG_RELEASE:=1

解決方法:將版本號後面的空格去掉

結果:問題解決。

參考:https://forum.openwrt.org/viewtopic.php?id=20353

 

(2)【close】SDK修改目錄名稱後無法繼續編譯問題解決

問題現象:check 了一份openwrt的SDK,執行編譯之後又重新修改了該SDK的名稱,導致後續再編譯時無法編譯。

原因:有些編譯器是動態編譯生成的,但是make clean之後編譯器不會重新編譯,其路徑與絕對路徑有關,修改名稱後無法找到相關編譯器。

解決方法:進入SDK根目錄執行make distclean,將所有編譯記錄完整清除即可。

結果:問題解決(應該有更加優化的方法,即刪除其中交叉編譯鏈相關內容,後續有時間再解決)

(3)【close】編譯單個模塊軟件時,提示缺少C庫

編譯單個模塊軟件時,在最後一步執行打包操作時提示缺少libc.so.6而無法打包,信息如下:

Package skysoft_net6scan is missing dependencies for the following libraries:

libc.so.6

原因:編譯單個模塊時,缺少目標平臺相同的libc.so.6文件。

解決方法:

參考:http://my.oschina.net/hevakelcj/blog/411944

真正解決問題的參考:http://www.cnblogs.com/liushannet/p/3895092.html

 

查看依賴文件:

nickli@NewRouterDev:qsdk$ readelf -d build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/skysoft_net6scan/net6scan

Dynamic section at offset 0x2e28 contains 24 entries:

Tag        Type                         Name/Value

0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

0x000000000000000c (INIT)               0x400c28

0x000000000000000d (FINI)               0x401ad0

0x0000000000000019 (INIT_ARRAY)         0x602e10

0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)

0x000000000000001a (FINI_ARRAY)         0x602e18

0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)

0x000000006ffffef5 (GNU_HASH)           0x400298

 

實際解決方法:

先檢查系統裏面有沒有這個庫存在,如果沒有,安裝 (在/lib /lib64 等目錄找)
之後添加庫openwrt的編譯環境
修改 libc.provides 平臺不同,可能目錄不同,find ./stagging_dir -name libc.provides 下
一般在 stagging_dir/target-mipsel_r2_uClibc-0.9.33.2/pkginfo/libc.provides
底部添加
libc.so.6
或其他需要的庫,編譯時候會把這個so轉爲openwrt平臺的庫

相關命令:

1332  find /lib* -name “libc.so.6”

1333  find ./staging_dir/ -name libc.provides

1334  vim ./staging_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/pkginfo/libc.provides

在該文件末尾添加libc.so.6後保存並退出,之後執行編譯:

1335  make package/skysoft_net6scan/{clean,prepare,compile,install} V=99

能正常打包了!

 

結果:問題解決。

(4)【close】編譯的模塊無法在opentwr系統中運行

root@rt4230w:~# /sbin/net6scan

/sbin/net6scan: line 1: syntax error: unexpected “(”

問題原因:在編譯的模塊Makefile中將編譯器寫死成了gcc,而實際上目標平臺爲arm需要使用交叉編譯器。

解決方法:修改源碼內的makefile,將gcc 改成$(CC),結果如下:

CFLAGS += -Wall -D_GNU_SOURCE

 

net6scan : main.o func.o

$(CC) $(CFLAGS) -o net6scan main.o func.o

main.o : main.c

$(CC) $(CFLAGS) -c main.c

func.o : func.c

$(CC) $(CFLAGS) -c func.c

clean:

rm -rf ip6scan *.o

 

結果:問題解決

(5)【close】在原odhcp6c源碼中增加了log.c log.h文件後,編譯時出現如下問題:

make[3]: Entering directory `/home/nickli/cascade_sdk_new_platform/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/odhcp6c-2015-07-13′

make[4]: Entering directory `/home/nickli/cascade_sdk_new_platform/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/odhcp6c-2015-07-13′

make[5]: Entering directory `/home/nickli/cascade_sdk_new_platform/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/odhcp6c-2015-07-13′

make[5]: Leaving directory `/home/nickli/cascade_sdk_new_platform/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/odhcp6c-2015-07-13′

make[5]: Entering directory `/home/nickli/cascade_sdk_new_platform/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/odhcp6c-2015-07-13′

[ 16%] Building C object CMakeFiles/odhcp6c.dir/src/odhcp6c.c.o

[ 33%] Building C object CMakeFiles/odhcp6c.dir/src/log.c.o

/home/nickli/cascade_sdk_new_platform/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/odhcp6c-2015-07-13/src/log.c: In function ‘_get_time’:

/home/nickli/cascade_sdk_new_platform/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/odhcp6c-2015-07-13/src/log.c:117:9: error: missing initializer [-Werror=missing-field-initializers]

/home/nickli/cascade_sdk_new_platform/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/odhcp6c-2015-07-13/src/log.c:117:9: error: (near initialization for ‘tv.tv_usec’) [-Werror=missing-field-initializers]

/home/nickli/cascade_sdk_new_platform/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/odhcp6c-2015-07-13/src/log.c:118:9: error: missing initializer [-Werror=missing-field-initializers]

/home/nickli/cascade_sdk_new_platform/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/odhcp6c-2015-07-13/src/log.c:118:9: error: (near initialization for ‘time_value.tm_min’) [-Werror=missing-field-initializers]

/home/nickli/cascade_sdk_new_platform/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/odhcp6c-2015-07-13/src/log.c: In function ‘debug_log_print’:

/home/nickli/cascade_sdk_new_platform/qualcomm_sdk/qsdk/build_dir/target-arm_v7-a_uClibc-0.9.33.2_eabi/odhcp6c-2015-07-13/src/log.c:140:51: error: comparison between signed and unsigned integer expressions [-Werror=sign-compare]

cc1: all warnings being treated as errors

分析:error: missing initializer [-Werror=missing-field-initializers],應該是編譯程序時將警告當錯誤了,提示這裏需要初始化,而實際上一時間沒有看出哪兒來執行正確的初始化,所以從取消掉這種警告機制着手解決。

解決辦法:修改編譯目錄內的(build_dirvim) CMakeLists.txt文件,將-Werror改爲-Wno-missing-field-initializers,如下:

8 #add_definitions(-D_GNU_SOURCE -Wall -Werror -Wextra -pedantic)

9 add_definitions(-D_GNU_SOURCE -Wall –Wno-missing-field-initializers -Wextra -pedantic)

結果:問題解決。

小結:

(1)-Werror 選線會將警告升級爲錯誤來報告

(2)odhcp6c源碼編譯採用了Cmake而沒有使用我們一般使用的方式——在src目錄內寫一份Makefile文件來編譯文件,所以其規則文件都在和src目錄同級的CMakeLists.txt文件中。可以學習瞭解一下CMake機制。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章