Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 321 lines (212 sloc) 10.389 kb
83a4096 @luislavena Add wiki example link to README. Close GH-26
luislavena authored
1 = rake-compiler
2
3 rake-compiler aims to help Gem developers deal with Ruby extensions, simplifying
4 code and reducing duplication.
5
6 It followss *convention over configuration* and sets a standardized structure to
7 build and package both C and Java extensions in your gems.
8
9 This is the result of experiences dealing with several Gems that required native
10 extensions across platforms and different user configurations where details like
11 portability and clarity of code were lacking.
12
13 == An Overview
14
15 Let's summarize what rake-compiler provides:
16
17 * No custom rake tasks required. Less code duplication and errors.
18
19 * Painlessly build extensions on different platforms (Linux, OSX and Windows).
20
21 * Painlessly build extensions for different Ruby implementations (JRuby,
22 Rubinius and MRI).
23
24 * Allow multiple extensions be compiled inside the same gem.
25
26 * Mimics RubyGems installation process, so helps as a test environment.
27
28 * Simplify cross platform compilation of extensions (target Windows from Linux).
29
30 == I'm sold! show me how to use it! (Installation)
31
32 Usage of rake-compiler is pretty much straight forward.
33
34 First, you need to install the gem:
35
36 $ gem install rake-compiler
37
38 == Now what? (Usage)
39
40 Now that you have the gem installed, let's give your project some structure.
41
42 === Structure
43
44 Let's say we want to compile an extension called 'hello_world', so we should
45 organize the code and folders that will help rake-compiler do its job:
46
47 |-- ext
48 | `-- hello_world
49 | |-- extconf.rb
50 | |-- HelloWorldService.java
51 | `-- hello_world.c
52 |-- lib
53 `-- Rakefile
54
55 TIP: Having a consistent folder structure will help developers and newcomers
56 to find code and also contribute back to your project more easily.
57
58 === Adding the code
59
60 So now it's time to introduce the code to compile our extension:
61
62 # File: Rakefile
63
64 require 'rake/extensiontask'
65
66 Rake::ExtensionTask.new('hello_world')
67
68 Ok, that's it. No other line of code.
69
70 If we wanted to do the same for a JRuby extension (written in Java):
71
72 # File: Rakefile
73
74 require 'rake/javaextensiontask'
75
76 Rake::JavaExtensionTask.new('hello_world')
77
78 === Compile process
79
80 Those *two* lines of code automatically added the needed rake tasks to build
81 the hello_world extension. Running Rake on 1.8.x/1.9 (MRI):
82
83 $ rake -T
84 (in /home/user/my_extension)
85 rake compile # Compile the extension(s)
86 rake compile:hello_world # Compile just the hello_world extension
87
88 Simply calling <tt>compile</tt>:
89
90 $ rake compile
91
92 Will do all the compile process for us, putting the result extension inside
93 <tt>lib</tt> directory.
94
95 NOTE: Please be aware that building C extensions requires the proper
96 development environment for your Platform, which includes libraries, headers
97 and build tools. Check your distro / vendor documentation on how to install it.
98
99 NOTE: Building Java extensions requires the <tt>javac</tt>, part of the Java
100 Development Kit (JDK). This should be included by default on Mac OS X, and
101 downloadable from http://java.sun.com for other operating systems.
102
103 === Generate native gems
104
105 A common usage scenario of rake-compiler is generate native gems that bundles
106 your extensions.
107
108 This got over-simplified with <tt>Rake::ExtensionTask</tt>:
109
110 # somewhere in your Rakefile, define your gem spec
111 spec = Gem::Specification.new do |s|
112 s.name = "my_gem"
113 s.platform = Gem::Platform::RUBY
114 s.extensions = FileList["ext/**/extconf.rb"]
115 end
116
117 # add your default gem packing task
118 Rake::GemPackageTask.new(spec) do |pkg|
119 end
120
121 # feed your ExtensionTask with your spec
122 Rake::ExtensionTask.new('hello_world', spec)
123
124 Now, as usual, you can build your pure-ruby gem (standard output):
125
126 $ rake gem
127 (in /projects/oss/my_gem.git)
128 mkdir -p pkg
129 Successfully built RubyGem
130 Name: my_gem
131 Version: 0.1.0
132 File: my_gem-0.1.0.gem
133 mv my_gem-0.1.0.gem pkg/my_gem-0.1.0.gem
134
135 Plus, you have the functionality to build native versions of the gem:
136
137 # rake native gem
138 (... compilation output ...)
139 mkdir -p pkg
140 Successfully built RubyGem
141 Name: my_gem
142 Version: 0.1.0
143 File: my_gem-0.1.0.gem
144 mv my_gem-0.1.0.gem pkg/my_gem-0.1.0.gem
145 Successfully built RubyGem
146 Name: my_gem
147 Version: 0.1.0
148 File: my_gem-0.1.0-x86-mingw32.gem
149 mv my_gem-0.1.0-x86-mingw32.gem pkg/my_gem-0.1.0-x86-mingw32.gem
150
151 You get two gems for the price of one.
152
153 And the same for JRuby extensions:
154
155 # rake java gem
156 (... compilation output ...)
157 mkdir -p pkg
158 Successfully built RubyGem
159 Name: my_gem
160 Version: 0.1.0
161 File: my_gem-0.1.0.gem
162 mv my_gem-0.1.0.gem pkg/my_gem-0.1.0.gem
163 Successfully built RubyGem
164 Name: my_gem
165 Version: 0.1.0
166 File: my_gem-0.1.0-java.gem
167 mv my_gem-0.1.0-java.gem pkg/my_gem-0.1.0-java.gem
168
169
170 === What about breaking the standards? (Customization)
171
172 In case you want to bend the convention established, rake-compiler let you
173 personalize several settings for <tt>Rake::ExtensionTask</tt>:
174
175 Rake::ExtensionTask.new do |ext|
176 ext.name = 'hello_world' # indicate the name of the extension.
177 ext.ext_dir = 'ext/weird_world' # search for 'hello_world' inside it.
178 ext.lib_dir = 'lib/my_lib' # put binaries into this folder.
179 ext.config_script = 'custom_extconf.rb' # use instead of 'extconf.rb' default
180 ext.tmp_dir = 'tmp' # temporary folder used during compilation.
181 ext.source_pattern = "*.{c,cpp}" # monitor file changes to allow simple rebuild.
182 ext.config_options << '--with-foo' # supply additional configure options to config script.
183 ext.gem_spec = spec # optional indicate which gem specification
184 # will be used to based on.
185 end
186
187 == Future is now: Cross compilation
188
189 rake-compiler provides now an standardized way to generate, from Linux or OSX
190 both extensions and gem binaries for Windows!
191
192 It takes advantages from GCC host/target to build binaries (for target) on
193 different OS (hosts).
194
195 === How I enjoy this?
196
197 Besides having the development tool chain installed (GCC), you should install
198 also <tt>mingw32</tt> cross compilation package.
199
200 Installation depends will depend on your operating system/distribution. On
201 Ubuntu and Debian machines, a simple <tt>apt-get install mingw32</tt> will be
202 enough.
203
204 On OSX, mingw32 is available via MacPorts: <tt>port install i386-mingw32-gcc</tt>
205 (ensure you update your ports tree before hand as <tt>mingw32</tt> has been
206 been broken).
207
208 === I have my tool-chain, now what?
209
210 You need to build Ruby for Windows.
211
212 Relax, no need to freak out! Let rake-compiler do it for you:
213
214 rake-compiler cross-ruby
215
216 And you're done. It will automatically download, configure and compile latest
217 stable version of Ruby for Windows, and place it into <tt>~/.rake-compiler</tt>
218
219 If, instead, you want to build another version than the default one, please
220 supply a <tt>VERSION</tt>:
221
222 rake-compiler cross-ruby VERSION=1.8.6-p114
223
68be722 @luislavena Added some documentation to HOST option
luislavena authored
224 If you, like me, have multiple versions of MinGW packages, you can specify the
225 HOST that will be used to cross compile ruby:
226
227 rake-compiler cross-ruby HOST=i386-mingw32 # (OSX mingw32 port)
228
229 The host will vary depending on provider (mingw32 versus mingw-w64 projects).
230 Consult the documentation and website of the MinGW package provider before
231 reporting any issue.
232
83a4096 @luislavena Add wiki example link to README. Close GH-26
luislavena authored
233 === Let's build some gems!
234
235 Now, you only need to use additional options in your extension definition:
236
237 Rake::ExtensionTask.new('my_extension', gem_spec) do |ext|
238 ext.cross_compile = true # enable cross compilation (requires cross compile toolchain)
239 ext.cross_platform = 'i386-mswin32' # forces the Windows platform instead of the default one
240 # configure options only for cross compile
241 ext.cross_config_options << '--with-something'
242
243 # perform alterations on the gemspec when cross compiling
244 ext.cross_compiling do |gem_spec|
245 gem_spec.post_install_message = "You installed the binary version of this gem!"
246 end
247 end
248
249 By default, cross compilation targets 'i386-mingw32' which is default GCC platform
250 for Ruby.
251
252 To target gems for current Ruby official distribution, please force the platform
253 to the one shown before.
254
255 === Magician doing some tricks, don't blink!
256
257 Compiles keeps being simple:
258
259 rake cross compile
260
261 And now, build your gems for Windows is just 5 more letters:
262
263 rake cross native gem
264
265 And you're done, yeah.
266
267 === Take it even further
268
269 You can specify against with version of Ruby you want to build the extension:
270
271 rake cross compile RUBY_CC_VERSION=1.8.6
272
273 If you installed <tt>1.9.1</tt>, you can do:
274
275 rake cross compile RUBY_CC_VERSION=1.9.1
276
277 Even more, you can target multiple versions (ie. 1.8.6 and 1.9.1):
278
279 rake cross compile RUBY_CC_VERSION=1.8.6:1.9.1
280
281 And more exiting, bundle both binaries in one "fat" Gem:
282
283 rake cross native gem RUBY_CC_VERSION=1.8.6:1.9.1
284
285 That will place binaries for 1.8 and 1.9 versions of ruby inside <tt>lib_dir</tt>
286
287 lib/1.8/my_extension.so
288 lib/1.9/my_extension.so
289
290 Now is up to you to make your gem load the proper one ;-)
291
292 === What are you talking about? (Give me examples)
293
294 I know all the above sounds like a complete foreign language (it does even for me!). So, what if I show you some examples?
295
296 Check our wiki with links to the proper rake files used by many developers and projects and how they use rake-compiler.
297
298 http://github.com/luislavena/rake-compiler/wiki/projects-using-rake-compiler
299
300 == Future
301
302 rake-compiler is a work in progress and we will appreciate feedback during the
303 development of it! (and contributions too!)
304
305 You can find more information about rake-compiler:
306
307 Blog: http://blog.mmediasys.com
308 RubyForge: http://rubyforge.org/projects/rake-compiler
309 GitHub: http://github.com/luislavena/rake-compiler
310 Issues: http://github.com/luislavena/rake-compiler/issues
311 Wiki: http://github.com/luislavena/rake-compiler/wiki
312
313 == Disclaimer
314
315 If you have any trouble, don't hesitate to contact the author. As always,
316 I'm not going to say "Use at your own risk" because I don't want this library
317 to be risky.
318
319 If you trip on something, I'll share the liability by repairing things
320 as quickly as I can. Your responsibility is to report the inadequacies.
Something went wrong with that request. Please try again.