Windows平台基于Android NDK编译boost小记

前言

本文记录在 Windows 环境下,使用 android-ndk-r26d 编译 Boost 1.74 Android 静态库的完整过程。

目标 ABI:

  • armeabi-v7a
  • arm64-v8a
  • x86
  • x86_64

⚠️ 说明:较新的 NDK 已移除 armeabi ABI,android-ndk-r26d 同样不再支持它。本文仅涵盖 NDK r26d 所支持的 Android ABI。


1. 准备 Android NDK

下载并解压 Android NDK,本文以 android-ndk-r26d 为例,假设安装路径为:

D:/Installed_Files/android_ndk/android-ndk-r26d

NDK 自带的 Clang 包装脚本位于:

D:/Installed_Files/android_ndk/android-ndk-r26d/toolchains/llvm/prebuilt/windows-x86_64/bin

后续我们将直接使用这些 .cmd 编译器包装脚本,例如:

aarch64-linux-android21-clang++.cmd
armv7a-linux-androideabi21-clang++.cmd
i686-linux-android21-clang++.cmd
x86_64-linux-android21-clang++.cmd

💡 这些 wrapper 已经内置了目标架构与 Android API Level,因此无需再手动传递 --target=...--sysroot=...


2. 准备 Boost 1.74

下载并解压 Boost 1.74,例如解压到:

D:/workspace/boost_1_74_0

从开始菜单打开 VS20XX 的开发人员命令提示符(x86 或 x64 版本都可以):
VS2022命令行编译环境

切换到 Boost 源码根目录:

cd D:\workspace\boost_1_74_0

选一个对应的msvc版本(这里以vc142为例),生成 b2 构建工具:

.\bootstrap.bat vc142

执行成功后,根目录下会出现 b2.exe


后续所有编译命令都在 Boost 根目录下执行。

3. 编辑 user-config.jam

在 Boost 根目录新建(或编辑) user-config.jam,内容如下:

import os ; 

# 替换成你的 NDK 路径
androidNDKRoot = D:/Installed_Files/android_ndk/android-ndk-r26d ;
androidToolchain = $(androidNDKRoot)/toolchains/llvm/prebuilt/windows-x86_64 ;
androidBin = $(androidToolchain)/bin ;
androidSysroot = $(androidToolchain)/sysroot ;

# Android armeabi-v7a, API 21.
using clang : android_armv7 :
    $(androidBin)/armv7a-linux-androideabi21-clang++.cmd
    :
    <compileflags>-fPIC
    <compileflags>-mthumb
    <cxxflags>-std=c++14
    <cxxflags>-g
    <cxxflags>-Wno-enum-constexpr-conversion
    <linkflags>-mthumb
    <archiver>$(androidBin)/llvm-ar.exe
    <ranlib>$(androidBin)/llvm-ranlib.exe
    ;

# Android arm64-v8a, API 21.
using clang : android_arm64 :
    $(androidBin)/aarch64-linux-android21-clang++.cmd
    :
    <compileflags>-fPIC
    <cxxflags>-std=c++14
    <cxxflags>-g
    <cxxflags>-Wno-enum-constexpr-conversion
    <archiver>$(androidBin)/llvm-ar.exe
    <ranlib>$(androidBin)/llvm-ranlib.exe
    ;

# Android x86, API 21.
using clang : android_x86 :
    $(androidBin)/i686-linux-android21-clang++.cmd
    :
    <compileflags>-fPIC
    <cxxflags>-std=c++14
    <cxxflags>-g
    <cxxflags>-Wno-enum-constexpr-conversion
    <archiver>$(androidBin)/llvm-ar.exe
    <ranlib>$(androidBin)/llvm-ranlib.exe
    ;

# Android x86_64, API 21.
using clang : android_x86_64 :
    $(androidBin)/x86_64-linux-android21-clang++.cmd
    :
    <compileflags>-fPIC
    <cxxflags>-std=c++14
    <cxxflags>-g
    <cxxflags>-Wno-enum-constexpr-conversion
    <archiver>$(androidBin)/llvm-ar.exe
    <ranlib>$(androidBin)/llvm-ranlib.exe
    ;

⚠️ 特别注意:工具集版本名(如 android_armv7android_arm64)请使用下划线 _,不要写成 android-armv7android-x86_64。包含 - 的名称可能被 Boost.Build 解析为子特性,从而引发如下错误:

error: "android" is not a known subfeature value of <toolset>clang

4. 编译 armeabi-v7a

在管理员 PowerShell 中,确保当前目录仍为 Boost 根目录,然后执行:

.\b2 -q -j8 -a -d+2 --debug-configuration `
  --user-config=.\user-config.jam `
  toolset=clang-android_armv7 `
  target-os=android architecture=arm address-model=32 abi=aapcs binary-format=elf `
  threadapi=pthread threading=multi link=static variant=release `
  --without-python `
  --stagedir=stage/android/armv7 stage `
  2>&1 | Tee-Object -FilePath .\build-ndk-armv7-release.log

📁 编译产物目录:stage/android/armv7/lib


5. 编译 arm64-v8a

.\b2 -q -j8 -a -d+2 --debug-configuration `
  --user-config=.\user-config.jam `
  toolset=clang-android_arm64 `
  target-os=android architecture=arm address-model=64 abi=aapcs binary-format=elf `
  threadapi=pthread threading=multi link=static variant=release `
  --without-python `
  --stagedir=stage/android/arm64 stage `
  2>&1 | Tee-Object -FilePath .\build-ndk-arm64-release.log

📁 编译产物目录:stage/android/arm64/lib


6. 编译 x86

.\b2 -q -j8 -a -d+2 --debug-configuration `
  --user-config=.\user-config.jam `
  toolset=clang-android_x86 `
  target-os=android architecture=x86 address-model=32 abi=sysv binary-format=elf `
  threadapi=pthread threading=multi link=static variant=release `
  --without-python `
  --stagedir=stage/android/x86 stage `
  2>&1 | Tee-Object -FilePath .\build-ndk-x86-release.log

📁 编译产物目录:stage/android/x86/lib


7. 编译 x86_64

.\b2 -q -j8 -a -d+2 --debug-configuration `
  --user-config=.\user-config.jam `
  toolset=clang-android_x86_64 `
  target-os=android architecture=x86 address-model=64 abi=sysv binary-format=elf `
  threadapi=pthread threading=multi link=static variant=release `
  --without-python `
  --stagedir=stage/android/x86_64 stage `
  2>&1 | Tee-Object -FilePath .\build-ndk-x86_64-release.log

📁 编译产物目录:stage/android/x86_64/lib


注意:

  • --stagedir= 后应改为您希望输出库文件的目录路径。
  • variant= 后应改为你希望编译的模式(debug / release
  • address-model= 后根据目标平台填写 32(x86)或 64(x64)。

8. 关于 --without-python

所有编译命令中都添加了 --without-python

原因在于 bootstrap.bat 可能会自动探测到本机安装的 Python(例如 C:\Program Files\Python311\Include\pyconfig.h),交叉编译 Android 时若误用了 Windows 下的 Python 头文件,就会出现类似错误:

C:\Program Files\Python311\Include\pyconfig.h:59:10: fatal error: 'io.h' file not found
#include <io.h>
         ^~~~~~

io.h 属于 Windows C Runtime 头文件,Android NDK 的 sysroot 中并不存在它。

🔹 除非你确实需要编译 Android 版 Boost.Python,并且已准备好对应目标 ABI 的 Python 头文件与库,否则建议一律使用 --without-python


9. 获取编译制品

四个 ABI 的静态库分别位于:

stage/android/armv7/lib
stage/android/arm64/lib
stage/android/x86/lib
stage/android/x86_64/lib

建议按 Android 工程常见的 ABI 目录结构整理:

boost_1_74_0_android/
  include/
    boost/
  lib/
    armeabi-v7a/
    arm64-v8a/
    x86/
    x86_64/

⚠️ Android 的 .a 静态库不能像 macOS universal library 那样将多个 ABI 合并成一个 .a。实际接入工程时,必须按 ABI 分目录存放,并在 CMake 中通过 ${ANDROID_ABI} 选择对应目录。

CMake 集成示例:

set(BOOST_ROOT "${CMAKE_CURRENT_LIST_DIR}/third_party/boost_1_74_0_android")
set(BOOST_LIB_DIR "${BOOST_ROOT}/lib/${ANDROID_ABI}")

add_library(boost_system STATIC IMPORTED)
set_target_properties(boost_system PROPERTIES
    IMPORTED_LOCATION "${BOOST_LIB_DIR}/libboost_system.a"
)

target_include_directories(your_target PRIVATE
    "${BOOST_ROOT}/include"
)

target_link_libraries(your_target PRIVATE
    boost_system
)

10. 常见问题

10.1 找不到 cstddef

fatal error: 'cstddef' file not found

通常是 NDK sysroot 或 target 未正确生效。本文使用 NDK 内置的 *-clang++.cmd wrapper,可避免手动配置 --target--sysroot 带来的错误。

10.2 std::unary_function 报错

若使用 -std=c++17,Boost 1.74 可能遇到 std::unary_function 已被移除的问题。因此本文统一使用:

<cxxflags>-std=c++14

10.3 enum-constexpr-conversion 警告

新版 Clang 可能在 Boost.MPL 中报出此类警告。本文通过以下参数规避:

<cxxflags>-Wno-enum-constexpr-conversion

10.4 日志过多,难以定位错误

本文编译命令中使用了:

-d+2 --debug-configuration

这两个参数会输出更详细的编译命令与 Boost.Build 配置加载信息,便于排查 user-config.jam 是否生效、实际调用的编译器及参数。确认配置无误后,可将其移除以减少日志量。

同时,命令中的:

2>&1 | Tee-Object -FilePath $log

可以同时在控制台显示输出并保存完整日志到文件。

若错误日志仍然混乱,可临时将 -j8 改为 -j1,以单线程方式编译,更容易定位第一个编译错误。


📚 参考

posted @ 2026-08-05 14:56  倚剑问天  阅读(8)  评论(0)    收藏  举报