> For the complete documentation index, see [llms.txt](https://openwrt-nctu.gitbook.io/project/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://openwrt-nctu.gitbook.io/project/openwrt-compile-env/openwrt-cross-compiler.md).

# 建立編譯環境 (Cross Compiler)

## Cross Compiler 的建立

為了在 OpenWRT 上執行所設計的程式，我們需要建立 cross-compiler (toolchain) 來進行程式的編譯，為了建立此環境，我們選用 Ubuntu 12.04 以及 Ubuntu 16.04 作為 VM 的作業系統，並按照官網的步驟，建立 cross-compiler 的環境。詳細的步驟可以參考:

* <https://openwrt.org/docs/guide-developer/build-system/install-buildsystem>&#x20;
* <https://wiki.openwrt.org/doc/howto/buildroot.exigence>

**(1)** 在安裝好 Ubuntu 的 VM 上，一開始先取消 SED 的功能

```
$ unset SED
```

**(2)** 安裝需要的程式

```
$ sudo apt-get install build-essential subversion git-core libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr ecj cvs unzip
```

**(3)** 下載 OpenWRT 的環境。對於 AR300M 而言，這裡相對應的版本為15.05 branch (Chaos Calmer)。要注意的是，由於 Chaos Calmer 已不在主專案 (openwrt.git) 中， <https://dev.archive.openwrt.org/wiki/GetSource> 的指令是錯誤的。

```
$ git clone -b chaos_calmer git://github.com/openwrt/chaos_calmer.git
```

對於 AR750S，要下載 18.06 版的 OpenWRT，指令如下:

```
$ git clone git://github.com/openwrt/openwrt.git
```

由於一開始此操作文件是對 AR300M 製作，所以會以 Chaos Calmer 的版本為主。對於 AR750S 而言 (18.06)，以下提及 chaos\_clamer 的資料夾都會變成 openwrt，此資料夾的名稱和GIT專案中名稱一致。

{% hint style="info" %}
在使用 git 時，-b 指定不同的分支，而後面的網址代表不同專案。考慮到版本不斷演進，通常 openwrt.git 中只有最新的方案。
{% endhint %}

{% hint style="info" %}
\[2022 更新] 18.06 版本的指令改成:

git clone -b openwrt-18.06 <https://github.com/openwrt/openwrt.git>

和之前指令有兩個差別: 加入 branch name, git 只支援 https
{% endhint %}

**(4)** 透過 git 取得 OpenWRT 的資料後，會產生一個相對應的資料夾 (chaos\_calmer)，在此，先更新 OpenWRT 的對應檔案:

```
$ cd chaos_calmer
$ ./scripts/feeds update -a
$ ./scripts/feeds install -a
```

{% hint style="info" %}
如果遇到下列錯誤:fatal: unable to access '[https://my.git.com:port/user\\\_name/project.git/](https://openwrt-nctu.gitbook.io/project/openwrt-compile-env/https:/my.git.com:port/user\\_name/project.git)': server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none

可以使用指令:export GIT\_SSL\_NO\_VERIFY=1

來源:<https://cynthiachuang.github.io/Git-Https-Server-Certificate-Verification-Failed-Solution/>
{% endhint %}

**(5)** 接著，開始安裝 (make) 的準備

```
make menuconfig
```

{% hint style="info" %}
`Your display is too small to run Menuconfig!`

`It must be at least 19 lines by 80 columns.`

`make: *** [menuconfig] Error 1`

這裡會一個錯誤訊息，似乎是VM的螢幕顯示尺寸問題，由於需要開起圖形化介面，當使用VirtualBox進行操作時，顯示的解析度無法調動。因此，設定介面無法正確顯示。

在這邊我的解決方案為透過putty登入該VM，方法為:

1. 設定 NAT 網路，進行 port-port 的轉換。經過設定後，將12422 port 對應於 VM 的 22 port。
2. 利用 putty 登入 VM (127.0.0.1:12422)。
   {% endhint %}

![Menuconfig的介面](/files/-LNhbYVBzuDq8fVio16P)

這邊檢查了一下使用的晶片和 WiFi AP 所使用的晶片是否一致。在 OpenWRT 下查詢晶片內容的方法為: cat /proc/cpuinfo，透過指令，以AR-750S為例，我們可以看到如下的硬體資訊列表：

![cat /proc/cpuinfo](/files/vGYF7kjB8wnuNbBhFQot)

在系統資訊中，最重要的就是晶片組的資訊，AR-750S使用沒 Qualcomm QCA956X 的晶片，此處的規格必須和上述 menuconfig 的 Target System 設定一致。

記得在 Build the OpenWrt SDK 的選項**不要包含**，此介面也可以用以編輯燒錄時要使用的 OpenWRT 映像檔，不過目前並未測試此功能。

{% hint style="info" %}
在安裝 OpenWRT 18.06 時，改用 Ubuntu 16.04 64bit 版本，就沒有顯示的問題，應該是 Ubuntu 12.04 的問題。只是要注意硬碟空間，在安裝時，我使用 20G 的硬碟空間，裝完後剩下不到 1G。使用 10G 的空間則會在make時出錯 (沒有足夠空間)。
{% endhint %}

**(6)** 執行 OpenWRT 的安裝，耗時數小時，安裝好占約 3GB 的硬碟空間 (chaos calmer)

```
$ make
```

此指會依序安裝不同的功能，安裝完後會顯示以下資訊:

![](/files/-LOn7s3AM5x0PVbTl6Zx)

**(7)** 完成後，cross-compiler 已經完成。在執行編譯前，我們需要預先宣告編譯環境，將 cross compiler 所在的資料夾加入 PATH 環境變數，將環境變數 STAGING\_DIR 定義為資料夾 staging\_dir 的所在路徑。指令如下:

```
$ export PATH=$PATH:~/chaos_calmer/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/
$ export STAGING_DIR=~/chaos_calmer/staging_dir/
```

{% hint style="info" %}
`export PATH=$PATH:~/dir/`這個指令是把之後的資料夾加入PATH的路徑中，也就是產生一個開啟的捷徑，讓我們可以在家目錄下開啟 mips compiler，每一次安裝好後，路徑可能都不太一樣，舉例來說，18.06的路徑為: `~/openwrt/staging_dir/toolchain-mips_24kc_gcc-7.3.0_musl/bin/`。對於不同版本的安裝，記得用TAB檢查一下安裝目錄。
{% endhint %}

{% hint style="info" %}
這些設定每次重開機都必須重新執行。可以將此指令存入文件中，例如: initial\_exp.sh。可以透過 `source initial_exp.sh` 來載入這些設定。或是寫入`~/.bashrc` 中，開機自動執行。
{% endhint %}

**(8)** 設定完成之後，在任意資料夾輸入 mips 之後，按兩下 TAB 鍵，應該會出現各種 cross-compiler，如下圖顯示:

![mips cross-compiler](/files/-LNhemxp8qtddVvnM9tS)

**(9)** 進行 hello\_world 的簡單測試

![](/files/-LNia73A6nBEYB-CQqYG)

編譯好的 hello\_world 不能在 Ubuntu 上執行，但是可以在 OpenWRT 系統上執行。透過 winscp，我們可以將編譯好的檔案移到 OpenWRT 平台上執行，結果顯示於下圖中。

{% hint style="info" %}
Winscp 提供 Linux 和 Windows 之間的檔案傳送的圖形化介面，使用上只需要填入 IP 以及 port (通常為22)，就可以透過圖形化介面傳輸檔案。請參考: <https://winscp.net/eng/download.php>
{% endhint %}

![AR750S上執行的成果](/files/-LNif-J56FccK6A60US1)

{% hint style="info" %}
考慮到 Linux 和 Windows 系統的差別，執行的權限會在搬移檔案後需要設定。最簡單的方法就是使用 `# chmod 777 filename`，直接賦予檔案執行的權限。若是想要知道關於執行權限的設定，可以參考: <http://linux.vbird.org/linux_basic/0210filepermission.php>
{% endhint %}

## package 的引入與環境建立

透過`make menuconfig`我們可以設定要額外編譯的 package，以 libnl-3 為例，我們可以從 Libraries 進入，並把相對應的 libnl package 勾選 (如下圖所示)， 之後，再進行`make`。

![](/files/-LlzQHlXjHUP3PRf7j_k)

完成`make`之後，相對應的 package 出現於`build_dir`底下 (如下圖)，其中，要引入的 header 檔位於`include`的資料夾內。

![](/files/-LlzSa7NzBXy2U-7czD5)

另一方面，編譯好的 .o/.a 檔則位於`staging_dir`資料夾中的`usr/lib`之下，透過取得 header 檔以及 .o/.a 檔的位置，我們就可以在進行 openwrt 程式開發時，引入額外的 package，進行較複雜的程式編譯。

![](/files/-LlzV-o_GkDg4x3XPLy2)

{% hint style="info" %}
當使用 gcc 引入編譯好的 .o/.a 檔時，若出現以下錯誤: `/home/ofwrt/openwrt/staging_dir/target-mips_24kc_musl/usr/lib/libnl-3.a: file not recognized: file truncated`\
代表編譯的時候出現一些問題，可以試著重新`make openwrt`一次，並清理 (`make clean`) 原有專案後，有機會可以消除此問題。
{% endhint %}

## 外部 package 的編譯

考慮到版本問題，有時候我們也需要從 source code 開始進行編譯，相同的這樣的過程需要透過 cross compile 進行，我們以 openssl-1.0.2 為例進行說明。

一開始，先下載相對應的程式碼，並解壓縮:

```
$ wget https://www.openssl.org/source/openssl-1.0.2g.tar.gz
$ tar -zxf openssl-1.0.2g.tar.gz
```

接著，把檔案移到`staging_dir`底下

```
$ cd -R openssl-1.0.2g /home/ofwrt/openwrt/staging_dir/target-mips_24kc_musl/
```

進入`openssl-1.0.2g`資料夾下，並對其 config 檔進行設定:

```
$ cd openssl-1.0.2g
$ setarch i386 ./config --cross-compile-prefix=mips-openwrt-linux- shared no-asm
```

其中，設定包含以下內容:

* shared: 產生 .so 的動態函式庫
* no-asm: 取消 asm 功能
* setarch i386: 在 32 bit 環境下進行編譯
* \--cross-compile-prefix=mips-openwrt-linux- 使用 cross-compile 進行編譯

完成後，執行`make`，執行後應會產生檔案如下圖所示:

![](/files/-Llzi4fLY1KUIzwzWcIm)

使用`file`檢查所產生的`libssl.so.1.0.0.`

```
$ file libssl.so.1.0.0 
libssl.so.1.0.0: ELF 32-bit MSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, not stripped
```

可以看到，所產生的函示庫支援 mips 架構 (openwrt CPU 的計算架構)。若需要使用可以直接連接 .a 檔 (靜態函式庫)，進行程式的開發。
