<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title>Copious Free Time</title>
  <subtitle>Jeremy Hinegardner</subtitle>
  <link href="http://copiousfreetime.org/feed/atom.xml" rel="self" />
  <link href="http://copiousfreetime.org/" />
  <updated>2010-09-20T13:07:43-06:00</updated>
  <author>
    <name>Jeremy Hinegardner</name>
    <email>jeremy@copiousfreetime.org</email>
  </author>
  <id>http://copiousfreetime.org/</id>
  
  <entry>
    <title>Managing a Gem Repository with Stickler</title>
    <link href="http://copiousfreetime.org/articles/2008/10/09/managing-a-gem-repository-with-stickler.html" />
    <id>tag:copiousfreetime.org,2008-10-09:1223612346</id>
    <updated>2008-10-09T22:19:06-06:00</updated>
    <content type="html">&lt;div style=&quot;border:2px solid #ccc;background-color:#e3ffeb;padding:1em;margin-bottom:1em;&quot;&gt;
&lt;h5 style=&quot;float: left;padding-right: 5px;&quot;&gt;2010-09-20:&lt;/h5&gt;
Stickler has been completely rewritten and is now at version 2.0.1.  Please see
the &lt;a href=&quot;/projects/stickler/&quot;&gt;latest documentation&lt;/a&gt;
&lt;/div&gt;




&lt;h3 class=&quot;post-title&quot;&gt;
    &lt;a href=&quot;/articles/2008/10/09/managing-a-gem-repository-with-stickler.html&quot;&gt;Managing a Gem Repository with Stickler&lt;/a&gt;
    &lt;span class=&quot;post-date&quot;&gt;(2008-10-09)&lt;/span&gt;
&lt;/h3&gt;


&lt;p&gt;One of the items Fernand and I mentioned in our Lone Star talk was
&lt;a href=&quot;http://copiousfreetime.rubyforge.org/stickler/&quot;&gt;Stickler&lt;/a&gt;.  This was a project I
had originally started on back in June and it lay dormant for a little while.&lt;/p&gt;

&lt;h5&gt;The first public version (0.1.0) is now released.&lt;/h5&gt;

&lt;h4&gt;Why should I use Stickler?&lt;/h4&gt;

&lt;p&gt;One of the problems that we have had at work is inadvertently upgrading a gem on
a production system.  For example, you are adding a gem to a system that
depends on &lt;code&gt;activerecord,  &amp;gt;= 2.0.2&lt;/code&gt;.  This is great, until &lt;code&gt;active_record 2.1.1&lt;/code&gt;
comes out and on your production system you type &lt;code&gt;gem install somegem&lt;/code&gt; and it
updates your active record installation, as a side effect.  Yes, you can just
quickly uninstall it, but it is annoying.&lt;/p&gt;

&lt;p&gt;Another issue that some installations have, is production boxes are unable to
talk directly to the Internet.  This is a problem when doing a gem installation
using rubygems.  You either have to run your own gem server, or install the gems
locally.&lt;/p&gt;

&lt;h4&gt;Installation and Setup&lt;/h4&gt;

&lt;p&gt;Stickler currently has a basic workflow.  First, install and setup your Stickler
repository.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
jeremy@aramis:~ % sudo gem install stickler
  ============================================================

  Thank you for installing Stickler!

  * Create a new stickler repository:
      stickler setup /path/to/repo

  * Look at the help:
      stickler help

  ============================================================
Successfully installed stickler-0.1.0
1 gem installed
Installing ri documentation for stickler-0.1.0...
Installing RDoc documentation for stickler-0.1.0...

jeremy@aramis:~ % stickler setup /tmp/stickler
created repository root /tmp/stickler
created directory /tmp/stickler/gems
created directory /tmp/stickler/log
created directory /tmp/stickler/specifications
created directory /tmp/stickler/dist
created directory /tmp/stickler/cache
copied in default configuration to /tmp/stickler/stickler.yml
Setting up sources
 * loading http://gems.rubyforge.org/
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;A Stickler repository is a specific directory that holds all the gem files that
are managed by Stickler for your personal distribution.  In this case, Stickler
is now installed as a gem and we have setup a repository in &lt;code&gt;/tmp/stickler&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;Populating the Repository&lt;/h4&gt;

&lt;p&gt;A repository is great, and completely useless unless it is populated with gems
to distribute.  So that is what we will do.  The best way to operate on a
Stickler repository is to be in it.  You can also use the &lt;code&gt;--directory&lt;/code&gt;
commandline option on every command, but that can get old.  Therefore, we'll
operate from the root of the repository.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
cd /tmp/stickler
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;First lets look at the state of the repository using the &lt;code&gt;info&lt;/code&gt; command.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
jeremy@aramis:/tmp/stickler % stickler info
Setting up sources
 * loading http://gems.rubyforge.org/

Upstream Sources
----------------

  http://gems.rubyforge.org/ : 16651 gems available
                             : 0 gems existing

Configured gems (in stickler.yml)
---------------------------------


Existing gems
-------------
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Yes, that definitely is empty.  We do a fair number of merb apps, so lets add
merb to our repository.  It is a 2 step process to add a gem to the repository
via the commandline.  We first pick the requirement operator, and then the
version.  In our case, we want to stick with a specific version of merb so we'll
add &lt;code&gt;merb, = 0.9.8&lt;/code&gt; to our repository&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
jeremy@aramis:/tmp/stickler % stickler add gem merb
Setting up sources
 * loading http://gems.rubyforge.org/

You need to pick the merb Requirement to configure Stickler.
This involves picking one of the following Requirement operators
See http://docs.rubygems.org/read/chapter/16#page74 for operator info.

You need to (1) pick an operator and (2) pick a requirement.
The most common operators are &amp;gt;=, &amp;gt; and ~&amp;gt;
1. =  Equals version
2. != Not equal to version
3. &amp;gt;  Greater than version
4. &amp;lt;  Less than version
5. &amp;gt;= Greater than or equal to
6. &amp;lt;= Less than or equal to
7. ~&amp;gt; Approximately greater than
(1) Pick an operator ? 1

Now to pick a requirement.  Based upon your chosen operator '=',
These are the available version of the merb gem.
1. = 0.9.8   7. = 0.9.2   13. = 0.4.1  19. = 0.3.0  25. = 0.0.6
2. = 0.9.7   8. = 0.5.3   14. = 0.4.0  20. = 0.2.0  26. = 0.0.5
3. = 0.9.6   9. = 0.5.2   15. = 0.3.7  21. = 0.1.0  27. = 0.0.4
4. = 0.9.5   10. = 0.5.1  16. = 0.3.4  22. = 0.0.9  28. = 0.0.3
5. = 0.9.4   11. = 0.5.0  17. = 0.3.3  23. = 0.0.8  29. = 0.0.2
6. = 0.9.3   12. = 0.4.2  18. = 0.3.1  24. = 0.0.7  30. = 0.0.1
(2) Pick a requirement ? 1

Resolving gem dependencies for merb (= 0.9.8, runtime) ...
Adding ParseTree-2.1.1-x86-mswin32
Adding ruby2ruby-1.1.9
Adding RubyInline-3.7.0
Adding ParseTree-2.2.0
Adding merb-action-args-0.9.8
Adding merb-assets-0.9.8
Adding highline-1.4.0
Adding diff-lcs-1.1.2
Adding templater-0.3.2
Adding merb-gen-0.9.8
Adding haml-2.0.3
Adding merb-haml-0.9.8
Adding builder-2.1.2
Adding merb-builder-0.9.8
Adding mailfactory-1.4.0
Adding merb-mailer-0.9.8
Adding merb-parts-0.9.8
Adding merb-cache-0.9.8
Adding merb-slices-0.9.8
Adding merb-jquery-0.9.8
Adding extlib-0.9.7
Adding abstract-1.0.0
Adding erubis-2.6.2
Adding json_pure-1.1.3
Adding rubyforge-1.0.0
Adding rake-0.8.3
Adding hoe-1.8.0
Adding rspec-1.1.8
Adding rack-0.4.0
Adding mime-types-1.15
Adding hpricot-0.6.161-java
Adding hpricot-0.6.161
Adding hpricot-0.6-x86-mswin32
Adding thor-0.9.6
Adding merb-core-0.9.8
Adding merb-helpers-0.9.8
Adding merb-more-0.9.8
Adding mongrel-1.1.5-java
Adding mongrel-1.1.1-java
Adding daemons-1.0.10
Adding fastthread-1.0.1
Adding fastthread-1.0.1-x86-mswin32
Adding mongrel-1.1.5
Adding mongrel-1.1.3-x86-mswin32
Adding mongrel-1.1.5-x86-mswin32-60
Adding mongrel-1.1.2-x86-mswin32
Adding gem_plugin-0.2.3
Adding cgi_multipart_eof_fix-2.5.0
Adding mongrel-1.1.5-x86-mingw32
Adding merb-0.9.8
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Wow, that's a lot of gems added with for merb.  And this is more than would be
normally installed if you did a &lt;code&gt;gem install merb&lt;/code&gt;.  Stickler assumes you are
redistributing gems, and as such gets every available platform for a gem when
you add it to the repository.  And then it recurses through all runtime and
development dependencies.  And now when we look at the repository state we see:&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
Setting up sources
 * loading http://gems.rubyforge.org/

Upstream Sources
----------------

  http://gems.rubyforge.org/ : 16652 gems available
                             : 50 gems existing

Configured gems (in stickler.yml)
---------------------------------

merb : = 0.9.8

Existing gems
-------------

ParseTree-2.1.1-x86-mswin32
ParseTree-2.2.0
RubyInline-3.7.0
abstract-1.0.0
builder-2.1.2
cgi_multipart_eof_fix-2.5.0
daemons-1.0.10
diff-lcs-1.1.2
erubis-2.6.2
extlib-0.9.7
fastthread-1.0.1
fastthread-1.0.1-x86-mswin32
gem_plugin-0.2.3
haml-2.0.3
highline-1.4.0
hoe-1.8.0
hpricot-0.6-x86-mswin32
hpricot-0.6.161
hpricot-0.6.161-java
json_pure-1.1.3
mailfactory-1.4.0
merb-0.9.8
merb-action-args-0.9.8
merb-assets-0.9.8
merb-builder-0.9.8
merb-cache-0.9.8
merb-core-0.9.8
merb-gen-0.9.8
merb-haml-0.9.8
merb-helpers-0.9.8
merb-jquery-0.9.8
merb-mailer-0.9.8
merb-more-0.9.8
merb-parts-0.9.8
merb-slices-0.9.8
mime-types-1.15
mongrel-1.1.1-java
mongrel-1.1.2-x86-mswin32
mongrel-1.1.3-x86-mswin32
mongrel-1.1.5
mongrel-1.1.5-java
mongrel-1.1.5-x86-mingw32
mongrel-1.1.5-x86-mswin32-60
rack-0.4.0
rake-0.8.3
rspec-1.1.8
ruby2ruby-1.1.9
rubyforge-1.0.0
templater-0.3.2
thor-0.9.6
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;There is a difference between &lt;em&gt;configured&lt;/em&gt; gems and &lt;em&gt;existing&lt;/em&gt; gems.  Configured
gems are those you have specifically requested to be in the repository.
Existing gems are those that are added to support the configured gems and the
configured gems themselves.&lt;/p&gt;

&lt;h4&gt;Adding Additional Sources&lt;/h4&gt;

&lt;p&gt;Part of the reason for Stickler is to merge upstream gem repositories into your
own internal repository.  Say you use the github repository and want to add a
gem or two from it to your internal system.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
jeremy@aramis:/tmp/stickler % stickler add source http://gems.github.com
Setting up sources
 * loading http://gems.rubyforge.org/
 * loading http://gems.github.com/
http://gems.github.com added to sources
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;That was easy enough.  Now lets add a gem from github and watch the dependencies
roll in.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
jeremy@aramis:/tmp/stickler % stickler add gem aniero-tire_swing
Setting up sources
 * loading http://gems.rubyforge.org/
 * loading http://gems.github.com/

You need to pick the aniero-tire_swing Requirement to configure Stickler.
This involves picking one of the following Requirement operators
See http://docs.rubygems.org/read/chapter/16#page74 for operator info.

You need to (1) pick an operator and (2) pick a requirement.
The most common operators are &amp;gt;=, &amp;gt; and ~&amp;gt;
1. =  Equals version
2. != Not equal to version
3. &amp;gt;  Greater than version
4. &amp;lt;  Less than version
5. &amp;gt;= Greater than or equal to
6. &amp;lt;= Less than or equal to
7. ~&amp;gt; Approximately greater than
(1) Pick an operator ? =

Now to pick a requirement.  Based upon your chosen operator '=',
These are the available version of the aniero-tire_swing gem.
1. = 0.0.3  2. = 0.0.2
(2) Pick a requirement ? 1

Resolving gem dependencies for aniero-tire_swing (= 0.0.3, runtime) ...
Adding polyglot-0.2.3
Adding treetop-1.2.4
Adding attributes-5.0.1
Adding activesupport-2.1.1
Adding aniero-tire_swing-0.0.3
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You can see that &lt;code&gt;aneiro-tire_swing&lt;/code&gt; was added from github, and it also
resolved the dependencies to gems that reside on rubyforge.  Looking at &lt;code&gt;info&lt;/code&gt;
shows us:&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
jeremy@aramis:/tmp/stickler % stickler info
Setting up sources
 * loading http://gems.rubyforge.org/
 * loading http://gems.github.com/

Upstream Sources
----------------

  http://gems.rubyforge.org/ : 16652 gems available
                             : 54 gems existing
     http://gems.github.com/ : 2463 gems available
                             : 1 gems existing

Configured gems (in stickler.yml)
---------------------------------

aniero-tire_swing : = 0.0.3
merb : = 0.9.8
...
&lt;/pre&gt;
&lt;/div&gt;


&lt;h4&gt;Batch Addition&lt;/h4&gt;

&lt;p&gt;It can get repetitive to manually add gem after gem from the commandline.  When
you know exactly what you need, crack open the &lt;code&gt;stickler.yml&lt;/code&gt; file and add a few
gems.  For instance, lets say that we are in the process of updating all our
rails apps to 2.1.  In the meantime we want to make sure we do not inadvertently
update our production systems to 2.1.  They are still at 2.0.2.  So we add all
the rails gems at the 2.0.2 level to the &lt;code&gt;stickler.yml&lt;/code&gt; file in the repository.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
&lt;span class=&quot;head&quot;&gt;&lt;span class=&quot;head&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;ke&quot;&gt;downstream_source&lt;/span&gt;: &lt;span class=&quot;s&quot;&gt;http://gems.example.com/&lt;/span&gt;
&lt;span class=&quot;ke&quot;&gt;sources&lt;/span&gt;:
- &lt;span class=&quot;s&quot;&gt;http://gems.rubyforge.org/&lt;/span&gt;
- &lt;span class=&quot;s&quot;&gt;http://gems.github.com/&lt;/span&gt;
&lt;span class=&quot;ke&quot;&gt;gems&lt;/span&gt;:
  &lt;span class=&quot;er&quot;&gt;aniero-tire_swing&lt;/span&gt;:
  - &lt;span class=&quot;s&quot;&gt;= 0.0.3&lt;/span&gt;
  &lt;span class=&quot;ke&quot;&gt;merb&lt;/span&gt;:
  - &lt;span class=&quot;s&quot;&gt;= 0.9.8&lt;/span&gt;
  &lt;span class=&quot;ke&quot;&gt;activerecord&lt;/span&gt;: &lt;span class=&quot;s&quot;&gt;= 2.0.2&lt;/span&gt;
  &lt;span class=&quot;ke&quot;&gt;activesupport&lt;/span&gt;: &lt;span class=&quot;s&quot;&gt;= 2.0.2&lt;/span&gt;
  &lt;span class=&quot;ke&quot;&gt;actionmailer&lt;/span&gt;: &lt;span class=&quot;s&quot;&gt;= 2.0.2&lt;/span&gt;
  &lt;span class=&quot;ke&quot;&gt;actionpack&lt;/span&gt;: &lt;span class=&quot;s&quot;&gt;= 2.0.2&lt;/span&gt;
  &lt;span class=&quot;ke&quot;&gt;activeresource&lt;/span&gt;: &lt;span class=&quot;s&quot;&gt;= 2.0.2&lt;/span&gt;
  &lt;span class=&quot;ke&quot;&gt;rails&lt;/span&gt;: &lt;span class=&quot;s&quot;&gt;= 2.0.2&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;We can now use the &lt;code&gt;sync&lt;/code&gt; command to add all of them in at once.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
jeremy@aramis:/tmp/stickler % stickler sync
Setting up sources
 * loading http://gems.rubyforge.org/
 * loading http://gems.github.com/

Making sure that all gems listed in configuration are available

Resolving gem dependencies for rails (= 2.0.2, runtime) ...
Adding activerecord-2.0.2
Adding actionpack-2.0.2
Adding actionmailer-2.0.2
Adding activesupport-2.0.2
Adding activeresource-2.0.2
Adding rails-2.0.2
Resolving gem dependencies for activerecord (= 2.0.2, runtime) ...
Resolving gem dependencies for activeresource (= 2.0.2, runtime) ...
Resolving gem dependencies for aniero-tire_swing (= 0.0.3, runtime) ...
Resolving gem dependencies for actionpack (= 2.0.2, runtime) ...
Resolving gem dependencies for actionmailer (= 2.0.2, runtime) ...
Resolving gem dependencies for merb (= 0.9.8, runtime) ...
Resolving gem dependencies for activesupport (= 2.0.2, runtime) ...
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You can see that it added in all the gems in and then it also made sure that
&lt;code&gt;aneiro-tire_swing&lt;/code&gt; and &lt;code&gt;merb&lt;/code&gt; were also synced up.  If you need to rebuild the
entire repository from scratch, use &lt;code&gt;stickler sync --rebuild&lt;/code&gt; and it will wipe
out the current gems and specifications in the repo and download them again.&lt;/p&gt;

&lt;h4&gt;Distribution of Gems&lt;/h4&gt;

&lt;p&gt;Populating the repository is only good if you can get your internal systems to
utilize the repo.  This is where the &lt;code&gt;generate&lt;/code&gt; commands come into play.  The
&lt;code&gt;generate index&lt;/code&gt; command does exactly what a &lt;code&gt;gem generate_index&lt;/code&gt; does, but it
uses your repository as the base.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
Setting up sources
 * loading http://gems.rubyforge.org/
 * loading http://gems.github.com/
Generating rubygems index in /private/tmp/stickler/dist
Loading 61 gems from /private/tmp/stickler/dist
...............WARNING:  Skipping misnamed gem: /private/tmp/stickler/dist/gems/fastthread-1.0.1-x86-mswin32.gem =&amp;gt; fastthread-1.0.1-x86-mswin32 (fastthread-1.0.1-mswin32)
.....WARNING:  Skipping misnamed gem: /private/tmp/stickler/dist/gems/hpricot-0.6-x86-mswin32.gem =&amp;gt; hpricot-0.6-x86-mswin32 (hpricot-0.6-mswin32)
WARNING:  Skipping misnamed gem: /private/tmp/stickler/dist/gems/hpricot-0.6.161-java.gem =&amp;gt; hpricot-0.6.161-java (hpricot-0.6.161-jruby)
..................WARNING:  Skipping misnamed gem: /private/tmp/stickler/dist/gems/mongrel-1.1.1-java.gem =&amp;gt; mongrel-1.1.1-java (mongrel-1.1.1-jruby)
WARNING:  Skipping misnamed gem: /private/tmp/stickler/dist/gems/mongrel-1.1.2-x86-mswin32.gem =&amp;gt; mongrel-1.1.2-x86-mswin32 (mongrel-1.1.2-mswin32)
WARNING:  Skipping misnamed gem: /private/tmp/stickler/dist/gems/mongrel-1.1.3-x86-mswin32.gem =&amp;gt; mongrel-1.1.3-x86-mswin32 (mongrel-1.1.3-i386-mswin32)
....WARNING:  Skipping misnamed gem: /private/tmp/stickler/dist/gems/ParseTree-2.1.1-x86-mswin32.gem =&amp;gt; ParseTree-2.1.1-x86-mswin32 (ParseTree-2.1.1-i386-mswin32)
............
Loaded all gems
Generating quick index gemspecs for 54 gems
......................................................
Complete
Generating specs index
Generating latest specs index
Generating quick index
Generating latest index
Generating Marshal master index
Generating YAML master index for 54 gems (this may take a while)
......................................................
Complete
Compressing indicies
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The generated, distributable gem repository based upon your stickler repository
is generated in the &lt;code&gt;dist&lt;/code&gt; sub directory in your repository.  This directory can
be rsynced to a web server in your infrastructure, or run a web server on this
machine and point its document root, or a directory alias to the &lt;code&gt;dist&lt;/code&gt;
directory.&lt;/p&gt;

&lt;p&gt;An extra item you may do is globally configure your rubygems installations to
automatically use your internal gem server as the canonical source instead of
&lt;a href=&quot;http://gems.rubyforge.org/&quot;&gt;http://gems.rubyforge.org/&lt;/a&gt;.  Stickler provides a quick command to generate
this top level configuration, and the file contains the information on where to
put it.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
jeremy@aramis:/tmp/stickler % stickler generate sysconfig &amp;gt; gemrc
Setting up sources
 * loading http://gems.rubyforge.org/
 * loading http://gems.github.com/
Generating configuration to stdout

jeremy@aramis:/tmp/stickler % cat gemrc
#
# This is the system wide configuration to be used by
# rubygem clients that install gems from the repository
# located at :
#
#   http://gems.example.com/
#
# On Unix like machines install in
#
#   /etc/gemrc
#
# On Windows machines install in
#
#   C:\Documents and Settings\All Users\Application Data\gemrc
#
---
:sources:
- http://gems.example.com/
&lt;/pre&gt;
&lt;/div&gt;


&lt;h4&gt;Conclusions&lt;/h4&gt;

&lt;p&gt;Hopefully you can find Stickler useful in your infrastructure.  Please let me
know about &lt;a href=&quot;http://rubyforge.org/tracker/?group_id=3707&quot;&gt;features and bugs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/articles/2008/10/09/managing-a-gem-repository-with-stickler.html#disqus_thread&quot;&gt;Comments (View)&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Packaging an Application With Crate</title>
    <link href="http://copiousfreetime.org/articles/2008/11/30/package-an-application-with-crate.html" />
    <id>tag:copiousfreetime.org,2008-11-30:1228095874</id>
    <updated>2008-11-30T18:44:34-07:00</updated>
    <content type="html">

&lt;div style=&quot;border:2px solid #ccc;background-color:#e3ffeb;padding:1em;margin-bottom:1em;&quot;&gt;
&lt;h5 style=&quot;float: left;padding-right: 5px;&quot;&gt;2009-01-18:&lt;/h5&gt;
Updated tutorial with new versions of crate (0.2.1) and amalgalite (0.7.1)
&lt;/div&gt;




&lt;h3 class=&quot;post-title&quot;&gt;&lt;a href=&quot;/articles/2008/11/30/package-an-application-with-crate.html&quot;&gt;Packaging an Application With Crate&lt;/a&gt;
&lt;span class=&quot;post-date&quot;&gt;(2008-11-30)&lt;/span&gt;
&lt;/h3&gt;


&lt;p&gt;Crate is way to package up your ruby applications as statically compiled
binaries.  I was lucky enough to &lt;a href=&quot;http://rubyconf2008.confreaks.com/crate-packaging-your-ruby-application.html&quot;&gt;talk about Crate at RubyConf
'08&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is a small tutorial that expands upon my RubyConf talk and demonstrates how
to package gem application as a standalone statically compiled executable.&lt;/p&gt;

&lt;h4&gt;Step 1 &amp;mdash; Install Crate&lt;/h4&gt;

&lt;p&gt;To get started, you'll need to install crate.  It is distributed mainly as a gem
from rubyforge and installs in the standard way.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
gem install crate
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Crate is part of my &lt;a href=&quot;http://copiousfreetime.rubyforge.org/crate&quot;&gt;copiousfreetime rubyforge
project&lt;/a&gt; and its git repository is
available on github.  Patches are always welcome.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/copiousfreetime/crate/tree/master&quot;&gt;crate on github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;public clone url - &amp;lt;git://github.com/copiousfreetime/crate.git&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;Step 2 &amp;mdash; Create a new Crate Application&lt;/h4&gt;

&lt;p&gt;In this tutorial we are going to package up the htpassword-ruby commandline
application in my &lt;a href=&quot;http://copiousfreetime.rubyforge.org/htauth/&quot;&gt;htauth&lt;/a&gt; gem as a
standalone executable.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
% crate -v
Crate 0.2.1

% crate htpassword-ruby
[16:39:00]  INFO: creating htpasswd-ruby
[16:39:00]  INFO: creating htpasswd-ruby/Rakefile
[16:39:00]  INFO: creating htpasswd-ruby/crate_boot.c
[16:39:00]  INFO: creating htpasswd-ruby/recipes/amalgalite
[16:39:00]  INFO: creating htpasswd-ruby/recipes/amalgalite/amalgalite.rake
[16:39:00]  INFO: creating htpasswd-ruby/recipes/arrayfields
[16:39:00]  INFO: creating htpasswd-ruby/recipes/arrayfields/arrayfields.rake
[16:39:00]  INFO: creating htpasswd-ruby/recipes/configuration
[16:39:00]  INFO: creating htpasswd-ruby/recipes/configuration/configuration.rake
[16:39:00]  INFO: creating htpasswd-ruby/recipes/openssl
[16:39:00]  INFO: creating htpasswd-ruby/recipes/openssl/openssl.rake
[16:39:00]  INFO: creating htpasswd-ruby/recipes/ruby
[16:39:00]  INFO: creating htpasswd-ruby/recipes/ruby/ext-extmk.rb.patch
[16:39:00]  INFO: creating htpasswd-ruby/recipes/ruby/ruby.rake
[16:39:00]  INFO: creating htpasswd-ruby/recipes/rubygems
[16:39:00]  INFO: creating htpasswd-ruby/recipes/rubygems/rubygems.rake
[16:39:00]  INFO: creating htpasswd-ruby/recipes/zlib
[16:39:00]  INFO: creating htpasswd-ruby/recipes/zlib/zlib.rake

% cd htpassword-ruby
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This created a new directory structure to do the building of our standalone
htpassword-ruby application.  Change into the new &lt;code&gt;htpassword-ruby&lt;/code&gt; directory
now and run &lt;code&gt;rake -T&lt;/code&gt; to see the full set of tasks that are available.  Most of
them you will not use.  The two you want to pay attention to are &lt;code&gt;default&lt;/code&gt; and
&lt;code&gt;ruby&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;Step 3 &amp;mdash; Integrate HTAuth Dependency Targets&lt;/h4&gt;

&lt;p&gt;The way all of this is integrated together is a final single binary with the
name &lt;code&gt;htpassword-ruby&lt;/code&gt; which is an embedded ruby interpreter wrapped up in a
thin C application.  The C application is in the &lt;code&gt;crate_boot.c&lt;/code&gt; file you'll see
in the top level of the project directory.&lt;/p&gt;

&lt;p&gt;The pure ruby code involved in the whole system is stored in SQLite databases.
This will included the ruby standard library and your application code.  As part
of a Crate application, the &lt;code&gt;require&lt;/code&gt; statement is overwritten to load from rows
in an SQLite database instead of the file system.  This feature is all from the
amalgalite gem and anyone case use it for other projects if they so choose.&lt;/p&gt;

&lt;p&gt;In the mean time, we now have a build system setup to build ruby, but not our
application.  There is no facility as of yet in Crate to automatically add build
targets for a gem, but they are in the works for a later version.  In the mean
time we'll need to roll our own, its not that hard.   Currently I'm not
completely satisfied with the way this integrates and will most likely change it
in a future release.&lt;/p&gt;

&lt;p&gt;The HTAuth gem is pretty self contained, it only has one dependency,
&lt;a href=&quot;http://highline.rubyforge.org/&quot;&gt;highline&lt;/a&gt;.  We're going to add two new recipes,
one for highline and one for htauth.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
% mkdir recipes/highline
% vi recipes/highline/highline.rake
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;We edit it to be the following:&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# The recipe for integrating highline into the ruby build&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;co&quot;&gt;Crate&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;GemIntegration&lt;/span&gt;.new(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;highline&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;1.5.0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |t|
  t.upstream_source = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;http://rubyforge.org/frs/download.php/46328/highline-1.5.0.gem&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;And we do the same for htauth:&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
% mkdir recipes/htauth
% vi recipes/htauth/htauth.rake
&lt;/pre&gt;
&lt;/div&gt;




&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# The recipe for integrating htauth into the ruby build&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;co&quot;&gt;Crate&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;GemIntegration&lt;/span&gt;.new(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;htauth&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;1.0.2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |t|
  t.upstream_source = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;http://rubyforge.org/frs/download.php/47663/htauth-1.0.2.gem&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;And finally we we integrate these two new build targets into the final ruby
build.  Edit the &lt;code&gt;recipes/ruby/ruby.rake&lt;/code&gt; file and add the two noted lines.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
&lt;span class=&quot;co&quot;&gt;Crate&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Ruby&lt;/span&gt;.new( &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;ruby&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;1.8.6-p287&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |t| 
  t.depends_on( &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;openssl&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; )
  t.depends_on( &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;zlib&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; )

  t.integrates( &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;amalgalite&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; )
  t.integrates( &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;arrayfields&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; )
  t.integrates( &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; )

  t.integrates( &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;highline&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; )    &lt;span class=&quot;c&quot;&gt;# Add this line&lt;/span&gt;
  t.integrates( &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;htauth&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; )      &lt;span class=&quot;c&quot;&gt;# and this line&lt;/span&gt;

  t.upstream_source  = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p287.tar.gz&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  t.upstream_md5     = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;f6cd51001534ced5375339707a757556&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;

  &lt;span class=&quot;co&quot;&gt;ENV&lt;/span&gt;[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CPPFLAGS&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]= &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;-I&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;idl&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;co&quot;&gt;File&lt;/span&gt;.join( t.install_dir, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;usr&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;span class=&quot;idl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;co&quot;&gt;ENV&lt;/span&gt;[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;LDFLAGS&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;] = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;-L&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;idl&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;co&quot;&gt;File&lt;/span&gt;.join( t.install_dir, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;usr&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; )&lt;span class=&quot;idl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; 

  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; t.build
    &lt;span class=&quot;c&quot;&gt;# put the .a files from the fakeroot/usr/lib directory into the package&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# directory so the compilation can use them&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%w[&lt;/span&gt;&lt;span class=&quot;k&quot;&gt; libz.a libcrypto.a libssl.a &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;]&lt;/span&gt;&lt;/span&gt;.each &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |f| 
      &lt;span class=&quot;co&quot;&gt;FileUtils&lt;/span&gt;.cp &lt;span class=&quot;co&quot;&gt;File&lt;/span&gt;.join( install_dir, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;usr&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, f ), pkg_dir
    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt; 
    sh &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;./configure --disable-shared --prefix=&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;idl&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;co&quot;&gt;File&lt;/span&gt;.join( &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;usr&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; )&lt;span class=&quot;idl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; 
    sh &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;

  t.install_commands &amp;lt;&amp;lt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;make install DESTDIR=&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;idl&quot;&gt;#{&lt;/span&gt;t.install_dir&lt;span class=&quot;idl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now we are setup to do the two big build steps.&lt;/p&gt;

&lt;h4&gt;Step 4 &amp;mdash; Building Ruby as a Static Library&lt;/h4&gt;

&lt;p&gt;In order to build a static ruby based application we first need to build ruby
itself as a static library.  In doing so we also need to build all the binary
dependencies of ruby statically.  In this case, that includes zlib, openssl and
amalgalite.&lt;/p&gt;

&lt;p&gt;Fortunately, all that is taken care of for you in the rake tasks.  All you need
to do at this point is run the &lt;code&gt;ruby&lt;/code&gt; rake task.  It will download, unpack and build
all the various components. This may take a while, so take a break and get
something to drink.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
% rake ruby
# snip lots of output, look in project.log for the full output.  
....
23:54:58  INFO: Bulding zlib 1.2.3
....
23:55:30  INFO: Bulding openssl 0.9.8i
...
00:01:22  INFO: Integrating highline into ruby's tree
...
00:01:24  INFO: Integrating htauth into ruby's tree
...
00:01:24  INFO: Bulding ruby 1.8.6-p287
...
00:02:59  INFO: ruby 1.8.6-p287 is installed
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You should now have a ruby executable in &lt;code&gt;fakeroot/usr/bin/ruby&lt;/code&gt;.  You can run
this script to prove that it is statically compiled.  Notice that there are no
&lt;code&gt;require&lt;/code&gt; statements.  This script will not run on a normal ruby, it will only
work with one that is statically compiled.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
% cat versions.rb
puts &amp;quot;zlib    : #{Zlib::zlib_version}&amp;quot;
puts &amp;quot;OpenSSL : #{OpenSSL::OPENSSL_VERSION}&amp;quot;
puts &amp;quot;SQLite  : #{Amalgalite::SQLite3::Version}&amp;quot;

% /opt/local/bin/ruby versions.rb
ruby versions.rb
versions.rb:1: uninitialized constant Zlib (NameError)

% fakeroot/usr/bin/ruby versions.rb
zlib    : 1.2.3
OpenSSL : OpenSSL 0.9.8j 07 Jan 2009
SQLite  : 3.6.10
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The really important products of this build process are all the &lt;code&gt;.a&lt;/code&gt; files in the
ruby build directory that will be used to build the final &lt;code&gt;httpassword-ruby&lt;/code&gt;
executable.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
% ls -1 build/ruby/ruby-1.8.6-p287/*.a
build/ruby/ruby-1.8.6-p287/libcrypto.a
build/ruby/ruby-1.8.6-p287/libruby-static.a
build/ruby/ruby-1.8.6-p287/libssl.a
build/ruby/ruby-1.8.6-p287/libz.a
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Additionally the &lt;code&gt;highline&lt;/code&gt; and &lt;code&gt;htauth&lt;/code&gt; ruby code was integrated into the ruby
stdlib directory structure.&lt;/p&gt;

&lt;h4&gt;Step 5 &amp;mdash; Building the final executable&lt;/h4&gt;

&lt;p&gt;The final step is to create out final &lt;code&gt;htpasswd-ruby&lt;/code&gt; executable.  The output of
this step is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a single executable&lt;/li&gt;
&lt;li&gt;multiple SQLite databases holding all the ruby source code&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;At this point we need to update the top level &lt;code&gt;Rakefile&lt;/code&gt; in your build system.
We need to set the executable name and tell the crate build system how to launch
the application.&lt;/p&gt;

&lt;p&gt;In our case, we are going to wrap only the &lt;code&gt;htpasswd-ruby&lt;/code&gt; application that is
part of &lt;code&gt;htauth&lt;/code&gt;.  For this we look at that script which comes with the htauth
gem.  This script boils down to the single line:&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
&lt;span class=&quot;co&quot;&gt;HTAuth&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Passwd&lt;/span&gt;.new.run(&lt;span class=&quot;pc&quot;&gt;ARGV&lt;/span&gt;, &lt;span class=&quot;co&quot;&gt;ENV&lt;/span&gt;)
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Which, it turns out, is exactly the way that crate likes to have applications
launched.  At this point I should sidestep and say how a crate based application
is launched.&lt;/p&gt;

&lt;div style=&quot;border:2px solid #ccc;background-color:#e3e6eb;padding:1em;margin-bottom:1em;&quot;&gt;

&lt;h5&gt;Crate Bootstrap Process&lt;/h5&gt;

&lt;p&gt;
A Crate built application is fundamentally an embedded ruby interpreter that
runs a single script.  The file &lt;code&gt;crate_boot.c&lt;/code&gt; at the top of your build system
&lt;strong&gt;is&lt;/strong your application.  The process is generically:
&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;initialize the ruby interpreter&lt;/li&gt;
  &lt;li&gt;set ARGV for ruby&lt;/li&gt;
  &lt;li&gt;initialize all statically compiled extensions&lt;/li&gt;
  &lt;li&gt;bootstrap the Amalgalite driver&lt;/li&gt;
  &lt;li&gt;remove all filesystem directories from the &lt;code&gt;$LOAD_PATH&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;switch to using Amalgalite backed &lt;code&gt;require&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;require&lt;/code&gt; the file in the C constant &lt;code&gt;CRATE_MAIN_FILE&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;instantiate a single instance of the class named in the C constant &lt;code&gt;CRATE_MAIN_CLASS&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;invoke &lt;code&gt;run( ARGV, ENV)&lt;/code&gt; on the newly instantiated class&lt;/li&gt;
  &lt;li&gt;exit&lt;/li&gt;
&lt;/ol&gt;

&lt;/div&gt;


&lt;p&gt;Now we dive into the &lt;code&gt;Rakefile&lt;/code&gt; and put the final touches on our build to make
everything come out the way we want.  Currently crate only supports launching an
application from a top level class.  That means no &lt;code&gt;Module::Class&lt;/code&gt; to use for
the main class.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;crate&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;co&quot;&gt;PROJ_NAME&lt;/span&gt; = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;htpasswd-ruby&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;co&quot;&gt;Crate&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Project&lt;/span&gt;.new( &lt;span class=&quot;co&quot;&gt;PROJ_NAME&lt;/span&gt; ) &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |crate|

  &lt;span class=&quot;c&quot;&gt;# setting these will set the appropriate C constants&lt;/span&gt;
  crate.main_file  = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  crate.main_class = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  crate.run_method = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# make sure 'application.rb' is packed into the databases&lt;/span&gt;
  crate.packing_lists &amp;lt;&amp;lt; &lt;span class=&quot;co&quot;&gt;Crate&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;PackingList&lt;/span&gt;.new( &lt;span class=&quot;co&quot;&gt;Dir&lt;/span&gt;.glob(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;*.rb&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) )

&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;We then have the &lt;code&gt;application.rb&lt;/code&gt; file at the top of our build system directory.
It is very simple and gives you an idea of how to put a thin ruby wrapper around
any existing ruby application.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;App&lt;/span&gt;
  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;run&lt;/span&gt;( argv, env )
    require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;htauth&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;co&quot;&gt;HTAuth&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Passwd&lt;/span&gt;.new.run( argv, env )
  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Run the &lt;code&gt;default&lt;/code&gt; rake task and take a look at the output.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
% rake default
(in /Users/jeremy/tmp/htpasswd-ruby)
mkdir -p /Users/jeremy/tmp/htpasswd-ruby/dist
16:59:27  INFO: Packing amalgalite into /Users/jeremy/tmp/htpasswd-ruby/dist/lib.db
16:59:28  INFO: Packing ruby standard lib into /Users/jeremy/tmp/htpasswd-ruby/dist/lib.db
16:59:29  INFO: Packing ruby extension libs into /Users/jeremy/tmp/htpasswd-ruby/dist/lib.db
16:59:31  INFO: Packing project packing lists lists into /Users/jeremy/tmp/htpasswd-ruby/dist/app.db
16:59:32  INFO: Build htpasswd-ruby

% file dist/*
dist/app.db:        SQLite database (Version 3)
dist/htpasswd-ruby: Mach-O executable i386
dist/lib.db:        SQLite database (Version 3)
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Our final result, a self-contained set of 3 files containing a statically
compiled ruby interpreter and and app to run in it.  In this case, we can
deploy these 3 files to any i386 Mac OS X machine and run it, it will not use
the system ruby.  All the ruby libs are in the SQLite3 databases.  And just to
show that it works.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
% cd dist/
% ./htpasswd-ruby -c test.db jjh
Adding password for jjh.
        New password: *****************
Re-type new password: *****************
% cat test.db 
jjh:GtPOQTplES6BE
&lt;/pre&gt;
&lt;/div&gt;


&lt;h4&gt;Closing Thoughts&lt;/h4&gt;

&lt;p&gt;Well, there you have it; self-contained, statically-built, shippable ruby
applications.  There are definite improvements that can be made, and I would
love to hear what people would like to do with Crate.&lt;/p&gt;

&lt;p&gt;Some specific features that I will be adding in no particular order and as my
copious free time allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;cratify&lt;/em&gt; an existing gem for one-stop packaging&lt;/li&gt;
&lt;li&gt;cross compilation targets so you can build, from one library, any executable for any target you have a cross compiler&lt;/li&gt;
&lt;li&gt;installer wrappers, so you can ship

&lt;ul&gt;
&lt;li&gt;.dmg for Mac OS X&lt;/li&gt;
&lt;li&gt;setup.exe for Windows&lt;/li&gt;
&lt;li&gt;rpm for CentOS/RHEL/Fedora/etc&lt;/li&gt;
&lt;li&gt;shar for general UNIX&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;smart dependency tracking so only those portions of the ruby stdlib that your application needs is packaged&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;a href=&quot;/articles/2008/11/30/package-an-application-with-crate.html#disqus_thread&quot;&gt;Comments (View)&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>FFI Talk at MountainWest RubyConf 2009</title>
    <link href="http://copiousfreetime.org/articles/2009/03/14/ffi-talk-at-mountainwest.html" />
    <id>tag:copiousfreetime.org,2009-03-14:1237046211</id>
    <updated>2009-03-14T09:56:51-06:00</updated>
    <content type="html">

&lt;h3 class=&quot;post-title&quot;&gt;
    &lt;a href=&quot;/articles/2009/03/14/ffi-talk-at-mountainwest.html&quot;&gt;FFI Talk at MountainWest RubyConf 2009&lt;/a&gt;
    &lt;span class=&quot;post-date&quot;&gt;(2009-03-14)&lt;/span&gt;
&lt;/h3&gt;


&lt;p&gt;I presented my talk on FFI at MountainWest RubyConf yesterday.  Lots of good
comments from folks, thank you all.  Here's all the links from my talk and a
copy of the presentation on SlideShare.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://kenai.com/projects/ruby-ffi&quot;&gt;FFI Project at Kenai&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.headius.com/2008/10/ffi-for-ruby-now-available.html&quot;&gt;Charles Nutter's announcement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://wmeissner.blogspot.com&quot;&gt;Wayne Meissner's blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.igvita.com/2009/01/15/bridging-mri-jruby-rubinius-with-ffi&quot;&gt;Ilya Grigorik's post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.segment7.net/articles/2008/01/15/rubinius-foreign-function-interface&quot;&gt;Eric Hodel's post&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;object style=&quot;margin:0px&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot;
value=&quot;http://static.slideshare.net/swf/ssplayer2.swf?doc=ffi-090314105040-phpapp01&amp;stripped_title=ffi-building-cross-engine-ruby-extensions&quot;
/&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;/&gt;&lt;param name=&quot;allowScriptAccess&quot;
value=&quot;always&quot;/&gt;&lt;embed
  src=&quot;http://static.slideshare.net/swf/ssplayer2.swf?doc=ffi-090314105040-phpapp01&amp;stripped_title=ffi-building-cross-engine-ruby-extensions&quot;
  type=&quot;application/x-shockwave-flash&quot;
  allowscriptaccess=&quot;always&quot;
  allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;
&lt;/object&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/articles/2009/03/14/ffi-talk-at-mountainwest.html#disqus_thread&quot;&gt;Comments (View)&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Writing SQL Functions in Ruby</title>
    <link href="http://copiousfreetime.org/articles/2009/01/10/writing-sql-functions-in-ruby.html" />
    <id>tag:copiousfreetime.org,2009-01-10:1231637280</id>
    <updated>2009-01-10T18:28:00-07:00</updated>
    <content type="html">&lt;h3 class=&quot;post-title&quot;&gt;&lt;a href=&quot;/articles/2009/01/10/writing-sql-functions-in-ruby.html&quot;&gt;Writing SQL Functions in Ruby&lt;/a&gt;
&lt;span class=&quot;post-date&quot;&gt;(2009-01-10)&lt;/span&gt;
&lt;/h3&gt;


&lt;p&gt;I just released &lt;a href=&quot;http://copiousfreetime.rubyforge.org/amalgalite/&quot;&gt;Amalgalite 0.6.0&lt;/a&gt;
with a couple of major enhancements.  The biggest of which is the ability to
write your own scalar and aggregate SQL functions in Ruby.  You may not know
them by that name, but that's the proper terminology according to SQLite.&lt;/p&gt;

&lt;p&gt;I'm going to do a brief overview of what these function types are and then show
how to write a scalar and an aggregate SQL function for SQLite using Amalgalite.&lt;/p&gt;

&lt;h4&gt;Scalar SQL Functions&lt;/h4&gt;

&lt;p&gt;Scalar SQL Functions are the functions used to do some sort of data
transformation, or some test on a piece of data.  They return a one value, based
upon the input parameter(s). In the following statement the &lt;em&gt;length()&lt;/em&gt; function
is a scalar function.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
&lt;span class=&quot;r&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;&quot;&gt;name&lt;/span&gt;, &lt;span class=&quot;&quot;&gt;length&lt;/span&gt;( &lt;span class=&quot;&quot;&gt;name&lt;/span&gt; ) &lt;span class=&quot;r&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;&quot;&gt;country&lt;/span&gt;;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;These pages give the complete list of built-in scalar functions in SQLite.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://sqlite.org/lang_corefunc.html&quot;&gt;Core Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sqlite.org/lang_datefunc.html&quot;&gt;Date &amp;amp; Time Functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;There are lots of functions in there that you probably recognize from general SQL
usage: &lt;em&gt;hex()&lt;/em&gt;, &lt;em&gt;coalesce()&lt;/em&gt;, &lt;em&gt;lower()&lt;/em&gt;, &lt;em&gt;trim()&lt;/em&gt;, etc.&lt;/p&gt;

&lt;h4&gt;Aggregate SQL Functions&lt;/h4&gt;

&lt;p&gt;Aggregate SQL Functions are the functions used to do, well, aggregation of data
across rows.  They return a single value, based upon multiple rows of data.
You use aggregate functions when you use &lt;code&gt;GROUP BY&lt;/code&gt; SQL clauses.  In this code
example, the &lt;em&gt;sum()&lt;/em&gt; function is an aggregate function.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
&lt;span class=&quot;r&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;&quot;&gt;country&lt;/span&gt;, &lt;span class=&quot;pd&quot;&gt;sum&lt;/span&gt;( &lt;span class=&quot;&quot;&gt;population&lt;/span&gt; ) &lt;span class=&quot;r&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;&quot;&gt;subcountry&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;GROUP&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;&quot;&gt;country&lt;/span&gt;;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href=&quot;http://sqlite.org/lang_aggfunc.html&quot;&gt;Aggregate Functions&lt;/a&gt; lists the built-in
aggregate functions for SQLite.&lt;/p&gt;

&lt;h4&gt;Writing a Scalar SQL Function&lt;/h4&gt;

&lt;p&gt;Sometimes you get to a point doing database work that you want your own scalar
function, or you know of a scalar function in some other database that you want
to use with Amalgalite.  For instance the &lt;em&gt;sha1()&lt;/em&gt; function is available in
PostgreSQL and MySQL, so lets add it for use in our SQLite databases.&lt;/p&gt;

&lt;p&gt;Functions are defined with respect to database instances in Amalgalite.
They must be defined each time the database is opened.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;rubygems&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;amalgalite&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Create a database and a contrived test table&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
db = &lt;span class=&quot;co&quot;&gt;Amalgalite&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Database&lt;/span&gt;.new( &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:memory:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; )
db.execute( &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CREATE TABLE test( filename, line_number, data)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; )

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# add some data&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;open-uri&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
db.prepare(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;INSERT INTO test( filename, line_number, data ) VALUES( ?, ?, ? )&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |stmt|
  lines = open(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;http://redmine.ruby-lang.org/repositories/entry/ruby-18/README.EXT?format=raw&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).readlines
  lines.each_with_index &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |line, i|
    stmt.execute( &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;README.EXT&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, i + &lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;, line )
  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Define the sha1 SQL function&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;digest/sha1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
db.define_function( &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;sha1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; ) &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |x|
  &lt;span class=&quot;co&quot;&gt;Digest&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;SHA1&lt;/span&gt;.hexdigest( x.to_s )
&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;And that is it. We just defined the &lt;em&gt;sha1(t)&lt;/em&gt; SQL function for use in this
database.  We told SQLite that there is now a function available &lt;em&gt;sha1&lt;/em&gt; that
takes a single argument &lt;em&gt;x&lt;/em&gt;.  Let's use it.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
rows = db.execute(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;SELECT sha1('I love ruby')&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
puts rows.first[&lt;span class=&quot;i&quot;&gt;0&lt;/span&gt;] &lt;span class=&quot;c&quot;&gt;# =&amp;gt; d729b72eceebbc2c690ca9b586edd895d8bd4405&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;And use it on some actual table data too.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
db.execute(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;SELECT data, sha1( data ) as sha1 FROM test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |row|
  print &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;idl&quot;&gt;#{&lt;/span&gt;row[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;sha1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;]&lt;span class=&quot;idl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;idl&quot;&gt;#{&lt;/span&gt;row[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;]&lt;span class=&quot;idl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Also look at the rdoc for
&lt;a href=&quot;http://copiousfreetime.rubyforge.org/amalgalite/classes/Amalgalite/Database.html#M000187&quot;&gt;Amalgalite::Database#define_function&lt;/a&gt;
and
&lt;a href=&quot;http://copiousfreetime.rubyforge.org/amalgalite/classes/Amalgalite/Function.html&quot;&gt;Amalgalite::Function&lt;/a&gt;
for other ways to implement a scalar function.&lt;/p&gt;

&lt;p&gt;And a more complete example ships as
&lt;a href=&quot;http://github.com/copiousfreetime/amalgalite/tree/master/examples/define_function.rb&quot;&gt;examples/define_function.rb&lt;/a&gt;
with Amalgalite.&lt;/p&gt;

&lt;h4&gt;Writing an Aggregate SQL Function&lt;/h4&gt;

&lt;p&gt;Aggregate functions are possibly more rare to write, but no less effective.  An
implementation of an aggregate function is different in that it has 2 methods
and needs to save state.  Therefore it is implemented as a class.  Lets
implement a &lt;em&gt;wordcount(s)&lt;/em&gt; aggregate that counts the number of words.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
&lt;span class=&quot;c&quot;&gt;# Implementation of the wordcount( s ) SQL aggregate&lt;/span&gt;
&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;WordCount&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;Amalgalite&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Aggregate&lt;/span&gt;
    &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;initialize&lt;/span&gt;
      &lt;span class=&quot;iv&quot;&gt;@name&lt;/span&gt; = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;wordcount&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;iv&quot;&gt;@arity&lt;/span&gt; = &lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;
      &lt;span class=&quot;iv&quot;&gt;@word_count&lt;/span&gt; = &lt;span class=&quot;i&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;step&lt;/span&gt;( str )
      &lt;span class=&quot;iv&quot;&gt;@word_count&lt;/span&gt; += str.strip.split(&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\s&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;).size
    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;finalize&lt;/span&gt;
      &lt;span class=&quot;r&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;iv&quot;&gt;@word_count&lt;/span&gt;
    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# define the aggregate in the database&lt;/span&gt;
db.define_aggregate( &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;wordcount&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;co&quot;&gt;WordCount&lt;/span&gt; )
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;We always define an aggregate as a class.  The rules regarding the class are
listed in the rdoc for
&lt;a href=&quot;http://copiousfreetime.rubyforge.org/amalgalite/classes/Amalgalite/Aggregate.html&quot;&gt;Amalgalite::Aggregate&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The way it works is that for each row that is grouped into a single output row
has the &lt;em&gt;step()&lt;/em&gt; method called once, and then the &lt;em&gt;finalize()&lt;/em&gt; method is called
one time at the end.  A new instance of the class implementing the aggregate is
instantiated every time the aggregate is used in a statement.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
row = db.execute(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;SELECT filename, wordcount( data ) as wc  FROM test GROUP BY filename&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).first
puts &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;idl&quot;&gt;#{&lt;/span&gt;row[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;]&lt;span class=&quot;idl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;idl&quot;&gt;#{&lt;/span&gt;row[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;wc&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;]&lt;span class=&quot;idl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;# =&amp;gt;  README.EXT: 4736&lt;/span&gt;
db.close
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Also read the rdoc for
&lt;a href=&quot;http://copiousfreetime.rubyforge.org/amalgalite/classes/Amalgalite/Aggregate.html&quot;&gt;Amalgalite::Aggregate&lt;/a&gt;
and look at another example
&lt;a href=&quot;http://github.com/copiousfreetime/amalgalite/tree/master/examples/define_aggregate.rb&quot;&gt;examples/define_aggregate.rb&lt;/a&gt;
that ships with Amalgalite.&lt;/p&gt;

&lt;p&gt;Now go define some crazy useful functions.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/articles/2009/01/10/writing-sql-functions-in-ruby.html#disqus_thread&quot;&gt;Comments (View)&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Amalgalite Pthread Error</title>
    <link href="http://copiousfreetime.org/articles/2008/07/05/amalgalite-pthread-error.html" />
    <id>tag:copiousfreetime.org,2008-07-05:1215323932</id>
    <updated>2008-07-05T23:58:52-06:00</updated>
    <content type="html">

&lt;h3 class=&quot;post-title&quot;&gt;&lt;a href=&quot;/articles/2008/07/05/amalgalite-pthread-error.html&quot;&gt;Amalgalite Pthread Error&lt;/a&gt;
&lt;span class=&quot;post-date&quot;&gt;(2008-07-05)&lt;/span&gt;&lt;/h3&gt;


&lt;p&gt;If you happen to get an error like the following when running amalgalite, it was
a bug in how amalgalite was built.  I wasn't matching the thread support in
amalgalite with the threadsupport of the installed ruby.&lt;/p&gt;

&lt;pre&gt;
amalgalite-0.2.0/ext/amalgalite3.so: undefined symbol: pthread_mutexattr_init
&lt;/pre&gt;


&lt;p&gt;For future reference this is how you can see how ruby was compiled on my iMac&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
&amp;gt;&amp;gt; puts &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;idl&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;co&quot;&gt;RUBY_VERSION&lt;/span&gt;&lt;span class=&quot;idl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt; &lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;idl&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;co&quot;&gt;RUBY_PATCHLEVEL&lt;/span&gt;&lt;span class=&quot;idl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;idl&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;co&quot;&gt;RUBY_RELEASE_DATE&lt;/span&gt;&lt;span class=&quot;idl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;idl&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;co&quot;&gt;RUBY_PLATFORM&lt;/span&gt;&lt;span class=&quot;idl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;fl&quot;&gt;1.8&lt;/span&gt;.&lt;span class=&quot;i&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;i&quot;&gt;114&lt;/span&gt; (&lt;span class=&quot;i&quot;&gt;2008&lt;/span&gt;-&lt;span class=&quot;i&quot;&gt;03&lt;/span&gt;-&lt;span class=&quot;i&quot;&gt;03&lt;/span&gt;) i686-darwin9.&lt;span class=&quot;fl&quot;&gt;2.2&lt;/span&gt;
&amp;gt;&amp;gt; require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;rbconfig&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
&amp;gt;&amp;gt; puts &lt;span class=&quot;co&quot;&gt;Config&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;CONFIG&lt;/span&gt;[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;configure_args&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;]
 &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;--prefix=/opt/local&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;--enable-shared&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;--mandir=/opt/local/share/man&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;--enable-pthread&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;--without-tk&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CC=/usr/bin/gcc-4.0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CFLAGS=-O2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;LDFLAGS=-L/opt/local/lib&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CPPFLAGS=-I/opt/local/include&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CPP=/usr/bin/cpp-4.0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;versus my OpenBSD server:&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
&amp;gt;&amp;gt; puts &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;idl&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;co&quot;&gt;RUBY_VERSION&lt;/span&gt;&lt;span class=&quot;idl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt; &lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;idl&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;co&quot;&gt;RUBY_PATCHLEVEL&lt;/span&gt;&lt;span class=&quot;idl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;idl&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;co&quot;&gt;RUBY_RELEASE_DATE&lt;/span&gt;&lt;span class=&quot;idl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;idl&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;co&quot;&gt;RUBY_PLATFORM&lt;/span&gt;&lt;span class=&quot;idl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;fl&quot;&gt;1.8&lt;/span&gt;.&lt;span class=&quot;i&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;i&quot;&gt;110&lt;/span&gt; (&lt;span class=&quot;i&quot;&gt;2007&lt;/span&gt;-&lt;span class=&quot;i&quot;&gt;09&lt;/span&gt;-&lt;span class=&quot;i&quot;&gt;23&lt;/span&gt;) x86_64-openbsd4.&lt;span class=&quot;i&quot;&gt;2&lt;/span&gt;
&amp;gt;&amp;gt; require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;rbconfig&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
&amp;gt;&amp;gt;puts &lt;span class=&quot;co&quot;&gt;Config&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;CONFIG&lt;/span&gt;[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;configure_args&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;]
 &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;--enable-shared&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;--enable-ipv6&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;--with-dbm-type=bogus&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;--with-opt-dir=/usr/local&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;--with-tcl-include=/usr/local/include/tcl8.4&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;--with-tk-include=/usr/local/include/tk8.4&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;--with-X11-dir=/usr/X11R6&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;--prefix=/usr/local&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;--sysconfdir=/etc&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;--mandir=/usr/local/man&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;--infodir=/usr/local/info&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CC=cc&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CFLAGS=-O2 -pipe&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;CPPFLAGS=-DOPENSSL_NO_STATIC_ENGINE&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;YACC=yacc&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You can see that on my iMac ruby was compiled with @--enable-pthread@ but on
my OpenBSD machine that configuration option is missing.  I didn't take this
into account when building Amalgalite.&lt;/p&gt;

&lt;p&gt;Version 0.2.1 was just released which fixes this bug.&lt;/p&gt;

&lt;div class=&quot;CodeRay&quot;&gt;
&lt;pre&gt;
gem install amalgalite
&lt;/pre&gt;
&lt;/div&gt;




&lt;p&gt;&lt;a href=&quot;/articles/2008/07/05/amalgalite-pthread-error.html#disqus_thread&quot;&gt;Comments (View)&lt;/a&gt;&lt;/p&gt;

</content>
  </entry>
  
</feed>
