Skip to content

#464#573

Open
eesmith72 wants to merge 15 commits intoAleph-One-Marathon:masterfrom
eesmith72:xcode-cleanup
Open

#464#573
eesmith72 wants to merge 15 commits intoAleph-One-Marathon:masterfrom
eesmith72:xcode-cleanup

Conversation

@eesmith72
Copy link

#464: xcode-cleanup branch for review

I’ve restructured the AlephOne.xcodeproj to reduce macOS build times by relocating all code except main.cpp into static libraries which are shared by all apps.

== Changes

  1. I’ve renamed the ./PBProjects dir to ./Xcode, and organized and updated the AlephOne.xcodeproj and the directory’s contents.

  2. I’ve renamed the Targets and Schemes as follows:

     libalephone
     Aleph One
     Marathon 1
     Marathon 2
     Marathon 3
     libalephonesteam
     Marathon 1 Steam
     Marathon 2 Steam
     Marathon 3 Steam
     Steam Launcher
     Tests Replays
    

    I’ve updated the CI YAMLs in ./.github to use these names. The new Test Replays Target+Scheme is duplicated from Aleph One and modified to use ./tests/main.cpp.

  3. AO’s guts are now in static-linked libalephone and libalephonesteam libraries. Each AO app Target declares libalephone* in its Target Dependencies so these libraries are built automatically as needed.

  4. I’ve kept Mac-specific macro/code changes to a minimum:

    • I’ve replaced the macOS-specific PREFER_APP_NAME_TO_BUNDLE_ID macro with a run-time A1_PREFER_APP_NAME_TO_BUNDLE_ID flag defined in each app’s Info.plist, so each app should use the same paths to Preferences, et as before. Please confirm each app still uses the previous version’s existing Preferences and other game files.

    • The standalone M1-3 Targets no longer set the SCENARIO_IS_BUNDLED macro. The embedded DataFiles dir is on the search path anyway so I don’t think this’ll affect run-time behavior on Mac (I can’t comment on Win/Lin.). Please confirm the standalone M1–3 apps behave as before.

  5. I have updated paths in .vdffiles and ./Makefile.am. Please confirm the M1-3 Steam releases and various Source source releases build correctly as I haven’t tested these.

  6. I’ve added a convenience script, ./Xcode/build-macos-apps.sh, which builds all apps on Mac desktop.

== Notes

A clean build of all apps now takes 1:40 on my M1 Mac. With already-built libraries, rebuilding all apps takes 15sec.

I’ve confirmed the CI tests pass and all AO apps launch OMM. I am unable to test Classic Marathon Launcher, Steam-enabled apps, and the Test Replays.

…roj` and directory structure for easier maintenance. Updated `Makefile.am` and related files accordingly (not tested).

* Moved AO guts into `libalephone` and `libalephonesteam` libraries so they can be built once and shared by multiple `.app` Targets for faster build times. Updated `.app` Targets, static `Info*.plist` files and `cspaths.mm` accordingly.

* Added a `Test Replays` Target + Scheme to build a modified AO app with custom `main.cpp` to test the game engine by replaying movie files.
- renamed `Aleph One Test Replays.app` to `AlephOne Tests.app` for consistency with Linux build
Kolfering added a commit that referenced this pull request Feb 10, 2026
@Kolfering
Copy link
Member

I was able to have the CI tests running based on that branch so that's great. However, the Aleph One Test binary built as an .app was giving me some troubles and I was wondering if it would be possible (if that's easy for you) to change it to be a cmd line application like Classic Marathon Launcher. That would simplify the github workflow. (as long as it doesn't create a new issue I didn't anticipate) If that's not possible or too hard/time consuming that’s totally fine as well of course.

@storm312
Copy link

Good to go as it seems

@eesmith72
Copy link
Author

@Kolfering: The standard way to run a macOS .app from command line is to use open:

OPEN(1)                     General Commands Manual                    OPEN(1)

NAME
     open – open files and directories

SYNOPSIS
     open [-e] [-t] [-f] [-F] [-W] [-R] [-n] [-g] [-j] [-h] [-u URL] [-s sdk]
          [-b bundle_identifier] [-a application] [--env VAR] [--stderr PATH]
          [--stdin PATH] [--stdout PATH] [--arch ARCH] [--args arg1 ...]

DESCRIPTION
     The open command opens a file (or a directory or URL), just as if you had
     double-clicked the file's icon. If no application name is specified, the
     default application as determined via LaunchServices is used to open the
     specified files.

     If the file is in the form of a URL, the file will be opened as a URL.

     You can specify one or more file names (or pathnames), which are
     interpreted relative to the shell or Terminal window's current working
     directory. For example, the following command would open all Word files
     in the current working directory:

     open *.doc

     Opened applications inherit environment variables just as if you had
     launched the application directly through its full path.  This behavior
     was also present in Tiger.

     The options are as follows:

     -a application
         Specifies the application to use for opening the file

     -b bundle_identifier
         Specifies the bundle identifier for the application to use when
         opening the file

     -e  Causes the file to be opened with the TextEdit application

     -t  Causes the file to be opened with the default text editor, as
         determined via LaunchServices

     -f  Reads input from standard input and opens the results in the default
         text editor.  End input by sending EOF character (type Control-D).
         Also useful for piping output to open and having it open in the
         default text editor.

     -F  Opens the application "fresh," that is, without restoring windows.
         Saved persistent state is lost, except for Untitled documents.

     -W  Causes open to wait until the applications it opens (or that were
         already open) have exited.  Use with the -n flag to allow open to
         function as an appropriate app for the $EDITOR environment variable.

     -R  Reveals the file(s) in the Finder instead of opening them.

     -n  Open a new instance of the application(s) even if one is already
         running.

     -g  Do not bring the application to the foreground.

     -j  Launches the app hidden.

     --arch ARCH
         Launch with the given cpu architecture type and subtype; ARCH should
         be one of any, arm, arm64, arm64e, arm64_32, x86_64, x86_64h, i386.
         Two integers matching the values for cpu_type_t and cpu_subtype_t can
         be specified as integers separated by a '/' character, like "12/13"
         for CPU_TYPE_ARM/CPU_SUBTYPE_ARM_V8.

     -h  Searches header locations for a header whose name matches the given
         string and then opens it.  Pass a full header name (such as NSView.h)
         for increased performance.

     -s  For -h, partial or full SDK name to use; if supplied, only SDKs whose
         names contain the argument value are searched. Otherwise the highest
         versioned SDK in each platform is used.

     -u  Opens URL with whatever application claims the url scheme, even if
         URL also matches a file path

     --args
         All remaining arguments are passed to the opened application in the
         argv parameter to main().  These arguments are not opened or
         interpreted by the open tool.

     --env VAR
         Adds VAR to the environment of the launched application.  VAR should
         be formatted NAME=VALUE or NAME.

     --stdin PATH
         Launches the application with stdin connected to PATH.

     --stdout PATH
         Launches the application with stdout connected to PATH.

     --stderr PATH
         Launches the application with stderr connected to PATH.

EXAMPLES
     "open '/Volumes/Macintosh HD/foo.txt'" opens the document in the default
     application for its type (as determined by LaunchServices).

     "open '/Volumes/Macintosh HD/Applications/'" opens that directory in the
     Finder.

     "open -a /Applications/TextEdit.app '/Volumes/Macintosh HD/foo.txt'"
     opens the document in the application specified (in this case, TextEdit).

     "open -b com.apple.TextEdit '/Volumes/Macintosh HD/foo.txt'" opens the
     document in the application specified (in this case, TextEdit).

     "open -e '/Volumes/Macintosh HD/foo.txt'" opens the document in TextEdit.

     "ls | open -f" writes the output of the 'ls' command to a file in /tmp
     and opens the file in the default text editor (as determined by
     LaunchServices).

     "open http://www.apple.com/" opens the URL in the default browser.

     "open 'file://localhost/Volumes/Macintosh HD/foo.txt'" opens the document
     in the default application for its type (as determined by
     LaunchServices).

     "open 'file://localhost/Volumes/Macintosh HD/Applications/'" opens that
     directory in the Finder.

     "open -h NSView" lists headers whose names contain NSView and allows you
     to choose which ones to open.

     "open -h NSView.h" immediately opens NSView.h.

     "open --env MallocStackLogging=YES -b com.apple.TextEdit" launches
     TextEdit with the environment variable "MallocStackLogging" set to "YES"

     "open -h NSView -s OSX10.12" lists headers whose names contain NSView in
     the MacOSX 10.12 SDK and allows you to choose which ones to open.

HISTORY
     First appeared in NextStep.

@Kolfering
Copy link
Member

@eesmith72 Yeah I know that, however I'd like to be able to use the same code for linux, windows and macOS and not having to write "if" everywhere just because of macOS, even more when the script is using powershell core as the shell. So right now I'am calling directly the binary inside the .app with the same cross platform code, which works but is a bit ugly.

 - name: Run Tests
   uses: ./.github/actions/run-tests
   with:
      test_application_path: "Xcode/build/Release/AlephOne Tests.app/Contents/MacOS/AlephOne Tests"

if it was a command line application, it could simply be:

 - name: Run Tests
   uses: ./.github/actions/run-tests
   with:
      test_application_path: "Xcode/build/Release/AlephOne Tests"

@eesmith72
Copy link
Author

macOS GUI apps expect to be packaged in a specific way with Info.plist and other resources in the .app bundle. Building the library as a CLI executable would require modifying libalephone to behave differently when built for CLI vs GUI, which kinda defeats the purpose of system testing. Creating a command-line shim like the Steam Launcher which runs the GUI app using LaunchServices APIs would be an option, but again that’s creating extra complexity.

As long as the AlephOne Tests.app is behaving correctly when you call its binary directly, I’d keep doing that. Try modifying your macOS-specific build script so it also creates a symlink at "Xcode/build/Release/AlephOne Tests" pointing to "Xcode/build/Release/AlephOne Tests.app/Contents/MacOS/AlephOne Tests" and see if that works.

@Kolfering
Copy link
Member

ok, no prob, as I said I can live with it if it's too troublesome to change

@treellama
Copy link
Member

There is no such thing as Marathon 3...why did you change everything from Infinity to 3?

@treellama
Copy link
Member

The all-in-one apps build and run for me from Xcode, however if I run the release-macosx workflow, the resulting apps hang on startup with a spinning beach ball. Could it be due to the removal of SCENARIO_IS_BUNDLED?

@eesmith72
Copy link
Author

eesmith72 commented Feb 17, 2026

There is no such thing as Marathon 3...why did you change everything from Infinity to 3?

I changed the build Target+Scheme names to improve readability in Xcode: 1, 2, 3 is easier than "", "2", "Infinity". This has no effect on product names and bundle IDs which are same as before.

Screenshot 2026-02-17 at 19 46 35 Screenshot 2026-02-17 at 19 46 54 Screenshot 2026-02-17 at 19 52 08 Screenshot 2026-02-17 at 19 52 02 Screenshot 2026-02-17 at 19 51 56

@eesmith72
Copy link
Author

eesmith72 commented Feb 17, 2026

The all-in-one apps build and run for me from Xcode, however if I run the release-macosx workflow, the resulting apps hang on startup with a spinning beach ball. Could it be due to the removal of SCENARIO_IS_BUNDLED?

The lack of macro shouldn't make a difference: as you say, it works when built locally. The macro just skips over the extra scenario search paths. Maybe something in the release-macosx workflow. I’m not familiar with that. Let me dig into that and get back.

ETA: Can you tell me how to set up codesigning for the release-macosx workflow please?

  shell: /bin/bash -e {0}
  env:
    vcpkg_installation_root: vcpkg_binary
    vcpkg_current_hash: aa2d37682e
    runner_image_version: 20260209.0115.1
    xcode_arch: 
    xcode_targets: -target "Aleph One" -target "Marathon 1" -target "Marathon 2" -target "Marathon 3"
    MACOS_CERTIFICATE: 
    MACOS_CERTIFICATE_PWD: 
    MACOS_CERTIFICATE_NAME: 
    MACOS_CI_KEYCHAIN_PWD: 
security: SecKeychainItemImport: One or more parameters passed to a function were not valid.
Error: Process completed with exit code 1.

@Kolfering
Copy link
Member

Editing messages on github doesn't send new notifications FYI.
The first thing I'd try if not done yet, is to disable the signing and notorization steps and see if the problem was already there. You can simply delete the steps "Codesign app bundle" and "Notarize app bundle" from the workflow. If you want to setup the signing part on your fork, you will need an Apple certificate since the forks obviously don't have access to secrets from the upstream repo.
You can also push the commits you want to test on this PR or a new draft PR if you want to keep this one clean, and I can synchronize it with a branch from the main repo to trigger the release-macosx workflow. (as we already did to test the workflow)

@eesmith72
Copy link
Author

I’ve deleted the codesign and notarization steps from release-mac-osx.yml, successfully run a release build, and downloaded the resulting .dmgs.

I’ve unquarantined the 4 .apps and manually signed them, e.g.:

sudo xattr -r -d com.apple.quarantine 'Classic Marathon 2.app'
codesign -s Developer -v --force --deep --timestamp --entitlements 'AlephOne.entitlements' -o runtime 'Classic Marathon 2.app'

All apps open and play successfully here, so process of elimination. Codesign and notarization would be obvious things to check.

  1. Force re-sign your .apps, then run them again to see if they still hang.

  2. Go through the AO and M1-3 Targets in AlephOne.xcodeproj, update the “Signing & Capabilities” section with your own settings, then push those changes to see if this changes the headless build. (Your yml performs its own signing so this shouldn’t make a difference, but best eliminate all the variables.)

  3. Please send me the d/l link to your builds and I will try running them here to see if the hang reproduces.

  4. Please talk me through process of setting up codesign and notarization on my repo so I can test that part of the process too.

@Kolfering
Copy link
Member

The problematic build can be downloaded from here https://github.com/Aleph-One-Marathon/alephone/actions/runs/21876572119

@eesmith72
Copy link
Author

Thanks. I can reproduce but I’m scratching my head. Something is throwing an exception, but all the try-catch blocks in main.cpp are suppressing it so I’ve no idea what.

Please edit the main.cpp file to remove all the try-catch blocks, then run the release-mac-osx workflow to build it again. Touch wood, when this new build crashes your OS will generate a crash report that can help identify the cause.

@Kolfering
Copy link
Member

Can you do it in this PR and revert 010e0d1 since it didn't help?
It's easier for me to just synchronize your PR with upstream to run the workflow.

Comment on lines +39 to +41
/*
try {

*/

Check notice

Code scanning / CodeQL

Commented-out code Note

This comment appears to contain commented-out code.

Check notice

Code scanning / CodeQL

Commented-out code Note

This comment appears to contain commented-out code.
@eesmith72
Copy link
Author

Well, I’ve tested these newest builds on 2 different Macs and they are all stubbornly launching and running as normal though I don’t think it’s cos of anything I did.
Here’s what I know: the “hang” occurred when AO tried to read files inside the .app bundle. The Boost XML library was throwing an exception, which I’m guessing was a filesystem permissions error but the try-catch block in main.cpp was suppressing the details.

Inspecting the app bundle’s extended permissions (e.g. ls -lR@ 'Classic Marathon.app') showed the com.apple.quarantine flag was set, which I think macOS is meant to clear once the user OKs the security warning on first run. If I removed those flags manually (sudo xattr -r -d com.apple.quarantine 'Classic Marathon.app') and relaunched, the app worked as normal.

I didn’t see anything in the YML that might be a cause, though without recreating the codesign and notarization steps for myself I can’t be sure. I’m really not familiar with the CI, but the edits I made the were very simple.

Beyond that, scratching my head as to why it broke in first place and why it now seems to be working again. Appreciate if others could try these builds out, let us know how they get on. Any new crash logs, please send them my way (touch-wood the stack trace will be human-readable now).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants