工作需要不同模块的软件带上依赖交叉编译,以 Protable 的方式部署,所以写了一套脚本来编译整套依赖。
当然, SDK 能搞定的就尽量在 SDK 上搞定,毕竟厂商给的 SDK 是基本测试过的,需要在软件上严格版本的,比如 Python 、 Qt 这种东西,尤其是各种 Python 包,还是需要主动管理的,交付时放进系统的 rootfs 下一起 pack。
而且不同厂商不同 SDK 也有各种情况,为了让包管理不受这方面影响,也需要把应用以依赖的编译流程独立出来维护。
对于绝大多数情况,使用 Autotools 的软件的只需要传入下面的参数:
--build=... -host=...\
CC=...\
CXX=...\
AR=...\
STRIP=...\
RANLIB=...\
--prefix=...
使用 CMake 的话:
-DCMAKE_C_COMPILER=...\
-DCMAKE_CXX_COMPILER=...\
-DCMAKE_PREFIX_PATH=...
这些基本是通用的,但每个软件基本也都有特殊情况需要特殊处理。
为了语言的清晰性,对于交叉编译中指代平台的词汇,下面就依照 Autotools 的规则:
- host : 构建的目标平台
- build : 构建发生的平台
- target : 构建的目标平台的构建工具其所构建的目标平台,暂时不涉及
编译 Python 需要先编译 build 平台的 Python 再编译 host 平台的,一是因为要链接,二是为了用 crossenv 交叉编译扩展模块。
Python 扩展模块使用 crossenv 来交叉编译,首先用 build 平台的 Python 安装 crossenv 再创建 cross_venv 交叉环境之后,在交叉环境运行 get-pip.py 安装交叉环境的 pip 之后就只需要正常的 python -m pip install <package> 就可以正常编译安装目标 host 平台的第三方库到 /path/to/cross_venv/lib/python<version> 了:
${PYTHON_BUILD} -m pip install crossenv
${PYTHON_BUILD} -m crossenv --without-pip ${PYTHON_HOST} cross_venv
cd cross_venv/cross/bin
source activate
export CC=...
export CXX=...
export CFLAGS=...
export CPPFLAGS=...
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py -k
python get-pip.py
pip install numpy # ...
由于 source 到了 cross_venv ,所以编译 Python 以及扩展模块就放在最后完成。
对于编译时需要链接其他库的: 在 cross_venv 里面手动调用 python setup.py 或是 python -m pip install .
对于运行时加载其他动态库的: ctypes.util.find_library 可能失效,修改为直接 _ffi.dlopen
Qt 交叉编译需要通过 xplatform 参数指定工具链,如果没有自带的,就需要在 qtbase/mkspec 手动创建一个并选择。
Qt 默认会编译所有模块,对于不需要的可以在配置时 -skip :
-skip qt3d -skip qtwebengine ...
Qt 默认是不提供字体的,没有字体的情况下显示不了任何字符,所以 export QT_QPA_FONTDIR 来指向存放字体文件( ttf / otf )的目录。
Qt Plugin 和 QML 也需要:
export QT_QPA_PLATFORM_PLUGIN_PATH=/<package-install-dir>/plugins
export QML2_IMPORT_PATH=/<package-install-dir>/qml
export QML_IMPORT_PATH=/<package-install-dir>/qml
export QT_QPA_FONTDIR=<font-dir>