Apply --platform in gem build when it matches the local platform - #9863
Apply --platform in gem build when it matches the local platform#9863IslamElsayed wants to merge 1 commit into
Conversation
`gem build` never applied `--platform` itself. It relied on the platform
inference in `Gem::Specification#initialize`, which reads
`Gem.platforms.last` but deliberately skips it when that equals
`Gem::Platform.local`:
if (platform = Gem.platforms.last) && platform != Gem::Platform::RUBY &&
platform != Gem::Platform.local
That guard is load-bearing. `Gem.platforms` includes the local platform
by default, so without it every spec instantiated anywhere in the
process would silently become platform specific. The cost is that
`gem build --platform x86_64-linux` on x86_64-linux produced
`hello-0.1.0.gem` rather than `hello-0.1.0-x86_64-linux.gem`.
Passing `--platform` resets `Gem.platforms` to `[RUBY]` before appending
the requested value and sets `options[:added_platform]`, so an explicit
request is already distinguishable from the ambient default. Apply it in
`build_package` when that flag is set, leaving the shared guard alone.
|
Does this work with extension libraries? |
|
Yes. I checked it rather than reasoning about it — building the same gemspec with Before After So the local case now does what the non-local case already did, and Worth being explicit about what it still doesn't do, since it's your area: If you'd rather |
Fixes #9344. @kou wrote there that "
gem build --platformshould build a platform-specific gem" — this makes it do that in the one case where it currently doesn't.What was the end-user or developer problem that led to this PR?
gem build --platform aarch64-linuxon aarch64 Linux produceshello-0.1.0.geminstead ofhello-0.1.0-aarch64-linux.gem. The flag is silently dropped, but only when the requested platform happens to equal the machine's own — on any other platform it works, which is what makes it easy to miss.What is your fix for the problem, implemented in this PR?
gem buildnever applied--platformitself. It relied on the inference inGem::Specification#initialize:That
!= Gem::Platform.localguard is load-bearing and I deliberately left it alone:Gem.platformsis[RUBY, Gem::Platform.local]by default, so without it every spec instantiated anywhere in the process would silently become platform-specific. The cost is that a legitimate explicit request matching the local platform is indistinguishable from the ambient default, and gets dropped.But it is distinguishable one level up.
add_platform_optionresetsGem.platformsto[RUBY]before appending the requested value and setsoptions[:added_platform], so at the command layer an explicit--platformis unambiguous. The fix applies it there:One line in
build_package, plus a comment explaining why the inference can't be relied on. Nothing shared changes, so no other caller ofGem::Specification.newis affected.Alternative considered: relaxing the guard in
Gem::Specification#initializeto consultadded_platform. I didn't, because that guard protects every spec instantiation in the process and the command layer already has the unambiguous signal — fixing it where the ambiguity doesn't exist seemed safer than widening the blast radius.Make sure the following tasks are checked
test_execute_with_platform_matching_local_platformbuilds with--platform Gem::Platform.localand asserts both the output filename andspec.platform. It fails on master:Verified green: the full
test_gem_commands_build_command.rb(35 tests), plustest_gem_specification.rb(296),test_gem_package.rb(78),test_gem_platform.rb(33) andtest_gem_commands_install_command.rb(87) for regressions.bin/rake rubocopreports no offenses across 852 files.Disclosure
This was written with AI assistance (Claude). I can explain every line, and the behaviour was verified by running the tests rather than inferred.