Compiling multiple C source files into a single library

Discussion in 'Ruby' started by Daniel Berger, Jan 25, 2010.

  1. Hi,

    In the past I've always put all my code into a single source file and
    built it that way. However, I'd like to split out my C source files
    into a "one class per file" arrangement for a particular project, but
    I'm not sure how to do it. I'm using rake-compiler on Snow Leopard,
    btw.

    Here's the layout I have:

    my_project
    Rakefile
    ext/
    foo/
    extconf.rb
    foo.c
    bar.c

    foo.c and bar.c are pretty basic C source files:

    // foo.c
    #include <ruby.h>

    void Init_foo(){
    VALUE cFoo = rb_define_class("Foo", rb_cObject);
    rb_define_const(cFoo, "VERSION", rb_str_new2("0.0.1"));
    }

    // bar.c
    #include <ruby.h>

    // I also tried Init_foo here, but that lead to a compiler error
    void Init_bar(){
    VALUE cBar = rb_define_class("Bar", rb_cObject);
    rb_define_const(cBar, "VERSION", rb_str_new2("0.0.1"));
    }

    The extconf.rb file is just "require 'mkmf'; create_makefile('foo')".

    The Rake task is simply "Rake::ExtensionTask.new('foo')".

    Running "rake compile:stuff" builds like so:

    gcc -I. -I/opt/ree/lib/ruby/1.8/i686-darwin10.2.0 -I/opt/ree/lib/ruby/
    1.8/i686-darwin10.2.0 -I../../../../ext/foo -D_XOPEN_SOURCE -
    D_DARWIN_C_SOURCE -fno-common -g -Os -fno-strict-aliasing -pipe -
    fno-common -c ../../../../ext/foo/bar.c
    gcc -I. -I/opt/ree/lib/ruby/1.8/i686-darwin10.2.0 -I/opt/ree/lib/ruby/
    1.8/i686-darwin10.2.0 -I../../../../ext/foo -D_XOPEN_SOURCE -
    D_DARWIN_C_SOURCE -fno-common -g -Os -fno-strict-aliasing -pipe -
    fno-common -c ../../../../ext/foo/foo.c
    cc -dynamic -bundle -undefined suppress -flat_namespace -o foo.bundle
    bar.o foo.o -L. -L/opt/ree/lib -L. -ldl -lobjc
    cd -
    cp tmp/i686-darwin10.2.0/foo/1.8.7/foo.bundle lib/foo.bundle

    But, if I run the following test.rb program it fails:

    $:.unshift 'lib'
    require 'stuff' # ok
    p Foo::VERSION # ok
    p Bar::VERSION # fail, uninitialized constant Bar

    Why isn't Bar visible? What's the right way to do what I'm attempting?

    Regards,

    Dan
    Daniel Berger, Jan 25, 2010
    #1
    1. Advertising

  2. On Tue, Jan 26, 2010 at 04:46:37AM +0900, Daniel Berger wrote:
    > Hi,
    >
    > In the past I've always put all my code into a single source file and
    > built it that way. However, I'd like to split out my C source files
    > into a "one class per file" arrangement for a particular project, but
    > I'm not sure how to do it. I'm using rake-compiler on Snow Leopard,
    > btw.
    >
    > Here's the layout I have:
    >
    > my_project
    > Rakefile
    > ext/
    > foo/
    > extconf.rb
    > foo.c
    > bar.c
    >
    > foo.c and bar.c are pretty basic C source files:
    >
    > // foo.c
    > #include <ruby.h>
    >
    > void Init_foo(){
    > VALUE cFoo = rb_define_class("Foo", rb_cObject);
    > rb_define_const(cFoo, "VERSION", rb_str_new2("0.0.1"));
    > }


    Call Init_bar() from Init_foo(). Ruby will only call one function when
    your extension loads. The "Init_*" function maps to the name of the
    shared object you build. So if you build "foo.bundle", ruby will call
    "Init_foo", and only "Init_foo". Other initialization is up to you.

    > // bar.c
    > #include <ruby.h>
    >
    > // I also tried Init_foo here, but that lead to a compiler error
    > void Init_bar(){
    > VALUE cBar = rb_define_class("Bar", rb_cObject);
    > rb_define_const(cBar, "VERSION", rb_str_new2("0.0.1"));
    > }
    >
    > The extconf.rb file is just "require 'mkmf'; create_makefile('foo')".


    The create_makefile() call determines the name of the shared object
    built. Since you're building "foo.bundle", *only* Init_foo will be
    called.

    > The Rake task is simply "Rake::ExtensionTask.new('foo')".
    >
    > Running "rake compile:stuff" builds like so:
    >
    > gcc -I. -I/opt/ree/lib/ruby/1.8/i686-darwin10.2.0 -I/opt/ree/lib/ruby/
    > 1.8/i686-darwin10.2.0 -I../../../../ext/foo -D_XOPEN_SOURCE -
    > D_DARWIN_C_SOURCE -fno-common -g -Os -fno-strict-aliasing -pipe -
    > fno-common -c ../../../../ext/foo/bar.c
    > gcc -I. -I/opt/ree/lib/ruby/1.8/i686-darwin10.2.0 -I/opt/ree/lib/ruby/
    > 1.8/i686-darwin10.2.0 -I../../../../ext/foo -D_XOPEN_SOURCE -
    > D_DARWIN_C_SOURCE -fno-common -g -Os -fno-strict-aliasing -pipe -
    > fno-common -c ../../../../ext/foo/foo.c
    > cc -dynamic -bundle -undefined suppress -flat_namespace -o foo.bundle
    > bar.o foo.o -L. -L/opt/ree/lib -L. -ldl -lobjc
    > cd -
    > cp tmp/i686-darwin10.2.0/foo/1.8.7/foo.bundle lib/foo.bundle
    >
    > But, if I run the following test.rb program it fails:
    >
    > $:.unshift 'lib'
    > require 'stuff' # ok
    > p Foo::VERSION # ok
    > p Bar::VERSION # fail, uninitialized constant Bar
    >
    > Why isn't Bar visible? What's the right way to do what I'm attempting?


    Just call Init_bar() from inside Init_foo().

    Hope that helps!

    --
    Aaron Patterson
    http://tenderlovemaking.com/
    Aaron Patterson, Jan 25, 2010
    #2
    1. Advertising

  3. On Jan 25, 12:59=A0pm, Aaron Patterson <>
    wrote:
    > On Tue, Jan 26, 2010 at 04:46:37AM +0900, Daniel Berger wrote:
    > > Hi,

    >
    > > In the past I've always put all my code into a single source file and
    > > built it that way. However, I'd like to split out my C source files
    > > into a "one class per file" arrangement for a particular project, but
    > > I'm not sure how to do it. I'm using rake-compiler on Snow Leopard,
    > > btw.

    >
    > > Here's the layout I have:

    >
    > > my_project
    > > =A0 Rakefile
    > > =A0 ext/
    > > =A0 =A0 foo/
    > > =A0 =A0 =A0 extconf.rb
    > > =A0 =A0 =A0 foo.c
    > > =A0 =A0 =A0 bar.c

    >
    > > foo.c and bar.c are pretty basic C source files:

    >
    > > // foo.c
    > > #include <ruby.h>

    >
    > > void Init_foo(){
    > > =A0 VALUE cFoo =3D rb_define_class("Foo", rb_cObject);
    > > =A0 rb_define_const(cFoo, "VERSION", rb_str_new2("0.0.1"));
    > > }

    >
    > Call Init_bar() from Init_foo(). =A0Ruby will only call one function when
    > your extension loads. =A0The "Init_*" function maps to the name of the
    > shared object you build. =A0So if you build "foo.bundle", ruby will call
    > "Init_foo", and only "Init_foo". =A0Other initialization is up to you.
    >
    > > // bar.c
    > > #include <ruby.h>

    >
    > > // I also tried Init_foo here, but that lead to a compiler error
    > > void Init_bar(){
    > > =A0 VALUE cBar =3D rb_define_class("Bar", rb_cObject);
    > > =A0 rb_define_const(cBar, "VERSION", rb_str_new2("0.0.1"));
    > > }

    >
    > > The extconf.rb file is just "require 'mkmf'; create_makefile('foo')".

    >
    > The create_makefile() call determines the name of the shared object
    > built. =A0Since you're building "foo.bundle", *only* Init_foo will be
    > called.
    >
    >
    >
    > > The Rake task is simply "Rake::ExtensionTask.new('foo')".

    >
    > > Running "rake compile:stuff" builds like so:

    >
    > > gcc -I. -I/opt/ree/lib/ruby/1.8/i686-darwin10.2.0 -I/opt/ree/lib/ruby/
    > > 1.8/i686-darwin10.2.0 -I../../../../ext/foo -D_XOPEN_SOURCE -
    > > D_DARWIN_C_SOURCE =A0 -fno-common -g -Os -fno-strict-aliasing =A0-pipe =

    -
    > > fno-common =A0 -c ../../../../ext/foo/bar.c
    > > gcc -I. -I/opt/ree/lib/ruby/1.8/i686-darwin10.2.0 -I/opt/ree/lib/ruby/
    > > 1.8/i686-darwin10.2.0 -I../../../../ext/foo -D_XOPEN_SOURCE -
    > > D_DARWIN_C_SOURCE =A0 -fno-common -g -Os -fno-strict-aliasing =A0-pipe =

    -
    > > fno-common =A0 -c ../../../../ext/foo/foo.c
    > > cc -dynamic -bundle -undefined suppress -flat_namespace -o foo.bundle
    > > bar.o foo.o -L. -L/opt/ree/lib -L. =A0 =A0 -ldl -lobjc
    > > cd -
    > > cp tmp/i686-darwin10.2.0/foo/1.8.7/foo.bundle lib/foo.bundle

    >
    > > But, if I run the following test.rb program it fails:

    >
    > > $:.unshift 'lib'
    > > require 'stuff' # ok
    > > p Foo::VERSION # ok
    > > p Bar::VERSION # fail, uninitialized constant Bar

    >
    > > Why isn't Bar visible? What's the right way to do what I'm attempting?

    >
    > Just call Init_bar() from inside Init_foo().
    >
    > Hope that helps!


    Aha, thanks!

    Dan
    Daniel Berger, Jan 25, 2010
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    4
    Views:
    938
    M.E.Farmer
    Feb 13, 2005
  2. Horacius ReX

    Mix different C source files into a single one

    Horacius ReX, Dec 29, 2007, in forum: C Programming
    Replies:
    6
    Views:
    293
    Thad Smith
    Dec 30, 2007
  3. broli

    compiling multiple source files

    broli, Mar 28, 2008, in forum: C Programming
    Replies:
    5
    Views:
    729
    David Thompson
    Apr 7, 2008
  4. Oliver Graeser

    Compiling multiple source files.......

    Oliver Graeser, Aug 18, 2008, in forum: C++
    Replies:
    5
    Views:
    876
    Sherm Pendley
    Aug 18, 2008
  5. ela
    Replies:
    12
    Views:
    336
    Uri Guttman
    Apr 6, 2009
Loading...

Share This Page