1. 程式人生 > >擁抱Android:編譯nginx搭建移動平臺

擁抱Android:編譯nginx搭建移動平臺

Android編譯系列篇:

3 - Nginx

4 - MariaDB

再起:Nginx-1.10.2

初遇Nginx-1.9.5那回,把nginx編譯一遍,然後將build log抓出來分析處理,才手動編譯好。

對啊,用local的configure生成好一切東西,改改生成的檔案,再編譯就方便許多,過程也乾淨許多。

比較繁瑣的還是處理glob,把它幹掉;然後還有crypt函式沒有,直接用openssl裡的DES_crypt充當。

這樣一來session cache問題解決了,basic auth和gzip也可以用了。

初遇:Nginx-1.9.5

不知不覺已經開始寫擁抱Android的第三篇文章了,這次是nginx 1.9.5。

雖然過程很山寨,但是效果還不錯,至少在Android上能跑起來。

程式設計師作為手機黨出去旅遊可以給大家提供wifi和娛樂服務啦!去國外旅遊,買個十幾天無限流量,開個熱點,開個鬥地主或者三國殺什麼的,和大家玩得不及樂乎!

指令碼可以從github上獲得:https://github.com/dna2github/dna2oslab/tree/master/android/build

先放個模擬器執行成功圖(http和https):

(1)執行http的效果圖

(2)執行https的效果圖

其實還編譯了mail和stream(http v2)的模組,結合以前的python與nodejs,前端伺服器和後端wsgi~

這次的編譯沒有走尋常路線,因為發現nginx的編譯指令碼略坑。

當然,首先是想走普通路線的,執行一下,首先它會一堆check,這麼我完全沒有辦法cross compile啊,第一步就會test gcc報gcc編出來的東西不能執行。顯然的,arm程式碼何以橫行intel。

讀了下編譯指令碼,寫得挺結構化,就是不太好去掉每次check feature完都要執行程式test的部分,其實是懶。

然後就想,nginx程式碼也不多,直接寫指令碼一個檔案一個檔案編譯吧。

於是找了臺linux,裸編譯./configure --prefix=xxx $WANTED_MODULES && make | tee build.log得到一個build日誌。

這下好辦了,不過日誌有幾萬行呢,這麼多!

只是nginx強制使用openssl和pcre的source code然後編譯一遍,我這有現成的啊!

於是刪除所有openssl和pcre的編譯過程,發現nginx的編譯過程就2100多行,基本每3行編譯一個o檔案。

把include改成shell變數的形式寫,一下子log清晰了很多,處理好了就成了一個sh。

開始編譯,./droid-nginx.sh

當頭棒是ngx_auto_headers.h沒有,找找程式碼,是configure生成的,沒關係,我們只要把nginx編譯出來,所以這個直接從linux上編譯好的nginx的objs資料夾拿來用吧。

包括ngx_auto_headers.h, ngx_auto_config.h和ngx_modules.c三個檔案都需要。

一開始報的錯就是glob.h沒有,查了查這是什麼。檔案搜尋的庫函式,我們需要麼?

再看看是哪裡用了,最後就是在讀取conf的時候,如果你給了include一個不明確的檔案,它就執行搜尋。直接幹掉。於是grep "glob" nginx-1.9.5/src -r,把所有glob有關的申明和呼叫全部刪除。當然src/core/ngx_conf_file.c下面關於glob的部分刪除就刪除了,那個通過include讀conf的函式別刪除了,把裡面後半部分註釋掉,寫個返回錯誤就好了,這樣nginx還可以在conf檔案裡使用include載入具體檔案,比如conf/mime.types。

crypt.h這個標頭檔案也沒有,這會影響basic_auth模組,所以這個模組以後再研究,先把nginx編譯出來再說。直接幹掉too。

後面的事情就好辦了,什麼沒有加什麼,Linux Cross Reference是個好夥伴。

列舉下sed需要的對映:

所有 in_port_t 改 uint16_t

SO_REUSEPORT 改 0x2000

AT_EMPTY_PATH 改 0x2000

O_PATH 改 0x1000000

IOV_MAX 改 1024

SOCK_NONBLOCK 改 0x0080

然後有一些東西Android上沒有的,直接註釋掉:

比如http_degration和http_gzip的模組依賴有問題,先幹掉。比如ACCEPT4, POSIX_FADVIS, EPOLLRDHUP沒有, 通通在ngx_auto_conf.h裡幹掉!

於是程式最終很開心地走到了最後。

下面遇到一個檔案是libssl.a各種函式未定義,弄到最後原來是libcrypto.a和libssl.a的位置不能反,libssl.a在前面!

這裡就把nginx用hack的方式編譯完了。

能用麼?

adb push nginx /data/local/tmp

adb shell

# cd /data/local/tmp

# mkdir client_body_temp conf fastcgi_temp html logs proxy_temp sbin scgi_temp uwsgi_temp

# mv nginx sbin/

然後再把conf資料夾裡的東西全部adb push到/data/local/tmp/conf裡,跑起!

nginx: [emerg] getpwnam("nginx") failed (2: No such file or directory)

掛了。說沒有nginx這個使用者。

太離譜了,直接氣沖沖地跑去src/core/nginx.c找getpwnam算賬。把它們連帶grp的函式全部幹掉,uid 1000, gid 1000,再編譯一遍。

nginx: [alert] could not open error log file: open() "/usr/local/nginx/logs/error.log" failed (2: No such file or directory)

2015/11/09 12:27:53 [emerg] 787#0: open() "/usr/local/nginx/conf/nginx.conf" failed (2: No such file or directory)

又報錯,哪裡設定了prefix,經查辦,ngx_auto_conf.h裡有,把prefix設定為空字串"",這回編譯再執行,好了一切成功了。

先寫個index.html: echo '<html><body><h1>hello world</h1></body></html>' > html/index.html

開啟模擬器的瀏覽器,輸入http://127.0.0.1/ (模擬器已經root,所以可以用80,不然還是8080吧)

hello world

出現了!

openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout cert.key -out cert.crt

然後修改下nginx.conf,把https server配置上,第一個是session cache會有問題,先不管,估計是註釋了crypt.h的原因,統統幹掉。

再sbin/nginx執行,開啟瀏覽器輸入https://127.0.0.1,系統提示自簽名證書,繼續,頁面載入成功

hello world

至此,nginx編譯完成。

下一篇文章,我可能會帶大家一起編譯mariadb(先贊下它的模組化,編譯指令碼輸出也很清晰);

或者嘗試如何信手拈來,達到我要python或nodejs的入口,還有nginx的入口,寫一個Java App結合JNI技術將所有東西連起來。這樣寫的app就有python和node支援,可以不用都往internal scard上裝,直接把py或js檔案放sdcard上,可以方便運行了。