Tag Archives: OS X

Emptying the trash is creating files!

An amusing bug in OS X Yosemite:

Look carefully at the file count.

If you look carefully you will see that the file count is -301, does this mean OS X is creating files while emptying the trash? ūüôā

OS X Yosemite and Older iMacs

I had been using VMware Fusion 7 on my iMac running OS X Mavericks with no issues. ¬†However after upgrading to OS X Yosemite my VMs had severe performance problems to the point where the characters I typed in a terminal wouldn’t show up until I waggled the mouse.

A little bit of Google-Fu led me to this thread on¬†VMware’s community forum, however I wasn’t prepared to make the suggested changes to my NVRAM without understanding a little more. ¬†Reading through the thread I was led to similar thread on the Parallels forums suggesting the same fix, but with no more explanation. ¬†The thread did contain a link to a Parallels Knowledge Base article that explained suggested the exact issue I’d seen could be due to interrupt storms. ¬†Even better they linked to another knowledge base article that explained how to confirm this theory.

Having followed the steps on my iMac I confirmed that I was seeing interrupt storms relating to the¬†com.apple.driver.AppleACPIPlatform driver. ¬†This finally led me to a thread on Apple’s support forum that suggested the same fix.

After applying the fix the performance of my system was like night and day! ¬†I hadn’t appreciated quite how badly it had been running even out with VMware Fusion.

If you’ve made it this far you probably want to know what the fix is? ¬†Open a terminal and type the following:

sudo nvram boot-args="debug=0xd4e"

Once you’ve done this restart your iMac and it should be significantly faster! ¬†If this works for you please raise a support issue with Apple so that they address this properly in a future update to OS X Yosemite.

The only troubling thing is that I still don’t know what setting “debug” to “0xd4e” actually does…

Developing for Multiple Platforms with Xcode 6

I’ve been working on an app that targets both iOS and OS X devices, mainly to teach myself to code in Objective C, but also to scratch an itch in the best open source tradition. ¬†In Xcode I’ve had two projects and been syncing code between them using copy and paste. ¬†This is not a great experience so I looked around for more elegant solutions. ¬†The one I settled on was inspired by Session 233:¬†Sharing code between iOS and OS X¬†from the 2014 WWDC. ¬†This involves creating a single project with multiple targets aimed at different platforms and devices.

I was bothered by the fact that despite following what was done in the session I couldn’t get my project to look the same, eventually after much experimenting I came up with the following process. ¬†The caveat is that this works for me, there are quite possibly better ways to achieve the same result, which I’d love to hear!

Create the project

Create a Project

The first thing you need to¬†do is create a new project in Xcode, I usually start from the¬†iOS Single View Application template, but it doesn’t actually matter.

SS 02

On the above screen the key change is in setting the¬†project’s name. ¬†If you chose an iOS application¬†name the project¬†MyApp-iOS, substituting MyApp for your own project name. ¬†If you chose an OS X application ¬†name the project MyApp-OSX. ¬†Click next and finish creating the project by selecting a save location and enabling Git for version control if needed.

Rename the project

SS 03.1 SS 03.2

In the project navigator select the top item, the project itself.  Then move across to the file inspector on the righthand side and rename the project, dropping the suffix, to MyApp.

SS 04.1

The window shown above pops up offering to rename the targets, however as we will be adding targets for other platforms later we want to prevent Xcode from being over helpful by deselecting the targets:

SS 04.2

Clicking on rename might pop up another window where Xcode offers to turn on snapshots, I normally click enable but it doesn’t affect what we are trying to achieve here.

Adding a New Target

SS 06SS 07

The next step is to add a new target to build your application for a different Apple platform. ¬†Click the + button at the bottom of the window,¬†below the existing targets. ¬†In the window that opens select a different platform – in my case that’s an OS X Cocoa Application. ¬†Click next and name the target using the same convention as when you created the project: MyApp-OSX. ¬†Once you’ve added the additional target your project should look something like:

SS 08

Adding Common Code

The whole point of this exercise to create common code that can be used in both targets.  To do this create a group in the Project Navigator by right clicking on the project and selecting New Group.  I normally name this MyApp-Common.  Right clicking on the MyApp-Common group select New File and choose to create a new Objective C class.

SS 09

The two things you need to take care with are: making sure you don’t create a class that inherits from a platform specific class and that you remember to add the class to both targets, as shown in the screenshot above. ¬†You should then end up with a project that looks like this:

SS 10

The final task is to rename the products of the¬†two targets, if you compile and then install or distribute you will end up with applications named MyApp-iOS and MyApp-OSX which isn’t what users expect to see. ¬†Renaming the product is a two step process. ¬†First, for each non-test target, you need to select the target, select Build Settings and search for Product Name. ¬†Once you’ve got the Product Name setting you can change the value to the name you want for your application:

SS 11

Renaming the product in this way has an unexpected side effect – tests will no longer build and run. ¬†This is due to the linker being unable to link the test classes to the application classes as it’s still looking for the old application name (details here). ¬†To fix this you need to change the value for Test Host in the same way as you did for Product Name. ¬†Do this for both test targets, replacing all occurrences of MyApp-iOS and MyApp-OSX with MyApp (or whatever name you gave to your product in the previous step).

SS 12

At this point you should be able to build, install, and run both targets. ¬†As I said at the start, I’m sure there’s either things I’m missing or a better way to do this entirely – I will be looking into creating a framework that builds for both iOS and OSX, and then including the framework in a multi-platform application¬†project.

More on OS X Dynamic Linking

My recent blog post on using a third¬†party library within an Objective-C project had one fatal flaw – it didn’t actually work!

The problem was that even though I had copied the PROJ.4 library into my project, linked against that version of the library, and copied it into my application, the application was still looking for the library in it’s original location – /opt/local/lib.

After much Googling, and a fair amount of head scratching it turns out that dynamic libraries on OS X have an interesting feature where they hard code the path to the library at link time. ¬†That doesn’t sound like a problem, however the path the application hard codes for the library isn’t set by one of the many Build Settings within your Xcode project rather it’s hard coded into the library when the library is built!

Helpfully Apple provide some command line tools to resolve this issue.  The first is otool which we can use to inspect this hard coded path/name in the PROJ.4 library:

$ otool -L libproj.0.dylib 
libproj.0.dylib:
	/opt/local/lib/libproj.0.dylib (compatibility version 8.0.0, current version 8.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)

The first line of output gives us the name, which is also the path the linker will use, for the library.  This means that whenever we link an application against this library it will always look for it as /opt/local/lib/libproj.0.dylib no matter where we actually install it.

The other tool Apple provides, install_name_tool, allows us to modify the name/path of the library:

$ install_name_tool -id "@executable_path/../Frameworks/libproj.0.dylib" libproj.0.dylib

What this command does is replace the existing name/path with @executable_path/../Frameworks/libproj.0.dylib. The @executable_path keyword tells the system that it should look for the library relative to the executable, in this case one folder up, then in the Frameworks folder.

We can check that the change has taken:

$ otool -L libproj.0.dylib 
libproj.0.dylib:
	@executable_path/../Frameworks/libproj.0.dylib (compatibility version 8.0.0, current version 8.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)

With the library updated cleaning the project and then rebuilding creates an application that works as expected. ¬†I’ve updated the project on GitHub to include this fix and some clean up of the coordinate conversion code.

So the slightly updated sequence for adding a third party library to an application is:

  1. Copy the library into the project.
  2. Switch to the command line and update the library path/name using install_name_tool.
  3. Add a Copy Files build phase so that the library is copied into the application bundle.
  4. Update the Header Search Path in the build settings so that the header files for the library can be found by Xcode.

Your application should now work properly on any OS X system.  For more detail about linking and @executable_path take a look at this blog post by Mike Ash, his other blogs posts are good as well!

AWS Command Line Tools for Mac OS X

Just a quick guide to get the Amazon Web Services (AWS) command line tools installed and configured on an Apple Mac running Mountain Lion.

The first task was to get PIP installed:

sudo easy_install pip

Then it’s a simple case of using PIP to to install the AWS CLI:

sudo pip install awscli

After a few minutes you should have the CLI tools installed.  The final task is to set up your credentials.  Create the file $HOME/.aws/config, it should contain something like the following:

[default]
aws_access_key = YOURKEYHERE
aws_secret_access_key = YOURSECRETACCESSKEYHERE
region = eu-west-1

You should replace these values with your own access keys and preferred region. ¬†For extra credit, if you’re a Bash shell user, you can enable command completion:

complete -C aws_completer aws

There’s much more information on the AWS CLI available from Amazon.