Entries tagged “mac os x”

Unicode precomposition and decomposition

As a result of recent Mac troubles, I moved my iTunes library to a Linux file server and setup iTunes on my old TiBook to access the library over an AFP share using netatalk.

This worked unexpectedly well, until I noticed something very odd: I could no longer access any file whose name contained an accented character such as “é”. These files showed up in directory listings but were not readable. The filesystem complained that the file just did not exist. After a whole evening lost trying to find fault with everything from Mac OS X to netatalk, I found myself in unfamiliar Unicode territory:

It turns out there are two ways to represent certain accented characters such as “é” in Unicode, either using unique code points (U+00E9, “latin small letter e with acute”) or using a regular ASCII character “e” with a combining diacritical mark (U+0065, “latin small letter e” followed by U+0301, “combining acute accent”). The first form is known as “precomposed” and is the standard for filenames on Linux, while the latter “decomposed” form is standard on Mac OS X.

The Mac approach is unusual but has the advantage of making accent insensitive search easier. A string search for “cafe” will also match “café” because the last character is really two; “cafeteria” can match for “caféteria” if one simply strips out diacritical marks. Doing this with precomposed strings is much harder. (Thanks to @deepakg for identifying this.)

Mac OS X enforces the decomposed form for filenames, but Linux doesn’t. On Linux, precomposed UTF-8 is expected but not enforced. The netatalk AFP server recognises this difference and transparently translates filenames between what it calls UTF8 and UTF8-MAC. This is where I ran into trouble. I had transferred my files using rsync and ended up with decomposed filenames on Linux. These showed up fine over AFP, but when Mac OS X attempted accessing them, netatalk did the transparent translation to precomposed names and could no longer find the files. The solution? Rename all files on the Linux side:

convmv -r -f utf-8 --nfd -t utf8 --nfc ./* --notest

And in future, when rsyncing files from Mac OS X to Linux, ask it to translate the filenames with this additional option (reversed for Linux to OSX):

rsync --iconv=UTF8-MAC,UTF8

Gtk# on Mac OS X revisited

So much for the fuss with getting Gtk# installed. I threw out the Mono framework package this evening, reinstalled it and the Gtk# packages from Fink, and now it all just works. No mucking with DYLD_LIBRARY_PATH and miscellaneous symlinks involved.

I’m looking forward to writing first class Windows apps on OS X.

.Net, Mono, Gtk# and IronPython on Mac OS X

Today’s development platform test was on Mono and IronPython with Gtk#. I was testing the feasibility of achieving three goals:

  1. Support both Windows and Linux with a single codebase, using either Microsoft’s .Net Framework or Mono.
  2. Provide a smooth learning curve for my existing .Net dev team.
  3. Use Python for rapid development, without resulting in disjoint codebases.

My current requirement is for several hundred Windows desktops that I’d rather be using a more maintainable operating system on. I’m bound to Windows by third party software that I must support, but don’t want my team’s own work to become a barrier to migration in future.

Mono doesn’t support Windows.Forms very well, so if I am to adopt it, the first task will be to replace WinForms with Gtk# in existing apps. For the evaluation today, I tried the most basic: getting Mono and Gtk# working, and maybe writing a “Hello, World” Gtk# app in Python. My primary environment is a Mac, which made this evaluation more interesting. Could I actually do my development on OS X and deploy on Windows and Linux? The Mono distribution for Mac OS X includes IronPython but not Gtk# (Cocoa# is bundled instead). Gtk# requires the Gtk+ library, which is not a standard component on OS X, and hence Mono’s understandable omission.

Compiling Gtk# involved jumping a few hoops. Basically: symlink the Mono C# compiler /usr/bin/mcs to /usr/local/bin/csc.exe, because Gtk#’s configure script assumes a Microsoft .Net Framework environment, and then edit all Makefiles to set RUNTIME = mono. That compiled it. To install, I had to create gtk-sharp-2.0 under /Library/Frameworks/Mono.framework/Versions/1.2.1/lib/mono and throw in symlinks to all the DLLs from their source location in ../gac.

I then tried this simple Gtk# example in C#:

using Gtk;
using System;

class Hello {

    static void Main()
    {
        Application.Init ();

        Window window = new Window ("helloworld");
        window.Show();

        Application.Run ();

    }
}

But it wouldn’t compile:

$ mcs HelloGtk.cs -pkg:gtk-sharp-2.0
Package gtk-sharp-2.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `gtk-sharp-2.0.pc'
to the PKG_CONFIG_PATH environment variable
No package 'gtk-sharp-2.0' found
error CS8027: Error running pkg-config. Check the above output.

Turned out there were two copies of pkg-config, one from Fink and one from Mono. The solution was to set a common environment variable:

export PKG_CONFIG_PATH=/sw/lib/pkgconfig\
:/usr/lib/pkgconfig\
:/Library/Frameworks/Mono.framework/Versions/1.2.1/lib/pkgconfig

The code compiled but still wouldn’t run:

$ mono HelloGtk.exe 

Unhandled Exception: System.DllNotFoundException: libgtk-x11-2.0.0.dylib
  at (wrapper managed-to-native) Gtk.Application:gtk_init (int&,intptr&)
  at Gtk.Application.Init () [0x00000] 
  at Hello.Main () [0x00000] 

Mono couldn’t find the Gtk+ libraries in /sw/lib. Fixing this was uglier; it required messing with the DYLD_LIBRARY_PATH environment variable:

$ export DYLD_LIBRARY_PATH=/sw/lib\
:/Library/Frameworks/Mono.framework/Versions/1.2.1/lib

HelloGtk.exe would run after this, but if I tried anything else, it failed complaining about missing libraries. I couldn’t find a solution. Anyway, I moved on Gtk# from Python, translating the code above line for line. It wouldn’t work. No known module named “Gtk”. Much head-scratching and Googling later, I learnt that IronPython needs a special invocation for .Net assemblies (that’s .Net speak for “libraries”). Here’s the code:

import clr
clr.AddReference('gtk-sharp')

import Gtk

Gtk.Application.Init()
window = Gtk.Window("helloworld")
window.Show()
Gtk.Application.Run()

Kushal has a slightly more elaborate example.