From Fedora Project Wiki
Line 43: Line 43:
 
|Place for local architecture independent (e.g. *.rb) files.
 
|Place for local architecture independent (e.g. *.rb) files.
 
|}
 
|}
 +
  
 
{{admon/warning|Site versus Vendor|Do not use <code>%{ruby_sitelibdir}</code> and <code>%{ruby_sitearchdir}</code> for packaging, as they are under local. Use <code>%{ruby_vendorlibdir}</code> and <code>%{ruby_vendorarchdir}</code>.}}
 
{{admon/warning|Site versus Vendor|Do not use <code>%{ruby_sitelibdir}</code> and <code>%{ruby_sitearchdir}</code> for packaging, as they are under local. Use <code>%{ruby_vendorlibdir}</code> and <code>%{ruby_vendorarchdir}</code>.}}
Line 65: Line 66:
 
'''should''' be used to pass <code>CFLAGS</code> to <code>Makefile</code> correctly. Also, to place the files to the correct folders during build, pass <code>--vendor</code> to <code>extconf.rb</code> like this:
 
'''should''' be used to pass <code>CFLAGS</code> to <code>Makefile</code> correctly. Also, to place the files to the correct folders during build, pass <code>--vendor</code> to <code>extconf.rb</code> like this:
 
<pre>
 
<pre>
extconf.rb
+
extconf.rb --vendor
 
</pre>
 
</pre>
  
Line 74: Line 75:
 
[http://www.rubygems.org/ Ruby Gems]  are Ruby's own packaging format. Gems contain a lot of the same metadata that RPM's need, making fairly smooth interoperation between RPM and Gems possible. This guideline ensures that Gems are packaged as RPM's in a way that ensures (1) that such RPM's fit cleanly with the rest of the distribution and (2) make it possible for the end user to satisfy dependencies of a Gem by installing the appropriate RPM-packaged Gem.
 
[http://www.rubygems.org/ Ruby Gems]  are Ruby's own packaging format. Gems contain a lot of the same metadata that RPM's need, making fairly smooth interoperation between RPM and Gems possible. This guideline ensures that Gems are packaged as RPM's in a way that ensures (1) that such RPM's fit cleanly with the rest of the distribution and (2) make it possible for the end user to satisfy dependencies of a Gem by installing the appropriate RPM-packaged Gem.
  
Both RPM's and Gems use similar terminology --- there's specfiles, package names, dependencies etc. for both. To keep confusion to a minimum, whenever the term from the Gem world is meant, it is explicitly called the 'Gem specification'. An unqualified 'package' in the following always means an RPM.
+
Both RPM's and Gems use similar terminology --- there are specfiles, package names, dependencies etc. for both. To keep confusion to a minimum, whenever the term from the Gem world is meant, it is explicitly called the 'Gem specification'. An unqualified 'package' in the following always means an RPM.
  
* Packages that contain Ruby Gems '''must''' be called <code>rubygem-%{gemname}</code> where <code>gemname</code> is the name from the Gem's specification.
+
* Spec files must contain definition of <code>%{gem_name}</code>, which is the name from the Gem's specification.
 +
* Packages that contain Ruby Gems '''must''' be called <code>rubygem-%{gem_name}</code>.
 
* The <code>Source</code> of the package '''must''' be the full URL to the released Gem archive; the version of the package '''must''' be the Gem's version
 
* The <code>Source</code> of the package '''must''' be the full URL to the released Gem archive; the version of the package '''must''' be the Gem's version
* The package '''must''' have a <code>Requires</code> and a <code>BuildRequires</code> on <code>rubygems</code>
+
* The package '''must''' have a <code>Requires</code> on <code>ruby(rubygems)</code> and a <code>BuildRequires</code> on <code>rubygems-devel</code>
* The package '''must''' provide <code>rubygem(%{gemname})</code> where <code>gemname</code> is the name from the Gem's specification. For every dependency on a Gem named <code>gemdep</code>, the package must contain a <code>Requires</code> on <code>rubygem(%{gemdep})</code> with the same version constraints as the Gem
+
* The package '''must''' provide <code>rubygem(%{gem_name})</code> where <code>gem_name</code> is the name from the Gem's specification. For every dependency on a Gem named <code>gemdep</code>, the package must contain a <code>Requires</code> on <code>rubygem(%{gemdep})</code> with the same version constraints as the Gem
* The <code>%prep</code> and <code>%build</code> sections of the specfile '''should''' be empty.
+
* The <code>%prep</code> section '''should''' contain the local <code>gem install</code> similar to this (assuming that the <code>%{gem_name}-%{version}.gem</code> is <code>SOURCE0</code>):
* The Gem '''must''' be installed into <code>%{gemdir}</code> defined as
 
<pre>
 
%global gemdir %(ruby -rubygems -e 'puts Gem::dir' 2>/dev/null)
 
</pre>
 
The install '''should''' be performed with the command
 
 
<pre>
 
<pre>
gem install --local --install-dir %{buildroot}%{gemdir} --force %{SOURCE0}
+
gem install \
 +
-V \
 +
--local \
 +
        --install-dir .%{gem_dir} \
 +
--force \
 +
--rdoc \
 +
%{SOURCE0}
 
</pre>
 
</pre>
 +
* The <code>%build</code> section of the specfile '''should''' be empty.
 +
* The Gem '''must''' be installed into <code>%{gem_dir}</code>.
 +
* If the Gem has a binary extension, it must be installed under <code>%{gem_extdir}</code> directory.
 
* The package '''must''' own the following files and directories:
 
* The package '''must''' own the following files and directories:
 
<pre>
 
<pre>
%{gemdir}/gems/%{gemname}-%{version}/
+
%{gem_instdir}
%{gemdir}/cache/%{gemname}-%{version}.gem
+
%{gem_cache}
%{gemdir}/specifications/%{gemname}-%{version}.gemspec
+
%{gem_spec}
 +
%doc %{gem_docdir}
 
</pre>
 
</pre>
* Architecture-specific content '''must not''' be installed into <code>%{gemdir}</code>
+
* If the Gem only contains pure Ruby code, it '''must''' be marked as <code>BuildArch: noarch</code>. If the Gem contains binary content (e.g., for a database driver), it '''must''' be marked as architecture specific, and all architecture specific content '''must''' be moved from the <code>%{gem_instdir}</code> to the <code>%{gem_extdir}</code> during <code>%install</code>
* If the Gem only contains pure Ruby code, it '''must''' be marked as <code>BuildArch: noarch</code>. If the Gem contains binary content (e.g., for a database driver), it '''must''' be marked as architecture specific, and all architecture specific content '''must''' be moved from the <code>%{gemdir}</code> to the [#ruby_sitearch <code>%{ruby_sitearch}</code> directory]  during <code>%install</code>
 
  
 
=== Ruby Gem with extension libraries written in C ===
 
=== Ruby Gem with extension libraries written in C ===

Revision as of 08:03, 20 December 2011

Ruby Packaging Guidelines

Each Ruby package must indicate the Ruby ABI version it depends on with a line like

Requires: ruby(abi) = 1.9.1

Ruby packages must require ruby at build time with a BuildRequires: ruby, and may indicate the minimal ruby version they need for building.

Naming Guidelines

Note.png These naming guidelines only apply to ruby packages whose main purpose is providing a Ruby library; packages that mainly provide user-level tools that happen to be written in Ruby do not need to follow these naming guidelines, and should follow the general NamingGuidelines instead.

The name of a ruby extension/library package must be of the form ruby-UPSTREAM. If the upstream name UPSTREAM contains ruby, that should be dropped from the name. For example, the SQLite database driver for ruby is called sqlite3-ruby. The corresponding Fedora package should be called ruby-sqlite3, and not ruby-sqlite3-ruby.

A ruby extension/library package must indicate what it provides with a Provides: ruby(LIBRARY) = VERSION declaration in the spec file. The string LIBRARY should be the same as what is used in the require statement in a Ruby script that uses the library. The VERSION should be the upstream version of the library, as long as upstream follows a sane versioning scheme. For example, a Ruby script using the SQLite database driver will include it with require 'sqlite3'. The specfile for the corresponding Fedora package must contain a line Provides: ruby(sqlite3) = 1.1.0, assuming the package contains version 1.1.0 of the library.

Build Architecture and File Placement

The following only affects the files that the package installs into %{_libdir}/ruby/vendor_ruby (architecture specific) and %{_datadir}/ruby/vendor_ruby (architecture independent), i.e., Ruby library files. All other files in a Ruby package must adhere to the general Fedora Extras packaging conventions.

All non-gem ruby packages must require ruby-devel package at build time with a BuildRequires: ruby-devel.

align="bottom" style="color:#e76700;"
Macro Expanded path Usage
%{ruby_vendorarchdir} /usr/lib{64}/ruby/vendor_ruby Place for architecture specific (e.g. *.so) files.
%{ruby_vendorlibdir} /usr/share/ruby/vendor_ruby Place for architecture independent (e.g. *.rb) files.
%{ruby_sitearchdir} /usr/local/lib64/ruby/vendor_ruby Place for local architecture specific (e.g. *.so) files.
%{ruby_sitelibdir} /usr/local/share/ruby/vendor_ruby Place for local architecture independent (e.g. *.rb) files.


Warning.png
Site versus Vendor
Do not use %{ruby_sitelibdir} and %{ruby_sitearchdir} for packaging, as they are under local. Use %{ruby_vendorlibdir} and %{ruby_vendorarchdir}.

Pure Ruby packages

Pure Ruby packages must be built as noarch packages.

The Ruby library files in a pure Ruby package must be placed into %{ruby_vendorlibdir}. The specfile must use this macro.

Ruby packages with binary content/shared libraries

For packages with binary content, e.g., database drivers or any other Ruby bindings to C libraries, the package must be architecture specific.

The binary files in a Ruby package with binary content must be placed into %{ruby_vendorarchdir}. The Ruby files in such a package should be placed into %{ruby_vendorlibdir}. The specfile must use that path.

For packages which create C shared libraries using extconf.rb

export CONFIGURE_ARGS="--with-cflags='%{optflags}'"

should be used to pass CFLAGS to Makefile correctly. Also, to place the files to the correct folders during build, pass --vendor to extconf.rb like this:

extconf.rb --vendor

This applies to Ruby Gems, too.

Ruby Gems

Ruby Gems are Ruby's own packaging format. Gems contain a lot of the same metadata that RPM's need, making fairly smooth interoperation between RPM and Gems possible. This guideline ensures that Gems are packaged as RPM's in a way that ensures (1) that such RPM's fit cleanly with the rest of the distribution and (2) make it possible for the end user to satisfy dependencies of a Gem by installing the appropriate RPM-packaged Gem.

Both RPM's and Gems use similar terminology --- there are specfiles, package names, dependencies etc. for both. To keep confusion to a minimum, whenever the term from the Gem world is meant, it is explicitly called the 'Gem specification'. An unqualified 'package' in the following always means an RPM.

  • Spec files must contain definition of %{gem_name}, which is the name from the Gem's specification.
  • Packages that contain Ruby Gems must be called rubygem-%{gem_name}.
  • The Source of the package must be the full URL to the released Gem archive; the version of the package must be the Gem's version
  • The package must have a Requires on ruby(rubygems) and a BuildRequires on rubygems-devel
  • The package must provide rubygem(%{gem_name}) where gem_name is the name from the Gem's specification. For every dependency on a Gem named gemdep, the package must contain a Requires on rubygem(%{gemdep}) with the same version constraints as the Gem
  • The %prep section should contain the local gem install similar to this (assuming that the %{gem_name}-%{version}.gem is SOURCE0):
gem install \
	-V \
	--local \
        --install-dir .%{gem_dir} \
	--force \
	--rdoc \
	%{SOURCE0}
  • The %build section of the specfile should be empty.
  • The Gem must be installed into %{gem_dir}.
  • If the Gem has a binary extension, it must be installed under %{gem_extdir} directory.
  • The package must own the following files and directories:
%{gem_instdir}
%{gem_cache}
%{gem_spec}
%doc %{gem_docdir}
  • If the Gem only contains pure Ruby code, it must be marked as BuildArch: noarch. If the Gem contains binary content (e.g., for a database driver), it must be marked as architecture specific, and all architecture specific content must be moved from the %{gem_instdir} to the %{gem_extdir} during %install

Ruby Gem with extension libraries written in C

When a Ruby Gem contains extension libraries written in C,

  • First, %prep stage must contain %setup -q -c -T to create the directory where C libraries are compiled.
  • Then at %build stage the Ruby Gem must be installed under the directory created at %prep stage to get C libraries compiled under there.
  • When gem install is used to install Gem file, using -V option is recommend to check if CFLAGS is correctly honored.
  • Finally at %install stage the whole tree under the directory created at %prep stage should be copied (not moved) to under %{buildroot}%{gemdir}.
    • When all tree under the directory created at %prep stage is moved to under %{buildroot}, find_debuginfo.sh will complain that the corresponding source files are missing.
  • Installed C codes (usually under %{geminstdir}/etc) may be removed even if gem contents %{gemname} reports that installed C codes should be found there.

Note

The current guideline

If the Gem contains binary content (e.g., for a database driver), it must be marked 
as architecture specific, and all architecture specific content must be moved 
from the %{gemdir} to the [#ruby_sitearch %{ruby_sitearch} directory] during %install

must still apply.

Packaging for Gem and non-Gem use

If the same Ruby library is to be packaged for use as a Gem and as a straight Ruby library without Gem support, it must be packaged as a Gem first. To make it available to code that does not use Ruby Gems, a subpackage called ruby-%{gemname} must be created in the rubygem-%{gemname} package such that

  • The subpackage must require rubygem(%gemname) = %version
  • The subpackage must provide ruby(LIBRARY) = %version where LIBRARY is the same as in the [#ruby_naming general Ruby guideline] above.
  • All the toplevel library files of the Gem must be symlinked into ruby_sitelib.
  • The subpackage must own these symbolic links.

As an example, for activesupport, the rubygem-activesupport package would have a subpackge ruby-activesupport:

%package -n ruby-activesupport
...
Requires: rubygem(activesupport) = %version
Provides: ruby(active_support) = %version  # The underscore is intentional, not a typo
...
%files -n ruby-activesupport
%{ruby_sitelib}/active_support
%{ruby_sitelib}/active_support.rb

Tips for Packagers

Gems carry a lot of metadata; gem2rpm is a tool to generate an initial specfile and/or source RPM from a Gem. The generated specfile still needs some hand-editing, but conforms to 90% with this guideline.