Closed ronaldtse closed 10 months ago
The problem is also related to this: https://github.com/metanorma/emf2svg-ruby/issues/17
$ gem environment | grep -A 2 "RUBYGEMS PLATFORMS"
- RUBYGEMS PLATFORMS:
- ruby
- x86_64-linux-musl
Platform is detected as x86_64-linux-musl
.
$ gem help platforms
RubyGems matches platforms as follows:
* The CPU must match exactly unless one of the platforms has
"universal" as the CPU or the local CPU starts with "arm" and the gem's
CPU is exactly "arm" (for gems that support generic ARM architecture).
* The OS must match exactly.
* The versions must match exactly unless one of the versions is nil.
So it matches x86_64-linux
because the version part is nil.
The next step is to create a build for x86_64-linux-musl
, or rename x86_64-linux
to a more specific build.
The mismatch between glibc
and musl
platforms has been subject of work at rubygems
:
And that it is a known issue on Alpine that Rubygems can mistakenly install glibc
platform gems on Alpine, and therefore they maintain such a patch to only install platform=ruby
gems:
I reviewed the code in https://github.com/rubygems/rubygems/pull/4082 and apparently there is this rather undocumented differentiation of platforms:
'x86_64-linux' => ['x86_64', 'linux', nil],
'x86_64-linux-gnu' => ['x86_64', 'linux', nil],
'x86_64-linux-musl' => ['x86_64', 'linux', 'musl'],
'x86_64-linux-uclibc' => ['x86_64', 'linux', 'uclibc'],
According to this PR, technically, a platform gem that specifies x86_64-linux
should not be installed on x86_64-linux-musl
However, in the latest master
branch of Rubygems, this differentiation has been removed (this PR was reverted in https://github.com/rubygems/rubygems/pull/4434).
'x86_64-linux' => ['x86_64', 'linux', nil],
'x86_64-linux-musl' => ['x86_64', 'linux', 'musl'],
And the behavior at rubygems is now just broken:
The way we have to solve this is either:
The x86_64-linux
platform gem works natively on musl
. I don't know if our source code can be fixed that way (i.e. avoiding GNU extensions)
We publish platform gems for x86_64-linux-musl
so that on Alpine the x86_64-linux-musl
is always used.
"/lib/ld-linux-x86-64.so.2" -- is a dynamic loader.
IMHO it is worth trying compatibility package: https://pkgs.alpinelinux.org/contents?file=ld-linux-x86-64*
expressir is using rake-compiler-dock that supports:
Alpine will need to be added to this list
The compatibility package gcompat
worked:
/ # apk add gcc g++ cmake make libc-dev
...
/ # apk add gcompat
(1/3) Installing musl-obstack (1.2.2-r0)
(2/3) Installing libucontext (1.1-r0)
(3/3) Installing gcompat (1.0.0-r4)
OK: 256 MiB in 64 packages
/ # irb
irb(main):001:0> require 'expressir'
=> true
irb(main):002:0> require 'expressir/express/parser'
=> true
@maxirmx Maybe we should make a PR to rake-compiler-block
?
@maxirmx Maybe we should make a PR to
rake-compiler-block
?
@ronaldtse, we can if ruby really support differentiation but I am afraid that it won't be straightforwards either.
This (or closely related) issue is a blocker for: https://github.com/metanorma/packed-mn/issues/158
Whe packaged with tebako
in linux-musl
environment expressir loads x86_64-linux
extension which requires /lib/ld-linux-x86-64.so
It is worth to note that this issue occurs only for expressir and libemf2svg (that inherits platform logic from expressir) All other gems with native extensions work
It is worth to note that this issue occurs only for expressir and libemf2svg (that inherits platform logic from expressir) All other gems with native extensions work
Then if we update the platform logic, so it does not treat it as x86_64-linux
, it should work?
Then if we update the platform logic, so it does not treat it as
x86_64-linux
, it should work?
I do not understand why other gems work. Probably it shall be possible to implement platform logic as others do it
Well, so far it looks like a mistery
nokogiri gem taht uses the same build system installs and runs on Alpine using linux
prebuild native gem.
The authour and maintainer of nokogiri is sure that gcompat is a prerequisite, but it is not true.
Expressir looks different for ldd. The reason is yet unknown
Summary of research re Alpine (musl) support
The bottom line. For gems that use Rice there is no way to x86_64-linux platform gems to work on musl unless gcompat package is installed
What can be done
gcompat
or force_ruby_platform
a requirement for Alpine installations. I can probably implement reasonable error message if this requirement is not met. This is 'fast' approach, though packed_mn may require additional effort.@maxirmx thank you for the extensive investigation!
- We can make
gcompat
orforce_ruby_platform
a requirement for Alpine installations. I can probably implement reasonable error message if this requirement is not met. This is 'fast' approach, though packed_mn may require additional effort.
This is reasonable for packed-mn and our gems. We should take this approach.
- We make take over rubygems platform effort (Support non gnu libc linux (part 2) rubygems/rubygems#4488) and attempt to drive it to completion. This is the 'right' approach but it may last forever
This is risky for us because we do not know when the Ruby team is interested enough in musl. This PR has implications in the Rubygems system because other there is a backwards compatibility concern too, i.e. all currently available platform gems are assigned to 'glibc' to differentiate from 'musl'.
- For expressir and similar gems we can deploy musl binaries inside linux gem and implement a hack that will use these libaries if on Alpine. This is the risky approach, result cannot be guaranteed.
I think this is also a reasonable approach, and it should be doable, but it will bloat the gems, and there are not that many people who use Alpine anyway. Prefer using the gcompat
requirement.
I will do more tests with gcompat and/or packed_mn to be sure that gcompat is solid approach
Update Alpine test workflow: https://github.com/lutaml/expressir/actions/workflows/alpine.yml
force_ruby_platform
works, of coursegcompat
does not work. It is good enough to let extension load; however, the tests do not pass with blind exceptionRuntimeError:
No error information
# ./lib/expressir/express/parser.rb:35:in `initialize'
# ./lib/expressir/express/parser.rb:35:in `new'
# ./lib/expressir/express/parser.rb:35:in `from_file'
# ./spec/expressir/model/model_element_spec.rb:174:in `block (3 levels) in <top (required)>'
# ./spec/spec_helper.rb:19:in `block (2 levels) in <top (required)>'
I found that this exception is related to std::call_once
, i.e.: thread local memory again.
force_ruby_platform
helped to create packed_mn Alpine package but it will be painful for any user to take this approach. This setting cannot be applied to a single gem so we actually force to build everything in the bundle even if there are precompiled extensions out there.
gcompat
issue can be debugged further but neither time nor effort can be predicted.
Attn @ronaldtse
@maxirmx what is the best course ahead for now? Is Alpine a lost cause?
@ronaldtse Considering Expressir native extension gor musl I can imagine three options:
If you ask about packed-mn, the first version is ready as far as compilation and packaging is considered (https://github.com/metanorma/packed-mn/issues/158#issuecomment-1152660114) There is run-time issue with fontist gem that needs to be fixed
So the real question is if and where you are ready to invest
@maxirmx is this issue to be closed? Thanks!
@ronaldtse
Actually there are (there were) two related issues:
As a solution for both problems we do not use precompiled native extensions when Alpine version of tebako package is created. If we consider metanorma the issue was nokogiri. The maintainers claimed that its x64-linux extension worked for Alpine but in fact it did not. At least not for me.
So the answers is 1) We can publish x64-linux-musl native extension (now we do not have it published). It will close this issue. 2) We can revisit metanorma packaging on alpine to see if others also resolved there issues on Alpine. If they did it we can use prebuilt native extensions. will help to reduce Alpine package size and packaging time.
@maxirmx in this case, could you please help schedule 1 and 2 after the recent tebako work? Thanks!
Packaging of expressir gem is implemented with rack-compiler-dock I suggest we wait until https://github.com/rake-compiler/rake-compiler-dock/issues/75 is completed
In Alpine, the musl-dev library is used instead of glibc. Somehow, the platform gem "x86_64-linux" is installed for expressir.
When I install on aarch64, it correctly detects that I am on a different platform and therefore does not install the platform gem and compiles properly.