From: Daniel Berger Date: 2010-01-26T07:18:07+09:00 Subject: Re: Compiling multiple C source files into a single library On Jan 25, 12:59 pm, 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 > >   Rakefile > >   ext/ > >     foo/ > >       extconf.rb > >       foo.c > >       bar.c > > > foo.c and bar.c are pretty basic C source files: > > > // foo.c > > #include > > > 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 > > > // 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! Aha, thanks! Dan