Win-win with Cocotron and Xcode 4.3 — code for Mac, build for Windows (Part 1)

This is the first part of a tutorial in which I’d like to introduce you to one of my favorite open-source projects, The Cocotron (imagine the ominous silence of a Soviet nuclear reactor as the backdrop for pronouncing this name).

Cocotron lets you take a Cocoa-based Mac app and port it to Windows without ever leaving Xcode — just add a Windows target to your project and you’re set. Sounds too good to be true? Well, as usual, some limitations apply. Cocoa is a large and rapidly evolving framework, and it would be very difficult for a loose team of open-source volunteers to achieve 100% compatibility with Apple’s latest and greatest. But Cocotron can take you most of the way, and if you have the possibility to plan ahead for compatibility, the odds of being able to make use of Cocotron are further increased.

The Cocotron is not just a vapor framework outlining some kind of theoretical feasibility: it’s been publicly available since late 2006, and ports accomplished using Cocotron are out in the wild. Personally I have used it deploy Mac-developed custom apps on Windows, including a fairly complex GUI subtitling tool used by the Finnish Broadcasting Company for a popular TV game show. (Based on activity in the Cocotron mailing list, there is also a company with a well-known consumer-oriented Mac product who are nearing completion of a Windows port using Cocotron.)

Something that appeals to me in Cocotron is its strict, almost austere “no-frills” policy. Christopher Lloyd, the project’s initiator, runs a tight ship. Unlike some other cross-platform toolkits (* cough Gtk+ and Qt *), the framework is lean: Cocotron’s Windows DLLs for Foundation and AppKit only take about 6-7 MB. And it’s self-contained – there are no other dependencies by default. As fits this culture of independence, Cocotron is MIT-licensed, so you can basically do anything you please with the code as long as credit is given.

True cross-compiling on the Mac is a core part of Cocotron’s promise. As such, its fortunes are closely tied to Apple’s Xcode development environment which has undergone a lot of changes over the past five years. Luckily Xcode has consistently remained open enough to allow custom cross-compilers (perhaps largely thanks to the advent of iOS and Cocoa Touch on ARM CPUs, which has made cross-compiling an essential part of Xcode).

Xcode 4 was the biggest change in the product’s history. I had been long dreading making the leap to Xcode 4 for two reasons: the new UI would force me to re-learn many workflows, and I was worried that Cocotron might not work properly anymore. Now it has been a week since I finally made the change, and I can report that I’m pretty happy about it. That means you could be happy too with Cocotron and Xcode 4.3! This tutorial will tell you how.

What is The Cocotron?

Fundamentally, it’s two things:

  • The Cocotron Developer Tools (CDT) – a cross-compiler and associated software that installs alongside Xcode and targets the platform(s) of your choice. (Not just Windows on x86 – you can also use Cocotron to build for Linux on ARM, Solaris on SPARC, and many other platforms. In this tutorial, I’m going to talk about Windows only because that’s what I’m familiar with.)
  • An open-source implementation of the Cocoa frameworks. Foundation and AppKit are the most important, but there are also pieces of other Mac OS X APIs implemented, e.g. parts of ImageKit, CoreText, ScriptingBridge… The guiding principle is that people implement what they need for their port.

That’s the big picture. To better understand what actually goes on, we also need to be aware of some specific components that link the high-level blocks:

  • The Objective-C runtime. The GNU Compiler Collection (GCC) has supported Obj-C for about 20 years. NeXT had to release their modifications to the C compiler, but they didn’t need to release the source code for their Obj-C runtime. So it happened that although GCC included support for the language, there was never a standard runtime to go with the compiler. For a dynamic language like Obj-C, this was a problem. NeXT became Apple and continued with their own proprietary runtime. The GNUStep project developed an open runtime for GCC, and it eventually diverged from Apple’s – different function names, etc. Because of this old incompatibility in open-source Obj-C land, Cocotron includes its own Objective-C runtime that is more compatible with the NeXT/Apple runtime. (Today this is largely a historical artifact. A new modern runtime has been introduced in GCC 4.6, and probably Cocotron will eventually adopt it, removing the need for a custom runtime altogether.)
  • A modified GCC. The C/C++/Obj-C compiler installed in Cocotron is not quite stock GCC. It’s patched to use the Cocotron Obj-C runtime, and also to support some of Apple’s extensions to GCC which Xcode assumes are present (e.g. specific linker flags that are necessary on Mac OS X but don’t exist elsewhere – with a stock GCC, these would produce errors).
  • A set of Xcode templates. These are installed into Xcode’s support files so that you can easily choose the Cocotron compiler for your Windows targets. This is the only modification made in Xcode by the Cocotron install. If you remove these, your Xcode will be just like it was before.

Now that we know what’s going to be installed, let’s get started.

Prerequisites

This tutorial is written for Apple’s latest development platform: OS X 10.7 Lion and Xcode 4.3. You can also use Cocotron on older OS and Xcode versions, but you may need different versions of some software, and some workflow may be different. (I’ll try to include links to support files for older platforms, to the extent that I’m aware of issues.)

Xcode 4.3 was a watershed release because it no longer includes command-line development tools by default. (In other words, when you type gcc in the terminal, you’ll get “command not found”). Xcode doesn’t even install in /Developer anymore, like all previous versions – it is now just another app from the Mac App Store, although one with far greater privileges than 3rd party apps. This is really great for those of us that like to keep multiple versions of Xcode around, and it has also cut down on the size of the install quite a bit.

To make this install work, you’ll need to get those missing command-line tools, though. They are available as a package on Apple’s Mac developer site, or you can install them directly in Xcode (more information: What’s New in Xcode 4.3).

Building the cross-compiler

A few versions back, something big happened in Mac compiler land. After having used GCC practically ever since NeXT was a twinkle in the eyes of Steve Jobs and Avie Tevanian, Xcode switched away from GCC to a new compiler architecture called LLVM. This new compiler comes in two forms: there’s a whole new shiny front-end called Clang, and then there’s a another front-end called llvm-gcc which, unsurprisingly, is compatible with good old GCC. The idea is that you can feed llvm-gcc your existing projects, and it will build them just as GCC did.

For some projects, this doesn’t quite work. There’s software that either takes advantage of some rare GCC features not supported by llvm-gcc, or perhaps has been compiled only with GCC for so long that it has acquired non-obvious dependencies on the compiler. As it happens, GCC itself is one of these projects. This is problematic for Cocotron because its cross-compiler is a modified GCC, as outlined above. If we can’t compile GCC on the Mac, we can’t build the Cocotron Developer Tools.

In the long term, this can be solved by either fixing the issue that prevents llvm-gcc from building a working GCC, or by changing Cocotron to use Clang instead for its cross-compiler. (In fact this may already be possible, but it’s not supported by the default Cocotron installation, and I don’t know the details of what’s required to set up Clang for Cocotron.)

In the short term, we need a solution that’s more easily available. The High Performance Computing for Mac OS X project provides a regularly updated build of the latest GCC for the Mac, so I decided to use that. You can download readymade GCC binaries directly from their site (both Lion and Snow Leopard are supported).

For extra convenience, I’ve made an installer package of their GCC for Lion. Click this link to download it from my site:

HPC GCC 4.7 Installer for Lion (69.4 MB)

This installer doesn’t overwrite the Xcode command-line tools. It merely places GCC 4.7 in the folder /usr/hpc-gcc-4.7 and creates a symlink that allows you to access this compiler by the command gcc-4.7 in the Terminal.

Cocotron’s install script assumes that the compiler is named gcc, though. But if we look at the file /usr/bin/gcc, we see that it’s just a symlink that points to the real compiler executable elsewhere. Here’s the file listing on my system:

$ cd /usr/bin
$ ls -l gcc*
lrwxr-xr-x  1 root  wheel  12 Feb 22 12:47 gcc -> llvm-gcc-4.2
lrwxr-xr-x  1 root  wheel  24 Feb 22 12:32 gcc-4.7 -> /usr/hpc-gcc-4.7/bin/gcc

So, by default gcc points to llvm-gcc-4.2 (which itself is just another symlink). Let’s change gcc to point to the GCC 4.7 that we just installed. Don’t worry, this will be restored as soon as we’ve finished installing Cocotron’s tools:

$ sudo ln -sf gcc-4.7 gcc

(The $ sign is not part of the command, it just indicates the prompt.)

We can verify that the command gcc now indeed calls GCC 4.7:

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/hpc-gcc-4.7/bin/../libexec/gcc/x86_64-apple-darwin11.3.0/4.7.0/lto-wrapper
Target: x86_64-apple-darwin11.3.0
Configured with: ../gcc-4.7-20120204/configure --enable-languages=c,c++,fortran
Thread model: posix
gcc version 4.7.0 20120204 (experimental) (GCC)

Now that we have a compiler that’s known to work for the job at hand, we can proceed with installing Cocotron. Download the latest installation package from here:

Install CDT Tools
(at the time of writing, the latest file was InstallCDT-2011-12-27.zip)

Unzip InstallCDT, and you have a folder containing a bunch of shell scripts. In the Terminal, go to the InstallCDT folder and enter:

$ sudo ./install.sh

(Now you may be asking: does this install script really need to run as root? I first tried it without sudo, but the installation failed at the last moment. Since the script takes quite a long time to run – it’s building a whole compiler, after all – I didn’t feel like experimenting to figure out what’s going wrong.)

After the script has finished and you’ve had a cup of coffee, you can check that the Cocotron cross-compiler was correctly installed:

$ /Developer/Cocotron/1.0/Windows/i386/gcc-4.3.1/bin/i386-mingw32msvc-gcc -v
Using built-in specs.
Target: i386-mingw32msvc
Configured with: /Developer/Cocotron/1.0/Source/gcc-4.3.1/configure [...]
Thread model: win32
gcc version 4.3.1 (GCC)

i386-mingw32msvc? What kind of platform is that? Well, this monster acronym is basically GNU-speak for “plain old Windows”. MinGW is the project that provides GNU-compatible tools for Windows that use Microsoft’s standard infrastructure to the maximum extent possible. (There’s another project, Cygwin, that provides a complete GNU userland running on Windows but is not as compatible as MinGW. You can’t mix the two.) After mingw, the platform identifier has the number 32, which indicates that we’re going to be building 32-bit binaries. Finally there’s msvc, which is short for “Microsoft Visual C” — this indicates that this compiler produces binaries that link against Microsoft’s default C runtime, which is available on all Windows versions out there. So this is all good: we can use this compiler to produce binaries that work on Windows without needing any extra DLLs or other baggage.

CDT is in place, so it’s time for the post-install cleanup! First, let’s put the gcc symlink back the way it was:

$ sudo ln -sf /usr/bin/llvm-gcc-4.2 /usr/bin/gcc

Secondly, let’s apply more reasonable permissions to the Cocotron folders. Because I ran the CDT installer with sudo, everything in Cocotron is owned by root. That would make life difficult because our projects will need to write into those folders e.g. when building in Xcode. Here’s the fix:

$ sudo chmod -R a+rwx /Developer/Cocotron/

Building the frameworks

With the Cocotron Developer Tools installed, we can move on to the genuine meat of this juicy cross-platform hamburger – the Cocotron frameworks. These are hosted on Google Code. (If you want to have a look around the source beforehand, try browsing. In my humble opinion Cocotron is very cleanly organized for such a major project, so it’s easy to just look around.)

Google Code uses Mercurial, a distributed version control system that’s rather similar to Git (but quite different from CVS and SVN). If you don’t have Mercurial installed, you’ll need to do that first. You can get it through a package manager like Homebrew or MacPorts, or you can just download binaries from here:

Mercurial binary packages for Mac OS X

With Mercurial installed, you can “check out” your own local copy of the Cocotron source tree. Here are the instructions:

Instructions for cloning the Cocotron source repository

(If you’re new to Mercurial, have a look at their rather excellent Guide before going too crazy with commands – distributed version control may take some time to get used to the concepts and possibilities, but it’s definitely worth it.)

Once you’ve cloned the Cocotron source tree, you can build the projects. (Finally some Xcode action!)

Although there are a few dozen projects right under the “cocotron” root, don’t worry, you don’t need to build them all! Cocotron is organized so that most of the frameworks are just subprojects that are incorporated into one of the main projects that depend on their functionality. For example: building Foundation also builds CoreFoundation, and building AppKit also builds CoreText.

It’s easiest to start by building Foundation. Open Foundation.xcodeproj into Xcode. Click on the Targets button in the toolbar, and you’ll be presented with a rather bewildering array of targets to build:

Cocotron Foundation in Xcode 4.3

(See? I told you that Cocotron supports lots of platforms.)

Pick Foundation-Windows-i386 in this list. Next, we need to change the build configuration. This is a part of Xcode that was completely revamped in version 4, for reasons that are somewhat mysterious to me… Previously it was very easy to switch between Debug and Release build modes. Now, it’s a bit more tricky. If one doesn’t pay attention, it’s easy to accidentally build with the wrong mode.

For Cocotron, we always want to use Release mode. Trust me on this. Maintaining two sets of binaries is too much of a pain, and there’s nothing much to be gained by having a debug build on Windows anyway. (By the way, you can use gdb, the GNU debugger, on Windows to debug Objective-C binaries.)

So, before building Foundation, ensure that it’s going to be built using the Release configuration. With the Foundation-Windows-i386 target selected, choose Edit Scheme from the same toolbar menu. This view will open:

Cocotron build configuration in Xcode 4.3

Select Release under Build Configuration. Now you’re ready to build Foundation.

Congratulations – with Foundation in place, you now have a minimal Cocotron installation. You could take a Mac OS X command-line tool that uses Cocoa’s Foundation classes and build it for Windows. (Setting up the Windows target requires certain magic incantations, of course. I’ll get to that later.)

Next you can build AppKit using the same procedure as with Foundation: choose the right target, check the build configuration.

Building AppKit may require some setup if you want to include certain features. It’s possible to add support for things like JPEG writing and PDF compression, but these depend on external libraries (libjpeg and zlib, respectively).

Like I mentioned above, Cocotron has a policy of no dependencies: the base frameworks don’t depend on anything else. The same need not apply to your apps, of course. In practice most apps use libraries other than just Cocoa, so supporting installation of libraries is fairly important.

It’s pretty easy to make libraries available to Cocotron. I’ll show you how soon — but first, walk with me into the folder structure…

What lives in /Developer/Cocotron

As you may have noticed, Cocotron installed itself in the folder /Developer/Cocotron. As of version 4.3, Xcode itself doesn’t use /Developer anymore, but that doesn’t bother Cocotron – the folder was created by the InstallCDT script. (If you’re using an older Xcode, Cocotron will happily live alongside Xcode in /Developer/Cocotron.)

Under Cocotron’s folder, a deep structure unfolds. There’s a version-numbered folder, currently 1.0, which contains the Cocotron installation. Here are the downloaded files, sources, and utils. Platform-specific components are located under the platform’s name. So, my Cocotron Windows installation is in /Developer/Cocotron/1.0/Windows/i386:

Cocotron's Windows/i386 folder

I’ve got a bunch of libraries installed here. I’ll get to that in a moment, but first let’s take a look at Frameworks. Everything that we built from the Cocotron sources ends up here. There’s Foundation.framework, AppKit.framework, etc. These files are bundles, just like regular Mac OS X frameworks. The contents are a bit different:

Cocotron Windows AppKit folder

As you can see, there’s a symlink to a Windows dynamic library file, AppKit.1.0.dll (the actual file is located under Versions). There’s also an import library, libAppKit.a, which provides the symbol definitions so that the GCC linker can link our Windows executables against this Windows AppKit DLL.

Going back a bit – what about those other libraries? The convention on Cocotron is that libraries are installed in the platform folder. Each library goes in its own folder which has include and lib subfolders. (The former of course contains the headers needed for compilation, while lib contains the import library for linking.)

When deploying your app on Windows, you’ll also need the DLL file for the library. Windows’s dynamic library loader is not able to do complicated guided lookups for DLLs, so it’s easiest to place it in the same folder as your executable. (This same operation needs to be done for the Foundation and AppKit DLLs, but Cocotron provides a tool called retargetBundle that can handle this. I’ll explain that later.)

Where do you get these libraries for Cocotron? If you have the headers + import lib + DLL at hand, you can just make the folder structure by hand. Alternatively, in the InstallCDT zip file, there are a number of scripts that install libraries. You can try these. (I tried to install libz this way, but for some reason the install script didn’t give me the right import library. I made a bug report; it includes the missing file, if you have this same problem.)

To be continued

I’m afraid this Part 1 must end here. We now have Cocotron fully installed, and an idea of how the system is set up. What we don’t know yet is how to build an actual app for Windows. Clearly that’s going to be the focus for Part 2, then.

You can of course explore ahead on your own. There are sample projects on the Cocotron site. These can be used as a model for setting up your own Windows targets.

Thank you very much for actually reading this far! Don’t hesitate to let me know if you have any comments or problems.

Part 2 →

This entry was posted in Mac-related, Programming. Bookmark the permalink.

19 Responses to Win-win with Cocotron and Xcode 4.3 — code for Mac, build for Windows (Part 1)

  1. Gustaf says:

    Really great introduction! Thanks!

  2. John Fox says:

    Many thanks for this incredibly detailed and helpful post. As old-timer who remembers OpenStep, I’m happy to see that the ideal of cross-platform AppKit is still alive.

  3. Dave says:

    Pauli, great post and tutorial! I have need of the Cocotron again after a few years. I’ve run into one snag, though, when I try to compile Foundation for windows, I get the error “Unsupported compiler ‘Cocotron 1.0 Windows i386 gcc 4.3.1′ selected for architecture ‘i386′”

    gcc 4.3.1 doesn’t show up in the list of compilers available. Any ideas? Looking forward to part 2!

    Dave

  4. Dave says:

    Figured out my problem. I had some old pbcompspec files in my ~/Library/Application Support/Developer/Shared that were causing a conflict. Good to go!

  5. kirk kerekes says:

    Timely (for me) and useful piece.
    Thank you for expending the non-trivial effort to document the process.
    I would only add that Apple’s conversion of Xcode into a standalone app containing the Developer hierarchy has been a (possibly unintended) blessing for Cocotron — the /Developer/… tree is now free for Cocotron and others of their ilk to use at will without potentially getting trashed by Apple developer updates. I hope to see a downstream InstallCDT that Just Works™ with the new Xcode, preferably with full LLVM/CLANG support — but until then, this is the way to go.

    Of course the clever thing would be to have an InstallCDT that is (surprise!) packaged as a standalone app, just like XCode, and which does all necessary download install and build ops without significant user intervention. It could reside in the Applications directory, just like XCode, and have all of its Cocotron-specific items nestled safely inside the app directory — just like XCode.

    My goodness, it might even be possible to get it into the app store! (assuming that Apple gets its scheme for sandboxing and app validation sufficiently straightened out!)

    Vagrant thought — when OS-X finally moves to OS-XI, what will Xcode be called?

  6. Vincent R says:

    Hi,

    I am really waiting for part 2 because now I would like to create a small command line application and test it on windows.

  7. Jim Wolff says:

    Pauli,
    I’m using Xcode 4.3.1. I’ve followed your instructions but when I try to compile the Foundation-Windows-i386 target I get “Unsupported compiler ‘Coctron 1.0 Windows i375 gcc 4.3.1′ selected for architecture ‘i386′. Everything else was installed right (e.g. /Developer/Cocotron/1.0/Windows/i386/gcc-4.3.1/bin/i386-mingw32msvc-gcc -v shows right info).

    It’s as if install.sh doesn’t install the right compiler templates for Xcode 4.3.1 to recognize. In old cocotron using older Xcode you used to have to go to the “Build Rules” for the target and set a C Rule for the cocotron compiler and a Windows resource files rule. However the coctron compiler isn’t listed there any longer.

    As a result, I cannot compile the Cocotron frameworks nor my projects any longer. Any idea what I’m doing wrong or how to fix this?

    –Thanks

  8. Paolo says:

    Looking forward part 2!

  9. scott says:

    Hmmm. I guess windows is the default for installCDT/install.sh — so I finally found “Linux” (since it won’t take ‘linux’) … and this is what I get:

    ./InstallCDT/install.sh Linux
    Done.
    No download needed for /Developer/Cocotron/1.0/Downloads/gcc-4.3.1-02242010.tar.bz2
    No download needed for /Developer/Cocotron/1.0/Downloads/gmp-4.2.3.tar.bz2
    No download needed for /Developer/Cocotron/1.0/Downloads/binutils-2.21-20111025.tar.gz
    No download needed for /Developer/Cocotron/1.0/Downloads/mpfr-2.3.2.tar.bz2
    -n Unarchiving /Developer/Cocotron/1.0/Downloads/gcc-4.3.1-02242010.tar.bz2 …
    done.
    -n Unarchiving /Developer/Cocotron/1.0/Downloads/binutils-2.21-20111025.tar.gz …
    done.
    -n Unarchiving /Developer/Cocotron/1.0/Downloads/gmp-4.2.3.tar.bz2 …
    done.
    -n Unarchiving /Developer/Cocotron/1.0/Downloads/mpfr-2.3.2.tar.bz2 …
    done.
    Interface (headers, libraries, etc.) not present at /Developer/Cocotron/1.0/PlatformInterfaces/i386-ubuntu-linux, exiting

    Does anyone know if there is any documentation ANYWHERE that tells how
    to install cocotron to compile for linux — and NOT windows?

    Thanks!

    Scott

  10. Gonzalo says:

    This tutorial/intruduction is super great. Hope you have some time to write the second part soon. Looking forward for it. Thanks!

    PS: Didn’t find any AdSense banner to click on, you really deserve it :P

  11. Roland says:

    Pauli,
    I have the same problem as Jim Wolff. Has you already a fix for this problem?

    -Thanks

  12. Krzysztof says:

    Great post, helped me a lot in installing CDT. Can’t wait for the follow up, so I can finally compile something using it.

  13. Sensheng Xu says:

    Thank you for your sharing!
    I just followed your guide, but tried to build the CDT using default gcc provided by Xcode and everything seems well. Maybe hpc-gcc is not MUST-HAVE?

    • Sensheng Xu says:

      OK you’re right. Using default gcc just occurs something wrong with CDT , so Cocotron can’t be built. Will download hpc-gcc and build CDT again.

  14. Jack Dangler says:

    Wanted to know if installing the package version can be upgraded to 7.4.2 or does the installation package you assembled download/install the latest version? Thanks for the great information. I’m looking forward to the next part once this is setup.

  15. sandeep says:

    I downloaded cocotron on mavericks, got gcc 4.9 for mavericks from hpc and tried to run sudo ./install.sh from InstallCDT directory. I get an error
    checking for struct pst_processor.psp_iticksperclktick… no
    configure: error: no version of add found in path: x86/p6/p3mmx x86/p6/mmx x86/p6 x86 generic

    Has anyone got this to work on mavericks?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>