Hacker News new | ask | show | jobs
Show HN: TinyClock – a tiny true 5-arch universal Mac OS X single-binary GUI app (tycho.sytes.net)
192 points by zeymejbdv 1383 days ago
1. Single universal binary, that can be natively executed on every hardware platform Mac OS X was made for (32/64 bit, PowerPC/x86/AppleSilicon).

2. Minimalistic gadget-style design. If launched as a tool, there is no menubar, no dock icon, no nothing, just the clock window.

3. Support for hidpi and dark mode for environments, that have them.

4. Window title bar for moving the window with a mouse, and a handle to resize it (latter for OS versions, that have it).

5. Can be easily ported to GNUStep and thus other OSes (sources under GPLv3).

6. Simple Makefile build system.

15 comments

A much more impressive universal macOS application in my mind is the X Lossless Decoder (XLD), which you can run natively on PowerPC (32), Intel (32/64) and ARM (64). Not only is it a great app if you need to rip CDs or transcode audio, but the fact that it still runs on every Mac architecture is rather impressive.

https://tmkk.undo.jp/xld/index_e.html

Would it be possible to create a true universal binary that also runs on NeXT/Openstep on 68k, SPARC, PA-RISC and x86 as well as Rhapsody on PPC and x86?
This requires some investigation. Technically, I believe it is possible if the following 2 conditions are met:

1. The Mach-O executable format was not changed between all those OS versions (likely).

2. It is possible to gather sub-binaries for one CPU type but different OS types (less likely).

And SDK's and compillers (in emulator or on hardware) are required to try.

> Apple already documents that you could have a five-way binary

But enough about my private life. You're making us blush

I had a closer look at the earliest available NeXTstep version (0.8) running in the previous emulator - I still need to refurbish the MO drive in my Cube to run it natively (I have a 68030 CPU board)... C and ObjC compilers (though the objc.exe (!) provided seems to be a source-to-source compiler) are included in the image available on winworldpc and I can compile the included demo source code.

It seems that this early version is significantly different from later NeXTstep (3.3) and OpenStep versions. For example, it does not use app bundles. System apps installed in the /Apps folder, such as Terminal, are simple Mach-O executable m68k binaries.

If we wanted to target such an early NeXTstep, in addition, the source code of TinyClock would have to be changed significantly. One problem is that early versions of AppKit used "NX" instead of "NS" prefixes. More difficult is that a number of classes used by TinyClock seem to be unimplemented - not even NSString (resp. NXString) seems to be available. More complex classes such as NSCalendarDate or NSBezierPath also seem to be a later addition (unless the 0.8 install image is missing some header files, the earliest documentation I could find was on 1.0).

So it seems that a completely universal binary is out of the question, unfortunately.

1 is true, 2 is not.
Curiously it doesn't seem to run on my Intel Macbook running Big Sur - the icon is crossed out and I get

> “TinyClock.app” needs to be updated.

> The developer of this app needs to update it to work with this version of macOS. Contact the developer for more information.

https://jdon.at/Uff03u

It only has i386, ppc, and arm64 slices. So, an Intel Mac running recent macOS won't be able to launch it as it does not have an x86_64 slice (32-bit x86 execution having been removed).

Whether an app containing code for 3 architectures qualifies as "true 5-arch universal" is in the eye of the beholder I guess.

Interesting! I wonder why they didn't include x86_64. Doesn't seem likely to be problematic since it supports PPC64 and ARM64.

Edit: answered my own question by reading the actual page — "Unlike done in previous project, netop Tiger SDKs (used to build several intermediate binaries) don’t contain 64-bit AppKit versions, and thus ppc64 and x86_64 binaries are excluded from the binary release."

The binaries were updated and now include all the slices:

lipo -info TinyClock.app/Contents/MacOS/TinyClock Architectures in the fat file: TinyClock.app/Contents/MacOS/TinyClock are: i386 x86_64 ppc64 ppc arm64

Seems like it’s literally not “5-arch” then. 32 bit PPC, 64 bit PPC, 32 bit X86, 64 bit ARM.
It actually doesn’t have ppc64 either. Just 3 slices.
Same on 2019 Intel iMac running Monterey.
144K altogther. Delightful achievement! Most app icons are bigger than that nowadays.
Doesn't work on 10.0: https://0x0.st/ofjW.png

Not only does the binary not load, but the dmg itself won't extract, it just opens to a blank Disk Copy window no matter what you try to do.

IMO CarbonLib is more impressive as you can target MacOS 8.1-9 as well as X (up until x86 support was dropped).

> To obtain the full source tree do:

> bzr clone https://tycho.sytes.net/TinyClock/

I am surprised to find git not having built in support for cloning Bazaar repos. Almost as surprised as I am at finding a Bazaar repo in the wild.

For a bit of comparison, Windows 2.03's (analog!) clock:

    CLOCK    EXE      8960   9-04-87  11:11a
...will run on Windows 2.0 up to Windows 10 x86.
OClock and "aclock" statically built can be run under older kernels up to today's distros.

Oh, and it will run and render over the network with paleolitic Unixen thanks to X :).

Yeah but doing a static build is probably hard because you need a static build against x?
X works seamlessly, it's a client/server arch. Even if you run emulators, by exporting $DISPLAY to your host (and by running xhost +$EMULATOR_IP) you can run, for example, tools for older Unixen.

Except for SGI, but I am not that sure.

X's IPC is very stable (which is half the point of X); the instance on shared libraries has more to do with it being a memory hog on the kinds of systems that existed the first couple decades of it's life.
This. If you rum SIMH to emulate a Vax (and some other Unix), most Unix programs requiring X can be perfectly forwarded to use the host's X server. Or some Xephyr server.
I used to bring up openvms running Motif on a vax through xfree86.
I happened to have my 12" PowerBook G4 out, I just installed Sorbet Leopard* on it. I downloaded TinyClock and it's working on it.

*Sorbet Leopard is a modern update of Leopard, incorporating speedups from Tiger and the unreleased PPC Snow Leopard.

I want System 6 support for my SE/30 from 1989.
Check out Retro68, I still write classic mac apps using this toolchain.
What does 5-arch mean? Single Google yielded nothing (which may be more of a comment on Google's quality as of late)
It's not a common term. They're saying the exact same code will run successfully on 5 different CPU types (architectures).

I'm reminded of the Feynman "why" video. The other answers are technically more accurate than mine, and even mine assumes you understand the concept of CPU types. It's difficult to pitch answers at the right level.

Imagine you translate a book into 5 different languages. Then bind the five translations into a single volume. At the front, you put a brief table of contents listing the page number at which each translation begins. Each reader opens the book, checks the table of contents, then jumps to the page containing the translation in their language. All readers are reading the same book, but each reads the translation in their language. Unless you don’t know any of those five languages, in which case the book is unreadable for you.

Technically more accurate and complete than your answer, but an analogy I expect most non-technical people could understand.

AKA any instruction manual in Europe? (French/English/German/Spanish/Italian and so on).
It's a very impressive accomplishment. I support retro mac ppc/32/64, Windows 32 and 64, Linux on Intel and on Raspberry Pi, and signed mac Intel and Apple Silicon, for every (audio DSP, generic interface, mac AU and VST2.4) plugin I make. https://www.airwindows.com/

But I do it with lots of different available downloads, not as a single binary. That's what I find impressive about this. Somebody's running that XCode mod where you can bring in all the libraries from all the previous versions back to the dawn of time. I'm not even going to pretend to try to keep something like that working: I do my retro builds (and original design) on an antique machine dedicated to the purpose, and the modern stuff on a modern laptop dedicated to staying current.

Mach-O[1], the executable file format used by macOS and iOS (and other NeXTSTEP descendants) supports stuffing code segments for multiple architectures in the same file, aka "fat binaries"[2]. This is a fat binary that supports 5 architectures.

[1]https://en.wikipedia.org/wiki/Mach-O

[2]https://en.wikipedia.org/wiki/Fat_binary

32/64 bit, PowerPC/x86/AppleSilicon
Specifically, I'm guessing PPC-32, PPC-64, x86-32, x86-64 and ASi-64.
*AArch64
This binary is so universal that `file` utility gets confused about it.

    $ file /Volumes/TinyClock/TinyClock.app/Contents/MacOS/TinyClock 
    /Volumes/TinyClock/TinyClock.app/Contents/MacOS/TinyClock: Mach-O universal binary with 3 architectures: [i386:Mach-O executable i386
    - Mach-O executable i386] [ppc:Mach-O executable ppc
    - Mach-O executable ppc] [arm64:Mach-O 64-bit executable arm64Mach-O 64-bit executable arm64]
    /Volumes/TinyClock/TinyClock.app/Contents/MacOS/TinyClock (for architecture i386): Mach-O executable i386
    /Volumes/TinyClock/TinyClock.app/Contents/MacOS/TinyClock (for architecture ppc): Mach-O executable ppc
    /Volumes/TinyClock/TinyClock.app/Contents/MacOS/TinyClock (for architecture arm64): Mach-O 64-bit executable arm64
It's not confused; as noted in Known Bugs:

> Unlike done in previous project, netop Tiger SDKs (used to build several intermediate binaries) don’t contain 64-bit AppKit versions, and thus ppc64 and x86_64 binaries are excluded from the binary release.

The binary release is only three-architecture; it does not run on current Intel MacOS since it's missing an x86_64 segment. (You get a "this app needs to be updated" dialog if you try.)

Nice, thanks for sharing.
If we had a Busybox for every platform, and you compiled your app for every platform, you could bundle it all as one compressed shell script. Not as cool as one binary that works everywhere, but much simpler.

  #!/usr/bin/env sh
  set -eu
  FILE="${OS:-$(uname -s)}/${ARCH:-$(uname -p)}/${MACH:-$(uname -m)}/exe"
  unzip -d "${TMPDIR:-/tmp}" -X -b -o "$0" "$FILE"
  [ $? -gt 1 ] || exec "${TMPDIR:-/tmp}/$FILE"
  echo "$0: Error: could not execute '$FILE'" ; exit 126
  ########################################################
  # After here the Zip file is concatenated into the file
>Launches faster, than Safari.

As it should, since one is a clock, the other a web browser.

Interesting stuff. Cross platform development is inspiring.

As it should, but not a given now that it's common for apps to bundle a whole browser as a runtime.
Not mine.

I write native.

I do tend to release apps in UIKit, so I don't quite achieve Buzzword Bingo, but I have always been a fan of native apps, and have watched the various efforts to avoid native, with the kind of sick fascination usually reserved for train wrecks.

Do you rewrite your apps for other platforms? I don't think anyone avoids native, it's just that cross platform is a much more important goal for many.
No. I don't write apps for other platforms.

I am quite aware that it is not the ideal "business posture," but that's how I roll.

I've been writing for Apple platforms, pretty much exclusively, since 1986.

Safari “getting snappier” with every OS update is a running gag in at least the MacRumors community. Or has been for quite a while. Maybe it’s retired now, much like the old gold “but will it run Crysis?” one.

By now, Safari should be so snappy it opens your pages and have their document tree ready two seconds before you think of doing it.

I agree that a clock should absolutely open faster than a browser, but it would be good to know what this metric actually represents. I don't know much about this style of universal binaries, so I don't know if the binary being "true 5-arch universal binaries" is the focus of the application start time metric.
Support for different architectures doesn't impact start time much. The code for the different archs is in different chunks of the file.

Linking more libraries slows down launch due to initialization that happens to get the libraries ready to use. Besides that it's mostly what the app itself is doing on startup.

So yes, beating Safari for a tiny app is… a good thing, but not very impressive.

> As it should, since one is a clock, the other a web browser

Yeah. Surely a better statistic to be had.here. System preferences?

Can’t remember the last time I thought about app launch speed outside of network access issues.
And instantly GIMP comes to my mind.
OT, but as someone who's never used Bazaar, how does this work?

    bzr clone https://tycho.sytes.net/TinyClock/
EDIT: To clarify, I'm curious since this is the same URL I'm opening in my browser.
Honestly, the most surprising thing to me was that people still use bzr. It looks like Canonical abandoned it back in 2016 [0]. It seems like it was suceeded by breezy [1], at least.

[0] https://en.wikipedia.org/wiki/GNU_Bazaar

[2] https://github.com/breezy-team/breezy

Same URL, different port. The website is at 80(http) or 443(https). Bzr seems to run on 4155.
I successfully cloned the repo using breezy. Did I get punked? It's empty.

    > bzr log
    ------------------------------------------------------------
    revno: 1
    committer: TinyClock <TinyClock@tycho.sytes.net>
    branch nick: TinyClock
    timestamp: Wed 2022-09-07 20:18:32 +0300
    message:
      initial commit

    > bzr clone https://tycho.sytes.net/TinyClock/
    > cd TinyClock
    > bzr checkout
    > ls
    controller.h  LICENSE  Makefile   view.h
    controller.m  main.m   README.md  view.m
Ah! thank you.
The website is openbsd httpd serving the repository.

https://tycho.sytes.net/TinyClock/README.md

The Makefile creates index.html from README.md (and also TinyClock.dmg)

Same as `git clone <repo>` - it downloads a local copy of the repo into a folder called ./TinyClock, which it will create if it doesn't exist.
One (IMO reasonable) objection/confusion might be that the the repo URL is the exact same as the web page, i.e. the actual posted article.

When coming from git/Mercurial/subversion etc as I do, it is at least mildly weird that the Bazaar repo address is the same as the address of a web document. The two objects are not (at least in my world) the same, so why should they share URIs?

Edit: deduped.

Because sending different content based on the content-type the user-agent asks for, e.g. with the "Accept:" header, has explicitly been part of the HTTP spec since version 1.1 in 1997?

https://datatracker.ietf.org/doc/html/rfc2068#section-12

https://datatracker.ietf.org/doc/html/rfc2068#section-14.1

See also https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_ne...

(FWIW - I don't know if that's how `bzr` does this, but it might, and the concept is 25 years old now.)

Edit: s/different content/different representations of the same resource/

True of course, didn't think about that. I'm not a web developer. :) Still think it's weird and kind of against my feeling for the spirit of a URI, but that's just me. Thanks.
You can git clone normal GitHub URLs without the .git at the end too.
Huh… didn’t realize OS X made it to Apple Silicon
Hairsplitting. We all know there was nothing major in macOS 11 justifying it not being an X-os anymore. They just got tired of the naming scheme.
Yep, since 2020 [0]. Or are you being pedantic about OS X vs macOS?

[0] https://en.wikipedia.org/wiki/Apple_M1#Products_that_use_the...

It's a Mac OS X program that runs on post-X macOS.