NodeJS for Android完美编译大全
完美地编译了NodeJS for android-{arm,arm64,x86,x64,mipsel},并且提供预编译版,和作为持续编译环境的Docker image。
-
完美, 意思是不去掉任何功能(不加
--without-...
选项),尽量不修改任何源码(包括编译设定文件)。 借助工具android-gcc-toolchain 实现了这个目标。见Full Build)。这个工具让人快捷地使用NDK的独立toolchain做交叉编译,并且有些奇妙的功能。
-
一个编译环境用的Docker image
osexp2000/build-nodejs-for-android
可以用来按自己的需求编译. 见 Docker Images.
由头
交叉编译,是个不大不小的土活儿,很无聊,很干扰正题。
一开始我也没想要搞什么完美编译,我只是因为对NDK有怨念, 所以做了个辅助工具android-gcc-toolchain (这里有简单介绍), 以便顺利地做交叉编译。于是一般的交叉编译过程变轻松了之后,就凸显出NodeJS的编译错误了。
编译NodeJS for Android,目前都是去掉某些功能,或者修改源码里的编译设定,才能编译成功,例如:
- --without-snapshot (*1)(*2)
- --openssl-no-asm (*1)
- --without-intl (*2)
- --without-inspector (*2)
(*1):NodeJS源码里的android-configure 里用了这个。(*2):这个选项常常被用到。
例如在Mac上编译NodeJS for android-arm64,不去掉任何功能,不修改任何源码(包括编译设定文件),这样的完美编译方法,居然没找到(arm的也是)!
复杂之处是:不仅使用用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这边编译时出的问题。
- ar: 静态库生成器ar误用(用Mac的ar命令处理Android的lib),导致连接错误。
- -lrt: 试图连接linux特有的librt但实际Mac没有,导致连接错误。
- -m32: 有的编译成32bit,有的是64bit,导致连接出错。
- -lpthread: 忘了加必要的-l某lib的连接选项了,例如-lpthread,导致连接时报莫名其妙的"DSO missing from command line"错误。
- gnustl(libstdc++) vs libc++: 有的代码使用更新的libc++的一点东西,例如std::snprintf,这在标准的gnustl里命名空间不一样。
都是源码里的错误造成的(就是编译设定文件有错误,但是不太好找,每次都要伺候这些很烦)。
碰巧都想出了通用的方法,虽然方法有点黑,但是管用,可以完美编译了,于是记录下来。
开发环境
源码:
- NodeJS: v6.3.1-7.4.0
编译工作机器:
- Mac: OS X 10.11.5/10.11.6 EI Capitan (64bit), (可选)Xcode 8.0(8A218a)
- Linux: Ubuntu 16.04 (64bit), (可选)gcc/g++ 5.4.0
- Windows: Windows Pro 7 (64bit). Docker-Toolbox. 虽然
android-gcc-toolchain
支持MINGW,但是NodeJS的编译系统把所有的路径都混合使用了mix和/,所以导致make失败
NDK:
辅助工具 tool:
- android-gcc-toolchain,下载一下就好了。
(可选) CCACHE
- 如果重复的clean&make,那最好安装CCACHE以便用编译缓存来加速这种重复编译.
- 安装:
brew install ccache
on Mac或者sudo apt-get install ccache
on Linux export 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。
Limited Build
去掉NodeJS的一些功能(指定--without-snapshot --without-inspector --without-intl)就可以在Mac/Linux上编译。