Skip to content

Commit

Permalink
documentation updates and new documentation
Browse files Browse the repository at this point in the history
git-svn-id: http://ruby2cext.rubyforge.org/svn/trunk@44 fb9c67ac-1a16-0410-bc3f-e42715d93028
  • Loading branch information
dbat committed Jun 4, 2007
1 parent ed3240a commit 6e8f553
Show file tree
Hide file tree
Showing 5 changed files with 473 additions and 45 deletions.
120 changes: 110 additions & 10 deletions doc/eval2c.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
h1. Eval2C

Eval2C is a class that allows the compilation of Ruby code to a C extension at
runtime. The compiled C extension will be require'd automatically and the
compiled code will be available as a Proc.
runtime. The compiled C extension will be <code>require</code>d automatically
and the compiled code will be available as a Proc.

It is easy to integrate Eval2C into existing scripts or libraries to improve
performance. It is also pretty simple to provide fallback code for when
Expand Down Expand Up @@ -35,8 +35,8 @@ $some_global_var = proc { puts 'hello' }
$some_global_var.call
PREEND

The proc is compiled to a C extension that C expension is then require'd and
finally the proc is called.
The proc is compiled to a C extension, that C expension is then
<code>require</code>d and finally the proc is called.

The implementation of @toplevel_eval@ is actually pretty simple:

Expand All @@ -61,7 +61,7 @@ SOME_CONST = :toplevel

class A
SOME_CONST = :A
$e2c.compile_to_proc("SOME_CONST") # => :toplevel, not :A!
$e2c.compile_to_proc("SOME_CONST").call # => :toplevel, not :A!
end
PREEND

Expand All @@ -85,7 +85,8 @@ A.new(5).foo(6) # => 11
$e2c.instance_eval("4321", "reverse") # => "1234"
PREEND

There implementation is very similar to that of @toplevel_eval@:
Their implementations also use @compile_to_proc@ and they are very similar to
the implementation of @toplevel_eval@:

PRE
def module_eval(mod, code_str)
Expand All @@ -98,7 +99,7 @@ def instance_eval(object, code_str)
end
PREEND

With @module_eval@/@class_eval@ it is possible selectively compile some
With @module_eval@/@class_eval@ it is possible to selectively compile some
performance critical methods to C and leave the rest in Ruby.

But there is one more thing: @compile_methods@
Expand Down Expand Up @@ -134,13 +135,112 @@ There are some limitations: @compile_methods@ only works with methods defined
using @def@ and the methods must not need a cref (for more informations on
what crefs are please see the respective section in
"limitations":limitations.html). This mainly means that constants must be
prefixed with a double colon: Array needs a cref, ::Array
does not.
prefixed with a double colon: @Array@ needs a cref, while @::Array@ does not.


h2. Options

Eval2C is configured with an option hash, the available options are:

* @:path@: this is the path where the compiled extensions are stored, the
default is the directory @.ruby2cext@ in the current users home dir.
* @:prefix@: this is the prefix for the names of the generated extensions, the
names of the extensions are generated from this prefix and a SHA1 digest of
the code and options. The default is @"eval2c"@ and it is generally not
necessary to change it.
* @:plugins@: this is used to configure the options for the compilation
(compare "rb2cx":rb2cx.html) and it is another option hash. The default is
<code>{:optimizations => :all}</code>, but all of the following keys are
possible:
** @:warnings@: if set to @true@, then warnings about possible problems will
be sent to the logger (see below).
** @:require_include@: can be set to a single search path or an array of
search paths (equivalent to the @-I@ option of @rb2cx@).
** @:optimizations@: yet another option hash to configure the
"optimizations":optimizations.html. The valid keys are @:const_cache@,
@:builtin_methods@, @:inline_methods@ and @:case_optimize@, each with
@true@ or @false@ as value. To just use all optimizations it is also
possible to just use the symbol @:all@ instead of the hash.
* @:logger@: used for log messages, can be either @nil@ or an instance of
@Logger@ (<code>require "logger"</code>). The default is @nil@, which means
that no output is generated.
* @:force_recompile@: if this is set to @true@, then each generated extension
is (re)compiled, even if it is already available from a previous run. The
default is @false@.

Some examples:

PRE
Eval2C.new(:path => ".", :plugins => {})
Eval2C.new(:plugins => {:require_include=>[".", "../lib"], :optimizations=>:all})
Eval2C.new(:plugins => {:warnings=>true, :optimizations=>{:builtin_methods=>true}})
Eval2C.new(:prefix => "my_lib_name", :logger => Logger.new(STDOUT))
PREEND


h2. Implementation Details

The @compile_to_proc@ method works as follows:

# The name of the extension is determined from the given prefix combined with
the SHA1 digest of the Ruby code and some extra data (Ruby version,
Ruby2CExtension version and plugin options). So the code determines the
extension name and if the same code is compiled with the same version and
settings, the name will be the same. This allows very simple and efficient
caching of the compiled extensions.
# From the extension name a global variable name is constructed. The compiled
proc will be stored in that global variable by the generated C extension.
# If the extension with the generated name already exists, then we are
basically done and can skip this step. Otherwise the Ruby proc code is
translated to C and compiled to a C extension in the specified path.
# The generated or already existing C extension is <code>require</code>d.
# The global variable that now contains the compiled proc is read and the
result is returned.

The @compile_methods@ method works similar.

As mentioned above, this scheme allows very efficient caching of the C
extensions. Basically each extension is only compiled once when the
program/library is executed for the first time. In later runs the extension
will already exist and just be <code>require</code>d.

Adding the Ruby version and the Ruby2CExtension version to the digest avoids
problems if multiple versions of Ruby or Ruby2CExtension are installed and
used in parallel and it also guarantees that the extensions are automatically
recompiled if Ruby or Ruby2CExtension are updated.


h2. Using Eval2C Only When It Is Available

Having Ruby2CExtension as a hard dependency just for some speedup might not
be acceptable for many projects, in particular since Ruby2CExtension requires
that a C compiler is available at runtime.

An alternative that avoids the hard dependency is to use Ruby2CExtension only
if it is installed anyway and otherwise just execute the Ruby code as usual.
This works works very well if Eval2C and @compile_methods@ is used, for
example:

PRE
begin
require "ruby2cext/eval2c"
$e2c = Ruby2CExtension::Eval2C.new
rescue LoadError
$e2c = nil
end

class A
def initialize(x)
@x = x
end
def foo(y)
@x + y
end

$e2c && $e2c.compile_methods(self, :initialize, :foo)
end
PREEND

h3. Implementation details
So if Ruby2CExtension is available, then the methods will be compiled and
fast, otherwise the Ruby code will just work as well (but it might be a bit
slower of course).
67 changes: 41 additions & 26 deletions doc/index.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ PREEND
This will produce the files @foo.c@ and @foo.so@ (on Linux). @foo.c@ is the
generated C extension source code and @foo.so@ is the compiled C extension.

If @foo.rb@ is a library, you can just rename, move or delete (only if you
have a backup, of course) @foo.rb@ and your Ruby program will just use
@foo.so@ instead.
If @foo.rb@ is a library, you can just rename, move or delete @foo.rb@ (only
if you have a backup, of course) and your Ruby program will just use @foo.so@
instead.

If @foo.rb@ is a script, then it isn't possible to just run @foo.so@, because
Ruby does not support running C extensions directly, but you can do this:
Expand All @@ -39,28 +39,34 @@ Well, like everybody else I wanted a faster Ruby and I also wanted to learn
about Ruby's internals, so I thought translating Ruby to C might be worth a
try...

The results are not as good as I had hoped, but they aren't bad either: the
generated C extension is practically never slower than the Ruby code and I
found cases where it is more than twice as fast, usually it is somewhere in
between.
The initial results were not as good as I had hoped, but they weren't bad
either: without optimizations the generated C extension is practically never
slower than the Ruby code and I found cases where it is more than twice as
fast, usually it is somewhere in between. But, starting from version 0.2.0,
Ruby2CExtension can use some "optimizations":optimizations.html to
sigmificantly speedup execution in some cases (sometimes more than five times
faster than normal Ruby).

Of course Ruby2CExtension can also be used as an obfuscator for Ruby code,
though this was not my main motivation.


h2. Requirements

Ruby2CExtension is developed for and only tested with Ruby 1.8.4. So you should
really use that version. It might work with other 1.8 versions, it definitely
won't work with Ruby 1.9.
Ruby2CExtension is developed for the Ruby 1.8 versions (only 1.8.4 and above).
It is currently tested with Ruby 1.8.4, 1.8.5 and 1.8.6. Only those versions
should be used. If an untested Ruby version is used, then there will be a
warning. It might work for later 1.8 versions, but it definitely won't work
with Ruby 1.9.

Ruby2CExtension requires RubyNode to access Ruby's node trees (the AST).
RubyNode is available at
"http://rubynode.rubyforge.org/":http://rubynode.rubyforge.org/.

Ruby2CExtension is pure Ruby code, so it should work on all plattforms that
Ruby2CExtension is pure Ruby code, so it should work on all platforms that
Ruby supports, but it is currently only tested on Linux. There might be
problems with the C code to shared object compiling step on some platforms.
problems with the automatic compilation of the generated C code on some
platforms (in particular on Windows).


h2. Download
Expand All @@ -73,13 +79,19 @@ h2. Installation

Just run (as root):

PRE
gem install ruby2cext
PREEND

Or if you do not use the gem:

PRE
ruby setup.rb
PREEND

This will install @rb2cx@ and @ruby2cext.rb@ to the default locations.
Optionally you can supply some options to @setup.rb@ to customize the
installation (see @"ruby setup.rb --help"@).
This will install Ruby2CExtension to the default locations. Optionally you
can supply some options to @setup.rb@ to customize the installation (see
@"ruby setup.rb --help"@).


h2. Features
Expand All @@ -98,7 +110,7 @@ Things that (currently) don't work:

* @break@ with a value from inside a block
* @return@ from inside a block
* @return@, @break@, @next@, @redo@ "through" a @rescue@/@ensure@ clause
* @return@, @break@, @next@, @redo@ inside @ensure@
* @defined?@ is not implemented for all cases
* block pass (passing a proc as block to a method) works, but only through a
hack and it doesn't work (correctly) for things like @instance_eval@
Expand All @@ -116,24 +128,22 @@ Things that don't work as expected and probably never will:
* some more things, please see "limitations":limitations.html

Ruby2CExtension will translate and compile Ruby files using one or more of the
above functionalities without a warning, so if your Ruby code uses such
above functionalities without a warning (for some cases warnings can be
enabled, see "rb2cx":rb2cx.html), so if your Ruby code uses such
functionality, please verify that the compiled C extension works as expected.

For more details please see "limitations":limitations.html.


h2. Usage

As described above just run @rb2cx@ with the file(s) you want to translate and
compile as argument(s).
There are two "interfaces" to use Ruby2CExtension:

@rb2cx@ also accepts some options:
* "rb2cx":rb2cx.html: the command line compiler.
* "Eval2C":eval2c.html: a class that allows dynamic compilation of Ruby code
at runtime.

| @-c@ | @--only-c@ | only translate to C |
| @-v@ | @--verbose@ | print status messages |
| @-h@ | @--help@ | print help |

Have fun!
Please see their respective documentations.


h2. Feedback
Expand All @@ -146,8 +156,13 @@ I am also interested to know if Ruby2CExtension works under Windows (or other
non Linux platforms).


h2. Thanks

TODO


h2. License

Copyright 2006 "Dominik Bathon":mailto:dbatml@remove_nospam.gmx.de.
Copyright 2006-2007 "Dominik Bathon":mailto:dbatml@remove_nospam.gmx.de.

Ruby2CExtension is licensed under the same terms as Ruby.
18 changes: 9 additions & 9 deletions doc/limitations.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ will return @-1@ as @arity@. So if your Ruby code depends on the method
h2. Continuations

Continuations (@callcc@) are possible in compiled Ruby code, but you might see
wrong behaviour with local variables (i.e. they will have an old value),
wrong behavior with local variables (i.e. they will have an old value),
depending on whether these local variables are needed for a closure or not.

In short, you probably should not use continuations in Ruby code that you want
Expand Down Expand Up @@ -126,7 +126,7 @@ visibility newly defined methods get.

Ruby2CExtension can not (easily) access Ruby's internal vmode, instead it
tries to figure out at compile time what visibility a method defined using
@def@ will get. But be careful with @Module#define_method@ and
@def@ will get. But be careful with @Module#define_method@ and
@Module#attr*@: those methods will use Ruby's internal vmode.

So, there are actually two different vmodes at work for compiled Ruby
Expand Down Expand Up @@ -203,10 +203,10 @@ It is a bit more complicated for methods/attributes defined using
Ruby's internal vmode at run time.

As explained above, C extension code does not get its own SCOPE, so it also
doesn't get its own vmode. When require'ing a C extension, Ruby sets the vmode
to public before loading the C extension. All the class/module scopes, that
are executed when require'ing, are executed in the same SCOPE and so also with
the same vmode.
doesn't get its own vmode. When a C extension is <code>require</code>d, Ruby
sets the vmode to public before loading the C extension. All the class/module
scopes, that are executed during the @require@, are executed in the same SCOPE
and so also with the same vmode.

Because all the vmode changing method calls are replaced with @nil@, Ruby's
internal vmode will probably stay public all the time and so all
Expand Down Expand Up @@ -313,8 +313,8 @@ PRE
}
PREEND

The second case fails because the constant lookup for Array needs a cref. If
you really need this to work, then you can use ::Array instead of Array,
The second case fails because the constant lookup for @Array@ needs a cref. If
you really need this to work, then you can use @::Array@ instead of @Array@,
because that won't need a cref.

Again in the usual case everything should be fine and if you really need to
Expand Down Expand Up @@ -501,7 +501,7 @@ variables and @$~@ (and derived). Ruby2CExtension fails at compile time if a
case is not supported.


h3. @super@ with implicit arguments in Ruby 1.8.5
h3. @super@ with implicit arguments in Ruby 1.8.5 and later

For Ruby 1.8.5 @super@ with implicit arguments is only supported in methods (not in blocks or
@rescue@/@ensure@ clauses). For Ruby 1.8.4 @super@ with implicit arguments is
Expand Down
Loading

0 comments on commit 6e8f553

Please sign in to comment.