Building bundles fails whenever model classes refer to other model classes

2 views
Skip to first unread message

Stu

unread,
Feb 2, 2009, 2:24:57 PM2/2/09
to Ruby-based iPhone Testing
First, exciting project! Testing model stuff, particularly given db
interaction, is much nicer to work with in ruby.

I'm able to get tests running with simple model elements, basically
just VOs.

But as soon as I introduce a base class, or have a model element refer
to another element I get the following:

** Execute build/bundles/Trail.bundle
gcc -o build/bundles/Trail.bundle -bundle -framework Foundation
Classes/Trail.m
Undefined symbols:
".objc_class_name_ModelBase", referenced from:
.objc_class_name_Trail in cc4QElk5.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

In the above project, ModelBase is in the same directory, and simply
has a getter for the FMDatabase. What I'm finding is that I get the
above linker error whenever a class refers to any other class in the
project.

And I'm a relative Objective-c newbie, so I'm having trouble figuring
it out. I suspect I need to change the rakefile so I pass another
param to the gcc command letting it know where to find the .o files,
but I'm not sure.

Any ideas?

Tim Haines

unread,
Feb 2, 2009, 2:29:27 PM2/2/09
to rbipho...@googlegroups.com
I dealt with this 6 months or so ago from memory.  I think the bundle builds are setup to only include the class in question.  You need to adjust the build task to include all model classes.

Tim.

Stuart Robertson

unread,
Feb 2, 2009, 2:31:21 PM2/2/09
to rbipho...@googlegroups.com
Thanks Tim.  So when you fixed this, you had a single bundle for all of your model classes?  I'll start looking into how to do that.  Let me know if you have any suggestions.

Stu

Aaron VonderHaar

unread,
Feb 2, 2009, 3:24:59 PM2/2/09
to rbipho...@googlegroups.com
Hi Stu, 

I have rbiphonetest-0.3.0 installed, and the Rakefile that is generated has this:

  file "build/bundles/#{bundle_name}.bundle" => dot_o_files do |t|
    FileUtils.mkdir_p "build/bundles"
    FileUtils.rm Dir["build/bundles/#{bundle_name}.bundle"]
    sh "gcc -o build/bundles/#{bundle_name}.bundle #{dot_o_files.join(" ")} -bundle " +
      "#{make_options '-framework ', req_frameworks} " +
      "#{make_options '-l', req_libraries} " +
      "#{make_options '-I', src_paths}"
  end

Which you'll notice is trying to build the bundle from #{dot_o_files.join(" ")}, and earlier in the Rakefile is:

dot_o_files = src_files.map { |file| "build/" + File.basename(file).gsub(/\.m$/,'') + ".o" }

So that should do what you are looking for-- compile all the .m files into .o files, and then combine the .o files into a bundle.  Is your Rakefile different from that?

--Aaron V.

Stuart Robertson

unread,
Feb 2, 2009, 4:06:32 PM2/2/09
to rbipho...@googlegroups.com
Hi Aaron.  Strange.  I pulled rbiphonetest down from git and installed the gem from that.  The Rakefile it generates isn't aware of .o files at all (see end of this message).

Could you send the full Rakefile that's working for you?  I'll see if I can get the snippet you sent along working, but it's strange that the two are so different.

Once I get things working I'll be happy to share if there's something interesting.

Stu

===

require "rubygems"
require "rake"

Dir['tasks/**/*.rake'].each { |rake| load rake }

namespace :objc do
  desc "Compiles all Objective-C bundles for testing"
  task :compile
end

task :compile => "objc:compile"

namespace :objc do
  # look for Classes/*.m files containing a line "void Init_ClassName"
  # These are the primary classes for bundles; make a bundle for each
  model_file_paths = `find Classes/*.m -exec grep -l "^void Init_" {} \\;`.split("\n")
  model_file_paths.each do |path|
    path =~ /Classes\/(.*)\.m/
    model_name = $1

    task :compile => model_name do
      if Dir.glob("**/#{model_name}.bundle").length == 0
        STDERR.puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
        STDERR.puts "Bundle actually failed to build."
        STDERR.puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
        exit(1)
      end
    end

    task model_name.to_sym => "build/bundles/#{model_name}.bundle"

    file "build/bundles/#{model_name}.bundle" => ["Classes/#{model_name}.m", "Classes/#{model_name}.h"] do |t|
      FileUtils.mkdir_p "build/bundles"
      FileUtils.rm Dir["build/bundles/#{model_name}.bundle"]
      sh "gcc -o build/bundles/#{model_name}.bundle -bundle -framework Foundation Classes/#{model_name}.m"
    end
  end

end

Aaron VonderHaar

unread,
Feb 2, 2009, 4:21:55 PM2/2/09
to rbipho...@googlegroups.com
Aha!  I thought I was using 0.3.0, but I actually have a more recent version installed (which is calling itself 0.4.0).  

Check out the onebundle branch from drnic's git repo.


--Aaron V.

Stuart Robertson

unread,
Feb 2, 2009, 4:47:19 PM2/2/09
to rbipho...@googlegroups.com
Wow, Thanks Aaron.  That wasn't obvious, and I just got things compiling (hooray!).  I'll be exploring testing models and fmdb, and will let you know how this ends up working.  

Stu

Stuart Robertson

unread,
Feb 5, 2009, 4:49:00 PM2/5/09
to rbipho...@googlegroups.com
So I was able to get rbiphonetest working.  The bundle name has to match one of the classes exposed to ruby or it doesn't load, which was a little non-obvious.  And of course, only classes which don't reference UIKit can be tested.  But since I want this for testing the data model, that's how it should be anyway.

Here's the part of the Rakefile I changed to get things working:

bundle_name    = 'Trail'
src_paths      = %w[Classes] # any included projects, add folders here
src_files      = FileList.new('Classes/**/*.m')  do |fl|
    fl.exclude(/Controller/)
    fl.exclude(/Delegate/);
  end # any included projects, add files here
req_frameworks = %w[Foundation] # use only frameworks available to both Cocoa + iPhone SDKs
req_libraries  = %w[sqlite3] # e.g. add sqlite3 for libsqlite3 to be used by linking step

The fl.excludes worked at leaving out UI bits which wouldn't have compiled anyway.
Reply all
Reply to author
Forward
0 new messages