完美地编译了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参数了。