rakudo / star

Rakudo Star (Raku distribution)
https://rakudo.org/
Artistic License 2.0
266 stars 41 forks source link

Fix DMG creation on newer versions of macOS #126

Closed clarkema closed 5 years ago

clarkema commented 5 years ago

The only problem with building on more recent versions (this was tested on 10.14) seems to be the deprecation of utilities used for setting the icon on the perl6 executable.

Evidently this is only possible now via Cocoa APIs. The usual solution seems to be using the system Python, which comes with a Cocoa module.

lizmat commented 5 years ago

OOC, how difficult would it be to do the necessary Cocoa calls with NativeCall ?

clarkema commented 5 years ago

I have absolutely no idea. As the diff shows we don't need much Cocoa, and it would certainly be nice to have a reusable module in the Perl ecosystem for this rather than having to farm out to Python, but I haven't played with either NativeCall or Cocoa.

clarkema commented 5 years ago

After a bit more experimentation this evening I have a PoC version of CLI tool to set file icons in Swift. This allows for at least some minimal error checking, so might end up being the way forwards.

clarkema commented 5 years ago

Note that the Python version will almost certainly support building on older versions of macOS than the Swift version, since the language spec for the latter is still evolving quickly. I don't have any versions of macOS older than 10.14 available right now to test on.

scovit commented 5 years ago

Not that I care about icons, but I own a Mac. Just for curiosity, I came out with a Perl 6 version of your script, although I had to make up a hack to load the AppKit framework and didn't dare to add any sugar to the objC interface, please feel free to take inspiration!

#!/usr/bin/env perl6

use NativeCall;

INIT symlink '/System/Library/Frameworks/AppKit.framework/AppKit', './libAppKit.dylib';
END  unlink './libAppKit.dylib';

constant \kCFStringEncodingUTF8 = 0x08000100;
constant \LIB = "AppKit";

sub CFStringCreateWithCString(Pointer, Str, int32 --> Pointer) is native(LIB) { * };
sub NSSelectorFromString(Pointer --> Pointer) is native(LIB) { * };
sub sel_getUid(Str --> Pointer) is native(LIB) { * };
sub objc_getClass(Str --> Pointer) is native(LIB) { * }
sub objc_msgSend0(Pointer, Pointer --> Pointer) is native(LIB) is symbol('objc_msgSend') { * }
sub objc_msgSend1(Pointer, Pointer, Pointer --> Pointer) is native(LIB) is symbol('objc_msgSend') { * }
sub objc_msgSend3(Pointer, Pointer, Pointer, Pointer, Pointer --> Pointer) is native(LIB) is symbol('objc_msgSend') { * }

sub CFSTR(Str $str --> Pointer) {
   CFStringCreateWithCString(Pointer, $str, kCFStringEncodingUTF8)
}

sub MAIN(Str $target, Str $icon) {
   my $img = objc_getClass("NSImage");
   $img = objc_msgSend0($img, NSSelectorFromString(CFSTR("alloc")));
   $img = objc_msgSend1($img, NSSelectorFromString(CFSTR("initWithContentsOfFile:")), CFSTR($icon))
      or die "Failed to load icon";

   my $wrk = objc_getClass("NSWorkspace");
   $wrk = objc_msgSend0($wrk, NSSelectorFromString(CFSTR("sharedWorkspace")));
   $wrk = objc_msgSend3($wrk, NSSelectorFromString(CFSTR("setIcon:forFile:options:")),
                        $img, CFSTR($target), Pointer) 
      or die "Failed to set icon";
}
clarkema commented 5 years ago

Thanks @scovit! Really interesting to see how it would look using NativeCall :)

In this instance I think I'm going to go ahead and merge the Swift version, just because it feels a little less magic is involved. It does add a dependency on /usr/bin/swift, but we know that has to be available anyway if we're building using the macOS dev tools.