Apache Arrow Java Jars Task:跨平台 C++ JNI 共享库打包机制与构建流程解析
发布时间:2026/9/23 3:37:06 作者:尧图编辑部 阅读量:1,286

数据工程大数据序列化数据分析【免费下载链接】arrowApache Arrow is a multi-language toolbox for accelerated data interchange and in-memory processing项目地址https://gitcode.com/gh_mirrors/arrow13/arrow点击查看免费下载本文基于 Apache Arrow 仓库中 dev/tasks/java-jars/README.md 及其配套工作流与构建脚本系统讲解 Arrow 如何为依赖 C 共享库的 Java 组件C Data Interface、Dataset、ORC、Gandiva生成跨平台可用的捆绑 jar。读者将掌握为什么这些 jar 需要内嵌 C 原生库、Linux/macOS/Windows 三平台如何分别编译并静态链接依赖、如何通过archery linking check-dependencies校验产物纯净性以及新增第三方依赖时应修改哪些文件。一、任务背景为什么 Arrow Java 组件需要打包 C 共享库Apache Arrow 的 Java 实现中有一部分组件在执行时依赖 C 编译出的原生共享库通过 JNIJava Native Interface完成跨语言的数据通道与高性能计算。这类组件包括C Data Interfacearrow-c-data基于 Arrow C Data Interface 规范与 C 侧交换内存数据对应的原生库为libarrow_cdata_jniDatasetarrow-dataset访问 C Dataset API 的 JNI 封装对应libarrow_dataset_jniORCadapter/orc读取 ORC 文件的 JNI 实现对应libarrow_orc_jniGandivagandiva基于 LLVM 的表达式求值引擎对应libgandiva_jni。这些组件在 java/pom.xml 中被统一归入arrow-jniprofile 管理注释明确写着 these have dependency on cpp包含adapter/orc、gandiva、dataset、c四个模块C Data Interface 单独对应arrow-c-dataprofile 中的c模块。为了让用户拿到单个 jar 即可直接运行不需要预先安装 C 运行库dev/tasks/java-jars目录的任务采用如下核心策略也是关联文档的核心描述Arrow C 库在macOS 和 Linux 两个系统上分别编译编译时将其第三方依赖静态链接进产物最终把原生共享库一并打进 jar使同一份 jar 产物在两个系统上都能直接使用。二、任务整体架构四阶段 CI 流水线dev/tasks/java-jars目录下只有两个文件README.md与github.yml。其中 github.yml 是一份基于 Jinja2 模板使用 dev/tasks/macros.jinja 中定义的github_header、github_checkout_arrow、github_upload_releases等宏生成的 GitHub Actions 工作流整体分为四个 JobJob运行平台职责产物build-cpp-ubuntuubuntu-latest 自托管 arm64在 manylinux Docker 镜像中编译 Linux 版 C 库arrow-shared-libs-linux-{arch}.tar.gzbuild-cpp-macosmacos-13 / macos-14编译 macOS 版 C 库arrow-shared-libs-macos-{arch}.tar.gzbuild-cpp-windowswindows-2019编译 Windows 版 C 库arrow-shared-libs-windows.tar.gzpackage-jarsmacos-latest汇总三平台共享库打包成最终 jar上传至 release 的*.jar、*.pom等package-jars通过needs关键字依赖前三个构建 Job保证只有三平台共享库全部就绪后才开始打包。跨平台的共享库最终统一输出到arrow/java-dist/目录按组件名/架构名/共享库的目录结构组织例如arrow/java-dist/arrow_cdata_jni/x86_64/libarrow_cdata_jni.so arrow/java-dist/arrow_dataset_jni/aarch_64/libarrow_dataset_jni.so arrow/java-dist/arrow_orc_jni/x86_64/libarrow_orc_jni.dylib arrow/java-dist/gandiva_jni/x86_64/gandiva_jni.dll三、Linux 构建manylinux Docker 镜像与静态依赖3.1 构建镜像新增依赖时唯一需要修改的文件关联文档明确指出Linux 下编译 C 库使用 Docker 镜像如果需要添加任何新依赖需要修改构建镜像文件。需要说明的是当前仓库中已不存在 README 里写的ci/docker/java-bundled-jars.dockerfile实际承载该职责的是 ci/docker/java-jni-manylinux-201x.dockerfilegithub.yml中通过archery docker run ... java-jni-manylinux-2014引用该镜像2014 为 manylinux 版本标签。该镜像在基础镜像之上完成三件事通过 vcpkg 安装全部第三方依赖且显式声明了各特性RUN vcpkg install \ --clean-after-build \ --x-install-root${VCPKG_ROOT}/installed \ --x-manifest-root/arrow/ci/vcpkg \ --x-featuredev \ --x-featureflight \ --x-featuregcs \ --x-featurejson \ --x-featureparquet \ --x-featuregandiva \ --x-features3其中gandiva特性还特别注释了 Use enable llvm[enable-rtti] in the vcpkg.json to avoid link problems in Gandiva即通过 ci/vcpkg/vcpkg.json 启用 LLVM 的 RTTI 支持避免 Gandiva 链接失败。这也是新增依赖时的关键入口之一。安装 Java 与 MavenARG java1.8.0、ARG maven3.9.3通过 yum 安装java-1.8.0-openjdk-devel并下载官方 Maven 二进制解压到/usr/local后建立mvn软链接。设置构建环境变量ARROW_HOME/tmp/local、ARROW_JAVA_CDATAON、ARROW_JAVA_JNION、ARROW_USE_CCACHEON供后续ci/scripts/{cpp,java}_*.sh脚本使用。3.2 工作流中的 Linux 构建步骤build-cpp-ubuntuJob 使用构建矩阵覆盖两个架构架构runs_onarchery 架构参数说明x86_64ubuntu-latestamd64aliasx86_64标准 GitHub 托管 runneraarch_64self-hosted Linux arm64arm64v8aliasaarch64自托管 ARM runner且archery_use_docker_cli0核心构建命令只有一条其余工作释放磁盘空间、安装 archery、配置 sccache 环境变量均由宏模板展开archery docker run \ -e ARROW_JAVA_BUILDOFF \ -e ARROW_JAVA_TESTOFF \ java-jni-manylinux-2014构建完成后用tar -cvzf arrow-shared-libs-linux-{{ arch }}.tar.gz arrow/java-dist/压缩产物并上传为ubuntu-shared-lib-{arch}artifact。此外在默认分支arrow.is_default_branch()上工作流还会登录 Docker Hub 并执行archery docker push java-jni-manylinux-2014把更新后的镜像推回仓库。3.3 manylinux 构建脚本静态链接策略实际编译逻辑在 ci/scripts/java_jni_manylinux_build.sh 中它先编译 C 库再调用 ci/scripts/java_jni_build.sh 编译 JNI 封装。其静态链接策略集中体现在 CMake 参数上cmake \ -DARROW_ACERO${ARROW_ACERO} \ -DARROW_BUILD_SHAREDOFF \ -DARROW_BUILD_TESTSON \ -DARROW_CSV${ARROW_DATASET} \ -DARROW_DATASET${ARROW_DATASET} \ -DARROW_SUBSTRAIT${ARROW_DATASET} \ -DARROW_DEPENDENCY_SOURCEVCPKG \ -DARROW_DEPENDENCY_USE_SHAREDOFF \ -DARROW_GANDIVA${ARROW_GANDIVA} \ -DARROW_GANDIVA_PC_CXX_FLAGS${GANDIVA_CXX_FLAGS} \ -DARROW_GCS${ARROW_GCS} \ -DARROW_JEMALLOC${ARROW_JEMALLOC} \ -DARROW_ORC${ARROW_ORC} \ -DARROW_PARQUET${ARROW_PARQUET} \ -DARROW_RPATH_ORIGIN${ARROW_RPATH_ORIGIN} \ -DARROW_S3${ARROW_S3} \ -DARROW_USE_CCACHE${ARROW_USE_CCACHE} \ -DCMAKE_BUILD_TYPE${CMAKE_BUILD_TYPE} \ -DCMAKE_INSTALL_PREFIX${ARROW_HOME} \ -DCMAKE_UNITY_BUILD${CMAKE_UNITY_BUILD} \ -DORC_SOURCEBUNDLED \ -DPARQUET_REQUIRE_ENCRYPTIONOFF \ -DVCPKG_MANIFEST_MODEOFF \ -DVCPKG_TARGET_TRIPLET${VCPKG_TARGET_TRIPLET} \ -GNinja \ ${arrow_dir}/cpp关键参数解读-DARROW_DEPENDENCY_USE_SHAREDOFF所有第三方依赖强制静态链接这是打进 jar 即可直接运行的根本保证-DARROW_BUILD_SHAREDOFFC 主库只构建静态版本最终的 JNI 共享库动态加载它-DARROW_DEPENDENCY_SOURCEVCPKG依赖统一由 vcpkg 提供配合VCPKG_TARGET_TRIPLET默认x64-linux-static-${CMAKE_BUILD_TYPE}即静态 triplet与VCPKG_MANIFEST_MODEOFF-DORC_SOURCEBUNDLEDORC 使用 bundled 源码而非系统包GANDIVA_CXX_FLAGS注入 devtoolset 工具链的 C 头文件路径与-lpthread规避 manylinux 环境下的链接问题。同时脚本默认开启ARROW_DATASETON、ARROW_GANDIVAON、ARROW_ORCON、ARROW_S3ON、ARROW_GCSON、ARROW_ACEROON因此生成的 JNI 库完整覆盖上述四类组件。测试阶段会排除需要 MinIO 的arrow-s3fs-test、在 aarch64 上崩溃的arrow-gcsfs-test以及两个不稳定的 Acero 连接测试。JNI 层的编译在 ci/scripts/java_jni_build.sh 中完成CMake 配置重点cmake \ -DARROW_JAVA_JNI_ENABLE_DATASET${ARROW_DATASET:-OFF} \ -DARROW_JAVA_JNI_ENABLE_GANDIVA${ARROW_GANDIVA:-OFF} \ -DARROW_JAVA_JNI_ENABLE_ORC${ARROW_ORC:-OFF} \ -DBUILD_TESTING${ARROW_JAVA_BUILD_TESTS} \ -DCMAKE_BUILD_TYPE${CMAKE_BUILD_TYPE} \ -DCMAKE_PREFIX_PATH${arrow_install_dir} \ -DCMAKE_INSTALL_PREFIX${prefix_dir} \ -DProtobuf_USE_STATIC_LIBSON \ -GNinja \ ${arrow_dir}/java其中-DProtobuf_USE_STATIC_LIBSON进一步确保 protobuf 也是静态链接。脚本末尾会根据平台把安装产物从lib/Linux/macOS或bin/Windows 的 DLL移动到分发目录dist_dir。四、macOS 构建Homebrew 环境清理与静态链接4.1 工作流配置build-cpp-macosJob 同样使用矩阵架构runs_onx86_64macos-13aarch_64macos-14环境变量MACOSX_DEPLOYMENT_TARGET10.15保证了产物的最低系统兼容版本。该 Job 安装 Python 3.12 与 archerypip install -e arrow/dev/archery[all]后通过brew bundle --filearrow/cpp/Brewfile与arrow/java/Brewfile安装依赖。4.2 为什么要卸载 Homebrew 的若干包工作流中有一段容易被忽略但非常关键的环境清理逻辑其目的是防止 Homebrew 的共享库污染静态链接结果llvm卸载llvm而保留llvm14。注释解释了原因llvm依赖 z3而 Homebrew 的 z3 只提供共享库z3 的 CMake 不支持同时构建 shared 与 static 两种库llvm14不依赖 z3可避免 Gandiva 的 LLVM 依赖落入共享链接。若系统中存在llvmArrow C 会优先选择较新的llvm而非llvm14因此必须显式卸载aws-sdk-cppHomebrew 只提供共享版若保留会使构建混用 Homebrew 与 bundled 的 aws-sdk-cpp故卸载以强制使用 bundled 版本re2 / grpc / grpc1.54为保证 RE2 使用 bundled 静态版本先卸载 grpc它依赖 RE2再卸载 re2protobuf防止 Homebrew 的 protobuf 头文件/库文件被测试阶段意外引用确保使用 bundled protobuf。此外还有一段针对python的brew install --overwrite处理用于规避非 Homebrew 安装的 Python 3 与 GitHub Actions 上/usr/local路径冲突导致的更新失败。4.3 macOS 构建脚本ci/scripts/java_jni_macos_build.sh 与 manylinux 脚本结构类似但依赖管理走 Homebrew 而非 vcpkg静态链接通过-DARROW_DEPENDENCY_USE_SHAREDOFF实现并额外开启-DARROW_GANDIVA_STATIC_LIBSTDCPPONGandiva 静态链接 libstdc。工作流在调用前还需设置JAVA_HOME$(brew --prefix openjdk11)/libexec/openjdk.jdk/Contents/Home使 CMake 能找到 Homebrew 的 JDK。macOS 上架构归一化规则为arm64 → aarch_64、i386 → x86_64与 Linux 侧保持一致。4.4 共享依赖白名单校验两个平台的构建脚本末尾都会运行 archery 的链接校验命令例如 macOS 侧archery linking check-dependencies \ --allow CoreFoundation \ --allow Security \ --allow libSystem \ --allow libarrow_cdata_jni \ --allow libarrow_dataset_jni \ --allow libarrow_orc_jni \ --allow libc \ --allow libcurl \ --allow libgandiva_jni \ --allow libncurses \ --allow libobjc \ --allow libz \ arrow_cdata_jni/${normalized_arch}/libarrow_cdata_jni.dylib \ arrow_dataset_jni/${normalized_arch}/libarrow_dataset_jni.dylib \ arrow_orc_jni/${normalized_arch}/libarrow_orc_jni.dylib \ gandiva_jni/${normalized_arch}/libgandiva_jni.dylibLinux 侧的白名单则只允许ld-linux-*、libc、libdl、libgcc_s、libm、libpthread、librt、libstdc、libz、linux-vdso等系统基础库。任何超出白名单的共享依赖都会导致构建失败这是从机制上杜绝jar 里偷偷依赖外部共享库的保障也是理解依赖被静态链接这一策略的落地点。五、Windows 构建MSVC 环境下的 JNI 编译build-cpp-windowsJob 运行在windows-2019上流程要点通过actions/setup-javav3安装 Temurin JDK 11运行 ci/scripts/download_tz_database.sh 下载时区数据库ORC 读取依赖TZDIR安装 sccache 并配置缓存环境变量在cmdshell 中先执行vcvarsall.bat x64初始化 MSVC 环境再通过 bash 调用 ci/scripts/java_jni_windows_build.sh 完成构建输出arrow/java-dist压缩为arrow-shared-libs-windows.tar.gz上传。Windows 的 JNI 产物是*.dll且会被安装到bin/目录因此java_jni_build.sh中专门处理了bin/与lib/两种安装路径。六、统一打包Maven 构建与最终产物6.1 汇总与产物校验package-jarsJob 在 macos-latest 上运行下载全部五个共享库包Linux x86_64 / aarch_64、macOS x86_64 / aarch_64、Windows并逐一解压。随后用一组test -f断言验证三平台所有关键共享库确实存在例如 Linux 的 4 个.so、macOS 的 4 个.dylib、Windows 的 3 个.dll注意 Windows 目前只打包arrow_cdata_jni、arrow_dataset_jni、arrow_orc_jni不包含 Gandiva任何缺失都会让流水线立即失败。6.2 版本号归一化打包前先用 Maven 的versions:set把版本统一替换为{{ arrow.no_rc_snapshot_version }}该值由 dev/archery/archery/crossbow/core.py 从发布版本推导生成并分别作用于根pom.xml、bom与maven三个 POM保证发布产物版本一致且不带 RC 后缀。6.3 完整构建脚本核心打包逻辑在 ci/scripts/java_full_build.shmvn clean \ install \ -Papache-release \ -Parrow-c-data \ -Parrow-jni \ -Darrow.cpp.build.dir$dist_dir \ -Darrow.c.jni.dist.dir$dist_dir \ --no-transfer-progress要点说明-Parrow-jni激活上文提到的 JNI 组件集合-Parrow-c-data激活 C Data Interface 模块-Darrow.cpp.build.dir与-Darrow.c.jni.dist.dir指向共享库分发目录java-dist供各 JNI 模块的 CMake 配置见 java/pom.xml 中arrow.dataset.jni.dist.dir、CMAKE_PREFIX_PATH等属性定位原生库-Papache-release会为产物生成 GPG 签名脚本先用一个批处理生成的临时密钥buildexample.com满足该 profile 的要求注释说明这些签名不用于正式发布流程构建前会清空本地 Maven 仓库~/.m2/repository/org/apache/arrow下残留的旧 jar/zip/pom避免污染构建结束后把 Maven 仓库中org/apache/arrow下所有*.jar、*.pom、*.xml、*.json、*.zip复制到java-dist分发目录。最后通过github_upload_releases宏定义于 dev/tasks/macros.jinja调用archery crossbow upload-artifacts把这些产物上传到 Crossbow 队列对应的 GitHub release并用archery crossbow status --validate校验上传完整性。上传的产物模式为arrow/java-dist/*.jar、*.json、*.pom、*.xml、*.zip。七、任务调度Crossbow 与发布流程中的位置java-jars任务通过 dev/tasks/tasks.yml 注册到 Crossbow 调度体系出现在三个任务组中packaging随其他打包任务conan、nuget、python-sdist、r-binary-packages 等一起执行nightly作为每日夜间构建的一部分nightly-packaging夜间打包任务的集合。发布阶段则由 dev/release/06-java-upload.sh 从${crossbow_package_dir}/${CROSSBOW_JOB_ID}/java-jars目录取用本任务产物进行上传。也就是说java-jars 任务既是每日构建的一部分也是 Apache Arrow 正式发布 Java 构件的前置流水线其产出直接影响最终发布到 Maven Central 的 jar 是否包含完整的原生库。八、实操建议新增依赖时改哪里结合关联文档与源码当需要为捆绑 jar 增加新的第三方依赖时操作路径如下Linux修改 ci/docker/java-jni-manylinux-201x.dockerfile 中vcpkg install的--x-feature列表或调整 ci/vcpkg/vcpkg.json 中的特性定义改完后需重新构建并推送java-jni-manylinux-2014镜像默认分支上工作流会自动执行archery docker pushmacOS修改 java/Brewfile 与 cpp/Brewfile并视需要在工作流中补充卸载同名 Homebrew 共享库的步骤保证静态链接不被干扰Windows修改 ci/scripts/java_jni_windows_build.sh 对应的依赖安装与 CMake 参数全平台把新增的共享依赖加入各平台archery linking check-dependencies的--allow白名单否则校验环节会失败同时更新package-jars中的test -f断言确保新产物出现在java/java-dist的预期路径下。九、延伸阅读关联文档与工作流dev/tasks/java-jars/README.md、dev/tasks/java-jars/github.yml构建镜像与脚本ci/docker/java-jni-manylinux-201x.dockerfile、ci/scripts/java_jni_manylinux_build.sh、ci/scripts/java_jni_macos_build.sh、ci/scripts/java_jni_build.sh、ci/scripts/java_full_build.shJava 侧工程配置java/pom.xmlarrow-jni/arrow-c-dataprofile、java/c/README.mdC Data Interface 模块本地构建方法mvn -Parrow-c-data install、java/README.md调度与发布dev/tasks/tasks.yml、dev/tasks/macros.jinja、dev/release/06-java-upload.sh赞分享数据工程大数据序列化数据分析【免费下载链接】arrowApache Arrow is a multi-language toolbox for accelerated data interchange and in-memory processing项目地址https://gitcode.com/gh_mirrors/arrow13/arrow点击查看免费下载相关推荐Apache Arrow Java Bundled Jars 构建任务解析把 C 原生库打进 JAR 的跨平台方案Apache Arrow Java Bundled Jars 构建任务解析把 C 原生库打进 JAR 的跨平台方案 Apache Arrow 的 Java数据工程数据分析大数据Apache Arrow Java 模块构建完全指南Maven、JNI 原生库与 Nightly 包安装Apache Arrow Java 模块构建完全指南Maven、JNI 原生库与 Nightly 包安装 本篇技术指南围绕 Apache Arrow 仓库中的数据工程数据分析大数据Apache Arrow 中 conda-forge Recipes 的维护与同步机制跨平台打包实践解析Apache Arrow 中 conda forge Recipes 的维护与同步机制跨平台打包实践解析 Apache Arrow 在仓库中维护着一套与 co数据工程数据分析大数据创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考