Skip to content
Colin Cogle edited this page Oct 10, 2024 · 3 revisions

aprs-weather-submit on macOS

It just works.

System Requirements

You will need a Mac running any version of macOS (also known as OS X and Mac OS X). The binary is compiled for PowerPC, Intel, and Apple Silicon, so it should run on pretty much any Mac ever made -- even the PowerPC 603 (XPostFacto users rejoice!).

The app, installer, and disk image are signed but not notarized. You may need to Control-click/right-click the disk image and/or the installer, and choose Open, to bypass Gatekeeper. This is normal. See the Roadmap below for my complaints.

Compilation

While there is no build script for macOS included, you can use the command-line gcc or clang tools to build this app.

Here are the steps to compile a combination Universal and Universal 2 Binary. If you want to build this from source to run on your own Mac, you won't need to go through all of these steps. These instructions are mainly for me, so I don't forget how to do this in between releases.

Preparing the Build Environments

No version of Xcode can compile for the five major architectures that macOS has supported, so you're going to need two Macs:

  1. The first Mac should be running Mac OS X 10.4 "Tiger" with Xcode 2.4, or Mac OS X 10.5 "Leopard" with Xcode 3. Be sure to install PackageMaker!
  2. The second Mac should be running macOS 11 "Big Sur" or newer, with the appropriate Xcode command-line tools installed.

The first Mac will compile code for PowerPC (ppc and ppc64) and Intel (i386 and x86_64) using Apple's version of GCC. The second Mac will compile for Apple Silicon (arm64 and arm64e) using Apple's version of Clang, then combine them into one six-way binary.

Build Script

I don't have a proper build script for macOS just yet, but this is what I run on the Tiger/Leopard Mac:

First Mac

#!/bin/sh
COMMON_ARGS="-Oz -std=gnu99 -fomit-frame-pointer -pipe -s src/*.h src/*.c -DHAVE_APRSIS_SUPPORT -lm"

# Compile for 32-bit PowerPC.  Try to target the first version of macOS.
gcc $COMMON_ARGS -DMACOSX_DEPLOYMENT_TARGET=10.0 -mmacosx-version-min=10.0 \
       -arch ppc -o aprs-weather-submit-ppc

# Compile for 64-bit PowerPC.  Though macOS 10.2 supported 64-bit command-line apps, I'm told, I wasn't able to use the MacOSX10.2.8 or MacOSX10.3 SDKs;  they wouldn't link correctly.  Thus, I'm targeting macOS 10.4.
gcc $COMMON_ARGS -DMACOSX_DEPLOYMENT_TARGET=10.4 -mmacosx-version-min=10.4 -isysroot /Developer/SDKs/MacOSX10.4u.sdk \
        -arch ppc64 -o aprs-weather-submit-ppc64 -maltivec

# Compile for 32-bit Intel.  The Core Solo is the earliest Intel CPU supported by macOS, so we can compile for i686 and assume MMX, SSE, and SSE2 support.  This might make our code a few nanoseconds faster.
gcc $COMMON_ARGS -DMACOSX_DEPLOYMENT_TARGET=10.4 -mmacosx-version-min=10.4 -isysroot /Developer/SDKs/MacOSX10.4u.sdk \
        -arch i686 -o aprs-weather-submit-i686 \
        -march=pentium-m -mtune=generic -mmmx -msse -msse2 -mno-sse3 -mfpmath=sse -m32

# Compile for 64-bit Intel.  The Core 2 Duo is the earliest Intel 64 CPU supported by macOS, so we can assume SSE3 will be available.  This may or may not make the app run a few nanoseconds faster.
gcc $COMMON_ARGS -DMACOSX_DEPLOYMENT_TARGET=10.4 -mmacosx-version-min=10.4 -isysroot /Developer/SDKs/MacOSX10.4u.sdk \
        -arch x86_64 -o aprs-weather-submit-x86_64 \
        -march=nocona -mtune=generic -mmmx -msse -msse2 -msse3 -mfpmath=sse -m64

# Now, combine them all into one four-way binary!
lipo -create aprs-weather-submit-ppc aprs-weather-submit-ppc64 aprs-weather-submit-i686 aprs-weather-submit-x86_64 \
     -output aprs-weather-submit

Copy this file to your newer Mac.

Second Mac

Run this script.

#!/bin/sh
# or whatever the default shell is; I was running this interactively.

COMMON_ARGS="-Oz -fomit-frame-pointer -pipe -flto -mmacosx-version-min=11.0 src/*.h src/*.c"

# Build an ARM64 build.
clang $COMMON_ARGS -arch arm64
strip a.out
mv a.out aprs-weather-submit-arm64

# Now do ARM64e.
clang $COMMON_ARGS -arch arm64e
strip a.out
mv a.out aprs-weather-submit-arm64e

# Build a six-way Universal/Universal 2 Binary
mv aprs-weather-submit aprs-weather-submit-ppc-intel
lipo -create aprs-weather-submit-ppc-intel aprs-weather-submit-arm64 aprs-weather-submit-arm64e \
     -output aprs-weather-submit
Sign the Code

If you don't have a code signing certificate, skip this.

codesign -s "YOUR CERT NAME HERE" --timestamp --deep --options runtime aprs-weather-submit

Build the Installer

On the first Mac, create a folder tree with the following files:

root/
   usr/
      local/
         bin/
            aprs-weather-submit
         man/
            aprs-weather-submit.1
      share/
         doc/
            aprs-weather-submit/
               AUTHORS.txt
               CHANGELOG.md
               LICENSE.rtf (download this from GNU.org)
               README.md
               SECURITY.gpg
               SECURITY.md
               (any other documentation I'm forgetting)

Use PackageMaker to build a nice graphical installer:

  • Use the root folder as your folder tree, using the default root/wheel permissions.
  • Select Administrator permissions! If you choose Root, you cannot install this on later versions of macOS.
  • Write some nice Welcome text for the first page of the installer.
  • Make a nice RTF version of README.md and use that on the second page.
  • Pick your license when prompted and use that.
  • Build the .pkg file.

Now, take the .pkg file to the second Mac and codesign that, too!

Make a nice disk image

You can zip up the .pkg file and distribute that, but let's make it all Mac-like. Use Disk Utility to create a blank disk image. Copy in the .pkg file and anything else you want to include (like the source code, license, README, and a link to GitHub). Make it look nice, then convert it to a read-only compressed disk image. Then codesign it, because apparently that's a thing macOS supports and expects.

Roadmap

There are some minor issues.

Notarizing the App

My code is signed, but it's not notarized, so recent versions of macOS will warn you or stop you when opening the installer. Control-click/right-click the installer and choose Open to get past it.

A code signing certificate was expensive enough! I'm not paying another $99/year just to notarize this app. If you're willing to do it for me, though, reach out!

Untested support for early versions of macOS

I had to compile my PowerPC binaries to support macOS 10.4 "Tiger". I wasn't able to link with the 10.2 or 10.3 SDKs without getting a lot of missing ppc64 symbols. If you have a Mac running macOS 10.3 or older, and you have Xcode or Project Builder installed, hit me up and we'll do some testing.

No support for iOS

I don't believe iOS supports stdio.h, so this may never work on iOS. Without a terminal, it'd be pretty useless anyway. However, if you can figure out an easy way to make this work (it'd be acceptable if it were only for jailbroken phones), feel free to submit a pull request! That being said, I could see someone using my code as a library, to create APRS packets for another app to use.

Not tested on ARM64e

macOS 11 introduced the arm64e architecture. This is some memory-safer variant of arm64. As of macOS 13 "Ventura", only arm64e binaries signed by Apple would run, with all others being killed. This is because the ABI was not yet stable. I don't know if that's changed in the latest macOS, but just in case, my app includes an ARM64e build. If someone could test it on Apple Silicon, that'd be great.

Not optimized for other architectures, but that's okay.

The version of GCC I used on macOS Tiger supports other architecture variants such as ppc603e, ppc604e, ppc7400 (G4), ppc7450 (G4e), ppc970 (G5, 32-bit code); and sometime around macOS 10.8, x86_64h (Haswell) showed up. However, the compiled code was functionally identical, even when forcing things like AltiVec and SSE4.2, so my binary doesn't include those sub-architectures. If you're compiling this code for your system, feel free to use one of these. I can't promise it'll be faster, but it will compile and run.