-
Notifications
You must be signed in to change notification settings - Fork 419
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New Approach to C/Java Native Extensions #186
Comments
I have to admit I have no idea how big of pain it was so I may easily misjudge. I am not sure I've understood the problem in #181? Heroku is always asking for pure Ruby? I am assuming that we would like to ideally support:
Then we could enable gem compilation and find a way how to fallback gracefully to pure Ruby if compilation fails (that may not be possible based on quick googling). Second option could be to provide two gems |
In #181, Heroku is not installing the pre-compiled gem. It is installing the pure-Ruby version. I haven't investigated yet, but there are two possible reasons that I can think of. 1) When Heroku pulls the gem from Rubygems it reports the "platform" as something Rubygems doesn't recognize so it defaults to the pure-Ruby version. 2) The user is caching the gem packages within the git repo (a very common practice with Rails) and the cached gem is the pure-Ruby one (possibly because development is being done on OS X). Either way, this isn't the behavior we desire. Heroku instanced have the build tools necessary for compiling the extensions so we want to make sure the compiled versions are installed. I do not know if it is possible to have the base gem support both compile-at-install and a pure-Ruby fallback. The problem is that Rubygems performs the compilation as it installs the gems. The mechanism by which it does this was not designed to be optional. If the necessary build tools do not exist the Rubygems generates an error and fails the gem installation. I've read a few hacks online and experimented with a few of them during my initial exploration with native extensions, but I do not have confidence in them at this point. I will have to do a lot more testing. Even so, a working solution would still be a hack that circumvents the normal operation of Rubygems and we'll need to be careful. |
I had a conversation today with a developer from MongoDB who gave a tall on C-extensions. To her knowledge there is no way to optionally compile extensions at gem installation, which is what my research has indicated. She explained that at MongoDB they put all their C and Java extensions in separate, optional gems, and recommended that we do the same. Presuming we take that approach, the remaining question is whether we create a new gem or use the existing ruby-atomic gem. I spoke to @headius briefly yesterday but haven't had a chance to ask him how he feels about us adding more code to ruby-atomic and using it that way. |
I don't understand what the benefits of re-using |
@chrisseaton No real advantage, but we have to do something with ruby-atomic. The original plan from @headius was to end-of-life that gem because the code is now in concurrent-ruby. It's been downloaded millions of times, however. What we don't know is whether the users of that gem will want to upgrade to concurrent-ruby (with vastly more code) or continue using the last release of ruby-atomic. If we decide to create a separate gem with the compiled atomic classes we may better serve the current users of ruby-atomic by keeping it alive and usable as a stand-alone gem. That's the only reason. |
Could make |
I should also note that if we choose to keep ruby-atomic around as a stand-alone gem that integrates with concurrent-ruby, rather than create a new gem that is purely and extension of concurrent-ruby, we'll may end up adding some duplication. Specifically, we'll have to decide how to handle the pure-Ruby versions of the atomic classes. When I get back home from RubyConf I can spike some of these ideas if that will help. |
I apologize for causing so much confusion. Let me start over. The question is this: Now that we have merged all code from ruby-atomic into concurrent-ruby, what do we do about the 600 thousand people who have downloaded the latest version of ruby-atomic? One option is to end-of-life The first option is best for the If we (specifically @headius) decide to end-of-life
If we decide on the second option then we need to devise a plan similar to my original suggestion. @headius @chrisseaton @mighe @pitr-ch @lucasallan Thoughts? |
It should also be noted that our pre-compiled Java gem package works flawlessly on all tested operating systems (Ubuntu and CentOS 32 and 64, Windows 32 and 64, Solaris, and OS X). This is to be expected thanks to the consistency of the JVM. Thus we would keep our compiled Java code in At each release we would use our automated build process to create the following gem packages:
We would also consider a pre-compiled gem for MRI on OS X, assuming I can figure out the bug that caused me to yank |
|
On Heroku, what I think is likely happening is that users add This is an known issue for people developing on Windows and trying to deploy to Heroku since precompiled Windows gems are more common than for other platforms. |
@mattwildig Thank you for that information! That makes a lot of sense. We use both Windows and Linux at work and I've run into that specific problem, it just never occurred to me that we would cause the same problem with our pre-compiled Linux gems. Assuming that this is the case (and assuming my reasoning is correct), then we should be OK if we put all the C code in Does my logic seem correct? |
@jdantonio I’ve had a deeper look into this, and it turns out I was wrong and you should disregard my previous comment. Bundler will install a platform specific gem if one is available and the On Heroku the Linux precompiled gem is being installed, but is giving an error when the extension is required:
The problem seems to be to with trying to find
But is trying to link against a non-existent file:
This is at the edge of my knowledge of linking/loading, but the problem seems to be to do with Ruby on Heroku being statically compiled and the prebuilt gem expecting it to be dynamically compiled, with a
|
@mattwildig Awesome work! Thank you for investigating this! This information is extremely useful. We'll definitely take this into account when we decide how to handle extensions in future releases. |
I have created a new |
I've created a PR which should address this issue in the next major release along with a companion gem for the native C code that would compile on any platform with the necessary build tools (such as Heroku). Anyone interested in giving feedback, please do so on that PR. Thank you! |
PR #205 is the next iteration of a better approach. |
PR #205 addresses this. It is the basis for the 0.8.0 release. |
Now that we've had C/Java native extensions in the latest release for a few months, they have proven to be as big of a pain as I expected. For the next major release I suggest that we move all C and Java native code into the ruby-atomic gem, keep
concurrent-ruby
pure Ruby, have this gem detect the presence ofruby-atomic
when installed, and use the optimized native code when present. Additionally, I suggest we use the current automated build process to build pre-compiled versions ofruby-atomic
, but allow for compilation of extensions on install (which we currently do not do forconcurrent-ruby
).A few other approaches have been suggested in other threads. Lets use this thread to discuss alternatives and make a decision.
The big problem posed by native extensions is obtaining a consistent build across all platforms. We've been able to manage this for many platforms by creating the pre-compiled builds. Things work as expected on Windows, JRuby, Rubinius, and standard Linux (Ubuntu and CentOS) installations. We have had problems on OS X (Issue #170) and Heroku (Issue #181). In both cases the pure-Ruby code is used even when the target platform supports compilations.
It is important to note that the issues #170 and #181 are the result of an intentional decision. Expecting a gem to compile on installation often causes problems because the necessary build tools may not be installed on the target system. This becomes an unrecoverable error that prevents installation of the gem. Even when the necessary build tools can be easily installed, many DevOps professionals prefer not to. Installing build tools on a production system is considered a security issue by many.
Although many applications will benefit by the performance improvements provided by the native code, many do not need them. Additionally, interpreters other than MRI and JRuby (such as Rubinius) cannot use the extensions anyway. Moving the native code into a different gem and making it optional seems like the most problem-free approach.
The text was updated successfully, but these errors were encountered: