libpng 1.6.58.5 → 1.6.58.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e9edc7cf7190ff782780b914a63bc3a26cd3c1dd71199c26ec144e3e3f72619f
4
- data.tar.gz: bed30533f0f5b33e4064213aa6bacecb8e815ca56234a8991ae8af70627cb40f
3
+ metadata.gz: fda67e6ac3b6280ed407565fc08a8166668093554afd534e33cf041d47900ecd
4
+ data.tar.gz: 060045bc45e2dc049d5957063a2dd045283b01f821666247b6a789638d35b277
5
5
  SHA512:
6
- metadata.gz: e94cbd6af3fbc2accb177d8f3adc9565582d1853e9f998ff314934b6b5f2816f058164b40a32ee7661b55ea5c58e920c03d600d30e49e7f1d51d5f71e280f3f7
7
- data.tar.gz: 88fca2579a17b68e184b381483687e43eef88d5a104ac74deb12056bd376e494db7e3b795312fad2042219979a0c9119b2daef8cd4dd2e47c6cf49925a2f5274
6
+ metadata.gz: 253211e3494d116f6cf13e78b5688cf171b0c4f85817b2f818fb3d69cffaa4e025687c7e086885b27ea57c2083555097a99732f188464f786676224987e4a08c
7
+ data.tar.gz: adc29322d89eb94d2f978f57e82be6f59d2a9691c233cefc09552d0c021e11f3f438fe1a8aebb6da2df56db5acbc9b7e8c0a1ff9697815489505f80b2ddc592b
@@ -143,12 +143,6 @@ jobs:
143
143
  platform: x86_64-linux-musl
144
144
  - os: ubuntu-24.04-arm
145
145
  platform: aarch64-linux-musl
146
- # OHOS (OpenHarmony / Huawei HarmonyOS PC) is musl-based arm64.
147
- # Built inside the same Alpine container as aarch64-linux-musl;
148
- # the resulting binary is byte-compatible. Only the gem's
149
- # platform label differs so RubyGems on OHOS selects it.
150
- - os: ubuntu-24.04-arm
151
- platform: aarch64-linux-ohos
152
146
 
153
147
  steps:
154
148
  - uses: actions/checkout@v4
@@ -174,27 +168,12 @@ jobs:
174
168
  git config --global --add safe.directory /work
175
169
  bundle install --jobs 4
176
170
  bundle exec rake "gem:native:${PLATFORM}"
177
- case "${PLATFORM}" in
178
- *-ohos)
179
- # OHOS gem is labeled aarch64-linux-ohos so RubyGems on OHOS
180
- # selects it, but Alpine Ruby reports *-linux-musl -- a
181
- # platform mismatch. The .so inside is musl-compatible, so
182
- # unpack the gem and load it via -Ilib directly to verify
183
- # the binary works without going through RubyGems install.
184
- mkdir -p /tmp/ohos-smoke
185
- gem unpack pkg/libpng-*.gem --target /tmp/ohos-smoke
186
- (cd /tmp/ohos-smoke/libpng-* && \
187
- ruby -Ilib -e 'require "libpng"; png = Libpng.encode(2, 2, "\xff" * 16, pixel_format: "RGBA"); puts Libpng.decode(png, pixel_format: "RGBA").inspect')
188
- ;;
189
- *)
190
- gem install -b pkg/libpng-*.gem
191
- # Smoke test from /tmp so bundler's source-tree LOAD_PATH doesn't
192
- # shadow the installed gem. Activate via `gem` so RubyGems resolves
193
- # the platform-specific binary gem (Alpine Ruby's platform string
194
- # is *-linux-musl, which must match the gem's platform suffix).
195
- (cd /tmp && ruby -e 'gem "libpng"; require "libpng"; png = Libpng.encode(2, 2, "\xff" * 16, pixel_format: "RGBA"); File.binwrite("test.png", png); puts Libpng.decode(png, pixel_format: "RGBA").inspect')
196
- ;;
197
- esac
171
+ gem install -b pkg/libpng-*.gem
172
+ # Smoke test from /tmp so bundler's source-tree LOAD_PATH doesn't
173
+ # shadow the installed gem. Activate via `gem` so RubyGems resolves
174
+ # the platform-specific binary gem (Alpine Ruby's platform string
175
+ # is *-linux-musl, which must match the gem's platform suffix).
176
+ (cd /tmp && ruby -e 'gem "libpng"; require "libpng"; png = Libpng.encode(2, 2, "\xff" * 16, pixel_format: "RGBA"); File.binwrite("test.png", png); puts Libpng.decode(png, pixel_format: "RGBA").inspect')
198
177
  BUILD_EOF
199
178
  chmod +x /tmp/alpine-build.sh
200
179
  docker run --rm \
@@ -208,4 +187,90 @@ jobs:
208
187
  - uses: actions/upload-artifact@v4
209
188
  with:
210
189
  name: pkg-${{ matrix.platform }}
190
+ path: pkg/*.gem
191
+
192
+ # OHOS (OpenHarmony / Huawei HarmonyOS PC) requires the official OHOS
193
+ # NDK to cross-compile. The NDK's clang and binary-sign-tool are x86_64
194
+ # ELF binaries; on this arm64 runner they run transparently via
195
+ # binfmt_misc + qemu-user-static. Verification (dockerharmony) runs
196
+ # natively because the arm64 rootfs matches the host architecture.
197
+ build_ohos:
198
+ name: build aarch64-linux-ohos (NDK)
199
+ runs-on: ubuntu-24.04-arm
200
+ needs: prepare
201
+ steps:
202
+ - uses: actions/checkout@v4
203
+
204
+ - name: Install host-side tools
205
+ # These are used for: NDK setup (curl/jq/unzip), artifact prep
206
+ # (file), and dockerharmony verification (docker is preinstalled).
207
+ run: |
208
+ sudo apt-get update
209
+ sudo apt-get install -y curl jq unzip file
210
+
211
+ - name: Register binfmt for amd64 docker emulation
212
+ # The OHOS NDK is x86_64-only. We run the entire build inside an
213
+ # amd64 docker container on this arm64 host -- docker's binfmt_misc
214
+ # registration handles the emulation transparently inside the
215
+ # container, with no library juggling on the host side.
216
+ run: docker run --privileged --rm tonistiigi/binfmt --install amd64
217
+
218
+ - name: Cache OHOS NDK
219
+ id: cache-ndk
220
+ uses: actions/cache@v4
221
+ with:
222
+ path: ext/ohos/ndk
223
+ key: ohos-ndk-${{ hashFiles('ext/ohos/setup-ndk.sh') }}
224
+
225
+ - name: Setup OHOS NDK (host-side; only curl/jq/unzip needed)
226
+ if: steps.cache-ndk.outputs.cache-hit != 'true'
227
+ run: sh ext/ohos/setup-ndk.sh --prefix ext/ohos/ndk
228
+
229
+ - name: Build OHOS gem in amd64 container
230
+ # The entire build (libpng + static zlib + signing) runs inside an
231
+ # amd64 docker container so the NDK's x86_64 clang + binary-sign-tool
232
+ # run natively (no qemu at the process level; docker's binfmt handles
233
+ # the container emulation as a whole).
234
+ run: |
235
+ docker run --rm --platform linux/amd64 \
236
+ -v "$PWD:/work" -w /work \
237
+ -e target_platform=aarch64-linux-ohos \
238
+ ruby:3.3 \
239
+ sh -c '
240
+ set -e
241
+ apt-get update
242
+ apt-get install -y --no-install-recommends cmake ninja-build zlib1g-dev
243
+ bundle install --jobs 4
244
+ bundle exec rake gem:native:aarch64-linux-ohos
245
+ # Confirm the .so was produced and is arm64 ELF (sanity).
246
+ file lib/libpng/libpng16.so
247
+ '
248
+
249
+ - name: Prepare dockerharmony artifacts (host-side)
250
+ # verify-prepare.sh cross-compiles smoke-test.c using the NDK clang.
251
+ # We run it inside the same amd64 container for the same reason.
252
+ run: |
253
+ docker run --rm --platform linux/amd64 \
254
+ -v "$PWD:/work" -w /work \
255
+ -e NDK_ROOT=/work/ext/ohos/ndk \
256
+ ruby:3.3 \
257
+ sh -c '
258
+ set -e
259
+ apt-get update
260
+ apt-get install -y --no-install-recommends file
261
+ sh ext/ohos/verify-prepare.sh
262
+ '
263
+
264
+ - name: Verify in dockerharmony (real OHOS userland, arm64-native)
265
+ run: |
266
+ docker pull ghcr.io/hqzing/dockerharmony:latest
267
+ docker run --rm \
268
+ -v "$PWD/ohos-verify:/work" \
269
+ -w /work \
270
+ ghcr.io/hqzing/dockerharmony:latest \
271
+ sh -c 'LD_LIBRARY_PATH=. ./smoke-test'
272
+
273
+ - uses: actions/upload-artifact@v4
274
+ with:
275
+ name: pkg-aarch64-linux-ohos
211
276
  path: pkg/*.gem
@@ -201,10 +201,6 @@ jobs:
201
201
  platform: x86_64-linux-musl
202
202
  - os: ubuntu-24.04-arm
203
203
  platform: aarch64-linux-musl
204
- # OHOS: same Alpine-built musl arm64 binary as aarch64-linux-musl,
205
- # packaged under a distinct platform label.
206
- - os: ubuntu-24.04-arm
207
- platform: aarch64-linux-ohos
208
204
  steps:
209
205
  - uses: actions/checkout@v4
210
206
  with:
@@ -222,22 +218,8 @@ jobs:
222
218
  git config --global --add safe.directory /work
223
219
  bundle install --jobs 4
224
220
  bundle exec rake "gem:native:${PLATFORM}"
225
- case "${PLATFORM}" in
226
- *-ohos)
227
- # OHOS gem is labeled aarch64-linux-ohos so RubyGems on OHOS
228
- # selects it, but Alpine Ruby reports *-linux-musl. The .so
229
- # inside is musl-compatible -- unpack and load via -Ilib to
230
- # verify the binary without going through RubyGems install.
231
- mkdir -p /tmp/ohos-smoke
232
- gem unpack pkg/libpng-*.gem --target /tmp/ohos-smoke
233
- (cd /tmp/ohos-smoke/libpng-* && \
234
- ruby -Ilib -e 'require "libpng"; png = Libpng.encode(2, 2, "\xff" * 16, pixel_format: "RGBA"); puts Libpng.decode(png, pixel_format: "RGBA").inspect')
235
- ;;
236
- *)
237
- gem install -b pkg/libpng-*.gem
238
- (cd /tmp && ruby -e 'gem "libpng"; require "libpng"; png = Libpng.encode(2, 2, "\xff" * 16, pixel_format: "RGBA"); puts Libpng.decode(png, pixel_format: "RGBA").inspect')
239
- ;;
240
- esac
221
+ gem install -b pkg/libpng-*.gem
222
+ (cd /tmp && ruby -e 'gem "libpng"; require "libpng"; png = Libpng.encode(2, 2, "\xff" * 16, pixel_format: "RGBA"); puts Libpng.decode(png, pixel_format: "RGBA").inspect')
241
223
  BUILD_EOF
242
224
  chmod +x /tmp/alpine-build.sh
243
225
  docker run --rm \
@@ -253,8 +235,79 @@ jobs:
253
235
  name: pkg-${{ matrix.platform }}
254
236
  path: pkg/*.gem
255
237
 
238
+ # OHOS NDK cross-compile. See build.yml's build_ohos job for full notes.
239
+ build_ohos:
240
+ needs: bump
241
+ if: always() && !cancelled() && !failure() && (needs.bump.result == 'success' || needs.bump.result == 'skipped')
242
+ runs-on: ubuntu-24.04-arm
243
+ steps:
244
+ - uses: actions/checkout@v4
245
+ with:
246
+ ref: ${{ needs.bump.outputs.sha || github.ref }}
247
+
248
+ - name: Install host-side tools
249
+ run: |
250
+ sudo apt-get update
251
+ sudo apt-get install -y curl jq unzip file
252
+
253
+ - name: Register binfmt for amd64 docker emulation
254
+ run: docker run --privileged --rm tonistiigi/binfmt --install amd64
255
+
256
+ - name: Cache OHOS NDK
257
+ id: cache-ndk
258
+ uses: actions/cache@v4
259
+ with:
260
+ path: ext/ohos/ndk
261
+ key: ohos-ndk-${{ hashFiles('ext/ohos/setup-ndk.sh') }}
262
+
263
+ - name: Setup OHOS NDK
264
+ if: steps.cache-ndk.outputs.cache-hit != 'true'
265
+ run: sh ext/ohos/setup-ndk.sh --prefix ext/ohos/ndk
266
+
267
+ - name: Build OHOS gem in amd64 container
268
+ run: |
269
+ docker run --rm --platform linux/amd64 \
270
+ -v "$PWD:/work" -w /work \
271
+ -e target_platform=aarch64-linux-ohos \
272
+ ruby:3.3 \
273
+ sh -c '
274
+ set -e
275
+ apt-get update
276
+ apt-get install -y --no-install-recommends cmake ninja-build zlib1g-dev
277
+ bundle install --jobs 4
278
+ bundle exec rake gem:native:aarch64-linux-ohos
279
+ file lib/libpng/libpng16.so
280
+ '
281
+
282
+ - name: Prepare dockerharmony artifacts
283
+ run: |
284
+ docker run --rm --platform linux/amd64 \
285
+ -v "$PWD:/work" -w /work \
286
+ -e NDK_ROOT=/work/ext/ohos/ndk \
287
+ ruby:3.3 \
288
+ sh -c '
289
+ set -e
290
+ apt-get update
291
+ apt-get install -y --no-install-recommends file
292
+ sh ext/ohos/verify-prepare.sh
293
+ '
294
+
295
+ - name: Verify in dockerharmony (real OHOS userland)
296
+ run: |
297
+ docker pull ghcr.io/hqzing/dockerharmony:latest
298
+ docker run --rm \
299
+ -v "$PWD/ohos-verify:/work" \
300
+ -w /work \
301
+ ghcr.io/hqzing/dockerharmony:latest \
302
+ sh -c 'LD_LIBRARY_PATH=. ./smoke-test'
303
+
304
+ - uses: actions/upload-artifact@v4
305
+ with:
306
+ name: pkg-aarch64-linux-ohos
307
+ path: pkg/*.gem
308
+
256
309
  publish:
257
- needs: [ bump, build, build_musl ]
310
+ needs: [ bump, build, build_musl, build_ohos ]
258
311
  if: always() && !cancelled() && !failure()
259
312
  runs-on: ubuntu-latest
260
313
  steps:
data/CHANGELOG.md CHANGED
@@ -7,6 +7,56 @@ This gem follows a `{LIBPNG_VERSION}.{LIBPNG_RUBY_ITERATION}` version
7
7
  scheme. `LIBPNG_VERSION` is the upstream libpng release; `ITERATION`
8
8
  bumps for Ruby-side changes and resets to 0 when LIBPNG_VERSION bumps.
9
9
 
10
+ ## [1.6.58.6] - 2026-07-26
11
+
12
+ ### Changed
13
+ - **OHOS (`aarch64-linux-ohos`) is now cross-compiled with the official OHOS
14
+ NDK** (Huawei's `ohos.toolchain.cmake` + LLVM-19 clang), replacing the
15
+ 1.6.58.4/.5 approach of shipping Alpine-built musl bytes labeled as OHOS.
16
+
17
+ The build runs on `ubuntu-24.04-arm`. The OHOS NDK clang is an x86_64
18
+ binary and runs transparently via `binfmt_misc` + `qemu-user-static`.
19
+ zlib is built statically with the same toolchain and linked into
20
+ `libpng16.so` (avoids the OHOS non-standard zlib SONAME
21
+ `libshared_libz.z.so`). The freshly built `.so` is code-signed with
22
+ `binary-sign-tool sign -selfSign 1` (mandatory for runtime loading on
23
+ production OHOS devices).
24
+
25
+ Verification: the signed `.so` is loaded by a smoke-test binary inside
26
+ real OHOS userland (the `dockerharmony` container running natively on
27
+ the same arm64 host -- no qemu). Build fails if the smoke test fails.
28
+
29
+ ### Added
30
+ - `lib/libpng/ohos.rb`, `lib/libpng/ohos/{ndk,zlib_builder,code_signer,recipe}.rb`
31
+ -- OHOS cross-compile support. Lazy-loaded only when building for OHOS.
32
+ - `Libpng::OHOS::NDK` -- pure-data class for NDK path discovery.
33
+ - `Libpng::OHOS::ZlibBuilder < MiniPortileCMake` -- static zlib build.
34
+ - `Libpng::OHOS::CodeSigner` -- wraps `binary-sign-tool`.
35
+ - `Libpng::OHOS::Recipe < Libpng::Recipe` -- orchestrates the OHOS build.
36
+ - `lib/libpng/recipe.rb`: `Recipe.for_target(platform)` factory -- OCP seam
37
+ that returns `OHOS::Recipe` for `*-ohos` targets, base `Recipe` otherwise.
38
+ - `ext/ohos/setup-ndk.sh` -- downloads OHOS SDK + LLVM-19 via daily_build API
39
+ (adapted from ohos-node's `build.sh`).
40
+ - `ext/ohos/smoke-test.c` -- minimal libpng round-trip test for dockerharmony.
41
+ - `ext/ohos/verify-prepare.sh` -- cross-compiles smoke-test with NDK clang,
42
+ bundles signed `.so` + SONAME symlinks (fixes PR #12's symlink bug).
43
+ - 49 new specs under `spec/ohos/` + `spec/recipe_factory_spec.rb`.
44
+
45
+ ### Caveats
46
+ - The 1.6.58.4/.5 OHOS gems shipped Alpine-built bytes without NDK
47
+ verification. This version is the first with proper OHOS NDK
48
+ cross-compilation + signing.
49
+ - Code signing uses `-selfSign 1` (self-signed). Sufficient for OHOS
50
+ userland load. Production deployment on Huawei-managed hardware may
51
+ require re-signing with an enrolled cert.
52
+
53
+ ### Superseded
54
+ - PR #11 (closed) -- hand-written `toolchain.cmake` + system CMake. Replaced
55
+ by NDK's bundled `ohos.toolchain.cmake`.
56
+ - PR #12 (closed) -- dockerharmony verification of Alpine bytes. The
57
+ verification step is reused here; the Alpine-built `.so` is replaced
58
+ with the NDK-built, signed one.
59
+
10
60
  ## [1.6.58.5] - 2026-07-26
11
61
 
12
62
  ### Added
data/CLAUDE.md CHANGED
@@ -29,8 +29,16 @@ loaded via `autoload` from `lib/libpng.rb`. **Never use `require_relative`
29
29
  | `lib/libpng/standard_decoder.rb` | `Libpng::StandardDecoder` (libpng standard read API; explicit transform control) |
30
30
  | `lib/libpng/metadata_writer.rb` | `Libpng::MetadataWriter` (validates + writes text/gAMA/sRGB/cHRM/iCCP/pHYs onto a png_ptr/info_ptr pair) |
31
31
  | `lib/libpng/text_writer.rb` | `Libpng::TextWriter` + `Libpng::TextEntry` (builds png_text struct array, calls `png_set_text`) |
32
- | `lib/libpng/recipe.rb` | `Libpng::Recipe < MiniPortileCMake` (builds libpng from source for the source gem) |
33
- | `ext/extconf.rb` | Gem extension entry. Triggers `Libpng::Recipe` autoload via `require 'libpng'`, then emits a dummy Makefile |
32
+ | `lib/libpng/recipe.rb` | `Libpng::Recipe < MiniPortileCMake` (builds libpng from source for the source gem). Has `.for_target(platform)` factory -- OCP seam that returns `OHOS::Recipe` for `*-ohos`, base `Recipe` otherwise |
33
+ | `lib/libpng/ohos.rb` | `Libpng::OHOS` namespace + autoloads. Lazy-loaded only when `Recipe.for_target` is called with an OHOS target |
34
+ | `lib/libpng/ohos/ndk.rb` | `OHOS::NDK` -- pure-data class for NDK path discovery (toolchain/sysroot/clang/sign-tool). Idempotent `#download` via `setup-ndk.sh` |
35
+ | `lib/libpng/ohos/zlib_builder.rb` | `OHOS::ZlibBuilder < MiniPortileCMake` -- builds `libz.a` statically with the OHOS toolchain |
36
+ | `lib/libpng/ohos/code_signer.rb` | `OHOS::CodeSigner` -- wraps `binary-sign-tool sign -selfSign 1`. Pure-data `#sign_command` is testable without invoking the tool |
37
+ | `lib/libpng/ohos/recipe.rb` | `OHOS::Recipe < Libpng::Recipe` -- orchestrates NDK setup, zlib build, libpng cross-compile with `ohos.toolchain.cmake`, and post-install signing |
38
+ | `ext/extconf.rb` | Gem extension entry. Calls `Libpng::Recipe.for_target(ENV['target_platform']).new`, then emits a dummy Makefile |
39
+ | `ext/ohos/setup-ndk.sh` | Downloads OHOS SDK + LLVM-19 via OpenHarmony daily_build API (adapted from ohos-node/build.sh). Idempotent |
40
+ | `ext/ohos/smoke-test.c` | Minimal libpng round-trip test, cross-compiled with NDK clang and run inside dockerharmony |
41
+ | `ext/ohos/verify-prepare.sh` | Cross-compiles smoke-test, bundles signed `.so` + SONAME symlinks for dockerharmony |
34
42
 
35
43
  ### Public API
36
44
 
@@ -74,6 +82,25 @@ bundle exec rake gem:native:any # source gem (compiles on install)
74
82
 
75
83
  Platform gem tasks: `x64-mingw32`, `x64-mingw-ucrt`, `aarch64-mingw-ucrt`, `x86_64-linux`, `x86_64-linux-musl`, `aarch64-linux`, `aarch64-linux-musl`, `aarch64-linux-ohos`, `x86_64-darwin`, `arm64-darwin`.
76
84
 
85
+ ### OHOS (`aarch64-linux-ohos`) build notes
86
+
87
+ OHOS uses a dedicated `build_ohos` CI job (see `.github/workflows/build.yml`)
88
+ that runs on `ubuntu-24.04-arm`. The NDK's clang and `binary-sign-tool` are
89
+ x86_64 ELF and run via `binfmt_misc` + `qemu-user-static`. The job:
90
+
91
+ 1. Downloads OHOS SDK + LLVM-19 via `ext/ohos/setup-ndk.sh` (~1.5 GB, cached
92
+ across runs by `actions/cache@v4`).
93
+ 2. Runs `rake gem:native:aarch64-linux-ohos`, which delegates to
94
+ `Libpng::OHOS::Recipe` (sets up NDK, builds static zlib, cross-compiles
95
+ libpng with `ohos.toolchain.cmake`, signs the `.so`).
96
+ 3. Cross-compiles `ext/ohos/smoke-test.c` with NDK clang via
97
+ `verify-prepare.sh`, then runs it inside the `dockerharmony` container
98
+ (real OHOS userland) — build fails if smoke-test doesn't output `OK`.
99
+
100
+ Local dev: `target_platform=aarch64-linux-ohos bundle exec rake compile`
101
+ will only succeed on an arm64 host with `qemu-user-static` registered,
102
+ because the NDK clang is x86_64 ELF. CI handles this automatically.
103
+
77
104
  ## Release process
78
105
 
79
106
  Releases are tag-triggered via `.github/workflows/release.yml`. Trigger with:
data/README.adoc CHANGED
@@ -44,7 +44,7 @@ for the current set):
44
44
  | `x86_64-linux-musl` | x86_64 Linux (musl, e.g. Alpine) | `ruby:<ver>-alpine` on x86_64
45
45
  | `aarch64-linux` | ARM64 Linux (glibc) | `ubuntu-24.04-arm` (native)
46
46
  | `aarch64-linux-musl` | ARM64 Linux (musl) | `ruby:<ver>-alpine` on arm64
47
- | `aarch64-linux-ohos` | ARM64 OpenHarmony / Huawei HarmonyOS PC | `ruby:<ver>-alpine` on arm64 (byte-compatible with `aarch64-linux-musl`)
47
+ | `aarch64-linux-ohos` | ARM64 OpenHarmony / Huawei HarmonyOS PC | `ubuntu-24.04-arm` + OHOS NDK (cross-compiled, signed, **verified in dockerharmony**)
48
48
  | `x64-mingw32` | x64 Windows, RubyInstaller < 3.0 (MSVCRT) | `windows-latest`
49
49
  | `x64-mingw-ucrt` | x64 Windows, RubyInstaller >= 3.0 (UCRT) | `windows-latest`
50
50
  | `aarch64-mingw-ucrt` | ARM64 Windows (Ruby >= 3.4) | `windows-11-arm` (native)
@@ -0,0 +1,105 @@
1
+ # 01 - Architecture
2
+
3
+ ## Goal
4
+
5
+ Cross-compile `libpng16.so` for `aarch64-linux-ohos` using the official OHOS
6
+ NDK (Huawei-blessed toolchain), code-sign it, and empirically verify it in
7
+ real OHOS userland (dockerharmony). Replace the 1.6.58.4/.5/.6 approach of
8
+ "Alpine-built bytes labeled as OHOS".
9
+
10
+ ## Why this design (vs PR #11 / PR #12)
11
+
12
+ | Approach | Status | Why rejected |
13
+ |---|---|---|
14
+ | Alpine bytes labeled OHOS (1.6.58.4/.5) | shipped | unverified assumption; user flagged musl symbol visibility, TLS, pthread layout risks |
15
+ | PR #11: hand-written `toolchain.cmake` + system CMake | closed | 5 CI iterations failed (sysroot path, missing zlib in sysroot, try_compile couldn't find crt objects) — root cause: NOT using NDK's bundled `ohos.toolchain.cmake` |
16
+ | PR #12: Alpine bytes + dockerharmony verification | closed | still ships Alpine bytes labeled OHOS; user wants proper NDK bytes |
17
+ | **PR #13 (this plan)** | current | NDK-bundled `ohos.toolchain.cmake` + static zlib + `binary-sign-tool` + dockerharmony verify |
18
+
19
+ ## Key insights from references
20
+
21
+ - **OHOS CMake doc** (`openharmony-6.0-app-dev-docs/napi/build-with-ndk-cmake.md`):
22
+ - NDK ships own CMake at `${SDK_PATH}/native/build-tools/cmake/bin/cmake`
23
+ - Toolchain file at `${SDK_PATH}/native/build/cmake/ohos.toolchain.cmake`
24
+ - Invoke: `cmake -DOHOS_ARCH=arm64-v8a -DOHOS_PLATFORM=OHOS -DCMAKE_TOOLCHAIN_FILE=...`
25
+ - Toolchain handles sysroot + `--target=arm-linux-ohos` + try_compile compatibility
26
+
27
+ - **ohos-node** (`~/src/external/ohos-node/build.sh`):
28
+ - NDK download via `https://dcp.openharmony.cn/api/daily_build/build/list/component`
29
+ - Two components needed: `ohos-sdk-public` (SDK + `binary-sign-tool`) + `LLVM-19` (clang + sysroot)
30
+ - `binary-sign-tool sign -selfSign 1` is mandatory post-build
31
+ - Output runs on OHOS via dockerharmony (real OHOS rootfs)
32
+
33
+ - **dockerharmony** (`~/src/external/dockerharmony/`):
34
+ - OHOS rootfs (musl + toybox + mksh) in Docker, runs aarch64-linux-musl binaries natively on arm64 hosts
35
+ - OHOS ships zlib as `libshared_libz.z.so` (NOT `libz.so`) — patchelf needed if linking dynamically
36
+
37
+ - **NDK architecture reality** (verified):
38
+ - `LLVM-19` tarball contains `llvm-linux-x86_64.tar.gz` (x86_64-build clang) + `ohos-sysroot.tar.gz` (architecture-independent sysroot files)
39
+ - There is **no arm64 build of the NDK clang** in the daily_build output
40
+ - `ohos.toolchain.cmake` is a CMake script (architecture-independent)
41
+ - `binary-sign-tool` is in the x86_64-build ohos-sdk
42
+
43
+ ## CI topology (corrected: native arm64 + transparent qemu for NDK binaries)
44
+
45
+ Single job on `ubuntu-24.04-arm` (native arm64 runner):
46
+
47
+ 1. Install `qemu-user-static` + `binfmt-support` — registers binfmt_misc so
48
+ x86_64 ELF binaries run transparently via `qemu-x86_64`.
49
+ 2. Run `ext/ohos/setup-ndk.sh` → NDK + LLVM-19 in `ext/ohos/ndk/`
50
+ 3. `bundle exec rake gem:native:aarch64-linux-ohos` →
51
+ - `OHOS::Recipe#cook` runs:
52
+ - Downloads libpng source (MiniPortile)
53
+ - Builds static zlib via `OHOS::ZlibBuilder` (NDK clang under binfmt)
54
+ - CMake-configures libpng with `ohos.toolchain.cmake` + static zlib (NDK cmake/clang under binfmt)
55
+ - Builds + installs `libpng16.so`
56
+ - Signs `.so` via `OHOS::CodeSigner` (`binary-sign-tool` under binfmt)
57
+ 4. Run `ext/ohos/verify-prepare.sh` → `ohos-verify/` artifacts (cross-compile smoke-test with NDK clang)
58
+ 5. Run dockerharmony natively: `docker run --rm -v ...:/work ghcr.io/hqzing/dockerharmony:latest sh -c 'LD_LIBRARY_PATH=. ./smoke-test'`
59
+
60
+ ### Why this is the right topology
61
+
62
+ | Aspect | x86_64 runner (original plan) | arm64 runner + qemu (revised) |
63
+ |---|---|---|
64
+ | NDK clang / binary-sign-tool | native speed | ~5x slower (qemu emulation) |
65
+ | dockerharmony verification | ~5x slower (qemu binfmt for arm64) | **native speed** |
66
+ | CI complexity | needs binfmt setup, multi-arch docker pull | standard docker pull |
67
+ | Total CI time | dominated by slow dockerharmony emulation | dominated by slow NDK compile (smaller) |
68
+
69
+ Compilation is ~1 min native → ~5 min under qemu (acceptable).
70
+ dockerharmony smoke-test is ~50ms native → ~250ms under qemu — small absolute number,
71
+ but the binfmt setup for arm64 emulation on x86_64 is finicky and has been flaky
72
+ in CI historically. Native arm64 docker is rock-solid.
73
+
74
+ **Net**: arm64 + qemu is simpler AND faster overall.
75
+
76
+ ## MECE file layout
77
+
78
+ ```
79
+ ext/ohos/
80
+ ├── setup-ndk.sh # Downloads SDK + LLVM-19 (idempotent, shell)
81
+ ├── smoke-test.c # Round-trip test (kept from PR #12)
82
+ ├── verify-prepare.sh # Cross-compiles smoke-test, bundles for dockerharmony
83
+ └── (no toolchain.cmake — we use NDK's bundled ohos.toolchain.cmake)
84
+
85
+ lib/libpng/
86
+ ├── recipe.rb # Add Recipe.for_target factory (OCP seam)
87
+ ├── ohos.rb # Module Libpng::OHOS + autoloads
88
+ └── ohos/
89
+ ├── ndk.rb # OHOS::NDK: pure-data path discovery + download
90
+ ├── zlib_builder.rb # OHOS::ZlibBuilder < MiniPortileCMake (static zlib)
91
+ ├── code_signer.rb # OHOS::CodeSigner: wraps binary-sign-tool
92
+ └── recipe.rb # OHOS::Recipe < Libpng::Recipe
93
+
94
+ lib/libpng.rb # Add autoload :OHOS, 'libpng/ohos'
95
+ ext/extconf.rb # Use Recipe.for_target(...) factory
96
+ ```
97
+
98
+ ## OCP compliance
99
+
100
+ Adding a new cross-compile platform = adding `lib/libpng/<platform>/` with a
101
+ `<Platform>::Recipe < Libpng::Recipe` subclass and registering it in
102
+ `Recipe.for_target`. No modification of `Libpng::Recipe` needed.
103
+
104
+ The existing `Libpng::Recipe` is unchanged (except adding the factory class
105
+ method). All OHOS logic is in `lib/libpng/ohos/`.
@@ -0,0 +1,30 @@
1
+ # 02 - Close PR #12, branch off main
2
+
3
+ ## Steps
4
+
5
+ 1. Close PR #12 with a comment explaining the pivot:
6
+
7
+ > Closing in favor of a proper OHOS NDK cross-compile approach (PR #13).
8
+ > The dockerharmony verification step is reused; the build approach changes
9
+ > from "Alpine-built bytes labeled OHOS" to "NDK-built bytes signed with
10
+ > binary-sign-tool". The smoke-test.c file is carried over.
11
+
12
+ 2. From `main`, create `fix/ohos-ndk-cmake`:
13
+ ```sh
14
+ git checkout main
15
+ git pull origin main
16
+ git checkout -b fix/ohos-ndk-cmake
17
+ ```
18
+
19
+ 3. Cherry-pick reusable files from `fix/ohos-dockerharmony`:
20
+ - `ext/ohos/smoke-test.c` — keep as-is
21
+ - `lib/libpng/version.rb` — keep iteration = 6 (it's already at 6 on PR #12 branch)
22
+
23
+ `verify-prepare.sh` will be rewritten (was Alpine-gcc-based; new version
24
+ uses NDK clang for cross-compile from x86_64 host).
25
+
26
+ ## Why branch off main (not off fix/ohos-dockerharmony)
27
+
28
+ PR #12's CI changes (build.yml, release.yml) are incompatible with the NDK
29
+ approach — they assume Alpine container build. Cleaner to start fresh and
30
+ re-introduce only what's needed.
@@ -0,0 +1,54 @@
1
+ # 03 - ext/ohos/setup-ndk.sh
2
+
3
+ ## Purpose
4
+
5
+ Download and extract the OHOS NDK (SDK + LLVM-19) into `ext/ohos/ndk/`.
6
+ Idempotent — skips if the destination already looks complete.
7
+
8
+ ## Source pattern
9
+
10
+ Adapted from `~/src/external/ohos-node/build.sh` (lines 14-49). Key pieces:
11
+
12
+ ```sh
13
+ query_component() {
14
+ component=$1
15
+ curl -fsSL 'https://dcp.openharmony.cn/api/daily_build/build/list/component' \
16
+ -H 'Accept: application/json, text/plain, */*' \
17
+ -H 'Content-Type: application/json' \
18
+ --data-raw '{"projectName":"openharmony","branch":"master","pageNum":1,"pageSize":10,"deviceLevel":"","component":"'${component}'","type":1,"startTime":"2025080100000000","endTime":"20990101235959","sortType":"","sortField":"","hardwareBoard":"","buildStatus":"success","buildFailReason":"","withDomain":1}'
19
+ }
20
+ ```
21
+
22
+ Two components needed:
23
+ - `ohos-sdk-public` → contains `toolchains/lib/binary-sign-tool` + `build/cmake/ohos.toolchain.cmake`
24
+ - `LLVM-19` → contains `llvm/bin/aarch64-unknown-linux-ohos-clang` + `ohos-sysroot.tar.gz`
25
+
26
+ ## Script contract
27
+
28
+ ```
29
+ Usage: setup-ndk.sh [--prefix <dir>]
30
+ Default prefix: $PWD/ext/ohos/ndk
31
+
32
+ Outputs:
33
+ $PREFIX/ohos-sdk/linux/ # SDK
34
+ $PREFIX/llvm-19/llvm/ # Clang
35
+ $PREFIX/llvm-19/sysroot/ # OHOS sysroot (extracted from ohos-sysroot.tar.gz)
36
+
37
+ Exits 0 if setup is complete (or was already complete).
38
+ ```
39
+
40
+ ## Idempotency
41
+
42
+ Skip download if `$PREFIX/ohos-sdk/linux/toolchains/lib/binary-sign-tool` exists
43
+ AND `$PREFIX/llvm-19/sysroot/usr/lib/aarch64-linux-ohos/` exists. This lets
44
+ CI cache the directory across runs.
45
+
46
+ ## Dependencies (CI-side)
47
+
48
+ - `curl`, `tar`, `unzip`, `jq` — apt-installed in workflow before script runs.
49
+
50
+ ## Why shell (not Ruby)
51
+
52
+ - curl + jq + tar pipeline is 5 lines of shell vs 50+ lines of Ruby (Net::HTTP + JSON parsing).
53
+ - Pattern is proven by ohos-node; we follow it verbatim.
54
+ - Ruby's role is orchestration (deciding *when* to invoke); the script does the heavy lifting.
@@ -0,0 +1,65 @@
1
+ # 04 - lib/libpng/ohos.rb + lib/libpng/ohos/ndk.rb
2
+
3
+ ## lib/libpng.rb modification
4
+
5
+ Add one autoload entry (follows existing convention):
6
+
7
+ ```ruby
8
+ # OHOS cross-compile support. Only loaded when building for aarch64-linux-ohos.
9
+ autoload :OHOS, 'libpng/ohos'
10
+ ```
11
+
12
+ ## lib/libpng/ohos.rb
13
+
14
+ Module namespace + sub-autoloads. Loaded lazily only when OHOS is referenced
15
+ (i.e., when `Recipe.for_target('aarch64-linux-ohos')` is called).
16
+
17
+ ```ruby
18
+ # frozen_string_literal: true
19
+
20
+ module Libpng
21
+ module OHOS
22
+ autoload :NDK, 'libpng/ohos/ndk'
23
+ autoload :Recipe, 'libpng/ohos/recipe'
24
+ autoload :ZlibBuilder, 'libpng/ohos/zlib_builder'
25
+ autoload :CodeSigner, 'libpng/ohos/code_signer'
26
+
27
+ TARGET_TRIPLE = 'aarch64-linux-ohos'
28
+ OHOS_ARCH = 'arm64-v8a'
29
+ end
30
+ end
31
+ ```
32
+
33
+ ## lib/libpng/ohos/ndk.rb
34
+
35
+ Pure-data class — discovers and validates NDK paths. No shell calls except
36
+ via explicit `#download` (which invokes `setup-ndk.sh`).
37
+
38
+ ### Public API
39
+
40
+ ```ruby
41
+ class NDK
42
+ def initialize(root:) # root = Pathname to NDK install dir
43
+ def exist? # true if all expected paths present
44
+ def toolchain_path # Pathname to ohos.toolchain.cmake
45
+ def clang_path # Pathname to aarch64-unknown-linux-ohos-clang
46
+ def sysroot_path # Pathname to OHOS sysroot root
47
+ def sign_tool_path # Pathname to binary-sign-tool
48
+ def cmake_path # Pathname to NDK's bundled cmake binary
49
+ def download # invoke setup-ndk.sh (no-op if exist?)
50
+ end
51
+ ```
52
+
53
+ ### Design notes
54
+
55
+ - All path accessors return `Pathname` (not String) for composability.
56
+ - `#exist?` checks the four critical paths (toolchain, clang, sysroot, sign-tool).
57
+ - `#download` invokes `ext/ohos/setup-ndk.sh` via `system()`. Idempotent.
58
+ - No `instance_variable_get`/`set` — ivars are private, accessed via methods.
59
+ - No `respond_to?` — type checks use `is_a?`.
60
+
61
+ ### Testability
62
+
63
+ Spec constructs a fake NDK directory structure (just empty files at expected
64
+ paths) and verifies accessors return correct Pathnames. No doubles, no real
65
+ download.