Fixing Mojave's brew install of netcdf

homebrew does not yet officially supports OSX 10.14 -Mojave-.

As such, its netcdf install is broken.

Fix

Mojave tends to drop 32bits supports. As such, the way introspecting binaries has changed.

Fix it as follows:

$ brew edit netcdf

Comment out (with a BOL #)

# SIP causes system Python not to play nicely with @rpath
# libnetcdf = (lib/"libnetcdf.dylib").readlink
# %w[libnetcdf-cxx4.dylib libnetcdf_c++.dylib].each do |f|
#   macho = MachO.open("#{lib}/#{f}")
#   macho.change_dylib("@rpath/#{libnetcdf}",
#   macho.write!
# end

Fixing Mojave's brew install of Qt

homebrew does not yet officially supports OSX 10.14 -Mojave-.

As such, its Qt install is broken. Also, it does not symlink to /usr/local because of it's cmake issue.

BEWARE, the following is not a fix. It is theoretically WRONG.

Fix

Fix it as follows:

For each file in:

  • /usr/local/lib/cmake/Qt5Core/Qt5CoreConfigExtraMkspecDir.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QCocoaIntegrationPlugin.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QFlatpakThemePlugin.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QGifPlugin.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QICNSPlugin.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QICOPlugin.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QJpegPlugin.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QMacHeifPlugin.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QMacJp2Plugin.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QMinimalIntegrationPlugin.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QOffscreenIntegrationPlugin.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QTgaPlugin.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QTiffPlugin.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QTuioTouchPlugin.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QVirtualKeyboardPlugin.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QWbmpPlugin.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QWebGLIntegrationPlugin.cmake
  • /usr/local/lib/cmake/Qt5Gui/Qt5Gui_QWebpPlugin.cmake
  • /usr/local/lib/cmake/Qt5Sql/Qt5Sql_QSQLiteDriverPlugin.cmake

Comment out (with a BOL #)

For Qt5Core:

# set(_qt5_corelib_extra_includes ...

For Qt5Gui:

# _populate_Gui_plugin_properties ...

For Qt5Sql:

# _populate_Sql_plugin_properties ...

Then:

# brew link qt --force

Fixing Mojave's brew install of cmake

homebrew does not yet officially supports OSX 10.14 -Mojave-.

As such, its cmake install is broken.

Fix

For some reason, the cmake binary has wrong permissions.

Fix it as follows:

$ chmod 744 /usr/local/bin/cmake
$ chmod 744 /usr/local/bin/ccmake
$ chmod 744 /usr/local/bin/cmakexbuild

On code injection on MacOSX High Sierra - continued

nil

This the second post in the series on MacOSX code injection using MIP. The latter makes it very trivial to inject code into existing application, let's focus on the following use case: use newly introduced Apple's API for dark appearance windows. For the special case of Terminal.app.

For this, we need to understand a little bit about an Objective-C/Cocoa application lifecycle. I won't make a fuss about it but for the sake of what follows, just consider that it implies many design patterns, and that windows are managed by NSWindowController.

Objective-C has that awesome feature that is, you can extend existing classes using categories. It then ends in finding a hook to replace a relevant method, in this case, - (void)windowDidLoad.

The implementation

Using MIP, code injection ends up in writing a few line of codes compiled as a Bundle, and the corresponding Info.plist in order for MIP's injector to know when to act.

Let's start with the category interface, that simply declares a method that will be used in place of another by the Objective-C runtime.

// Version: $Id$
//
//

// Commentary:
//
//

// Change Log:
//
//

// Code:

#import <AppKit/AppKit.h>

// ///////////////////////////////////////////////////////////////////
//
// ///////////////////////////////////////////////////////////////////

@interface NSWindowController(DarkTerminal)

- (void)injected_windowDidLoad;

@end

//
// DarkTerminal.h ends here

Let's continue with it's implementation. A + (void) load class method is loaded whenever the category is discovered. It replaces the stock implementation with the custom one.

// Version: $Id$
//
//

// Commentary:
//
//

// Change Log:
//
//

// Code:

#import <Cocoa/Cocoa.h>

#import <objc/runtime.h>

#import "DarkTerminal.h"

// ///////////////////////////////////////////////////////////////////
//
// ///////////////////////////////////////////////////////////////////

@implementation NSWindowController(DarkTerminal)

+ (void)load
{
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(windowDidLoad)),
                                   class_getInstanceMethod(self, @selector(injected_windowDidLoad)));
}

- (void)injected_windowDidLoad
{
    NSLog(@"MIP - injected_windowDidLoad");

    self.window.titlebarAppearsTransparent = true;
    self.window.titleVisibility = NSWindowTitleVisible;
    self.window.styleMask |= NSWindowStyleMaskTexturedBackground;
    self.window.appearance = [NSAppearance appearanceNamed:NSAppearanceNameVibrantDark];
}

@end

//
// DarkTerminal.m ends here

Finally, the mandatory Bundle's Info.plist. Note the MIP* directives.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>MIPUseBlacklistMode</key>
  <false/>
  <key>MIPBundleNames</key>
  <array>
    <string>com.apple.Terminal</string>
  </array>
  <key>MIPExecutableName</key>
  <string>Terminal</string>
  <key>CFBundleExecutable</key>
  <string>DarkTerminal</string>
  <key>CFBundleIdentifier</key>
  <string>local.DarkTerminal</string>
  <key>CFBundleInfoDictionaryVersion</key>
  <string>6.0</string>
  <key>CFBundleName</key>
  <string>DarkTerminal</string>
  <key>CFBundlePackageType</key>
  <string>BNDL</string>
  <key>CFBundleShortVersionString</key>
  <string>1.0</string>
  <key>CFBundleVersion</key>
  <string>1</string>
</dict>
</plist>

Using the Makefile as shown on Github, installs the Bundle is MIP's standard location.

Note

Beware that code injection is risky and can lead to undefined behavior. In this case, the hooked method - (void)windowDidLoad has a default empty implementation, which makes our approach safe. However when it is not the case, method swizzling is a preferred pattern, even though I did not get it to work yet.

On Code Injection on MacOSX High Sierra

nil

I've always fancied tweaking my system, and a distribution like ArchLinux and its open source Window Managers seem like a fine solution. However, I've been using MacOSX for ages, and despite the fact I'm having a close look at Xiaomi's expansion, I'm still in love with Darwin, a little bit less with Quartz.

Today I came across MIP a code injection platform that doesn't go for the obvious. Here's a starting guide to have it installed.

Disclaimer

The following is the first of a series of posts about code injection. It supposes SIP (System Integrity Protection) to be turned off at your own risks.

Prerequisistes

First, to build MIP, you'll have to create yourself a code signing identity. For now, we'll start with a self generated one.

Open Keychain Access.app and the menu, choose Keychain Access > Certificate Assistant > Create a Certificate.

nil

Follow the wizard, filling up fields to your likings, the certificate will end up in the login section of the Keychain Access application.

MIP

Building MIP is then straigthforward.

$ brew install binutils
$ cd ~/Development
$ git clone https://github.com/LIJI32/MIP.git mip
$ cd mip/MIP
$ emacs -nw -Q Makefile
$ # set SIGN_IDENTITY ?= "Julien Wintz" to match the name of your profile
$ make
$ make install