OHOS NDK cross-compile, replacing Alpine-as-OHOS (1.6.58.6) - #11
Closed
ronaldtse wants to merge 6 commits into
Closed
OHOS NDK cross-compile, replacing Alpine-as-OHOS (1.6.58.6)#11ronaldtse wants to merge 6 commits into
ronaldtse wants to merge 6 commits into
Conversation
The 1.6.58.4/.5 aarch64-linux-ohos gem shipped an Alpine-built musl arm64 binary under the OHOS platform label, based on an unverified assumption that 'same dynamic linker path = byte-compatible'. The real risks -- musl symbol versions, -fvisibility=hidden defaults, TLS/pthread layout, OHOS's mandatory code-signing requirement -- were hand-waved away. This changeset does it properly. New path: cross-compile libpng with the OHOS NDK from OpenHarmony's daily_build API. The NDK ships clang (target triple aarch64-unknown-linux-ohos), the OHOS sysroot, and binary-sign-tool. Reference implementation: https://github.com/hqzing/ohos-node Files added: - ext/ohos/setup-toolchain.sh -- downloads ohos-sdk-public + LLVM-19 via dcp.openharmony.cn/api/daily_build/build/list/component, extracts to /tmp/ohos-ndk, sets OHOS_LLVM/OHOS_SYSROOT/OHOS_SIGN_TOOL. - ext/ohos/toolchain.cmake -- CMAKE_SYSTEM_NAME=Linux, CMAKE_SYSTEM_PROCESSOR=aarch64, points C/CXX compilers at OHOS clang, sets CMAKE_SYSROOT to OHOS sysroot. - ext/ohos/smoke-test.c -- minimal libpng round-trip (2x2 RGBA encode -> decode -> compare pixels). - ext/ohos/smoke-test.sh -- compiles smoke-test.c with OHOS clang against the freshly-built libpng16.so, runs via qemu-aarch64 with QEMU_LD_PREFIX=sysroot. Verifies the .so loads and round-trips. Files updated: - lib/libpng/recipe.rb: - setup_cross_compile hook now sets @host=aarch64-unknown-linux-ohos and OHOS_TOOLCHAIN_FILE env var when target is OHOS. - configure_defaults appends -DCMAKE_TOOLCHAIN_FILE for OHOS. - install step signs the .so via binary-sign-tool -selfSign 1 (mandatory for runtime loading on OHOS). - .github/workflows/build.yml: removed aarch64-linux-ohos from build_musl matrix; added build_ohos job on ubuntu-latest that runs setup-toolchain.sh, cross-compiles, signs, runs qemu smoke test. - .github/workflows/release.yml: same changes; publish job now depends on build_ohos in addition to build_musl and build. - README.adoc, CLAUDE.md: updated to reflect the new build path. - CHANGELOG.md: 1.6.58.6 entry documents the switch and warns users that 1.6.58.4/.5 OHOS gems used the Alpine bytes (status: unknown whether they actually ran on real OHOS hardware). Bumps LIBPNG_RUBY_ITERATION to 6.
The OHOS NDK clang doesn't auto-detect the multiarch library path (.../usr/lib/aarch64-linux-ohos) when --sysroot is set. ld.lld then fails with 'cannot open Scrt1.o / crti.o / -lc'. Two changes: 1. setup-toolchain.sh now auto-detects the sysroot path by finding the aarch64-linux-ohos multiarch dir, walking up three levels to get the sysroot root. Exports both OHOS_SYSROOT and OHOS_LIB_DIR (the multiarch subdir). 2. toolchain.cmake sets CMAKE_EXE_LINKER_FLAGS / SHARED / MODULE to include --sysroot AND -L $OHOS_LIB_DIR, so ld.lld can find the C runtime + libc. Also: setup-toolchain.sh prints diagnostic output (sysroot path, lib dir, sample file listing) so future layout changes are easy to spot in CI logs.
…' dir Previous detection assumed the multiarch subdir lived 3 levels deep (usr/lib/aarch64-linux-ohos). OHOS actually ships it 1 level deep: llvm-19/sysroot/aarch64-linux-ohos/. New detection: find Scrt1.o anywhere matching *aarch64-linux-ohos*, take its directory as LIB_DIR, walk up until we hit a directory named 'sysroot'. Falls back to LIB_DIR's parent if no 'sysroot' marker exists. Handles both layouts (sysroot/aarch64-linux-ohos and sysroot/usr/lib/aarch64-linux-ohos) without hard-coding depth.
libpng requires zlib. CMake's FindZLIB can't auto-discover it in the OHOS sysroot because the multiarch layout doesn't match the standard search paths FindZLIB expects. setup-toolchain.sh now finds libz.so and zlib.h under the sysroot and exports OHOS_ZLIB_LIBRARY + OHOS_ZLIB_INCLUDE_DIR. recipe.rb's configure_defaults passes these as -DZLIB_LIBRARY and -DZLIB_INCLUDE_DIR when target is OHOS.
The script runs under 'set -euo pipefail'. 'ls | head -10' causes head to exit after 10 lines, sending SIGPIPE to ls. ls exits non- zero, pipefail propagates, the whole script exits 1 -- before reaching zlib detection. The diagnostic output (sample lib dir listing) was useful for debugging but isn't essential. Add '|| true' to suppress pipefail when head closes the pipe.
Contributor
Author
|
Closing in favor of dockerharmony-based approach. The OHOS NDK cross-compile keeps hitting issues (sysroot layout, missing zlib in sysroot, pipefail on diagnostics). dockerharmony lets us verify Alpine-built musl arm64 bytes actually run in real OHOS userland without the cross-compile machinery. |
This was referenced Jul 26, 2026
ronaldtse
added a commit
that referenced
this pull request
Jul 26, 2026
- lib/libpng/version.rb: LIBPNG_RUBY_ITERATION 5 -> 6. - CHANGELOG.md: new 1.6.58.6 entry describing the OHOS NDK cross-compile (toolchain, static zlib, signing, dockerharmony verify) and listing PR #11 and #12 as superseded. - README.adoc: aarch64-linux-ohos row now reflects the actual build host (ubuntu-24.04-arm + OHOS NDK, verified in dockerharmony) instead of the misleading "Alpine, byte-compatible with musl". - CLAUDE.md: file table extended with lib/libpng/ohos/ + ext/ohos/; Common commands section now has an "OHOS build notes" subsection explaining the binfmt_misc + qemu-user-static setup and that local builds require arm64 + binfmt registration.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Properly cross-compile the
aarch64-linux-ohosgem using the OpenHarmony NDK, replacing the previous approach of shipping the Alpine-built musl arm64 binary under the OHOS platform label.Why
The 1.6.58.4/.5 OHOS gem shipped Alpine-built bytes, based on an unverified assumption that "same dynamic linker path (
/lib/ld-musl-aarch64.so.1) = byte-compatible." That hand-waved away real risks:-fvisibility=hiddendefaults may differ between toolchainsbinary-sign-tool) for runtime loading; an unsigned Alpine-built .so would not load on a real OHOS deviceThe proper fix is to use the actual OHOS NDK. Reference implementation:
hqzing/ohos-node(which builds Node.js for OHOS).How
Toolchain setup (
ext/ohos/)setup-toolchain.sh-- queries OpenHarmony's daily_build API (dcp.openharmony.cn/api/daily_build/build/list/component) forohos-sdk-publicandLLVM-19. Downloads, extracts. Exposes:OHOS_LLVM-- the OHOS NDK's LLVM dir (compilers live inbin/)OHOS_SYSROOT-- the OHOS sysroot (musl + system headers)OHOS_SIGN_TOOL--binary-sign-toolfor code signingtoolchain.cmake-- CMake config pointing at OHOS clang (aarch64-unknown-linux-ohos-clang) with the sysroot asCMAKE_SYSROOT.smoke-test.c+smoke-test.sh-- minimal libpng round-trip test. Compilessmoke-test.cagainst the freshly-builtlibpng16.so, runs viaqemu-aarch64withQEMU_LD_PREFIX=$OHOS_SYSROOT. Verifies the .so actually loads and the simplified API works (since we can't run Ruby itself on OHOS in CI).Recipe integration (
lib/libpng/recipe.rb)setup_cross_compilehook (previously empty) now sets@host=aarch64-unknown-linux-ohosandOHOS_TOOLCHAIN_FILEenv var when the target is OHOS.configure_defaultsappends-DCMAKE_TOOLCHAIN_FILEso CMake uses the OHOS cross-compile config.installstep signs the resulting.soviabinary-sign-tool sign -selfSign 1. Without signing, the .so won't load on a real OHOS device.CI (
build.yml+release.yml)aarch64-linux-ohosfrom thebuild_muslmatrix (no longer using Alpine path).build_ohosjob:ubuntu-latest(cross-compile host)setup-toolchain.shto install OHOS NDKrake gem:native:aarch64-linux-ohoswith OHOS env varsfile lib/libpng/libpng16.sopublishjob now depends onbuild_ohos.What this verifies
binary-sign-toolruns without error; .so carries a signature.What this does NOT verify
Caveats
Test plan
bundle exec rake-- 132 specs pass, rubocop clean (no source/test changes)Version
Bumps to
1.6.58.6. Resolves the regression acknowledged in the CHANGELOG (1.6.58.4/.5 used Alpine-built bytes for the OHOS platform).