[jruby-user] MRI/JRuby Bundler Gemspec/Gemfile Problem

55 views
Skip to first unread message

Keith Bennett

unread,
Jun 12, 2013, 2:26:12 PM6/12/13
to us...@jruby.codehaus.org
Hi, everyone.

I'm writing a gem that can be used from both MRI Ruby and JRuby to talk to a Java library in a jar file.  In JRuby talking to the Java library requires no special configuration, but from MRI Ruby I need to use the rjb (Ruby Java Bridge) gem.
So, I want to install the rjb gem if in MRI Ruby, bot want *not* to install it if in JRuby, since it requires some native building.
I have this in my gemspec, which works fine:
  unless /java/ === RUBY_PLATFORM    spec.add_dependency 'rjb'  end
However, when I run bundle in MRI, the resulting Gemfile.lock contains the rjb dependency without any condition not to use it in JRuby:
...    rake (10.0.4)    rjb (1.4.6)    rspec (2.13.0) ... So if I build the gem, distribute it, and then gem install it in JRuby, the gem install tries to build rjb, and fails because of the native extensions.
What's the best way to deal with this?  Should I duplicate the gem dependencies, putting them in the Gemfile instead of the 'gemspec' that's there now?  Or build two different gems (I hope not)?
Thanks,Keith

Sébastien Le Callonnec

unread,
Jun 12, 2013, 4:00:19 PM6/12/13
to us...@jruby.codehaus.org
Hi Keith,

You do need to create a separate gem for the different platforms –
thankfully, rake-compiler (https://github.com/luislavena/rake-compiler)
makes it easy to do so.
I had described how over at SO
(http://stackoverflow.com/a/13540730/289466), but I should probably
stick that somewhere in the wiki too.

Regards,
Sébastien.

Le mer. 12 juin 2013 19:26:12 IST, Keith Bennett a écrit :
> Hi, everyone.
>
> I'm writing a gem that can be used from both MRI Ruby and JRuby to
> talk to a Java library in a jar file. In JRuby talking to the Java
> library requires no special configuration, but from MRI Ruby I need to
> use the rjb (Ruby Java Bridge) gem.
> So, I want to install the rjb gem if in MRI Ruby, bot want *not* to
> install it if in JRuby, since it requires some native building.
> I have this in my gemspec, which works fine:
> unless /java/ === RUBY_PLATFORM spec.add_dependency 'rjb' end
> However, when I run bundle in MRI, the resulting Gemfile.lock contains
> the rjb dependency without any condition not to use it in JRuby:
> ... rake (10.0.4) rjb (1.4.6) rspec (2.13.0)...So if I build
> the gem, distribute it, and then gem install it in JRuby, the gem
> install tries to build rjb, and fails because of the native extensions.
> What's the best way to deal with this? Should I duplicate the gem
> dependencies, putting them in the Gemfile instead of the 'gemspec'
> that's there now? Or build two different gems (I hope not)?
> Thanks,Keith
>

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email


Keith Bennett

unread,
Jun 12, 2013, 5:15:04 PM6/12/13
to us...@jruby.codehaus.org
Sebastien -

I've been trying to get your instructions to work but have been unable.  I've tried the following:

> rake native gem  # in MRI
...Don't know how to build task 'ext/my_gem_name/extconf.rb'...

> rake java gem  # in JRuby
...javac: no source files...

> rake gem
...Don't know how to build task 'gem'...

I gem installed rake-compiler.  Is it not there?

In my case, I don't need to compile anything.  The *only* difference is that MRI has a dependency that JRuby does not (RJB).  What am I doing wrong?

- Keith

Rhett Sutphin

unread,
Jun 12, 2013, 5:50:54 PM6/12/13
to us...@jruby.codehaus.org
Hi Keith,

I am not familiar with rake-compiler and I'm not sure it will help you in this case, but I can give you an overview of what you need to achieve.

When you have a gem that has different dependencies on different rubies, you need to package the gem separately for each platform. Adding a condition on the dependency in the gemspec is not sufficient; you actually need to build and publish variants of the gem with different values in the gemspec's "platform" attribute. (This is because the gemspec that is packaged in the gem isn't the literal code you author in the gemspec file -- it's a serialized representation derived from interpreting the gemspec in the interpreter on which the gem is being packaged. Any conditions will be evaluated in the published gemspec.)

One of my gems, ladle[1], has both JRuby and generic ruby versions. You can take a look at its source[2] to see how this happens, but basically I use RVM to package it separately on both MRI and JRuby and then publish both.

I believe if you do handle the packaging like this, bundler will do the right thing. I haven't tried it though, so I don't know for sure.

Rhett

[1]: http://rubygems.org/gems/ladle
[2]: https://github.com/NUBIC/ladle ; ladle.gemspec and meta.rakefile are the key files

Sébastien Le Callonnec

unread,
Jun 12, 2013, 6:26:21 PM6/12/13
to us...@jruby.codehaus.org
Hi Keith,

As you mentioned, you have the following in your gemspec:

unless /java/ === RUBY_PLATFORM spec.add_dependency 'rjb' end

The gemspec file is the description of how to package your gem, so the
RUBY_PLATFORM here will be the one of the ruby you use to build/package
your gem, not the one you�ll be using at runtime. This means you have
to package the gem for MRI with MRI, and the gem for JRuby with JRuby.

I am not sure what your library contains, but typically a MRI extension
contains C code, and a JRuby extension contains Java code �
rake-compiler comes in handy to handle cross-compilation, but you don�t
have to use it. The documentation is still useful to understand the
whole process.


Regards,
S�bastien.

Le 12/06/2013 22:15, Keith Bennett a �crit :
> Sebastien -
>
> I've been trying to get your instructions to work but have been unable.
> I've tried the following:
>
> > rake native gem # in MRI
> ...Don't know how to build task 'ext/my_gem_name/extconf.rb'...
>
> > rake java gem # in JRuby
> ...javac: no source files...
>
> > rake gem
> ...Don't know how to build task 'gem'...
>
> I gem installed rake-compiler. Is it not there?
>
> In my case, I don't need to compile anything. The *only* difference is
> that MRI has a dependency that JRuby does not (RJB). What am I doing wrong?
>
> - Keith
>
>
>
> On Wed, Jun 12, 2013 at 4:00 PM, S�bastien Le Callonnec <slc...@yahoo.ie
> <mailto:slc...@yahoo.ie>> wrote:
>
> Hi Keith,
>
> You do need to create a separate gem for the different platforms �
> thankfully, rake-compiler
> (https://github.com/__luislavena/rake-compiler
> <https://github.com/luislavena/rake-compiler>) makes it easy to do so.
> I had described how over at SO
> (http://stackoverflow.com/a/__13540730/289466
> <http://stackoverflow.com/a/13540730/289466>), but I should probably
> stick that somewhere in the wiki too.
>
> Regards,
> S�bastien.
>
> Le mer. 12 juin 2013 19:26:12 IST, Keith Bennett a �crit :
>
> Hi, everyone.
>
> I'm writing a gem that can be used from both MRI Ruby and JRuby to
> talk to a Java library in a jar file. In JRuby talking to the Java
> library requires no special configuration, but from MRI Ruby I
> need to
> use the rjb (Ruby Java Bridge) gem.
> So, I want to install the rjb gem if in MRI Ruby, bot want *not* to
> install it if in JRuby, since it requires some native building.
> I have this in my gemspec, which works fine:
> unless /java/ === RUBY_PLATFORM spec.add_dependency 'rjb' end
> However, when I run bundle in MRI, the resulting Gemfile.lock
> contains
> the rjb dependency without any condition not to use it in JRuby:
> ... rake (10.0.4) rjb (1.4.6) rspec (2.13.0)...So if I
> build
>
> the gem, distribute it, and then gem install it in JRuby, the gem
> install tries to build rjb, and fails because of the native
> extensions.
> What's the best way to deal with this? Should I duplicate the gem
> dependencies, putting them in the Gemfile instead of the 'gemspec'
> that's there now? Or build two different gems (I hope not)?
> Thanks,Keith
>
>
> ------------------------------__------------------------------__---------
> To unsubscribe from this list, please visit:
>
> http://xircles.codehaus.org/__manage_email
> <http://xircles.codehaus.org/manage_email>

Keith Bennett

unread,
Jun 12, 2013, 11:17:02 PM6/12/13
to us...@jruby.codehaus.org
Rhett and Sebastien -

Maybe I'm overthinking this...my code doesn't contain any extensions at all, I just have a dependency on a gem on one platform but not the other.  I don't think I need rake-compile.

If I have to create one gem per platform, then I guess all I need to do is something like this:

rvm 1.9
./build_gem.sh

rvm jruby
./build_gem.sh

...where build_gem.sh is the shell script I posted at https://gist.github.com/keithrbennett/5770915.

My gemspec file has this:

  is_jruby = /java/ === RUBY_PLATFORM
  spec.version = is_jruby ? CaptiveValidator::VERSION + '.java' : CaptiveValidator::VERSION

I've seen other gems use an underscore instead (_java) (yours included, Rhett), but when I try specifying that in the gemspec I get an error from the gem build:

Malformed version number string 0.1.0_java

Rhett, how did you do it?  Did you rename the file manually?  I could certainly do that, but I assume if the gem build forbids it there is a good reason...or no?

Thanks,
Keith

Rhett Sutphin

unread,
Jun 12, 2013, 11:32:23 PM6/12/13
to us...@jruby.codehaus.org
Hi Keith,

> I've seen other gems use an underscore instead (_java) (yours included, Rhett), but when I try specifying that in the gemspec I get an error from the gem build:
>
> Malformed version number string 0.1.0_java
>
> Rhett, how did you do it? Did you rename the file manually? I could certainly do that, but I assume if the gem build forbids it there is a good reason...or no?

You don't want to change the version number. You want to change `spec.platform` — if it is anything other than "ruby", rubygems will add an appropriate platform suffix to the gem package name. The platform attribute is also what rubygems (and hopefully bundler) will use to pick the right gem to install on MRI vs. JRuby.

Rhett

Keith Bennett

unread,
Jun 13, 2013, 9:34:04 AM6/13/13
to us...@jruby.codehaus.org
Rhett -

Thanks, I realized that shortly after writing you, and was composing another message when you responded.

I'm now doing the same thing with another gem, and gem build appends ".java" to the gem file name instead of "-java".  Any idea why?  The ".java" is interpreted by Gem in a Box as meaning it's a prerelease version (a gem convention I think), but that was not my intention.

Also, given that the Gemfile.lock file will differ in the respective platform, how do you deal with committing it to the version control repo?

- Keith

Keith Bennett

unread,
Jun 14, 2013, 9:33:59 AM6/14/13
to us...@jruby.codehaus.org
Sorry, I could swear I checked the gemspec and version files, but I had made the .java stuff happen myself.

I'm still perplexed as to how to handle committing the Gemfile.lock, given that it will differ for the two platforms.

- Keith

Brendan Grainger

unread,
Jun 14, 2013, 10:27:01 AM6/14/13
to us...@jruby.codehaus.org
I think the recommendation when developing a gem is to not check your Gemfile.lock into source control so it would just be generated for each platform you create the gem for.


"When developing a gem, use the gemspec method in your Gemfile to avoid duplication. In general, a gem’s Gemfile should contain the Rubygems source and a single gemspec line. Do not check your Gemfile.lock into version control, since it enforces precision that does not exist in the gem command, which is used to install gems in practice. Even if the precision could be enforced, you wouldn’t want it, since it would prevent people from using your library with versions of its dependencies that are different from the ones you used to develop the gem."


--
Brendan Grainger
www.kuripai.com

Rhett Sutphin

unread,
Jun 14, 2013, 11:00:13 AM6/14/13
to us...@jruby.codehaus.org
Hi,

> I'm still perplexed as to how to handle committing the Gemfile.lock, given that it will differ for the two platforms.

I don't have experience doing this with a real application, but I just tried a trivial test app and it seemed to work. I created a Gemfile with a gem that had both generic and java versions. Then I did `bundle install` on MRI, which created a Gemfile.lock. And then I did `bundle install` on JRuby, which updated Gemfile.lock so that it included the java-platform dependencies also. Then I switched back to MRI and did `bundle install` a third time; the java platform information in Gemfile.lock was preserved.

So, try it and see.

Rhett
Reply all
Reply to author
Forward
0 new messages