Skip to content

Commit 474bdf6

Browse files
committed
Merge pull request #205 from ruby-concurrency/refactor/two-gems-one-repo
Builds two gems from one repo.
2 parents 4b1ac2f + 372a68f commit 474bdf6

36 files changed

+687
-138
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@ matrix:
2525
- rvm: jruby-head
2626
- rvm: 1.9.3
2727

28-
script: "bundle exec rake compile && bundle exec rspec --color --backtrace --tag ~unfinished --seed 1 --format documentation ./spec"
28+
script: "rake compile && bundle exec rspec --color --backtrace --tag ~unfinished --seed 1 --format documentation ./spec"

Gemfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
source 'https://rubygems.org'
22

3-
gemspec
3+
gemspec name: 'concurrent-ruby'
44

55
group :development do
66
gem 'rake', '~> 10.3.2'
77
gem 'rake-compiler', '~> 0.9.2'
8+
gem 'gem-compiler', '~> 0.3.0'
89
end
910

1011
group :testing do

README.md

Lines changed: 90 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,8 @@
3737

3838
### Supported Ruby versions
3939

40-
MRI 1.9.3, 2.0, 2.1, JRuby (1.9 mode), and Rubinius 2.x are supported.
41-
Although native code is used for performance optimizations on some platforms, all functionality
42-
is available in pure Ruby. This gem should be fully compatible with any interpreter that is
43-
compliant with Ruby 1.9.3 or newer.
40+
MRI 1.9.3, 2.0, 2.1, 2.2, JRuby (1.9 mode), and Rubinius 2.x are supported.
41+
This gem should be fully compatible with any interpreter that is compliant with Ruby 1.9.3 or newer.
4442

4543
## Features & Documentation
4644

@@ -62,6 +60,7 @@ This library contains a variety of concurrency abstractions at high and low leve
6260
* [Promise](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Promise.html): Similar to Futures, with more features.
6361
* [ScheduledTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ScheduledTask.html): Like a Future scheduled for a specific future time.
6462
* [TimerTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TimerTask.html): A Thread that periodically wakes up to perform work at regular intervals.
63+
* [Channel](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Channel.html): Communicating Sequential Processes (CSP).
6564

6665
### Java-inspired ThreadPools and other executors
6766

@@ -98,28 +97,45 @@ Lower-level abstractions mainly used as building blocks.
9897
* [thread-local variables](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ThreadLocalVar.html)
9998
* [software transactional memory](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TVar.html) (TVar)
10099

101-
## Installing and Building
100+
## Usage
102101

103-
This gem includes several platform-specific optimizations. To reduce the possibility of
104-
compilation errors, we provide pre-compiled gem packages for several platforms as well
105-
as a pure-Ruby build. Installing the gem should be no different than installing any other
106-
Rubygems-hosted gem. Rubygems will automatically detect your platform and install the
107-
appropriate pre-compiled build. You should never see Rubygems attempt to compile the gem
108-
on installation. Additionally, to ensure compatability with the largest possible number
109-
of Ruby interpreters, the C extensions will *never* load under any Ruby other than MRI,
110-
even when installed.
102+
All abstractions within this gem can be loaded simply by requiring it:
111103

112-
The following gem builds will be built at every release:
104+
```ruby
105+
require 'concurrent'
106+
```
107+
108+
To reduce the amount of code loaded at runtime, subsets of this gem can be required:
113109

114-
* concurrent-ruby-x.y.z.gem (pure Ruby)
115-
* concurrent-ruby-x.y.z-java.gem (JRuby)
116-
* concurrent-ruby-x.y.z-x86-linux.gem (Linux 32-bit)
117-
* concurrent-ruby-x.y.z-x86_64-linux.gem (Linux 64-bit)
118-
* concurrent-ruby-x.y.z-x86-mingw32.gem (Windows 32-bit)
119-
* concurrent-ruby-x.y.z-x64-mingw32.gem (Windows 64-bit)
120-
* concurrent-ruby-x.y.z-x86-solaris-2.11.gem (Solaris)
110+
```ruby
111+
require 'concurrent' # everything
112+
113+
# groups
114+
115+
require 'concurrent/actor' # Concurrent::Actor and supporting code
116+
require 'concurrent/atomics' # atomic and thread synchronization classes
117+
require 'concurrent/channels' # Concurrent::Channel and supporting code
118+
require 'concurrent/executors' # Thread pools and other executors
119+
require 'concurrent/utilities' # utility methods such as processor count and timers
120+
121+
# individual abstractions
122+
123+
require 'concurrent/agent' # Concurrent::Agent
124+
require 'concurrent/async' # Concurrent::Async
125+
require 'concurrent/atomic' # Concurrent::Atomic (formerly the `atomic` gem)
126+
require 'concurrent/dataflow' # Concurrent::dataflow
127+
require 'concurrent/delay' # Concurrent::Delay
128+
require 'concurrent/exchanger' # Concurrent::Exchanger
129+
require 'concurrent/future' # Concurrent::Future
130+
require 'concurrent/ivar' # Concurrent::IVar
131+
require 'concurrent/mvar' # Concurrent::MVar
132+
require 'concurrent/promise' # Concurrent::Promise
133+
require 'concurrent/scheduled_task' # Concurrent::ScheduledTask
134+
require 'concurrent/timer_task' # Concurrent::TimerTask
135+
require 'concurrent/tvar' # Concurrent::TVar
136+
```
121137

122-
### Installing
138+
## Installation
123139

124140
```shell
125141
gem install concurrent-ruby
@@ -133,31 +149,64 @@ gem 'concurrent-ruby'
133149

134150
and run `bundle install` from your shell.
135151

136-
### Building
152+
### C Extensions for MRI
137153

138-
Because we provide pre-compiled gem builds, users should never need to build the gem manually.
139-
The build process for this gem is completely automated using open source tools. All of
140-
the automation components are available in the [ruby-concurrency/rake-compiler-dev-box](https://github.com/ruby-concurrency/rake-compiler-dev-box)
141-
GitHub repository.
154+
Potential performance improvements may be achieved under MRI by installing optional C extensions.
155+
To minimize installation errors the C extensions are available in the `concurrent-ruby-ext` extension
156+
gem. The extension gem lists `concurrent-ruby` as a dependency so it is not necessary to install both.
157+
Simply install the extension gen:
142158

143-
This gem will compile native C code under MRI and native Java code under JRuby. It is
144-
also possible to build a pure-Ruby version. All builds have identical functionality.
145-
The only difference is performance. Additionally, pure-Ruby classes are always available,
146-
even when using the native optimizations. Please see the [documentation](http://ruby-concurrency.github.io/concurrent-ruby/)
147-
for more details.
159+
```ruby
160+
gem install concurrent-ruby-ext
161+
```
148162

149-
To build and package the gem using MRI or JRuby, install the necessary build dependencies and run:
163+
or add the following line to Gemfile:
150164

151-
```shell
152-
bundle exec rake compile
153-
bundle exec rake build
165+
```ruby
166+
gem 'concurrent-ruby-ext'
167+
```
168+
169+
and run `bundle install` from your shell.
170+
171+
In code it is only necessary to
172+
173+
```ruby
174+
require 'concurrent'
154175
```
155176

156-
To build and package a pure-Ruby gem, on *any* platform and interpreter
157-
(including MRI and JRuby), run:
177+
The `concurrent-ruby` gem will automatically detect the presence of the `concurrent-ruby-ext` gem
178+
and load the appropriate C extensions.
158179

159-
```shell
160-
BUILD_PURE_RUBY='true' bundle exec rake build
180+
#### Note For gem developers
181+
182+
No gems should depend on `concurrent-ruby-ext`. Doing so will force C extensions on your users.
183+
The best practice is to depend on `concurrent-ruby` and let users to decide if they want C extensions.
184+
185+
### Building
186+
187+
All published versions of this gem (core, extension, and several platform-specific packages) are compiled,
188+
packaged, tested, and published using an open, [automated process](https://github.com/ruby-concurrency/rake-compiler-dev-box).
189+
This process can also be used to create pre-compiled binaries of the extension gem for virtally
190+
any platform. *Documentation is forthcoming...*
191+
192+
```
193+
*MRI only*
194+
rake build:native # Build concurrent-ruby-ext-<version>-<platform>.gem into the pkg directory
195+
rake compile:extension # Compile extension
196+
197+
*JRuby only*
198+
rake build # Build JRuby-specific core gem (alias for `build:core`)
199+
rake build:core # Build concurrent-ruby-<version>-java.gem into the pkg directory
200+
201+
*All except JRuby*
202+
rake build # Build core and extension gems
203+
rake build:core # Build concurrent-ruby-<version>.gem into the pkg directory
204+
rake build:ext # Build concurrent-ruby-ext-<version>.gem into the pkg directory
205+
206+
*All*
207+
rake clean # Remove any temporary products
208+
rake clobber # Remove any generated file
209+
rake compile # Compile all the extensions
161210
```
162211

163212
## Maintainers
@@ -167,6 +216,7 @@ BUILD_PURE_RUBY='true' bundle exec rake build
167216
* [Chris Seaton](https://github.com/chrisseaton)
168217
* [Lucas Allan](https://github.com/lucasallan)
169218
* [Petr Chalupa](https://github.com/pitr-ch)
219+
* [Paweł Obrok](https://github.com/obrok)
170220

171221
### Contributing
172222

Rakefile

Lines changed: 77 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,32 @@
1-
require 'bundler/gem_tasks'
2-
require 'rake/extensiontask'
3-
require 'rake/javaextensiontask'
1+
#!/usr/bin/env rake
42

5-
GEMSPEC = Gem::Specification.load('concurrent-ruby.gemspec')
6-
EXTENSION_NAME = 'concurrent_ruby_ext'
3+
require_relative './lib/extension_helper'
74

8-
Bundler::GemHelper.install_tasks
5+
## load the two gemspec files
6+
CORE_GEMSPEC = Gem::Specification.load('concurrent-ruby.gemspec')
7+
EXT_GEMSPEC = Gem::Specification.load('concurrent-ruby-ext.gemspec')
98

10-
$:.push File.join(File.dirname(__FILE__), 'lib')
11-
require 'extension_helper'
9+
## constants used for compile/build tasks
10+
11+
GEM_NAME = 'concurrent-ruby'
12+
EXTENSION_NAME = 'extension'
13+
JAVA_EXT_NAME = 'concurrent_ruby_ext'
14+
15+
if Concurrent.jruby?
16+
CORE_GEM = "#{GEM_NAME}-#{Concurrent::VERSION}-java.gem"
17+
else
18+
CORE_GEM = "#{GEM_NAME}-#{Concurrent::VERSION}.gem"
19+
EXTENSION_GEM = "#{GEM_NAME}-ext-#{Concurrent::VERSION}.gem"
20+
NATIVE_GEM = "#{GEM_NAME}-ext-#{Concurrent::VERSION}-#{Gem::Platform.new(RUBY_PLATFORM)}.gem"
21+
end
22+
23+
## safely load all the rake tasks in the `tasks` directory
1224

1325
def safe_load(file)
1426
begin
1527
load file
1628
rescue LoadError => ex
17-
puts 'Error loading rake tasks, but will continue...'
29+
puts "Error loading rake tasks from '#{file}' but will continue..."
1830
puts ex.message
1931
end
2032
end
@@ -23,21 +35,24 @@ Dir.glob('tasks/**/*.rake').each do |rakefile|
2335
safe_load rakefile
2436
end
2537

26-
desc 'Run benchmarks'
27-
task :bench do
28-
exec 'ruby -Ilib -Iext examples/bench_atomic.rb'
29-
end
38+
if Concurrent.jruby?
3039

31-
if defined?(JRUBY_VERSION)
40+
## create the compile task for the JRuby-specific gem
41+
require 'rake/javaextensiontask'
3242

33-
Rake::JavaExtensionTask.new(EXTENSION_NAME, GEMSPEC) do |ext|
43+
Rake::JavaExtensionTask.new(JAVA_EXT_NAME, CORE_GEMSPEC) do |ext|
3444
ext.ext_dir = 'ext'
3545
end
3646

3747
elsif Concurrent.allow_c_extensions?
3848

39-
Rake::ExtensionTask.new(EXTENSION_NAME, GEMSPEC) do |ext|
40-
ext.ext_dir = "ext/#{EXTENSION_NAME}"
49+
## create the compile tasks for the extension gem
50+
require 'rake/extensiontask'
51+
52+
Rake::ExtensionTask.new(EXTENSION_NAME, EXT_GEMSPEC) do |ext|
53+
ext.ext_dir = 'ext/concurrent'
54+
ext.lib_dir = 'lib/concurrent'
55+
ext.source_pattern = '*.{c,h}'
4156
ext.cross_compile = true
4257
ext.cross_platform = ['x86-mingw32', 'x64-mingw32']
4358
end
@@ -59,20 +74,61 @@ elsif Concurrent.allow_c_extensions?
5974
end
6075
end
6176
else
62-
task :clean
77+
## create an empty compile task
6378
task :compile
64-
task "compile:#{EXTENSION_NAME}"
6579
end
6680

67-
Rake::Task[:clean].enhance do
81+
task :clean do
6882
rm_rf 'pkg/classes'
6983
rm_rf 'tmp'
7084
rm_rf 'lib/1.9'
7185
rm_rf 'lib/2.0'
72-
rm_f Dir.glob('./lib/*.jar')
86+
rm_f Dir.glob('./**/*.so')
7387
rm_f Dir.glob('./**/*.bundle')
88+
rm_f Dir.glob('./lib/*.jar')
89+
mkdir_p 'pkg'
7490
end
7591

92+
## create build tasks tailored to current platform
93+
94+
namespace :build do
95+
96+
build_deps = [:clean]
97+
build_deps << :compile if Concurrent.jruby?
98+
99+
desc "Build #{CORE_GEM} into the pkg directory"
100+
task :core => build_deps do
101+
sh "gem build #{CORE_GEMSPEC.name}.gemspec"
102+
sh 'mv *.gem pkg/'
103+
end
104+
105+
unless Concurrent.jruby?
106+
desc "Build #{EXTENSION_GEM} into the pkg directory"
107+
task :ext => [:clean] do
108+
sh "gem build #{EXT_GEMSPEC.name}.gemspec"
109+
sh 'mv *.gem pkg/'
110+
end
111+
end
112+
113+
if Concurrent.allow_c_extensions?
114+
desc "Build #{NATIVE_GEM} into the pkg directory"
115+
task :native do
116+
sh "gem compile pkg/#{EXTENSION_GEM}"
117+
sh 'mv *.gem pkg/'
118+
end
119+
end
120+
end
121+
122+
if Concurrent.jruby?
123+
desc 'Build JRuby-specific core gem (alias for `build:core`)'
124+
task :build => ['build:core']
125+
else
126+
desc 'Build core and extension gems'
127+
task :build => ['build:core', 'build:ext']
128+
end
129+
130+
## the RSpec task that compiles extensions when available
131+
76132
begin
77133
require 'rspec'
78134
require 'rspec/core/rake_task'

0 commit comments

Comments
 (0)