#5257 Rubygems rebuild failed due to wrong expansion of %{_libdir} macro
Closed: Invalid None Opened 11 years ago by vondruch.

The RubyGems build failed during the mass rebuild [1]. Part of the rubygem.spec are following lines:

{{{
RUBYOPT="-Itest -Ilib"
RUBYOPT="$RUBYOPT -I%{_libdir}/gems/exts/io-console-0.3/lib/"

In case that rubygem-json is installed

RUBYOPT="$RUBYOPT -I%{gem_dir}/gems/json-1.6.5/lib -I%{_libdir}/gems/exts/json-1.6.5/ext/json/ext"
export RUBYOPT

testrb test
}}}

The problem is that although the build is done on x86_64, the macros are expanded to '/usr/lib/' instead of '/usr/lib64/'. The same build in mock on my local machine works just fine.

May be these two error lines might be somehow related?

{{{
error: Macro %__isa_name has empty body
error: Macro %__isa_bits has empty body
}}}

Or am I doing something wrong?

[1] http://koji.fedoraproject.org/koji/taskinfo?taskID=4304533


RPM does not define the "isa" macros on noarch builds, so everything reverts to defaults, in this case, libdir reverting to /usr/lib. I'm not sure why you see different behaviour on your local system.

The only safe way to use %{_libdir} is in an architecture specific package, because when the package build is noarch, koji could choose any available builder, regardless of architecture, giving you a 50% chance (i686 vs x86_64) of matching /usr/lib to the actual environment. I would argue that if a package is compiling against files in an architecture specific directory (aka under %{_libdir}), it is not truly a noarch package. (You may be able to get around this by having the main package be architecture specific, with all the files that end up under %{_libdir} in the main package, and any truly architecture independent packages in a noarch subpackage, but that might be more hackish than simply disabling noarch.)

Hope that helps.

Compiling against an architecture dependent package does not mean a package needs to be architecture specific itself. Is what I'm seeing here a package that needs to set a library path in order to run its unittests? If so, that does seem like the package can remain noarch even though it wants to do this.

In a python module spec file, if we needed to do something like this we'd use %python_sitearch. %python_sitearch uses values defined when the python package is built rather than what the buildroot thinks, therefore it would have the proper values at times like this. Here's a slightly contrived example:

{{{
%check
export PYTHONPATH=%{python_sitearch}/Cherrypy-2.3.0-py%{python_version}.egg
python setup.py check
}}}

Note that this does mean that packagers can use %python_sitearch incorrectly in their spec files. If they were to use it in a noarch package to define where to install something for this package, the package would build fine but a user on a different arch might have errors stemming from that usage.

It looks like there's no equivalent ruby rpm macro. All of the ruby rpm macros are defined like this: '%%{_libdir}/%{name}'. The double '%' means that the macro won't be expanded now (at the ruby package build time). Instead they will be expanded at the consuming package's build time. I'm not sure that this is the right thing for the macros to do -- For some of the cases, it is unnecessary but won't hurt (%{_prefix}, %{_datadir} won't differ between the ruby package build and consuming package builds). For the macros using %{_libdir} and %{_lib} expanding at ruby package build time would yield a different result than at the consuming package build time.

For this issue (and my experiences with python packaging) it seems like they should expand at ruby package build time but I don't know if other ruby packaging practices assume that they won't expand until the consuming package build time. (They probably shouldn't.... If you're using %{_libdir} with an arch specific package, then the package's %{_libdir} should match the %{_libdir} of the ruby package it's building against. If you're using %{_libdir} with a noarch package, the cases that %{_libdir} is useful seem like you want it to have expanded to be what the ruby package on that system is expecting... hence, it should have expanded at ruby package buildtime.)

If you need time to re-evaluate that macro to decide whether you can change it, you can use other methods to get the path from what was defined at ruby package build time. This snippet should work, for instance:

{{{
%check
RUBYLIBDIR=$(ruby -rrbconfig -e 'puts Config::CONFIG["libdir"]')

RUBYOPT="-Itest -Ilib".
RUBYOPT="$RUBYOPT -I$RUBYLIBDIR/gems/exts/io-console-0.3/lib/"

In case that rubygem-json is installed

RUBYOPT="$RUBYOPT -I%{gem_dir}/gems/json-1.6.5/lib -I$RUBYLIBDIR/gems/exts/json-1.6.5/ext/json/ext"
export RUBYOPT

testrb test
}}}

Additional Note: This entry in the rubygems %files section:
{{{
%dir %{_exec_prefix}/lib/gems
%dir %{_exec_prefix}/lib64/gems
%dir %{_exec_prefix}/lib/gems/exts
%dir %{_exec_prefix}/lib64/gems/exts
}}}
treads a fine line that I think pushes this particular package into being arch specific. A user on a 32 bit Fedora system really should not have a /usr/lib64 directory even if there's no actual files in it.

Question: It looks like the current ruby package is creating rubygems and rubygems-devel subpackages. What's the plan here? Are those going to be dropped as soon as this (rubygems) package is built?

Hi guys,

Thank you for your valuable input. However, nobody of you suggest solution. No matter how my package looks, I would expect that %{_libdir} will be expanded correctly for architecture it runs on. From your input, it seems that when the package is noarch, the %{_libdir} macro is not expanded correctly. Can we steer our discussion in that way?

Why the isa macro is not defined for noarch packages? What is the reason? Is that used as some flag to know that package is noarch? Shouldn't be there used different, separate flag?

The problem is that noarch packages need to be valid and correct on all possible architectures. If %{_libdir} was evaluated from the build env (x86_64), and files end up in %{_libdir} (/usr/lib64), that package would install files into a directory on i686 that is unused and for which the system runtime would have no reason to look in.

The solution is to not use %{_libdir} (or macros that evaluate from %{_libdir}) in a noarch package. Period.

The isa macro is not defined because we have no idea what the bitsize is for a noarch build, nor should we.

What you need to do is determine a path for these files that ruby will always search/find/locate/use, regardless of architecture, then either hardcode that into a macro. An initial look through the ruby config suggests that perhaps "rubylibdir" is appropriate. So, maybe define a systemwide macro called "%{ruby_sitelib}" which evaluates from the result of:

{{{
ruby -rrbconfig -e 'puts Config::CONFIG["rubylibdir"]'
}}}

This seems appropriate because /usr/share/$FOO is a universal target (remember, all files in a noarch package must be identical on all possible architectures), but I don't know Ruby well enough to be sure that this is indeed 100% correct. I looked for any pathing including /usr/lib in the x86_64 Config output, but there was none.

The equivalent for python is %{python_sitelib}, which is hardcoded (by the python executable) to:
/usr/lib/python2.7/site-packages. The reason this works is because A) It is not using %{libdir} to define this macro and B) python _always looks in /usr/lib/python2.7/site-packages, regardless of architecture.

Replying to [comment:4 spot]:

The problem is that noarch packages need to be valid and correct on all possible architectures. If %{_libdir} was evaluated from the build env (x86_64), and files end up in %{_libdir} (/usr/lib64), that package would install files into a directory on i686 that is unused and for which the system runtime would have no reason to look in.

The solution is to not use %{_libdir} (or macros that evaluate from %{_libdir}) in a noarch package. Period.

That make sense although it is not obvious. Would be nice if it could be mentioned somewhere (I hope I did not missed some part of guidelines :))

The isa macro is not defined because we have no idea what the bitsize is for a noarch build, nor should we.

Neither I do care about bit size, I just want to find my library.

What you need to do is determine a path for these files that ruby will always search/find/locate/use, regardless of architecture, then either hardcode that into a macro. An initial look through the ruby config suggests that perhaps "rubylibdir" is appropriate. So, maybe define a systemwide macro called "%{ruby_sitelib}" which evaluates from the result of:

{{{
ruby -rrbconfig -e 'puts Config::CONFIG["rubylibdir"]'
}}}

This seems appropriate because /usr/share/$FOO is a universal target (remember, all files in a noarch package must be identical on all possible architectures), but I don't know Ruby well enough to be sure that this is indeed 100% correct. I looked for any pathing including /usr/lib in the x86_64 Config output, but there was none.

The equivalent for python is %{python_sitelib}, which is hardcoded (by the python executable) to:
/usr/lib/python2.7/site-packages. The reason this works is because A) It is not using %{libdir} to define this macro and B) python _always looks in /usr/lib/python2.7/site-packages, regardless of architecture.

Ok, you proposed solution for Ruby and for Python, but what about other noarch packages? I'd like to have some generic solution. Let say %{runtime_libdir}, alternatively %{runtime_arch} or whatever you call it which could be used universally across all languages etc.

I'm not sure there is a generic solution here, or that one is even worthwhile. There is benefit in my opinion to a logical separation of files by type, runtime, architecture, etc, etc. Python uses /usr/lib/python2.7/site-packages because the python runtime knows (and expects) for noarch python components/files to be in that directory. There is no advantage to changing that pathing into /usr/share simply to have a common "noarch" directory.

Note that %{python_sitelib} is already in use, and has been for several years now.

The Filesystem Hierarchy Standard states that the "/usr/share hierarchy is for all read-only architecture independent data files", so if a new tool/language/interpreter was looking for a home for architecture-independent data files, /usr/share is where it should start. That directory is already macroized, as "%{_datadir}".

But ultimately, the correct full path value for ruby will end up being the one where ruby is expecting to find noarch files. I don't know what that is, I'm relying on you to determine that.

Replying to [comment:5 vondruch]:

Replying to [comment:4 spot]:

The equivalent for python is %{python_sitelib}, which is hardcoded (by the python executable) to:
/usr/lib/python2.7/site-packages. The reason this works is because A) It is not using %{libdir} to define this macro and B) python _always looks in /usr/lib/python2.7/site-packages, regardless of architecture.

Ok, you proposed solution for Ruby and for Python, but what about other noarch packages? I'd like to have some generic solution. Let say %{runtime_libdir}, alternatively %{runtime_arch} or whatever you call it which could be used universally across all languages etc.

There can't be a '''runtime'''_libdir or '''runtime'''_arch that has any meaning in the buildsystem for noarch packages. That is essentially what the existing %{_libdir} and %{_isa*} macros are and as stated, they are already either undefined or of no use for noarch packages.

What you're really looking for is a %{buildtime_libdir} that defines the %{_libdir} on the buildsystem. I'm not sure if this is a good idea. It has a large potential for being used incorrectly and thus embedding the builder's %{_libdir} into something that gets installed. OTOH, the potential already exists with per-language macros like %python_sitearch.

Replying to [comment:7 toshio]:

What you're really looking for is a %{buildtime_libdir} that defines the %{_libdir} on the buildsystem. I'm not sure if this is a good idea. It has a large potential for being used incorrectly and thus embedding the builder's %{_libdir} into something that gets installed. OTOH, the potential already exists with per-language macros like %python_sitearch.
[[BR]]
Yes, please please! I want such macro :) I knew there must be better name :) I cannot see more potential for incorrect use then what I can achieve with wrong usage of other macros.

I think that is a really bad idea, sorry Vit. Creating that macro and encouraging its use is simply begging for people to misuse it. Again, on an x86_64 box, that macro would eval to /usr/lib64, and I guarantee someone will put files in that path, and the package would build but not work on i686, since nothing on i686 is expecting to look in /usr/lib64 for anything.

I've pointed out the path to a viable and proper solution for ruby. Please consider focusing on that.

BTW, arguments about abusing some macro are moot, since nobody cares that for noarch subpackages of arch packages, the %{_libdir} is expanded. There should be at least some consistency.

Metadata Update from @vondruch:
- Issue set to the milestone: Fedora 18 Alpha

7 years ago

Log in to comment on this ticket.

Metadata