armv5 交叉编译节点的库兼容性
Libraries compatibilty by cross-compiling node for armv5
我尝试在我的 Ubuntu 14.04 桌面 x64 上为我的 QNAP armv5te 机器交叉编译 node。
QNAP App-center 中存在节点QPKG,但版本较旧(0.8.22)
以下是有关服务器的信息:
Linux SERVERNAME 3.4.6 #1 Mon Dec 29 06:00:47 CST 2014 armv5tel unknown
Processor name : Feroceon 88F6281 rev 1 (v5l) @ 1.2 GHz
BogoMIPS : 1196.85
Features : swp half thumb fastmult edsp
CPU implementer : 0x56
CPU architecture: 5TE
CPU variant : 0x2
CPU part : 0x131
CPU revision : 1
Hardware : Feroceon-KW
ARM Revision : 0000
Serial : 0000000000000000
这是我在桌面上使用的命令:
apt-get update
apt-get upgrade
apt-get install emdebian-archive-keyring
apt-get install libc6-armel-cross libc6-dev-armel-cross
apt-get install binutils-arm-linux-gnueabi
apt-get install gcc-4.7-arm-linux-gnueabi
apt-get install g++-4.7-arm-linux-gnueabi
apt-get install u-boot-tools
apt-get install libncurses5-dev
ln -s /user/bin/arm-linux-gnueabi-gcc-4.7 /usr/bin/arm-linux-gnueabi-gcc
ln -s /user/bin/arm-linux-gnueabi-g++-4.7 /usr/bin/arm-linux-gnueabi-g++
wget http://nodejs.org/dist/node-v0.10.35/node-v0.10.35.tar.gz
tar -zxf node-v0.10.35.tar.gz
cd node-v0.10.35
export TOOL_PREFIX="arm-linux-gnueabi"
export CC="${TOOL_PREFIX}-gcc"
export CXX="${TOOL_PREFIX}-g++"
export AR="${TOOL_PREFIX}-ar"
export RANLIB="${TOOL_PREFIX}-ranlib"
export LINK="${CXX}"
export CCFLAGS="-march=armv5te -mfpu=softfp -marm"
export CXXFLAGS="-march=armv5te -mno-unaligned-access"
export OPENSSL_armcap=5
export GYPFLAGS="-Darmeabi=soft -Dv8_can_use_vfp_instructions=false -Dv8_can_use_unaligned_accesses=false -Darmv7=0"
export VFP3=off
export VFP2=off
./configure --without-snapshot --dest-cpu=arm --dest-os=linux --prefix="/root/.nvm/v0.10.35"
make -j 4
make install
tar -zcf node-v0.10.35-linux-armv5.tar.gz v0.10.35
编译没有显示这些参数的任何失败。所以在那之后我将 tarball 发送到我的 QNAP 服务器:
scp /root/.nvm/node-v0.10.35-linux-armv5.tar.gz admin@SERVERNAME:/share/HDA_DATA/.qpkg/nodejs
ssh SERVERNAME -l admin
cd /share/HDA_DATA/.qpkg/nodejs
tar -zxf node-v0.10.35-linux-armv5.tar.gz
ln -s v0.10.35 node
我所有的环境变量都已经在我的服务器上设置好了。现在我可以测试节点二进制文件了...
# node -v
node: /usr/lib/libstdc++.so.6: version `CXXABI_ARM_1.3.3' not found (required by node)
node: /lib/libc.so.6: version `GLIBC_2.15' not found (required by node)
node: /lib/libc.so.6: version `GLIBC_2.11' not found (required by node)
node: /lib/libc.so.6: version `GLIBC_2.7' not found (required by node)
最后我有一个错误,因为 C 库在 Ubuntu 和 Qnap 上不一样,对于 Ubuntu 桌面我有 ldd (Ubuntu EGLIBC 2.19-0ubuntu6.5) 2.19
而在 QNAP ldd (GNU libc) 2.5
上。
libc-dev 和 libstdc++ 是由 Optware ipkg 在 Qnap 上处理的包,(旧版本也是)。
我的问题是解决此问题的更好方法是什么?强制更新服务器上的库? (以及如何做到这一点?)或者在编译期间使用静态库? (以及如何做到这一点?)或其他选择?
编辑:
在与 artless-noise 交谈后,我了解到我有几种方法可以修复库依赖性...
有问题的依赖项:
# ldd /opt/bin/node
/opt/node/bin/node: /usr/lib/libstdc++.so.6: version `CXXABI_ARM_1.3.3' not found (required by /opt/node/bin/node)
/opt/node/bin/node: /lib/libc.so.6: version `GLIBC_2.15' not found (required by /opt/node/bin/node)
/opt/node/bin/node: /lib/libc.so.6: version `GLIBC_2.11' not found (required by /opt/node/bin/node)
/opt/node/bin/node: /lib/libc.so.6: version `GLIBC_2.7' not found (required by /opt/node/bin/node)
libdl.so.2 => /lib/libdl.so.2 (0xb6ed2000)
librt.so.1 => /lib/librt.so.1 (0xb6ec3000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb6de2000)
libm.so.6 => /lib/libm.so.6 (0xb6d32000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb6d1e000)
libpthread.so.0 => /lib/libpthread.so.0 (0xb6cfe000)
libc.so.6 => /lib/libc.so.6 (0xb6bca000)
/lib/ld-linux.so.3 (0xb6ee4000)
将库从 Ubuntu GCC 复制到目标机器,并覆盖默认库:
这可能真的很危险,并且可能会破坏系统。此外,我的目标是为 QNAP 社区创建一个 QPKG,因此要求人们覆盖他们的 C 库并不是一个很好的方法。
复制库与原库同居:
一个不错的方法,只需要将 LD_LIBRARY_PATH
设置为包含应用程序最新库的目录。但我发现使用此方法时出错,再次使用 c++ lib.
错误:
node: symbol lookup error: /opt/node/lib/c/libstdc++.so.6: undefined symbol: _ZNSt11__timepunctIcE2idE, version GLIBCXX_3.4
- 创建静态应用程序:
最后,我找到了在编译期间和在目标机器上执行期间没有任何错误的方法。只需要添加一些标志。
新标志:
export CCFLAGS="-march=armv5te -mfpu=softfp -marm -static-libgcc"
export CXXFLAGS="-march=armv5te -mno-unaligned-access -static-libstdc++"
export LDFLAGS="-static"
正在检查动态库链接:
# ldd /opt/bin/node
not a dynamic executable
# npm version
{ test: '1.0.0',
npm: '2.3.0',
ares: '1.9.0-DEV',
http_parser: '1.0',
modules: '11',
node: '0.10.35',
openssl: '1.0.1j',
uv: '0.10.30',
v8: '3.14.5.9',
zlib: '1.2.8' }
编辑: 最后又出现了一个问题,大多数节点函数都可以工作,但 http
...
我测试了一个简单的脚本(来自 NodeJS API)来获取有关网页的信息:
http.get("http://www.google.com/index.html", function(res) {
console.log("Got response: " + res.statusCode);
}).on('error', function(e) {
console.log("Got error: " + e.message);
});
我得到了 Got error: getaddrinfo ENOTFOUND
,是否可能因为节点是静态的,所以某些功能无法工作?
最后,我没有尝试更改库,而是决定使用一个更好的交叉编译器来完美匹配我的目标。
我也用了Crosstools-NG for that, but I could use the official QNAP Maxwell-ARM Toolchain(我看到太晚了。。。)
gcc (GCC) 4.2.4
g++ (GCC) 4.2.4
GNU ld (crosstool-NG 1.20.0) 2.19.1
ldd (crosstool-NG) 1.20.0
Python 2.7.6 (with gyp)
但问题始终存在,存在节点依赖性(libuv) which uses a library named linux-atomic,并且该库是从版本 4 开始在 GCC 中引入的。4.X。所以这是我修复它的解决方法:
cd /src
wget -q https://ftp.gnu.org/gnu/gcc/gcc-4.6.3/gcc-core-4.6.3.tar.gz
tar -zxf gcc-core-4.6.3.tar.gz
sed -i -e 's/define HIDDEN.*/define HIDDEN/' /src/gcc-4.6.3/gcc/config/arm/linux-atomic.c
export CC=arm-none-linux-gnueabi-gcc
export AR=arm-none-linux-gnueabi-ar
export RANLIB=arm-none-linux-gnueabi-ranlib
cd /src/gcc-4.6.3/gcc/config/arm
libtool --tag=CC --mode=compile $CC -g -O2 -MT linux-atomic.lo -MD -MP -MF linux-atomic.Tpo -c -o linux-atomic.lo linux-atomic.c
$AR cru /src/gcc-4.6.3/gcc/config/arm/.libs/liblinux-atomic.a /src/gcc-4.6.3/gcc/config/arm/.libs/linux-atomic.o
$RANLIB /src/gcc-4.6.3/gcc/config/arm/.libs/liblinux-atomic.a
# IMPORTANT: Assign environment variables like I made in my question above.
# Go to node src dir and configure
./configure --without-snapshot --dest-cpu=arm --dest-os=linux --prefix="${PREFIX_DIR}"
# When configuration is done, edit out/node.target.mk
vi out/node.target.mk
# Find LD_INPUTS files list and add your new library as last one:
# -> /src/gcc-4.6.3/gcc/config/arm/.libs/liblinux-atomic.a
# Now you can build node !
make -j4 #-jX where X is the number of available cores
make install DESTDIR=$TEMPDIR # Use DESTDIR to avoid installation directly in $PREFIX_DIR path
使用该配置,我还可以使用 GCC 4.1.3 为 x86 处理器编译节点。我为不想自己编译的 QNAP 用户制作了 QPKG : https://github.com/jbltx/nodejs-QPKG/tree/master/node-v0.10.35
我尝试在我的 Ubuntu 14.04 桌面 x64 上为我的 QNAP armv5te 机器交叉编译 node。
QNAP App-center 中存在节点QPKG,但版本较旧(0.8.22)
以下是有关服务器的信息:
Linux SERVERNAME 3.4.6 #1 Mon Dec 29 06:00:47 CST 2014 armv5tel unknown
Processor name : Feroceon 88F6281 rev 1 (v5l) @ 1.2 GHz
BogoMIPS : 1196.85
Features : swp half thumb fastmult edsp
CPU implementer : 0x56
CPU architecture: 5TE
CPU variant : 0x2
CPU part : 0x131
CPU revision : 1
Hardware : Feroceon-KW
ARM Revision : 0000
Serial : 0000000000000000
这是我在桌面上使用的命令:
apt-get update
apt-get upgrade
apt-get install emdebian-archive-keyring
apt-get install libc6-armel-cross libc6-dev-armel-cross
apt-get install binutils-arm-linux-gnueabi
apt-get install gcc-4.7-arm-linux-gnueabi
apt-get install g++-4.7-arm-linux-gnueabi
apt-get install u-boot-tools
apt-get install libncurses5-dev
ln -s /user/bin/arm-linux-gnueabi-gcc-4.7 /usr/bin/arm-linux-gnueabi-gcc
ln -s /user/bin/arm-linux-gnueabi-g++-4.7 /usr/bin/arm-linux-gnueabi-g++
wget http://nodejs.org/dist/node-v0.10.35/node-v0.10.35.tar.gz
tar -zxf node-v0.10.35.tar.gz
cd node-v0.10.35
export TOOL_PREFIX="arm-linux-gnueabi"
export CC="${TOOL_PREFIX}-gcc"
export CXX="${TOOL_PREFIX}-g++"
export AR="${TOOL_PREFIX}-ar"
export RANLIB="${TOOL_PREFIX}-ranlib"
export LINK="${CXX}"
export CCFLAGS="-march=armv5te -mfpu=softfp -marm"
export CXXFLAGS="-march=armv5te -mno-unaligned-access"
export OPENSSL_armcap=5
export GYPFLAGS="-Darmeabi=soft -Dv8_can_use_vfp_instructions=false -Dv8_can_use_unaligned_accesses=false -Darmv7=0"
export VFP3=off
export VFP2=off
./configure --without-snapshot --dest-cpu=arm --dest-os=linux --prefix="/root/.nvm/v0.10.35"
make -j 4
make install
tar -zcf node-v0.10.35-linux-armv5.tar.gz v0.10.35
编译没有显示这些参数的任何失败。所以在那之后我将 tarball 发送到我的 QNAP 服务器:
scp /root/.nvm/node-v0.10.35-linux-armv5.tar.gz admin@SERVERNAME:/share/HDA_DATA/.qpkg/nodejs
ssh SERVERNAME -l admin
cd /share/HDA_DATA/.qpkg/nodejs
tar -zxf node-v0.10.35-linux-armv5.tar.gz
ln -s v0.10.35 node
我所有的环境变量都已经在我的服务器上设置好了。现在我可以测试节点二进制文件了...
# node -v
node: /usr/lib/libstdc++.so.6: version `CXXABI_ARM_1.3.3' not found (required by node)
node: /lib/libc.so.6: version `GLIBC_2.15' not found (required by node)
node: /lib/libc.so.6: version `GLIBC_2.11' not found (required by node)
node: /lib/libc.so.6: version `GLIBC_2.7' not found (required by node)
最后我有一个错误,因为 C 库在 Ubuntu 和 Qnap 上不一样,对于 Ubuntu 桌面我有 ldd (Ubuntu EGLIBC 2.19-0ubuntu6.5) 2.19
而在 QNAP ldd (GNU libc) 2.5
上。
libc-dev 和 libstdc++ 是由 Optware ipkg 在 Qnap 上处理的包,(旧版本也是)。
我的问题是解决此问题的更好方法是什么?强制更新服务器上的库? (以及如何做到这一点?)或者在编译期间使用静态库? (以及如何做到这一点?)或其他选择?
编辑:
在与 artless-noise 交谈后,我了解到我有几种方法可以修复库依赖性...
有问题的依赖项:
# ldd /opt/bin/node
/opt/node/bin/node: /usr/lib/libstdc++.so.6: version `CXXABI_ARM_1.3.3' not found (required by /opt/node/bin/node)
/opt/node/bin/node: /lib/libc.so.6: version `GLIBC_2.15' not found (required by /opt/node/bin/node)
/opt/node/bin/node: /lib/libc.so.6: version `GLIBC_2.11' not found (required by /opt/node/bin/node)
/opt/node/bin/node: /lib/libc.so.6: version `GLIBC_2.7' not found (required by /opt/node/bin/node)
libdl.so.2 => /lib/libdl.so.2 (0xb6ed2000)
librt.so.1 => /lib/librt.so.1 (0xb6ec3000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb6de2000)
libm.so.6 => /lib/libm.so.6 (0xb6d32000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb6d1e000)
libpthread.so.0 => /lib/libpthread.so.0 (0xb6cfe000)
libc.so.6 => /lib/libc.so.6 (0xb6bca000)
/lib/ld-linux.so.3 (0xb6ee4000)
将库从 Ubuntu GCC 复制到目标机器,并覆盖默认库:
这可能真的很危险,并且可能会破坏系统。此外,我的目标是为 QNAP 社区创建一个 QPKG,因此要求人们覆盖他们的 C 库并不是一个很好的方法。复制库与原库同居:
一个不错的方法,只需要将LD_LIBRARY_PATH
设置为包含应用程序最新库的目录。但我发现使用此方法时出错,再次使用 c++ lib.
错误:
node: symbol lookup error: /opt/node/lib/c/libstdc++.so.6: undefined symbol: _ZNSt11__timepunctIcE2idE, version GLIBCXX_3.4
- 创建静态应用程序:
最后,我找到了在编译期间和在目标机器上执行期间没有任何错误的方法。只需要添加一些标志。
新标志:
export CCFLAGS="-march=armv5te -mfpu=softfp -marm -static-libgcc"
export CXXFLAGS="-march=armv5te -mno-unaligned-access -static-libstdc++"
export LDFLAGS="-static"
正在检查动态库链接:
# ldd /opt/bin/node
not a dynamic executable
# npm version
{ test: '1.0.0',
npm: '2.3.0',
ares: '1.9.0-DEV',
http_parser: '1.0',
modules: '11',
node: '0.10.35',
openssl: '1.0.1j',
uv: '0.10.30',
v8: '3.14.5.9',
zlib: '1.2.8' }
编辑: 最后又出现了一个问题,大多数节点函数都可以工作,但 http
...
我测试了一个简单的脚本(来自 NodeJS API)来获取有关网页的信息:
http.get("http://www.google.com/index.html", function(res) {
console.log("Got response: " + res.statusCode);
}).on('error', function(e) {
console.log("Got error: " + e.message);
});
我得到了 Got error: getaddrinfo ENOTFOUND
,是否可能因为节点是静态的,所以某些功能无法工作?
最后,我没有尝试更改库,而是决定使用一个更好的交叉编译器来完美匹配我的目标。
我也用了Crosstools-NG for that, but I could use the official QNAP Maxwell-ARM Toolchain(我看到太晚了。。。)
gcc (GCC) 4.2.4
g++ (GCC) 4.2.4
GNU ld (crosstool-NG 1.20.0) 2.19.1
ldd (crosstool-NG) 1.20.0
Python 2.7.6 (with gyp)
但问题始终存在,存在节点依赖性(libuv) which uses a library named linux-atomic,并且该库是从版本 4 开始在 GCC 中引入的。4.X。所以这是我修复它的解决方法:
cd /src
wget -q https://ftp.gnu.org/gnu/gcc/gcc-4.6.3/gcc-core-4.6.3.tar.gz
tar -zxf gcc-core-4.6.3.tar.gz
sed -i -e 's/define HIDDEN.*/define HIDDEN/' /src/gcc-4.6.3/gcc/config/arm/linux-atomic.c
export CC=arm-none-linux-gnueabi-gcc
export AR=arm-none-linux-gnueabi-ar
export RANLIB=arm-none-linux-gnueabi-ranlib
cd /src/gcc-4.6.3/gcc/config/arm
libtool --tag=CC --mode=compile $CC -g -O2 -MT linux-atomic.lo -MD -MP -MF linux-atomic.Tpo -c -o linux-atomic.lo linux-atomic.c
$AR cru /src/gcc-4.6.3/gcc/config/arm/.libs/liblinux-atomic.a /src/gcc-4.6.3/gcc/config/arm/.libs/linux-atomic.o
$RANLIB /src/gcc-4.6.3/gcc/config/arm/.libs/liblinux-atomic.a
# IMPORTANT: Assign environment variables like I made in my question above.
# Go to node src dir and configure
./configure --without-snapshot --dest-cpu=arm --dest-os=linux --prefix="${PREFIX_DIR}"
# When configuration is done, edit out/node.target.mk
vi out/node.target.mk
# Find LD_INPUTS files list and add your new library as last one:
# -> /src/gcc-4.6.3/gcc/config/arm/.libs/liblinux-atomic.a
# Now you can build node !
make -j4 #-jX where X is the number of available cores
make install DESTDIR=$TEMPDIR # Use DESTDIR to avoid installation directly in $PREFIX_DIR path
使用该配置,我还可以使用 GCC 4.1.3 为 x86 处理器编译节点。我为不想自己编译的 QNAP 用户制作了 QPKG : https://github.com/jbltx/nodejs-QPKG/tree/master/node-v0.10.35