完美地編譯了NodeJS for android-{arm,arm64,x86,x64,mipsel},而且提供預編譯版,和做爲持續編譯環境的Docker image。html
完美, 意思是不去掉任何功能(不加--without-...
選項),儘可能不修改任何源碼(包括編譯設定文件)。 藉助工具android-gcc-toolchain 實現了這個目標。見Full Build)。這個工具node
讓人快捷地使用NDK的獨立toolchain作交叉編譯,而且有些奇妙的功能。python
編譯好了的二進制文件(arm,arm64,x86,x64,mipsel構架)能夠直接下載。linux
一個編譯環境用的Docker image osexp2000/build-nodejs-for-android
能夠用來按本身的需求編譯. 見 Docker Images.android
交叉編譯,是個不大不小的土活兒,很無聊,很乾擾正題。c++
一開始我也沒想要搞什麼完美編譯,我只是由於對NDK有怨念, 因此作了個輔助工具android-gcc-toolchain (這裏有簡單介紹), 以便順利地作交叉編譯。因而通常的交叉編譯過程變輕鬆了以後,就凸顯出NodeJS的編譯錯誤了。git
編譯NodeJS for Android,目前都是去掉某些功能,或者修改源碼裏的編譯設定,才能編譯成功,例如:github
(*1):NodeJS源碼裏的android-configure 裏用了這個。(*2):這個選項經常被用到。docker
例如在Mac上編譯NodeJS for android-arm64,不去掉任何功能,不修改任何源碼(包括編譯設定文件),這樣的完美編譯方法,竟然沒找到(arm的也是)!shell
複雜之處是:不只使用用Android的編譯器,還有用Host(編譯工做機器例如Mac/Linux)編譯器,幹嗎呢?生成一些Host上運行的臨時的執行文件(mksnapshot,icupkg,genccode...)。 並且,編譯設定環節層次太多(gyp,autoconf,CMake,...),不容易徹底掌控。
就算把gyp所須要的環境變量CC_target
...,GYP_DEFINES="host_os=<mac|linux>"
以及通用的CXX_host
,CXX_FLAGS
等設好並添加一些選項也依然會有某些工程不遵循設定。
我發現最終阻攔完美編譯的有幾個問題,大部分是host這邊編譯時出的問題。
都是源碼裏的錯誤形成的(就是編譯設定文件有錯誤,可是不太好找,每次都要伺候這些很煩)。
碰巧都想出了通用的方法,雖然方法有點黑,可是管用,能夠完美編譯了,因而記錄下來。
源碼:
編譯工做機器:
android-gcc-toolchain
支持MINGW,可是NodeJS的編譯系統把全部的路徑都混合使用了mix和/,因此致使make失敗NDK:
輔助工具 tool:
(可選) CCACHE
brew install ccache
on Mac或者sudo apt-get install ccache
on Linuxexport USE_CCACHE=1
告訴android-gcc-toolchain使用CCACHE.export CCACHE_DIR=some_dir_in_fast_disk
(默認是~/.ccache).ccache -M 50G
來設定最大緩存大小(默認是5G).(可選) 輔助工具 build-nodejs-for-android
: (就在這個project裏)
近一步簡化了編譯命令. 例如,以下這些命令作了其餘全部章節裏的事,編譯v6.5.0的全部構架(arm,...),限制版和徹底版,放到指定的目錄裏。
一個命令
cd node && build-nodejs-for-android v6.5.0
或者以下組合命令:
cd node && git checkout v6.5.0 build-nodejs-for-android arm -o ../nodejs-6.5.0-android-arm build-nodejs-for-android arm -o ../nodejs-6.5.0-android-arm-full --full build-nodejs-for-android arm64 -o ../nodejs-6.5.0-android-arm64 build-nodejs-for-android arm64 -o ../nodejs-6.5.0-android-arm64-full --full build-nodejs-for-android x86 -o ../nodejs-6.5.0-android-x86 build-nodejs-for-android x86 -o ../nodejs-6.5.0-android-x86-full --full build-nodejs-for-android x64 -o ../nodejs-6.5.0-android-x64 build-nodejs-for-android x64 -o ../nodejs-6.5.0-android-x64-full --full build-nodejs-for-android mipsel -o ../nodejs-6.5.0-android-mipsel build-nodejs-for-android mipsel -o ../nodejs-6.5.0-android-mipsel-full --full
你能夠查看到每一個編譯命令的命令行, 只要是從build-nodejs-for-android
或者android-gcc-toolchain
裏引起的,直接的或者間接的都行。
只要export AGCC_VERBOSE=1
或者把-v
(--verbose
)選項加到上述工具。 這裏編譯命令也包括了ar as ranlib ld strip nm。
去掉NodeJS的一些功能(指定--without-snapshot --without-inspector --without-intl)就能夠在Mac/Linux上編譯。
android-gcc-toolchain arm <<< "./configure --dest-cpu=arm --dest-os=android --without-snapshot --without-inspector --without-intl && make" android-gcc-toolchain arm64 <<< "./configure --dest-cpu=arm64 --dest-os=android --without-snapshot --without-inspector --without-intl && make" android-gcc-toolchain x86 <<< "./configure --dest-cpu=x86 --dest-os=android --without-snapshot --without-inspector --without-intl && make" android-gcc-toolchain x64 <<< "./configure --dest-cpu=x64 --dest-os=android --without-snapshot --without-inspector --without-intl --openssl-no-asm && make" android-gcc-toolchain mipsel <<< "./configure --dest-cpu=mipsel --dest-os=android --without-snapshot --without-inspector --without-intl && make"
對於x64: 須要加上--openssl-no-asm
,由於openssl的配置裏都沒有支持android-x64.
用android-gcc-toolchain --host ... -C
能夠編譯nodejs,包含全部機能.
這個--host ...
是Mandatory host compiler rules, 是在$PATH裏超越本機編譯器命令而後加減一點選項。
Full build須要用host(本機)的編譯器生成運行於本機的執行文件,因此須要安裝Xcode(for Mac) 或者gcc/g++(for linux) by sudo apt-get install gcc g++ gcc-multilib g++-multilib
爲了NodeJS 6.6.0, 若是使用低版本(<1.9.1)的android-gcc-toolchain
,那得
--stl libc++
選項給android-gcc-toolchain
來切換C++ STL,以便使用C++11 API(例如std::snprintf), 不然它會報錯說std:snprintf not definedexport CCACHE_NODIRECT=
來讓CCACHE用更精確的(可是慢一些)得方式來工做,以便檢測出系統include文件的變化。android-gcc-toolchain arm --host ar-dual-os,gcc-no-lrt,gcc-m32 -C <<< "./configure --dest-cpu=arm --dest-os=android && make" android-gcc-toolchain arm64 --host ar-dual-os,gcc-no-lrt -C <<< "./configure --dest-cpu=arm64 --dest-os=android && make" android-gcc-toolchain x86 --host ar-dual-os,gcc-no-lrt,gcc-m32 -C <<< "sed -i.bak 's/cross_compiling = target_arch != host_arch/cross_compiling = True/' configure && ./configure --dest-cpu=x86 --dest-os=android $(grep -o -- --cross-compiling configure) && make" android-gcc-toolchain x64 --host ar-dual-os,gcc-no-lrt -C <<< "sed -i.bak 's/cross_compiling = target_arch != host_arch/cross_compiling = True/' configure && ./configure --dest-cpu=x64 --dest-os=android $(grep -o -- --cross-compiling configure) --openssl-no-asm && make" android-gcc-toolchain mipsel --host ar-dual-os,gcc-no-lrt,gcc-m32 -C <<< "./configure --dest-cpu=mipsel --dest-os=android && make"
sed命令是修改源碼裏configure腳本里的錯誤. Note: 從node.js 7.4.0開始, 這段sed命令能夠去掉,而改爲添加--cross-compiling
到configure命令。
android-gcc-toolchain arm --host gcc-lpthread,gcc-m32 -C <<< "./configure --dest-cpu=arm --dest-os=android && make" android-gcc-toolchain arm64 --host gcc-lpthread -C <<< "./configure --dest-cpu=arm64 --dest-os=android && make" android-gcc-toolchain x86 --host gcc-lpthread,gcc-m32 -C <<< "sed -i.bak 's/cross_compiling = target_arch != host_arch/cross_compiling = True/' configure && ./configure --dest-cpu=x86 --dest-os=android $(grep -o -- --cross-compiling configure) && make" android-gcc-toolchain x64 --host gcc-lpthread -C <<< "sed -i.bak 's/cross_compiling = target_arch != host_arch/cross_compiling = True/' configure && ./configure --dest-cpu=x64 --dest-os=android $(grep -o -- --cross-compiling configure) --openssl-no-asm && make" android-gcc-toolchain mipsel --host gcc-lpthread,gcc-m32 -C <<< "./configure --dest-cpu=mipsel --dest-os=android && make"
對於x86:必須先安裝一些32bit的lib:sudo apt-get install -y g++-multilib gcc-multilib
, 不然它報錯說sys/cdefs.h找不到。
運行以下的docker images.
Docker image osexp2000/build-nodejs-for-android
包含了一個便於編譯的環境,還有NodeJS 6.5.0, 6.6.0版的預編譯結果
Notes:
docker run -it osexp2000/build-nodejs-for-android
nodejs-VER-ARCH[-full]
/bin(node),lib,include,share,和extras(cctest, openssl-cli...).~/node
下,是能夠用git管理的,例如:git log -1 --oneline --decorate
來確認版本。build-nodejs-for-android ...
來本身編譯, 未改變的源碼因爲被ccache了因此速度很快。-v HOST_DIR_OR_FILE:CONTAINER_DIR_OR_FILE
來把本機的目錄或者文件映射到容器裏。 注意: Docker-Toolbox on Windows要求:host(就是PC機)這邊的目錄或文件必須是爲C:\Users\...
之下(例如C:\Users\q\Downloads), 而且HOST_DIR_OR_FILE
必須轉換成/c/Users/...
形式。另外還須要環境變量MSYS_NO_PATHCONV=1docker cp
來copy進出容器,這在有時候忘了作卷映射時能夠救急.在實機和模擬器裏測試成功:
一些經驗:
以nodejs-6.5.0-arm爲例
adb push /home/devuser/nodejs-6.5.0-arm/bin/node /data/local/tmp/ adb push /home/devuser/nodejs-6.5.0-arm/lib /data/local/tmp/ adb shell chmod -R 755 /data/local/tmp/node /data/local/tmp/lib
NodeJS自己只須要/home/devuser/nodejs-6.5.0-arm/bin/node, lib那個是爲了npm的
運行/data/local/tmp/node就好了。可是以前得先export NODE_REPL_HISTORY=/data/local/tmp/node_history
, 否則會獲得Error: Could not open history file. REPL session history will not be persisted.
.
若是是用libc++而不是默認的gnustl(libstdc++)來編譯的, 那還得把libc++_shared.so
從NDK複製到android /data/local/tmp/
, 而後設定export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/data/local/tmp
.
這個 libc++_shared.so
在:
find $NDK -name libc++_shared.so
to find all用這個script代替npm, 而後就能夠用npm install
, -g
也行.
export HOME=/data/local/tmp export NODE_REPL_HISTORY=$HOME/node_history mkdir $HOME/npm-global 2> /dev/null export NPM_CONFIG_PREFIX=$HOME/npm-global $HOME/node $HOME/lib/node_modules/npm/bin/npm-cli.js "$@"
###具體的測試內容
多語言支持
> Buffer.from('新') <Buffer e6 96 b0>
網絡和DNS
> net.connect({host:"nodejs.org", port:443}, () => {console.log("------connected------")}) ... ------connected------
SSL
> https.get('https://encrypted.google.com/', (res) => {res.on('data', (d) => {process.stdout.write(d);});}) ... <!doctype html><html ...>...</html>
Debug
generic_arm64:/data/local/tmp $ ./node debug a.js debug> (To exit, press ^C again or type .exit) < Debugger listening on [::]:5858 connecting to 127.0.0.1:5858 ... ok break in a.js:1 > 1 console.log(0) 2 console.log(1) ...
npm
generic_arm64:/data/local/tmp $ ./npm install -g http-server /data/local/tmp/npm-global/bin/http-server -> /data/local/tmp/npm-global/lib/node_modules/http-server/bin/http-server ...
NodeJS對Android支持度很弱,想要Android版的,那就得折騰。那時大體有兩種方法:
各路高中低手都提供了修改源碼裏編譯配置文件的方法。
如今大都都已經被合併進來了,不提了。
Android真機debian Kit裏編譯。
在一個root過的Android裏裝上debian Kit後,就能夠輕鬆編譯成功。
/configure --without-snapshot --without-npm export LDFLAGS=-static #靜態鏈接 make
美中不足的是,生成的NodeJs竟然連localhost這樣的名字都解析不了,只能直接用IP。 這種編譯方法沒使用android的libc,因此水土不服,例如glibc裏的getaddrinfo 會尋找/etc/resolv.conf之類的東西,而Android實際不用那套機制。
又想隨手搞一個最新的,記得NodeJS有了很多進展的。結果的確有進展,可是依然不簡單。
官網裏的那個linux-arm執行文件是怎麼回事?
惋惜在Android裏用不了。這大都得怪Android搞了一套和linux不同的linker和.so。
loader不同。執行時爆"No such file or directory"
$ readelf --headers ~/Downloads/node-v4.4.7-linux-armv7l/bin/node | grep interpreter [Requesting program interpreter: /lib/ld-linux-armhf.so.3]
而Android變態不提供這個linux標準loader,而是用/system/bin/linker
來調執行文件。
黑實驗:強行改掉,結果引發下一個問題。
Android裏各個.so的名稱都和通常的linux的不同
$ readelf -d ~/Downloads/node-v4.4.7-linux-armv7l/bin/node ... Shared library: [libdl.so.2] [librt.so.1] [libstdc++.so.6] ...
黑實驗:強行改掉依賴的*.so名稱,結果引發下一個問題。
沒有編譯成PIE風格(像*.so同樣位置無關以便運行位置隨機化),因此會被Android 5+拒絕運行
$ readelf -d ~/Downloads/node-v4.4.7-linux-armv7l/bin/node | grep Type: Type: EXEC (Executable file)
而PIE風格的執行文件,至少得和.so同樣的類型DYN (Shared object file)
。
黑實驗:那就在4.4上作實驗,結果引發下一個問題。
有些api在android裏不存在。
黑實驗:沒法繼續了。更不要提/etc之類的設定文件不存在引發的主機名解析等問題了。
跑了一下子題,接着試試源碼裏提供的android-configure
編譯腳本。
在Mac上執行android-configure,make時出錯
./android-configure $NDK && make
出錯信息:
sh: /Users/q/Downloads/node/out/Release/icupkg: cannot execute binary file
並且,不能編譯arm64構架的。
因而試試源碼裏提供的configure
編譯腳本。
在Mac上執行configure,也在make時出錯
./configure --dest-cpu=arm64 --dest-os=android && make
出錯信息 openssl裏"unsupported ARM architecture":
cc .../obj.target/...openssl... ../deps/openssl/openssl/crypto/arm_arch.h:46:6: error: "unsupported ARM architecture"
obj.target目錄放得都是爲android生成的東西,obj.host裏的都是爲了當前機器生成的東西。
而這個光禿禿的cc命令就是指host(個人機器)的cc。 顯然這是用錯了cc,得告訴他用android的cc。這個看來不能怪NodeJS。
那就照慣例定義一下$CC
什麼的,部分參照android-configure
,生成單獨的toolchain也是必須的,假設生成到/tmp/tc下。
$ $NDK/build/tools/make_standalone_toolchain.py --arch arm64 --install-dir /tmp/tc --force $ export CC=/tmp/tc/bin/aarch64-linux-android-gcc $ export CXX=/tmp/tc/bin/aarch64-linux-android-g++ $ export AR=/tmp/tc/bin/aarch64-linux-android-ar $ export LINK=/tmp/tc/bin/aarch64-linux-android-g++ $ ./configure --dest-cpu=arm64 --dest-os=android && make
果真那一步經過了,cc變成了制定的android gcc了。
/tmp/tc/bin/aarch64-linux-android-gcc .../obj.target/...openssl...
可是接着出別的錯。
那就在Mac上繼續一個個看看怎麼回事,爲何編譯一個東西還要人費神呢?
gyp交叉編譯系統更須要$CC_target
...而不是$CC
...
新的錯誤和android-configure的那個同樣:
sh: /Users/q/Downloads/node_tmp/out/Release/icupkg: cannot execute binary file
看來NodeJS用到icu這個東西,他要生成一個我本機用的執行文件,狀況複雜了啊。
不但要生成Android的,還要本機用的一些關聯的東西,這就是混合模式了。
在往一點看,icupkg是由這個命令生成的:
/tmp/tc/bin/aarch64-linux-android-g++ ... -o ...icupkg .../obj.host/...icu...
這是發神經了嗎? 拿android-g++編譯obj.host的東西,可icupkg是要在host(也就是個人PC)上執行的啊, 爲何用android-g++編譯呢。
發如今決定host編譯器時,用的邏輯在make.py:
GetEnvironFallback(('CXX_host', 'CXX'), 'g++')
看來原來設定的$CXX
得換成$CXX_target
之類的,因而從新開個bash:
$ export CC_target=/tmp/tc/bin/aarch64-linux-android-gcc $ export CXX_target=/tmp/tc/bin/aarch64-linux-android-g++ $ export AR_target=/tmp/tc/bin/aarch64-linux-android-ar $ export LINK_target=/tmp/tc/bin/aarch64-linux-android-g++ $ ./configure --dest-cpu=arm64 --dest-os=android && make
果真,本地編譯的都經過了,包括剛纔的icu模塊。
V8(Chromium JavaScript)工程裏的host_os設定錯誤
新的錯誤是試圖編譯一個linux特有的文件:
g++ ... -c -o .../obj.host/... ...platform-linux.cc .../v8/src/base/platform/platform-linux.cc:53:10: fatal error: 'sys/prctl.h' file not found
顯然這是在編譯本地產品時誤包括了linux的源碼。
查到platform-linux.cc是在deps/v8/tools/gyp/v8.gyp#L1769 裏被選定爲本地編譯對象的。
'conditions': [ ['host_os=="mac"', { 'target_conditions': [ ['_toolset=="host"', { 'sources': [ '../../src/base/platform/platform-macos.cc' ] }, { 'sources': [ '../../src/base/platform/platform-linux.cc' ] }], ], }, { 'sources': [ '../../src/base/platform/platform-linux.cc' ] }], ],
看起來邏輯正確啊,host_os是mac就platform-macos.cc不然就platform-linux.cc。 強行把上述.cc改爲_xxxx1.cc,_xxxx2.cc,_xxxx3.cc後,從新執行configure,就會發現_xxxx3 出如今一個./out/deps/v8/tools/gyp/v8_libbase.host.mk裏。
試着把host_os=="mac"換成host=="android"反倒好了。
肯定是host_os搞錯了,在看這東西是誰設定的: deps/v8/build/toolchain.gypi#L88
'host_os%': '<(OS)',
上下看看,明白了OS
就是target OS,就是android了。這個host_os
在這個文件其餘地方都沒有被用到。
而另外一個它的使用者deps/v8/build/standalone.gypi#L264
'host_os%': "<!(uname -s | sed -e 's/Linux/linux/;s/Darwin/mac/')",
正確的檢測了host_os,結果是"mac". 用這句話替換掉'host_os%': '<(OS)'
,那麼就OK了。
可是,這個修改影響較大(例如Windows沒有uname命令,還得換成一段python才行),搞很差就是這麼設計的,讓使用者在外層設定。 反正一時半會兒考慮不全很差提交修改。
因而一查怎麼把host_os變量從./configure那層傳遞給gyp,發現又轉到了android-configure裏:
GYP_DEFINES+=" host_os=linux OS=android" export GYP_DEFINES ./configure ...
不過顯然,做者當時用的是linux主機作這事兒的,我得設成mac。因而:
$ export GYP_DEFINES=host_os=mac $ export CC_target=/tmp/tc/bin/aarch64-linux-android-gcc $ export CXX_target=/tmp/tc/bin/aarch64-linux-android-g++ $ export AR_target=/tmp/tc/bin/aarch64-linux-android-ar $ export LINK_target=/tmp/tc/bin/aarch64-linux-android-g++ $ ./configure --dest-cpu=arm64 --dest-os=android && make
試圖鏈接linux特有的librt(經-lrt選項)
新的錯誤是建立本地產品時的linker錯誤
g++ ... -o ...mksnapshot .../obj.host/... -dl -lrt ld: library not found for -lrt
這是試圖在host上尋找librt,可是若是手動執行不包括-lrt的命令,就會成功。
這個錯誤一樣是在deps/v8/tools/gyp/v8.gyp#L1769 裏,做者確定是在Linux主機上工做因此不出問題。
'libraries': [ '-ldl', '-lrt' ]
這個v8.gyp之後確定是要改的,可是先想了個黑辦法對付過去。 那就是把libdl複製成librt,把路徑包含在LIBRARY_PATH裏,讓ld可以找到。
$ find -L /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs -type f -name 'libdl.*' /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/lib/libdl.tbd $ cp /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/lib/libdl.tbd \ /tmp/tc/librt.tbd $ export LIBRARY_PATH=/tmp/tc:$LIBRARY_PATH
OK,這一關經過了。
近一步試探,發現librt.tbd裏只要寫這麼多就好了(包括...三個字符都得原本來本的寫進去)。
archs: [ i386, x86_64 ] platform: macosx install-name: /usr/lib/libSystem.B.dylib exports: - archs: [ i386, x86_64 ] re-exports: [ ] symbols: [ ] ...
2016/09/06:這個方法後來換成了gcc-no-lrt這個host compiler rule,超越系統原有的gcc等命令,把-lrt參數給去掉後在調用本來的gcc等。
靜態庫生成器ar誤用
新的問題就是一開始碰到的那一堆符號找不到的linker錯誤了。例如:
.../obj.target/cctest/src/inspector_socket.o: In function `inspector_write(inspector_socket_s*, char const*, unsigned long)': inspector_socket.cc:(.text+0x1af4): undefined reference to `uv_buf_init'
往上查這些.o的用處時,發現本機的ar命令竟然用來生成Android的靜態庫了!亂套了。
rm -f .../obj.target/tools/icu/libicustubdata.a && \ ar crsT .../obj.target/tools/icu/libicustubdata.a \ .../obj.target/...一堆.o文件
看來有有些子工程不聽話啊,壓根不鳥$AR_target
所指定的ar。 這查起來就囉嗦了,真不想進那些散發着腐朽味道的工程裏。 在Linux上看不出問題,由於Linux主機上的ar使用的格式和Android上的同樣,而Mac上的略有不一樣。 從Wiki上看,ar命令內部文件格式歷來就沒有統一過。
怎麼辦?彷佛就差這一步了。突然想起一個黑主意:作個wrapper ar代替本機的,裏面判斷輸入的*.o文件格式, 從而決定調用本機的仍是Android的ar。判斷就用toolchain裏的objdump好了,若是不出錯說明是Android的。
...省略,枯燥無味。都集成到android-gcc-toolchain了。
究竟是啥啊?這個--without-snapshot
意思是不對js進行預編譯。去掉這個功能彷佛不是什麼大事兒。 不指定這個選項時,make會先生成一個mksnapshot工具,而後運行這個工具生成snapshot.cc, 裏面包含了全部的js的預編譯結果,而後再把這個snapshot.cc編譯成android這邊的機器碼。 這個snapshot彷佛是爲了快速建立新的js context,也許Electron,NW.js之類和UI的時候須要用吧。
究竟是啥啊?這個--without-intl
意思是不提供Intl
機能,一個叫作Intl
的全局class。 Intl
不是必須的! 別被介紹裏的「Flags that lets you enable i18n features in Node.js」給嚇着了, 搞得好像是沒了他就不支持多語言似的了。
Intl
這個新東西幾乎沒人用,是什麼ECMAScript-402標準裏定義的一個可選項,就是作文字列的排序,日期格式等locale那套功能。
沒有Intl
機能的話,一切都轉的好好的。UTF8,中文,日語什麼的都支持。 無論怎樣,須要轉換文字集時仍是須要iconv-lite等東西。
NodeJS用icu這個文字集轉換庫實現了intl功能,可是icu常常在交叉編譯是出毛病,由於它要生成一些本地exe,例如genccode,icupkg, 而後調用genccode根據一個數據文件生成C代。
icu這個東西看起來有種腐朽的味道,看他的網頁就知道了(例如主頁,DEMO,Unicode Browser), 那個土啊,別提了,顯然沒人好好打理。
V8(Chromium JavaScript)工程裏的東西好龐大,並且顯得老舊了。很很差參與。
gyp那套編譯工具備成功之處,比Makefile好懂。但竟然仍是得一個個加源碼文件?不能"目錄/*.c"外加一些exclude的形式加到sources裏嗎?
在Mac上編譯NodeJS for Android-arm時碰到的錯誤和解決方法
此次多了一個問題,也是gyp或者別的什麼的錯誤,也是host這邊編譯問題,並且仍是icu那一塊的。
反正是有的編譯成32bit,有的是64bit。 很差查找。因此煩了,仍是繼續原來的野路子吧,把gcc和g++都給替換了,裏面強制加上-m32選項。
最終,這一切集成到android-gcc-toolchain裏,經過--host ar-dual-os,gcc-no-lrt,gcc-m32
選項能夠實現。
2016/09/02: 在Linux上編譯NodeJS for Android-arm64時碰到的錯誤和解決方法
此次多了一個問題,又是host這邊編譯問題,是最終鏈接生成mksnapshot時除奇怪的錯:
/usr/bin/ld: .../obj.host/.../v8/.../platform/condition-variable.o: undefined reference to symbol 'pthread_condattr_setclock@@GLIBC_2.3.3' //lib/x86_64-linux-gnu/libpthread.so.0: error adding symbols: DSO missing from command line
說符號找不到還有DSO什麼莫名其妙的東西,我用nm查了發現符號就在libpthread裏,因此加個-lpthread讓他鏈接libpthread就好了。
固然,到底在那個配置文件里加這個選項,有得頭痛的層層追尋配置,不想幹了。還不如黑路子快, 最終,把這一切集成到android-gcc-toolchain裏,經過--host gcc-lpthread
選項能夠實現。
2016/09/05: 支持ccache這個編譯緩存工具了,重複編譯時速度快了不少。選項--ccache
,注意是兩個c。2016/09/22:刪除這個選項了,單純靠USE_CCACHE=1環境變量來表達這個選項。
2016/09/06: 編譯android-mipsel版時,碰到bits/c++config.h找不到之類的錯誤。彷佛之前碰到過查了一下搞好了,可又忘了。得作個memo。
c++的bits目錄名稱實在操蛋!讓人誤覺得是位操做的東西, 實際裏面放得是c++ STL(template)的頭文件等東西,並且bits是gnu-libstdc++庫裏特有名稱。
bits目錄出如今三個地方:
獨立toolchain目錄/include/c++/4.9.x/ #通常的c++的.h文件,可是沒有STL的.h文件。 獨立toolchain目錄/include/c++/4.9.x/bits/ #STL的.h文件 獨立toolchain目錄/include/c++/4.9.x/mipsel-linux-android/bits #子構架關聯的.h文件。
第一個目錄是c++編譯器默認的包含目錄,天然其下的bits/xxx能夠用include <bits/xxx>。可是第三個目錄就不行了。
通常狀況下寫個文件a.cc
#include <functional> #這個裏面#include <bits/c++config.h>了。
而後調用toolchain裏的g++ -c -o a.o a.cc
是好好的,會自動子構架目錄裏的c++config.h。 用g++ -E a.cc
能夠看到c++config.h從哪裏來的。
V8裏默認添加了一個-mips32r2
給g++,表示生成CPU爲mips32r2的代碼,
結果g++不幹了,報錯說找不到bits/c++config.h。這應該是g++本身的毛病。
因此在mips構架裏,android-gcc-toolchain把這些文件子構架裏的.h都copy到標準的bits目錄下去了。
2016/09/17: NodeJS 6.6.0出來了,就編了一下,不出意外,Limited build是好的,Full build就出了個"std::snprintf照得不到" 之類的錯誤。換成--stl libc++來編譯就行了。就這麼個破snprintf也沒搞好,C++也真夠亂的。 這個東西是C++11裏明肯定義有的,但是如今用的是gnustl(libstdc++),裏面的<cstdio>裏定義了std::printf都沒有定義std::snprintf, 而<string>裏也沒有包含cstdio,反而包含了一堆拿什麼狗屁bits目錄。反正就不如lbc++裏的清爽。 只不過,據NDK裏說libc++是還不穩定的庫(竟然!,某些case沒經過,arm下有時崩潰),因此,仍是想辦法把gnustl裏的 <cstdio>和<string>給改一下。不過這東西那個該死的GPL3的,...
2016/09/26: 能夠看到每一個編譯命令的命令行。只要加個-v(--verbose)選項給這個工具,或者設定環境變量'export AGCC_VERBOSE=1'。例子:
$___ ccache '/Users/q/Library/Android/sdk/ndk-bundle/std-toolchains/android-9-arm/bin/arm-linux-androideabi-c++' \ $___ '-D_GLIBCXX_USE_C99_MATH' \ $___ '-I../deps/gtest' \ $___ '-I../deps/gtest/include' \ $___ '-Wall' \ $___ '-Wextra' \ $___ '-Wno-unused-parameter' \ $___ '-Wno-missing-field-initializers' \ $___ '-O3' \ $___ '-fno-omit-frame-pointer' \ $___ '-fPIE' \ $___ '-fno-rtti' \ $___ '-fno-exceptions' \ $___ '-std=gnu++0x' \ $___ '-MMD' \ $___ '-MF' \ $___ '/Users/q/Downloads/node/out/Release/.deps//Users/q/Downloads/node/out/Release/obj.target/gtest/deps/gtest/src/gtest-filepath.o.d.raw' \ $___ '-c' \ $___ '-o' \ $___ '/Users/q/Downloads/node/out/Release/obj.target/gtest/deps/gtest/src/gtest-filepath.o' \ $___ '../deps/gtest/src/gtest-filepath.cc'
這裏的$___純粹爲了grep篩選好用,另外反正$___是空的,就算原封不動copy下來在貼到別的地方執行也不會出錯。
2017/01/10: Node.js v7.4.0開始,configure腳本支持明確的--cross-compiling參數了。