Tag Archives: osx

How to support old OSX version with a recent xcode.

About

In this post i decided to share my experience about supporting build for old MacOSX versions using recent xcode/clang. I found that this topic is very tricky and documentation is not covering many parts of it.

How things should work

I am currently using OSX 10.14.1 as a build host with a latest Command Line Tools installed (by xcode-select --install). SDK 10.14.1 should support compilation for any OSX starting from 10.9 to the 10.14. We can specify version to use using -mmacosx-version-min= switch which is used by compiler/linker to generate correct binaries from the target system. Sounds brilliant! So lets test this and see why it is not always as good as it could be.

Testing with plain C code

Lets start with a simple code. I will use clock_gettime as an example. This POSIX function was added in OSX 10.12 and frequently used in opensource software. Here is a sample code i will use:

/*
 simple gettime test
 */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#define BILLION  1000000000L;

int main( int argc, char **argv )
  {
    struct timespec start, stop;
    double accum;

    if( clock_gettime( CLOCK_REALTIME, &start) == -1 ) {
      perror( "clock gettime" );
      exit( EXIT_FAILURE );
    }
    sleep(1);

    if( clock_gettime( CLOCK_REALTIME, &stop) == -1 ) {
      perror( "clock gettime" );
      exit( EXIT_FAILURE );
    }

    accum = ( stop.tv_sec - start.tv_sec )
          + ( stop.tv_nsec - start.tv_nsec )
            / BILLION;
    printf( "%lf\n", accum );
    return( EXIT_SUCCESS );
}

So, lets start testing.

  1. clang -Wall -o gettime gettime.c gives no errors and producing working binary. We can test minimal supported version with otool -l gettime|grep -A 4 'LC_BUILD_VERSION' – in our case it is 10.14.
  2. Lets try to restrict version with 10.9. Command clang -mmacosx-version-min=10.9 -Wall -o gettime gettime.c silently producing output and gettime binary! Minimal osx version is now marked as 10.9. That is weird, but nm -a gettime shows reference to _clock_gettime symbol which should not exist on 10.9 at all! As expected, this binary fails if running on OSX 10.11:
        ./gettime
        dyld: lazy symbol binding failed: Symbol not found: _clock_gettime
          Referenced from: /Users/vagrant/./gettime
          Expected in: /usr/lib/libSystem.B.dylib
        dyld: Symbol not found: _clock_gettime
          Referenced from: /Users/vagrant/./gettime
          Expected in: /usr/lib/libSystem.B.dylib
        Trace/BPT trap: 5
    

    So despite the switch clang created broken binary!

  3. It is possible to disable weak imports by using -no_weak_imports linker flag. Lets try it:

    clang -Wl,-no_weak_imports -mmacosx-version-min=10.9 -Wall -o gettime gettime.c
    

    will fail to link with an error:

    ld: weak import of symbol '_clock_gettime' not supported because of option: -no_weak_imports for architecture x86_64.
    

Sounds like a solution! Moreover – we can add -Werror=partial-availability key and if it is used – compilation will fail early, with gettime.c:17:9: error: 'clock_gettime' is only available on macOS 10.12 or newer [-Werror,-Wunguarded-availability] error which is explaining where the problem is. So, looks like we can just add -Werror=partial-availability to C(XX)FLAGS and -Wl,-no_weak_imports to the link flags to solve all the issues?
Not so easy 😦

Testing with autoconf or cmake

In the real world software is typically built using some build system, which trying to detect what is available on the host to set defines accordingly. In the opensource world autoconf and cmake are very popular choices. Now lets try to see if we can build some projects with a compatibility flags set to 10.9. As a real-world example i will use XZ Utils which uses autoconf as a build system.

  1. Lets try to build XZ Utils 5.2.4 with default CFLAGS/LDFLAGS. Typical ./configure && make command should provide binary src/xz/.libs/xz with minimal supported OS set to 10.14. But out goal is to compile it for 10.9+, so lets do make clean
  2. Now lets try to set LD/CFLAGS to enforce 10.9 compatibility:
    export CFLAGS="-mmacosx-version-min=10.9 -Werror=partial-availability"
    export LDFLAGS="-Wl,-no_weak_imports"
    

    and re-run ./configure && make. This time build will fail with ../../src/common/mythread.h:250:19: error: '_CLOCK_REALTIME' is only available on macOS 10.12 or newer [-Werror,-Wunguarded-availability] error message.

Looking in the source it is clear that HAVE_CLOCK_GETTIME is set despite the fact that we used correct compiler and linker flags. Why it happens? Due to autoconf detection algorithm. To detect if function is available its trying to compile and link such simple code:

#ifdef __cplusplus
extern "C"
#endif
char clock_gettime ();
int
main ()
{
return clock_gettime ();
  ;
  return 0;
}

As you could see – autoconf includes own function prototype (because it only wants to check that function exists in the system) and in this case all linker/preprocessor version selection logic in clang/osx will just never run because it depends on definitions from the SDK headers.

Lets check this in the command line:

clang -mmacosx-version-min=10.9 -Werror=partial-availability -Wl,-no_weak_imports -o test test.c

will return no errors, but resulted binary will link to the _clock_gettime symbol which will be not available on target OS. I found that cmake checks are behaving exactly the same, resulting with a broken binary or compilation/link error if appropriate flags are set.

Workarounds

If it is your own code which does not have million dependencies – probably easiest way is to just patch autoconf/cmake checks to not prototype this functions but use system headers instead. However, if you have a tonn of dependencies – it would take huge amount of time to patch every failed one. So i found another workaround.

If recent (10.14) SDK is not easy to use in out scenario with autoconf/cmake lets use one from 10.9 🙂 I downloaded and unpacked 10.9 SDK to the /Library/Developer/CommandLineTools/SDKs/MacOSX10.9.sdk directory. I found that it is enough to set SDKROOT environment variable to the MacOSX10.9.sdk directory to fix the problem. In this case SDK will not contain any definitions of the non-compatible symbols and autoconf/cmake checks will work as expected, so you will get 10.9+ compatible Mach-O binary in the end of the game.

Summary

It is possible, but not trivial to keep compatibility with an older systems with a recent clang/OSX.

If you know better solution or workaround or just found this post useful – please let me know in the comments.

Advertisements
Tagged , ,

MacBook Pro USB-C 10G interconnection

I just found that it is possible to connect 2 2016 Macbook Pro laptops with an USB-C cable. Just in case – one from power adapter will not work, but another one from the Lenovo monitor works just fine. Connection is named as Thunderbolt Bridge in the network preferences.

There is no connection speed in the ifconfig output (just “active” mark), so decided to measure it with iperf3 – it shows about 4.20 Gbits/sec with default MTU on TCP test. And when i set MTU to 9000 i finally got 10.4 Gbits/sec, what is amazing 🙂 So now i know fastest and very easy method to transfer data between new macbooks just by using usb-c data cable. Rare moments when i really like Apple engineering 🙂

Tagged , ,

Smartmontools SVN builds

Smartmontools SVN builds (Linux, Windows, FreeBSD and OSX) are now available at https://builds.smartmontools.org/. Builds are done using docker and CircleCI and should be 100% repeatable. Keep in mind that these builds are not releases – some functionality could be broken or not yet completed.

Tagged , , ,

GIMP 2.10.6/OSX port released

You can download latest GIMP 2.10.6/OSX build from the github project page. Feel free to report any bugs. It will become an official download soon.

Tagged , ,

First release of the Gimp 2.10.2/OSX port

There is no [yet] official dmg package of the Gimp Open Source Image Editor for OSX, so i created a new one. Work is mostly done, there are few non-critical issues i am planning to fix meantime. Also my plans are to merge my patches with an upstream, so hopefully this would become official port at some point.

Testers are welcome. OSX build could be found on project releases page.

Tagged , ,

How my Mac Book Pro 2017 destroyed 2 USB-C devices

Bad things happens

At morning my new Macbook was not working well – when i been disconnecting charger it was not detecting this properly, so i decided to reset SMC, and this resolved the problem. In the office i connected my passive USB-C hub with HDMI/USB output and it starts to smell very bad. I was stupid enough to connect my USB-C ubikey to the same socket and it was destroyed immediately, with the same smell and some lights. Both devices were destroyed. MacBook was working like nothing happens.

I realized that i already saw post about it on Reddit and been able to find original post Macbook Pro frying USB peripherals. It was looking exactly as my case. So i decided to validate it.

Measuring USB-C power voltage

I do have usb-c->microusb adapter from some charger + microusb power to power adapter plug. I connected to cables to it and been able to measure the voltage, thats how it looks:

IMG_2982

Now i connected it to the voltmeter and plugged in to the affected port with a usb-c charger plugged in a different port:
IMG_8925

20V!!! instead of maximum 5 allowed. All other sockets were provided ~1v, probably that is idle current when no data lines are connected:
IMG_4172

I tried different combinations, but only top right socket was failing. So it seems to be another “known issue” in this new model, in addition to very problematic keyboard.

Summary

I been using only original charger with original cable but got usb-c devices fried. According to the post i provided below – i am not alone with such issue. Tomorrow i will send this Mac to repair and hopefully replacement will not be affected. I think that Apple engineers should consider this issue as very serious one, but giving the fact how they handle keyboard-related issues it seems to be unlikely.

Tagged , , ,

Reassigning ESC key on the MacBook Pro with a touchbar

There is no escape

I like an idea of the touch-bar, but removing physical Esc button is nothing but a pain, especially if you are using vi/vim, but not only. I been touching it accidentally, closing some windows, etc. No way, really. So i had to find a way to remap.

Remapping

OSX allows to remap Escape key, but its possible to use only few options (e.g. to use Caps instead). For me it was not looking like a good option. So i started to look for an alternative and found it.
Karabiner Elements allows you to remap any key. You can find name of the key in the Event Viewer. For me it was non_use_backslash (which is The plus-minus key “±”) to the escape.

Removing touch-bar Escape

To make touch-bar escape harmless i just re-assigned it to the “right shift” button. That`s how my my final configuration looks like:

That`s it. Remapping works in the GUI and terminal programs, no problems found so far. Interesting what key will be removed in the next model.

Tagged

PPTP on OSX Sierra

After upgrading to OSX Sierra (10.12.2) my PPTP connections just disappeared. Also it is not possible to create new PPTP connections anymore. Yes, i know that PPTP protocol is old, could be insecure, but i still need it to connect to some legacy systems. And, after all, i don`t like when someone telling me what should i do 🙂

After quick research it was found that actually only GUI part is removed, but PPTP is still in the Darwin internals. You can use it using pppd tool from the command line (using sudo). Configuration should be placed into /etc/ppp/peers/ directory, e.g. /etc/ppp/peers/pptpvpn. Here is a sample config, which works for me:

        plugin PPTP.ppp
        noauth
#        logfile /tmp/ppp.log
        remoteaddress gwvpn.example.com
        redialcount 1
        redialtimer 5
        idle 1800
        mru 1368
        mtu 1368
        receive-all
        novj 0:0
        ipcp-accept-local
        ipcp-accept-remote
        #noauth
        refuse-pap
        refuse-chap-md5
        user userid
        hide-password
        mppe-stateless
        mppe-128
        looplocal
        password userpw
        nodetach
        ms-dns 8.8.8.8
        # used in ip-up script
        ipparam gwvpn 

To connect to the VPN use pppd call pptpvpn command. Use man pppd for the possible options in the config. Hopefully it will still be there some time 🙂

Tagged , , ,