Posts tagged "xcode"

Assorted MacRuby Snippets #2

This post references MacRuby 0.5, used with Xcode 3.2 on Snopard (10.6.2); the general technique will likely work on other OS/Xcode version, tho. Just saying.

Apps with more than just one framework

The standard MR app template massages $LOAD_PATH a bit in order to have apps which embed the MR framework use said embedded framework in Release builds. The piece of code in question looks like this:

if Dir.exist?(NSBundle.mainBundle.privateFrameworksPath)
  $:.map! { |x| x.sub(/^\/Library\/Frameworks/, NSBundle.mainBundle.privateFrameworksPath) }
  $:.unshift(NSBundle.mainBundle.resourcePath.fileSystemRepresentation)
end

Which is quite alright if all you embed is the MacRuby framework and are building a release. But as soon as you add another one (Sparkle, for example), the test will always be true, whether you’re debugging without embedding MR or not, and your console will show Ruby load errors. The fix is easy, but it took me a few minutes to find the issue, so here we go.

if Dir.exist?( File.expand_path("MacRuby.framework", NSBundle.mainBundle.privateFrameworksPath) )
  $:.map! { |x| x.sub(/^\/Library\/Frameworks/, NSBundle.mainBundle.privateFrameworksPath) }
  $:.unshift(NSBundle.mainBundle.resourcePath.fileSystemRepresentation)
end

Just a heads-up: the rb_main.rb template in the current MR nightlies doesn’t contain the code above anymore — it appears the “magic” was moved into macruby_deploy (changeset), so it’s likely my fix will be unnecessary in MR 0.6.

posted 3 weeks ago in xcode code macruby ruby snippets apple osx contains 1 note

Loading...

Accessing the Keychain with MacRuby

This post references MacRuby 0.5, used with Xcode 3.2 on Snopard (10.6.2); the general technique will likely work on other OS/Xcode version, tho. Just saying.

At some point in my project I needed to access OSX’ Keychain to store sensitive userdata. Unfortunately, due to the lack of void pointers in MacRuby 0.5 (see Trac ticket), I couldn’t use standard methods like SecKeychainAddGenericPassword. The guys on the mailing list told me to use a wrapper instead. Doing some reading and poking around the interwebs I finally figured it out, and since it’s a neat trick I thought I’d scribble it down, so maybe it will safe someone in a position like me a bit of time. ;)

I’ve decided to go with ExtendMac’s EMKeychain class because it’s simple, clean, free and has a liberal license (MIT license, if I’m not mistaken).

Disclaimer: I’m not a Obj-C person, and what you’re about to read is what works for me. I’ve tinkered until everything was moving in the right direction. There might be better ways (I’m pretty sure there are), and if what I’ve done here is bollocks, I’d be delighted if you would share your knowledge with me. :) Also, I’d enjoy a comment with your thoughts about this here article. Any opinion will do. Just curious is all.

Step 1: Build the wrapper, EMKeychain.dylib

First, we’ll have to make EMKeychain into a dynamic library. Download it from the site, unzip it, and fire up Xcode. There, start a new project of the type “Cocoa Library”.

Starting a new project of the type "Cocoa Library"

When asked for the name, call it “EMKeychain”. It kind of makes sense. This is what you’ll end up with:

New project view

In the screenshot you’ll notice a file called EMKeychain_Prefix.pch. That’s a so-called “precompiled header”; Xcode creates it automatically for you on project creation.

Next, add the files EMKeychain.m and EMKeychain.h to your project by dragging them from the download folder to the “Classes” folder.

Two files added to the project

Since the EMKeychain documentation said the class needs to be linked against Carbon and Security frameworks, do that by right-clicking on the “Linked Frameworks” folder in the tree and selecting Add Existing Frameworks…:

The linked frameworks show up in my project

Following the related MacRuby tutorial’s advice, add a constructor to the end of EMKeychain.m:

void Init_EMKeychain(void) { }

Next, adjust the build settings — switch the base SDK to 10.5…

Base SDK set

… and enable GC.

GC enabled

Build a release, and you’ll have your wrapper.

Step 2: Using it

Now for the fun part.

  1. Add the just built EMKeychain.dylib to your MacRuby project. (Don’t forget to copy the file over.)
  2. Add EMKeychain.dylib to Targets ➔ [project name] ➔ Copy Bundle Resources.

And that’s it. If all went well, you should now be able to use EMKeychain’s EMGenericKeychainItem.

Step 3: Mopping up

It’s very likely that when running your release build it’ll crash and burn and complain about a missing /usr/lib/EMKeychain.dylib. In this case, you’ll have to adjust the built executable accordingly using install_name_tool.

You can do that by adding a new Run Script build phase to the target, which should contain this code.

install_name_tool -change /usr/lib/EMKeychain.dylib \
  "@executable_path/../Resources/EMKeychain.dylib" \
  "$TARGET_BUILD_DIR/$PROJECT_NAME.app/Contents/MacOS/$PROJECT_NAME"

It’s possible that on the next build the executable will mope about a missing /usr/local/lib/EMKeychain.dylib now. Duplicate the snippet and adjust the second one accordingly.

Step 4: Get yourself a beer

Because if all went according to plan, you’re done. :)

posted 1 month ago in macruby keychain osx apple code xcode obj-c howto

Xcode & MacRuby: Embed, Compile, Fix

This post references MacRuby 0.5b2, used with Xcode 3.2 on Snopard (10.6.2).

At some point you’ll probably want to create a release build for your app. You’d like to compile it and embed the MacRuby framework so the app is self-contained. Cool beans.

Unfortunately, it’s not as easy as it seems. Yes, the MacRuby Xcode template contains both an “Embed” and a “Compile” target, and they seem to work fine. ;) The problem I ran into, though, was that whenever you would require anything from the Ruby standard library (say, yaml or stringio), the app would forget about the embedded version of MR and look for /Library/Frameworks/MacRuby.framework/….

I didn’t notice this at first since this folder exists on my dev machine (big surprise), but when I tested it on a clean machine (i.e. one where MacRuby isn’t installed), nothing would happen. Well, nothing except some lines in the system.log, that is:

Being a newb to the ancient arts of compiling shit self-written software I was scratching my head rather furiously. It took me several hours of digging around the Googles and macruby-devel to learn about install_name_tool, and how it’s used to adjust the path of a shared library inside a file.

And that’s what I did, then. I’ve created a new build target, “Embed and Compile”, which has two sub-targets:

  1. the reference to the default app build phase (which means “MyNewApp” is a direct dependency of the “Embed and Compile” target)
  2. a “Run Script” build phase named “Embed, Compile, Fix”

The script runs macruby_deploy and afterwards tells install_name_tool to do its dirty, dirty work. I found it’s not enough to have it adjust the executable only; for me it was necessary to fix all the *.rbo files as well.

So, that’s it. The above works for me, it might work for you as well. If you have comments, suggestions or recommendations, please sound off below. I’m still learning all of this, and any input is appreciated. :)

Oh, and in case I sound ungrateful or anything: I am not. MacRuby 0.5b2 is exactly what is says it is: the second beta of a software’s pre-1.0 version. It’s already pretty damn impressive but not really done yet. I had a hunch what I was getting into, so it’s cool. ;)

posted 1 month ago in code macruby ruby osx apple xcode snippets troubleshooting

MacRuby compilation step fixes

Just a note, mostly to myself: The default XCode MacRuby rb_main.rb template will contain these lines:

Dir.entries(dir_path).each do |path|
  if path != File.basename(__FILE__) && path.match(/\.rb$/)
    require(path)
  end
end

Works fine for uncompiled files, but when you want to compile your app, there’ll be no *.rb files — just *.rbo files. So rb_main.rb needs to be adjusted.

Dir.entries(dir_path).each do |path|
  if path != File.basename(__FILE__) && path.match(/\.rbo?$/)
    require(path)
  end
end

I just spent 15 minutes wondering about these Unknown class 'Controller', using 'NSObject' instead. Encountered in Interface Builder file at path … in my system log, and I tend to forget this kind of detail so I wanted to jot it down as a reminder to future Carlo.

So, listen up, future Carlo. This is important.

posted 1 month ago in macruby ruby xcode code osx contains 1 note

Loading...

About this site and its Author

  • czottmann
The personal blog of Carlo Zottmann, a freelance software developer from Munich, Germany.

He builds "applications" or "sites" for them so-called "internets". Currently notable projects are TwerpScan and Ephemera, a Mac tool for Instapaper enthusiasts with ebook readers.

His hobbies include taming dolphins, riding lemurs and collecting spores, molds and fungus — the food of the future. GP