leptris 1.9.201.1 → 1.9.201.2

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: 420777c52b2a204e7d2735237901cf304444ca8577df22da44663d444b25526d
4
- data.tar.gz: 5578ae956db7557409f5b73e6ba0e9a543b347e6fa73e391a1175c8cfe69c45a
3
+ metadata.gz: aad9938e69332952ad6bf3f10a58475f017f781fd8603dbec3c6591bb4c29b17
4
+ data.tar.gz: e56f8feb3a9dd9ba2e97772a1e1a10bbe0687f5fe7d60f6432ec898acc2dde9e
5
5
  SHA512:
6
- metadata.gz: 69a689e63cc05325a12430ad0d0d7d3b1515e2213e23487f84182b8406f9cc44e7d66befa5448334b6593d34109523814da95465e52697b3e55cf4f144816ce4
7
- data.tar.gz: 14f5a53ca0353dfca6a805ff1e2621241287e71cb79183117b90d4571ae29265361aa4ca55922ab902ee221d6f2b6aca0fdb60df232056302cb193d8e84ccb69
6
+ metadata.gz: a7771a13bbac1883902471c33a48979e63de5d64dff476d5b7a7c033f844feea831066e3ab079741a618a1e7c152c847b8bc0daa2e3dfa16e41af7193e9c03ea
7
+ data.tar.gz: 7a4e5a3557e59049de395a5d04c6c6034144a5aa253adff0b75efaaff5acd6fc6451fcf14d1378e454fbfe5faef13adec518dd581892802f328fd2ab823902b4
data/CHANGELOG.md CHANGED
@@ -5,6 +5,29 @@ All notable changes to Leptris will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.9.201.1] - 2026-09-19
9
+
10
+ ### Changed — source-distribution doctrine
11
+
12
+ - **Every platform gem now carries the full source** (engine +
13
+ utf8proc + `ext/`, staged under `vendor-src/` at build time,
14
+ ~8 MB) alongside the precompiled bundles — recompile rights per
15
+ the packaging doctrine. No extensions: installing a platform
16
+ gem never rebuilds.
17
+ - **The ruby-platform gem is now a real sdist**: it compiles at
18
+ install. `extconf.rb` orchestrates the vendored sources through
19
+ cmake (libleptris + utf8proc into the gem's `lib/`) before
20
+ building the native extension. Graceful degradation is the
21
+ contract: no mkmf (JRuby/TruffleRuby) → no-op Makefile, install
22
+ proceeds on the vendored binaries / FFI; no cmake or build
23
+ failure → loud skip, FFI surface applies.
24
+ - New CI proof legs (`source-install`): MRI installs the built
25
+ source gem and must round-trip on the **native layer**
26
+ (compiled at install); TruffleRuby installs the same gem and
27
+ must round-trip on the **FFI layer** (vendored binaries).
28
+ Verified locally end-to-end in an isolated GEM_HOME:
29
+ `SMOKE OK (native layer)`.
30
+
8
31
  ## [1.9.201.0] - 2026-09-19
9
32
 
10
33
  ### Changed — libleptris 1.9.199 → 1.9.201 (lockstep)
data/Rakefile CHANGED
@@ -97,6 +97,25 @@ task :compile do
97
97
  sh "cmake --build #{u8_dir}/build --config Release -j 4"
98
98
  sh "cmake --install #{u8_dir}/build --prefix #{u8_prefix}"
99
99
 
100
+ # Source distribution (packaging doctrine): EVERY gem — binary
101
+ # platform gems and the ruby source gem — carries the full
102
+ # engine + utf8proc + ext sources so users can recompile; the
103
+ # ruby variant additionally compiles at install (extconf.rb
104
+ # orchestrates these trees). Staged under vendor-src/ at build
105
+ # time (gitignored); binary dirs excluded.
106
+ vsrc = File.expand_path("vendor-src", __dir__)
107
+ rm_rf(vsrc)
108
+ mkdir_p(vsrc)
109
+ {
110
+ build => File.join(vsrc, "libleptris"),
111
+ u8_dir => File.join(vsrc, "utf8proc"),
112
+ }.each do |src, dest|
113
+ cp_r(File.join(src, "."), dest)
114
+ # Build byproducts (the cmake tree and the install prefix
115
+ # carry symlinks + binaries — source only).
116
+ rm_rf([File.join(dest, "build"), File.join(dest, "prefix")])
117
+ end
118
+
100
119
  # libleptris 1.9.18's xslt_functions.c:270 assigns LeptrisElement
101
120
  # to LeptrisNodeRef — GCC 14 (Alpine/musl) makes incompatible
102
121
  # pointer types an error by default and the musl platform gems
@@ -221,7 +240,7 @@ task :compile do
221
240
  # the release workflow runs the build script under 3.3/3.4/
222
241
  # 4.0 to produce the full set.
223
242
  sh "#{RbConfig.ruby} ext/build_windows_native.rb"
224
- else
243
+ elsif %w[ruby truffleruby].include?(RUBY_ENGINE)
225
244
  ext_dir = "ext/leptris/native"
226
245
  Dir.chdir(ext_dir) do
227
246
  sh "ruby extconf.rb"
@@ -252,18 +271,26 @@ task :compile do
252
271
  end
253
272
  end
254
273
  bundle = Dir.glob("#{ext_dir}/native.{bundle,so,dll}").first
255
- raise "native layer bundle not found after build" unless bundle
256
- if RUBY_PLATFORM =~ /darwin/
257
- # Build-log proof of the linkage contract: libSystem only.
258
- puts `otool -L #{bundle}`
274
+ if bundle.nil?
275
+ # Engines without an MRI C-ext toolchain (JRuby's mkmf is a
276
+ # stub): no native layer here — the FFI surface + vendored
277
+ # binaries apply (the sdist extconf mirrors this gate).
278
+ raise "native layer bundle not found after build" if
279
+ %w[ruby truffleruby].include?(RUBY_ENGINE)
280
+ warn "leptris: #{RUBY_ENGINE} — no native layer in rake compile"
281
+ else
282
+ if RUBY_PLATFORM =~ /darwin/
283
+ # Build-log proof of the linkage contract: libSystem only.
284
+ puts `otool -L #{bundle}`
285
+ end
286
+ # Atomic replace: overwriting a bundle another process still
287
+ # has mapped gets that loader SIGKILLed (CODESIGNING Invalid
288
+ # Page) — cp to a temp name, then mv.
289
+ dest = "lib/leptris/xml/#{File.basename(bundle)}"
290
+ cp(bundle, "#{dest}.new")
291
+ mv("#{dest}.new", dest)
292
+ puts "Vendored native layer (#{File.basename(bundle)}) into lib/leptris/xml/"
259
293
  end
260
- # Atomic replace: overwriting a bundle another process still
261
- # has mapped gets that loader SIGKILLed (CODESIGNING Invalid
262
- # Page) — cp to a temp name, then mv.
263
- dest = "lib/leptris/xml/#{File.basename(bundle)}"
264
- cp(bundle, "#{dest}.new")
265
- mv("#{dest}.new", dest)
266
- puts "Vendored native layer (#{File.basename(bundle)}) into lib/leptris/xml/"
267
294
  end
268
295
  end
269
296
 
@@ -347,6 +374,14 @@ task "platform:any" do
347
374
  # checkout — the variant then carries no binaries and the
348
375
  # system-library / LEPTRIS_LIB_PATH path applies as before.
349
376
  spec.files += Dir.glob("lib/leptris/vendor/**/*")
377
+ # Source distribution: the ruby variant is the sdist — it carries
378
+ # the engine + utf8proc + ext sources AND compiles at install
379
+ # (extensions). Engines without mkmf (JRuby) install through the
380
+ # guarded extconf no-op and run on the vendored binaries / FFI.
381
+ spec.files += Dir.glob("vendor-src/**/*")
382
+ spec.files += %w[ext/leptris/native/extconf.rb
383
+ ext/leptris/native/native.c]
384
+ spec.extensions = ["ext/leptris/native/extconf.rb"]
350
385
  task = Gem::PackageTask.new(spec)
351
386
  task.define
352
387
  end
@@ -379,6 +414,11 @@ platforms.each do |platform|
379
414
  spec.platform = Gem::Platform.new(platform)
380
415
  spec.files += Dir.glob("lib/libleptris.{dll,so,dylib}")
381
416
  spec.files += Dir.glob("lib/{libutf8proc.3.dylib,libutf8proc.so.3,libutf8proc.so,utf8proc.dll}")
417
+ # Binary gems carry the source too (recompile rights), but no
418
+ # extensions — installing a platform gem never rebuilds.
419
+ spec.files += Dir.glob("vendor-src/**/*")
420
+ spec.files += %w[ext/leptris/native/extconf.rb
421
+ ext/leptris/native/native.c]
382
422
  if platform.include?("mingw")
383
423
  # #207/#227: per-Ruby-minor DLLs (PE must bind its Ruby).
384
424
  # DOT-FREE names — MRI derives the init symbol from the
@@ -1,5 +1,90 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Install-time build orchestration for the SOURCE (ruby-platform)
4
+ # gem: compile libleptris (+ utf8proc) from the vendored
5
+ # vendor-src/ trees via cmake, then build the native C extension
6
+ # against nothing (dynamic_lookup — it dlopens the same library
7
+ # the FFI layer loads). Graceful degradation is the contract:
8
+ # - no mkmf (JRuby): emit a no-op Makefile; the gem installs and
9
+ # runs on the vendored binaries / FFI (#160 path).
10
+ # - no cmake / build failure: warn and build only the extension;
11
+ # native_layer's resolve! falls back loudly to the FFI surface
12
+ # (vendored binaries or system library).
13
+ # Platform gems ship the same sources but never run this at
14
+ # install (they carry no extensions) — recompile rights only.
15
+ gem_root = File.expand_path("../../..", __dir__) # <gem>/ext/leptris/native
16
+ lib_dir = File.join(gem_root, "lib")
17
+ vendored = File.join(gem_root, "vendor-src")
18
+
19
+ # Only engines that genuinely build MRI C extensions attempt the
20
+ # build. JRuby carries an mkmf STUB: require succeeds, but the
21
+ # generated Makefile fails on ruby.h — route it to the no-op too.
22
+ unless %w[ruby truffleruby].include?(RUBY_ENGINE)
23
+ File.write("Makefile", <<~MAKE)
24
+ all install clean:
25
+ \t@echo "leptris: no MRI C-ext toolchain on #{RUBY_ENGINE} — skipping the native extension; the FFI surface applies"
26
+ MAKE
27
+ warn "leptris: #{RUBY_ENGINE} cannot build MRI C extensions — " \
28
+ "installing without the compiled native layer"
29
+ exit 0
30
+ end
31
+ require "mkmf"
32
+
33
+ # A prebuilt libleptris in lib/ (dev checkout after rake compile,
34
+ # or any context that already provides one) means this extconf is
35
+ # NOT an sdist install — skip the orchestration entirely (it also
36
+ # keeps rake compile from redundantly rebuilding the engine into
37
+ # vendor-src/).
38
+ prebuilt = Dir.glob(File.join(lib_dir, "libleptris.{so,dylib,dll}")).first
39
+ if !prebuilt && File.directory?(File.join(vendored, "libleptris")) &&
40
+ find_executable("cmake")
41
+ begin
42
+ u8_src = File.join(vendored, "utf8proc")
43
+ u8_bld = File.join(vendored, "utf8proc-build")
44
+ u8_pre = File.join(vendored, "utf8proc-prefix")
45
+ FileUtils.mkpath(u8_bld)
46
+ sh_ok = lambda do |*cmd|
47
+ system(*cmd.map(&:to_s)) or raise "command failed: #{cmd.join(' ')[0, 120]}"
48
+ end
49
+ sh_ok.call("cmake", "-B", u8_bld, "-S", u8_src,
50
+ "-DCMAKE_BUILD_TYPE=Release", "-DBUILD_SHARED_LIBS=ON",
51
+ "-DUTF8PROC_ENABLE_TESTING=OFF")
52
+ sh_ok.call("cmake", "--build", u8_bld, "--config", "Release", "-j",
53
+ ENV.fetch("MAKEFLAGS", "-j4").split.first || "-j4")
54
+ sh_ok.call("cmake", "--install", u8_bld, "--prefix", u8_pre)
55
+
56
+ eng_src = File.join(vendored, "libleptris")
57
+ eng_bld = File.join(vendored, "libleptris-build")
58
+ FileUtils.mkpath(eng_bld)
59
+ sh_ok.call("cmake", "-B", eng_bld, "-S", eng_src,
60
+ "-DCMAKE_BUILD_TYPE=Release",
61
+ "-DLEPTRIS_BUILD_SHARED=ON", "-DLEPTRIS_BUILD_STATIC=OFF",
62
+ "-DBUILD_TESTING=OFF", "-DLEPTRIS_BUILD_CLI=OFF",
63
+ "-DLEPTRIS_BUILD_BENCHMARKS=OFF", "-DLEPTRIS_BUILD_MAN_PAGES=OFF",
64
+ "-DLEPTRIS_ENABLE_UTF8PROC=ON",
65
+ "-DCMAKE_PREFIX_PATH=#{u8_pre}")
66
+ sh_ok.call("cmake", "--build", eng_bld, "--config", "Release",
67
+ ENV.fetch("MAKEFLAGS", "-j4").split.first || "-j4")
68
+ built = Dir.glob(File.join(eng_bld, "**", "libleptris.{so,dylib,dll}")).first
69
+ raise "libleptris build produced no shared library" unless built
70
+ ext = File.extname(built)
71
+ FileUtils.cp(built, File.join(lib_dir, "libleptris#{ext}"))
72
+ Dir.glob(File.join(u8_pre, "lib", "libutf8proc.*")).each do |u8|
73
+ next if File.directory?(u8)
74
+ base = File.basename(u8)
75
+ next if base.end_with?(".pc")
76
+ FileUtils.cp(u8, File.join(lib_dir, base)) rescue nil
77
+ end
78
+ puts "leptris: compiled libleptris from source into #{lib_dir}"
79
+ rescue StandardError => e
80
+ warn "leptris: source build skipped (#{e.message}); the gem will " \
81
+ "load the vendored binary or system library instead"
82
+ end
83
+ else
84
+ warn "leptris: cmake or vendored sources unavailable — skipping the " \
85
+ "engine compile; vendored binaries / system library apply"
86
+ end
87
+
3
88
  # The bundle must load into ANY Ruby (not the building runner's):
4
89
  # macOS links with -undefined dynamic_lookup (Ruby symbols resolve
5
90
  # from the loading interpreter — the standard C-ext convention)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.201.1"
4
+ VERSION = "1.9.201.2"
5
5
  end
@@ -16,6 +16,19 @@ module Leptris
16
16
  # preference order (glibc before musl — dlopen falls through
17
17
  # on musl hosts).
18
18
  def self.vendor_platforms_for(ruby_platform)
19
+ # JVM engines report "x86_64-java" or bare "java" — the OS
20
+ # (and sometimes the arch) is lost. Rebuild cpu-os from
21
+ # RbConfig so the native vendor binaries resolve there too.
22
+ if ruby_platform =~ /java/
23
+ host_os = RbConfig::CONFIG["host_os"].to_s
24
+ if host_os =~ /mingw|mswin|windows/
25
+ return [] # no windows vendor tree; the .dll is gem-local
26
+ end
27
+ cpu = RbConfig::CONFIG["host_cpu"].to_s
28
+ cpu = "aarch64" if cpu.empty?
29
+ os = host_os =~ /darwin/ ? "darwin" : "linux"
30
+ ruby_platform = "#{cpu}-#{os}"
31
+ end
19
32
  case ruby_platform
20
33
  when /arm64.*darwin|aarch64.*darwin/ then %w[arm64-darwin]
21
34
  when /x86_64.*darwin/ then %w[x86_64-darwin]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leptris
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.201.1
4
+ version: 1.9.201.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -60,7 +60,8 @@ description: |
60
60
  email:
61
61
  - open.source@ribose.com
62
62
  executables: []
63
- extensions: []
63
+ extensions:
64
+ - ext/leptris/native/extconf.rb
64
65
  extra_rdoc_files: []
65
66
  files:
66
67
  - CHANGELOG.md