D. Obtaining and Building the Source
SpicyRPN is an Xcode project for native macOS, iPhone, and iPad applications. It supports iOS/iPadOS 18.0 and later, and macOS 15.0 Sequoia and later on compatible Apple-silicon and Intel Macs. The Mac application is universal, with arm64 and x86_64 code. The project links three static libraries, GMP, MPFR, and MPC, which must be built for the destination before building the app. GMP and MPFR provide the real-number foundation; MPC provides complex arithmetic and elementary functions for both entry modes. SQLite is compiled from source as part of the app. The manual has a separate LaTeX build and does not require Xcode.
This appendix describes the Release 2.0.0 source package and scripts. Retain the package version, its published checksum, and any local changes when building your own copy. Deployment settings below are requirements in the project, not a record of successful tests on each listed system.
D.2 Obtaining the release source package
D.3 Understanding the source layout
D.4 Library deployment settings
D.5 Building GMP, MPFR, and MPC
MPC source and integration
D.6 Signing and personal runs
D.7 Building and running on macOS
D.8 Building for iPhone and iPad
Simulator
Physical device
D.9 Rebuilding after modifying a library
D.10 Running the native test suites
A complete command-line run
Additional Intel testing with Rosetta
Reading a failure report
Database isolation in UI tests
D.11 Archiving and publishing the validated release
D.12 Checking independent numerical references
D.13 Building this manual
D.14 Diagnosing a build problem
D.1 Preparing the development machine
Use a Mac supported by the selected full Xcode installation, with the platform components needed for your destination. The macOS library builder accepts native arm64 and x86_64 hosts; the installed toolchain must support both target architectures to build the universal libraries. The project was created with Xcode 27-era tools. Although its Swift language setting is Swift 5, that setting is not a statement that an older Swift 5 toolchain can build the project. Check Apple’s current Xcode requirements and SDK table when choosing an installation: https://developer.apple.com/xcode/system-requirements.
Launch Xcode once to complete its setup and install the required platforms. Select that Xcode installation in the Command Line Tools setting. A standalone Command Line Tools installation is not a substitute for the full Xcode application when building and testing SpicyRPN. Use a native Terminal session: arm64 on Apple silicon or x86_64 on Intel. If more than one Xcode is installed, select the intended installation before checking the SDKs. A shell-local selection does not change the machine-wide setting. Adjust this path to your installation before running the export:
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
These commands show the active environment:
uname -m xcode-select --print-path xcodebuild -version xcodebuild -showsdks xcrun --sdk macosx --show-sdk-path
The host architecture should be arm64 on Apple silicon or x86_64 on Intel.
The selected developer path, or the DEVELOPER_DIR override when set, should
belong to the intended Xcode installation. Rosetta is optional for separately
testing the Intel application on Apple silicon; it is not required to compile that
slice.
Apple’s description of this selection mechanism is at https://developer.apple.com/documentation/xcode/configuring-command-line-tools-settings.
| Target | iOS | macOS |
| SpicyRPN | 18.0 | 15.0 |
| SpicyRPNTests | 18.0 | 15.0 |
| SpicyRPNUITests | 18.0 | 15.0 |
These values apply to both Debug and Release configurations and match the math-library defaults. Choose a simulator or device meeting these minimums. The Xcode installation may require a newer development Mac operating system than the app requires at runtime. The app supports iPhone and iPad device families and native macOS; Mac Catalyst is disabled. Other platform settings appearing in test project metadata do not establish an additional supported app platform.
The macOS recipe builds both arm64 and x86_64 libraries and merges them into universal archives. The iOS device and simulator recipes remain arm64-only; Intel simulator libraries are not supplied. An arm64 iOS device archive and an arm64 iOS simulator archive are different platform binaries, and neither can substitute for a macOS archive.
The scripts use Bash, Make, the Xcode C compiler and SDK tools, and standard macOS
utilities including curl, tar, shasum, and sysctl. Keep the extracted source in a path
without spaces, as required by the upstream Autoconf builds. The Xcode and SDK paths
must also have no spaces; the library builders reject them otherwise. Install Python 3.9
or later before bundle verification. The optional reference-fixture workflow in
section D.12 requires Python 3.11 or later. Install full MacTeX, including LuaLaTeX,
latexmk, and makeindex, before building the manual; see section D.13 for the build
command.
D.2 Obtaining the release source package
Download SpicyRPN-2.0.0-source.zip and its checksum file from https://spicyrpn.com/. The same site supplies the matching SpicyRPN-2.0.0-Manual.pdf and a ZIP containing that PDF. Keep an unchanged copy of the source ZIP. Work in its download directory, whose parent path must have no spaces for the subsequent library builds:
spicy_archive=SpicyRPN-2.0.0-source.zip
Compute the source archive’s digest:
shasum -a 256 "$spicy_archive"
Compare the result with the archive’s value in SHA256SUMS.txt; do not extract a mismatched file. Once it matches, use a fresh validation directory. The next command removes only the previous generated build/source-check/ copy; keep any changes you need elsewhere first. Then extract the ZIP and verify its contents:
rm -rf build/source-check mkdir -p build/source-check unzip "$spicy_archive" -d build/source-check cd build/source-check/SpicyRPN-2.0.0 shasum -a 256 -c SOURCE-SHA256SUMS.txt
Proceed only after every source checksum passes. All app and test commands below run from this extracted SpicyRPN-2.0.0 source root. Quote paths containing spaces, including the manual and SQLite subdirectories. For a release validation, keep this source set unchanged; if a correction is needed, fix the working tree, rebuild the package, and start again with its fresh extraction. Record personal-build modifications separately.
The complete package includes verified GMP, MPFR, and MPC source archives under ThirdParty/, SQLite sources under SpicyRPN/Third Party/, the Xcode project, app and test sources, build scripts, licensing notices, and editable manual. The math builders extract fresh working sources from the archives; the bundled MPC archive allows an offline library build after Xcode and its SDKs are installed. See section D.5.0 for the MPC source selection.
Read LICENSE and LICENSING.md alongside the source. The SpicyRPN application and original manual use MIT; bundled components retain their own licensing notices. Appendix D.14 reproduces the complete MIT, GNU GPLv3, and LGPLv3 texts. Keep those notices and the corresponding source and build material when preparing a source distribution. Signing a personal build does not change its licensing terms.
D.3 Understanding the source layout
|
Location |
Purpose |
|
SpicyRPN.xcodeproj/ |
App, unit-test, and UI-test targets; the shared SpicyRPN scheme. |
|
SpicyRPN/Preview/ |
Calculator model, presentation, and interface implementation used by the app. |
|
SpicyRPN/Math/ |
Multiprecision values, precision handling, and complex arithmetic. |
|
SpicyRPN/MathBridge/ |
C bridge to GMP, MPFR, and MPC. |
|
ThirdParty/ |
GMP 6.3.0, MPFR 4.2.2, and MPC 1.4.1 source archives with their upstream notices. |
|
build/downloads/ |
Optional verified MPC archive cache, used when the archive is absent from ThirdParty/. |
|
ThirdParty/SHA256SUMS.txt |
Checksums for the three bundled source archives. |
|
SpicyRPN/Third Party/ |
SQLite 3.51.2 amalgamation and associated headers. |
|
Scripts/ |
Platform-specific math builds and independent test-reference generators. |
|
SpicyRPNTests/ |
Native model, arithmetic, and other unit tests. |
|
SpicyRPNUITests/ |
XCTest tests that operate the launched calculator through its interface. |
|
Docs/ |
Project notes, including test architecture and coverage documentation. |
|
SpicyRPN Manual/ |
Manual sources and PDF build scripts. |
|
build/install/ |
Generated GMP, MPFR, and MPC installations, separated by destination. |
The project links the static libraries produced by its own scripts; a package manager’s GMP, MPFR, or MPC installation does not replace that step. There is no Swift package, CocoaPods, or Carthage dependency installation step in this build. SQLite’s C source is compiled by Xcode and does not need a separate library-build command.
To check the bundled source archives independently of a build, run:
( cd ThirdParty shasum -a 256 -c SHA256SUMS.txt )
The scripts also check the expected archive hashes and extract their working sources from those archives. Expanded reference trees, when present in a working copy, do not enter the build automatically. If an archive fails verification, obtain the correct file from the matching release source package before continuing.
D.4 Library deployment settings
All three libraries share an explicit minimum for their destination:
MACOSX_DEPLOYMENT_TARGET=15.0 IOS_SIM_DEPLOYMENT_TARGET=18.0 IOS_DEVICE_DEPLOYMENT_TARGET=18.0
These defaults match the app and test targets. If a Terminal session has older overrides, clear them before building for the supported baseline:
unset MACOSX_DEPLOYMENT_TARGET unset IOS_SIM_DEPLOYMENT_TARGET IOS_DEVICE_DEPLOYMENT_TARGET
These environment variables can deliberately override library compiler targets; they do not change the app or test targets in Xcode. Keep the settings aligned and rebuild the libraries and app after changing them. A library built for an earlier minimum does not lower the app’s minimum, and a library requiring a later system cannot establish support for the app’s earlier baseline.
D.5 Building GMP, MPFR, and MPC
Every library build replaces its generated sources and working trees. Preserve dependency patches separately before running a builder; see section D.9. The deployment settings above must match your intended baseline. Choose only the destinations you need; these are three separate commands, not three mandatory stages of every build:
bash Scripts/build-math-macos-universal.sh bash Scripts/build-math-ios-simulator-arm64.sh bash Scripts/build-math-ios-device-arm64.sh
Each script builds GMP 6.3.0 first, MPFR 4.2.2 against that GMP installation, and then MPC 1.4.1 against both. The macOS, iOS simulator, and iOS device outputs use suffixes macos-universal, ios-simulator-arm64, and ios-device-arm64, respectively. For example, the macOS installations are:
build/install/gmp-macos-universal/ build/install/mpfr-macos-universal/ build/install/mpc-macos-universal/
The macOS command builds each architecture separately, then merges both static-library slices. The thin-architecture scripts Scripts/build-math-macos-arm64.sh and Scripts/build-math-macos-x86_64.sh are available for library development. Their macos-arm64 and macos-x86_64 installations do not replace the universal prefixes selected by Xcode. Run the universal script after a library change to refresh both slices.
Each prefix contains its generated headers and static library. Xcode’s SDK-specific
header and library search paths select the matching prefixes; both Debug and Release
link using -lmpc -lmpfr -lgmp, in dependency order. There is no Xcode build phase
that automatically runs these scripts when a library is missing.
|
Destination |
Build and verification behavior |
|
macOS |
Builds arm64 and x86_64, checks each slice’s architecture, platform, and deployment target, and links the math bridge and MPC inverse-function smoke program for each. The native host slice runs upstream make check and the MPC program; the cross slice is checked by compilation and linking. Both are merged into universal static libraries. |
|
iOS simulator |
Cross-compiles arm64 simulator libraries, with GMP assembly disabled. Reports archive architecture and sample object platform metadata. Links the actual math bridge and the MPC inverse-function smoke program; does not run that program or upstream test executables. |
|
iOS device |
Cross-compiles arm64 device libraries, with GMP assembly disabled. Checks arm64 architecture and sample object iOS platform metadata, then links the actual math bridge against the libraries. Also links the MPC inverse-function smoke program. These checks establish linking, not execution on a device. |
The entry scripts share Scripts/lib/build-math.sh. Both --clean and -clean
remove the selected destination’s generated work and installations, retaining archives and
other destinations. For universal macOS this includes both thin builds and the merged
installation. Keep any patches outside those directories before a clean rebuild. Run only
the destinations you need:
bash Scripts/build-math-macos-universal.sh --clean bash Scripts/build-math-ios-simulator-arm64.sh --clean bash Scripts/build-math-ios-device-arm64.sh --clean
Use --help to display the options. Xcode’s Clean Build Folder is a separate app-build
operation.
The scripts verify minimum-OS metadata as well as platform metadata in a sample object from each archive and in the linked bridge and MPC smoke program. Each must match the selected deployment target. The check reads the operating-system deployment field from its Mach-O load command; embedded linker and other tool versions do not describe the minimum OS.
The macOS builds retain GMP’s optimized assembly for each architecture. Its CCAS
command includes -c so that GMP’s assembly probes and build rules produce object
files without attempting to link an executable. The iOS builds disable GMP
assembly.
MPC source and integration
MPC provides arbitrary-precision complex arithmetic on top of MPFR and GMP. The calculator calls it through a C bridge shared by RPN and ALG. The library for the selected destination is required to build the app. See chapter 8 and section C.4 for numerical conventions and the remaining limits of composed and special-function calculations.
MPC is part of each unified build. The release source package includes ThirdParty/mpc-1.4.1.tar.xz. Its upstream archive is https://ftp.gnu.org/gnu/mpc/mpc-1.4.1.tar.xz. The builder prefers the bundled archive; if it is absent, the builder reuses build/downloads/mpc-1.4.1.tar.xz or downloads it there. Every path is checked against the pinned SHA-256 before use:
91204cd32f164bd3b7c992d4a6a8ce6519511aadab30f78b6982d0bf8d73e931
A complete release ZIP therefore supplies MPC without a network request. A checksum mismatch stops the build. Retain the verified archive, its licensing notices, any local patches, and build settings with source distributions. MPC uses LGPL-3.0-or-later; see LICENSING.md.
The builder selects the SDK, compiler, architecture, static-library configuration, and matching dependency prefixes. It installs include/mpc.h and lib/libmpc.a beneath build/install/mpc-<target>/. The generated source and build trees are replaced on every invocation, so preserve patches separately.
After the libraries are built, follow the signing and application-build sections below. Header and library search paths and linker flags are already configured; no manual library attachment or Xcode build phase is needed. The macOS upstream tests and smoke program check MPC itself. Mobile smoke checks only compile and link; native app tests remain a separate step.
The C bridge transfers CalcNumber’s MPFR components directly, preserving its value representation and calculation provenance. Complex arithmetic and elementary functions use MPC, while valid real shortcuts retain MPFR behavior. Explicit signed-zero choices preserve the documented axis branches. Angle scaling and custom Gamma and error-function algorithms use appropriate intermediate precision and retain their own accuracy limits. The detailed setup and runtime description is in Scripts/BUILDING.md.
D.6 Signing and personal runs
For a personal build, configure signing before any application build, run, test, or archive. For a release, settle these project settings in the working tree before packaging, then verify them without changing the extracted sources. Open the project with:
open SpicyRPN.xcodeproj
The checked-in project uses automatic signing and contains the maintainer’s team and bundle identifiers. For your own build, add your Apple Account in Xcode’s settings, then select your team in the app target’s Signing & Capabilities pane. Use a bundle identifier that is valid and available for your team. If Xcode offers a Personal Team, it can be used within Apple’s current personal-development limits. Do not assume access to the maintainer’s signing identity.
Check the unit-test and UI-test targets as well when preparing to run tests. Their signing configuration must work with your account and the selected destination. Native macOS development on your own Mac does not generally require registering that Mac as an iOS-style provisioned device, but project signing settings and enabled capabilities still need to be compatible with your local setup.
For a development-signed iPhone or iPad app, follow Xcode’s device setup prompts. Developer Mode is managed in the device’s Settings under Privacy & Security; enabling it involves a restart and confirmation. The setting may become available after connecting the device to Xcode. Apple maintains the detailed procedures here:
A different app identity can have a different sandbox and saved calculator state. Do not expect a personal build with a changed bundle identifier to inherit another installation’s database.
For disposable manual experiments, add SPICYRPN_EPHEMERAL=1 to the Run scheme’s
environment. This makes the calculator use an in-memory database for that run. Remove
the variable to return to ordinary persistent storage; using the variable does not
delete an existing on-disk database. For normal state and recovery behavior, see
chapter 14.
D.7 Building and running on macOS
With the macOS libraries built and signing configured, select the shared SpicyRPN scheme and a native My Mac run destination. Configure signing as described in section D.6, then use Product \(\rightarrow \) Build or Product \(\rightarrow \) Run. The normal application launches the calculator interface. A foundation diagnostic view available as a SwiftUI preview is not the app’s main screen.
For command-line work, inspect the actual schemes and destinations:
xcodebuild -list -project SpicyRPN.xcodeproj xcodebuild -project SpicyRPN.xcodeproj \ -scheme SpicyRPN -showdestinations
Build a Debug app for the native host architecture with:
spicy_mac_arch="$(uname -m)" xcodebuild build -project SpicyRPN.xcodeproj \ -scheme SpicyRPN -configuration Debug \ -destination "platform=macOS,arch=$spicy_mac_arch" \ -derivedDataPath "build/DerivedData-mac-$spicy_mac_arch"
This command builds the product; it does not launch it. Xcode’s Run command handles launching and attaching its debugger. The chosen derived data directory holds Xcode products and intermediates. It is separate from build/install/, which holds the math libraries.
D.8 Building for iPhone and iPad
Simulator
Build the arm64 simulator math libraries on an Apple-silicon Mac, install a suitable iOS simulator runtime in Xcode, and select an arm64 iPhone or iPad simulator as the run destination. Both the app and tests require an iOS 18.0 or later runtime. A simulator’s device name alone does not identify its installed runtime.
Obtain the simulator identifier from xcodebuild -showdestinations with the project
and scheme options shown in section D.7. Then replace the placeholder:
spicy_simulator='REPLACE_WITH_SIMULATOR_UDID' xcodebuild build -project SpicyRPN.xcodeproj \ -scheme SpicyRPN -configuration Debug \ -destination "platform=iOS Simulator,id=$spicy_simulator" \ -derivedDataPath build/DerivedData-simulator
Use Xcode’s Run command to launch the app on the selected simulator. The simulator build uses its own static libraries even on an arm64 Mac; it cannot use the macOS or physical-device library installations.
Physical device
Build the device math libraries, connect and unlock the iPhone or iPad, and complete any trust or pairing steps shown by Xcode and the device. Configure your signing team and enable Developer Mode where required, as described in section D.6. Choose the actual device and use Run to build, install, and launch the app.
For a command-line build, use a device identifier reported as an available destination:
spicy_device='REPLACE_WITH_DEVICE_UDID' xcodebuild build -project SpicyRPN.xcodeproj \ -scheme SpicyRPN -configuration Debug \ -destination "platform=iOS,id=$spicy_device" \ -derivedDataPath build/DerivedData-device
This build command does not itself install or launch the product. A generic iOS build destination can produce build artifacts, but it is not a runnable test destination. Keep the simulator and device derived data directories distinct when using the recipes above.
D.9 Rebuilding after modifying a library
The release package supplies the application and library sources for the LGPLv3 section 4(d)(0) rebuilding route. Use a separate extraction for a modified personal build. Prepare signing as described in section D.6 before running the resulting application.
Keep changes as unified-diff .patch files whose paths have one leading directory, such as a/src/file.c and b/src/file.c. The builder applies them with patch -p1 relative to the library’s source root. Create patch directories first:
mkdir -p build/library-patches/gmp \ build/library-patches/mpfr build/library-patches/mpc
Save patches in the appropriate library subdirectory. Number multiple patches in application order, for example 01-change.patch and 02-followup.patch, then enable the patch directory:
export SPICYRPN_MATH_PATCH_DIR="$PWD/build/library-patches"
Every build verifies and extracts the original archives, then applies the patches in C-locale filename order before configuring any library. A failed patch stops the build. Both Mac architecture slices receive the same patches. The original archives and checksums stay unchanged; retain the patches separately. A library with no patches builds unchanged. Editing an expanded reference tree under ThirdParty/ alone does not change the build.
Rebuild every destination affected by the change. The supplied recipes build all
three libraries in the correct order, so a changed GMP is followed by MPFR
and MPC linked against the matching installation. Use --clean to remove
older generated working directories as well. Keep local patches outside those
directories.
Then rebuild the app so that it links the new static libraries. For example, on macOS:
bash Scripts/build-math-macos-universal.sh --clean spicy_mac_arch="$(uname -m)" xcodebuild clean build -project SpicyRPN.xcodeproj \ -scheme SpicyRPN -configuration Debug \ -destination "platform=macOS,arch=$spicy_mac_arch" \ -derivedDataPath "build/DerivedData-mac-$spicy_mac_arch"
Rebuilding a library does not update an already running app. Conversely, Xcode’s Clean Build Folder command does not rebuild the libraries under build/install/. Treat the library and app rebuilds as separate steps.
For iPhone or iPad, use the device or Simulator library recipe for the selected destination while the patch setting is active, then clean and run the app from Xcode. Choose your own team and bundle identifiers as described in section D.6. Run the native tests against the rebuilt application.
To return to the unmodified libraries, run unset SPICYRPN_MATH_PATCH_DIR, rebuild
the selected libraries, and clean/relink the app again. Keep the patches and build
settings with any modified distribution. Scripts/RELEASING.md describes a separate
modified-library rebuild check before publishing the release.
Replacing a dependency version requires reviewing the source archives, checksums, expanded directory names, build scripts, generated installation paths, project search paths, and bridge compatibility together. The scripts are pinned recipes, not automatic dependency upgraders. Retain the actual modified source and the build settings used for a modified binary, as well as the relevant licensing notices.
D.10 Running the native test suites
The shared scheme includes both SpicyRPNTests and SpicyRPNUITests. After preparing libraries and signing for the chosen destination, use Product \(\rightarrow \) Test in Xcode. The unit-test target uses Swift Testing, including aggregate numerical test runners. The UI-test target uses XCTest to launch the actual app, press its controls, and read accessibility values. UI tests do not import the calculator’s arithmetic implementation to manufacture expected answers.
The scheme permits unit tests to run in parallel and keeps the UI-test target serial. Preserve the serial UI configuration when diagnosing focus, modal, or input-order failures. Some unit-test runners control successful-case logging through a source-level verbosity constant; failures and their aggregate failure assertion remain active when that verbosity is disabled.
These are Apple-platform tests. Building documentation, checking scripts, or examining numerical fixtures on Linux does not establish that the app or its native test targets compile or pass in Xcode.
A complete command-line run
Run both test targets natively on an Apple-silicon Mac and on a compatible Intel Mac. The result-bundle path must not already exist. The following selects the current host architecture and creates a unique path for the results:
mkdir -p build/TestResults spicy_mac_arch="$(uname -m)" spicy_results="build/TestResults/$spicy_mac_arch-$(uuidgen)" spicy_results="$spicy_results.xcresult" xcodebuild test -project SpicyRPN.xcodeproj \ -scheme SpicyRPN -configuration Debug \ -destination "platform=macOS,arch=$spicy_mac_arch" \ -derivedDataPath "build/DerivedData-mac-$spicy_mac_arch" \ -resultBundlePath "$spicy_results" open "$spicy_results"
For an iOS run, substitute an available simulator or device destination and its separate derived data path, and prepare the matching libraries first. The selected iOS destination must satisfy the test targets’ iOS 18.0 minimum. A build, signing, or app-launch failure is not a completed test run.
The full UI suite includes long input sequences, large token-boundary cases, and broad conversion coverage. Allow a substantial run window; use a focused selection when investigating one failure. For example, this requests just the unit-test target for the native host:
spicy_mac_arch="$(uname -m)" xcodebuild test -project SpicyRPN.xcodeproj \ -scheme SpicyRPN -configuration Debug \ -destination "platform=macOS,arch=$spicy_mac_arch" \ -only-testing:SpicyRPNTests
To select UI tests instead, replace the final option with:
-only-testing:SpicyRPNUITests
A narrower selection can name a class:
-only-testing:SpicyRPNUITests/FinancialE2ETests
To select a current method within that class, use its identifier as reported by Xcode. Selecting tests controls what runs; Xcode may still build other targets required by the scheme.
Additional Intel testing with Rosetta
On Apple silicon with Rosetta installed, Xcode may offer an x86_64 Mac destination.
Use xcodebuild -showdestinations to verify that it is available, then run a separate
test pass:
xcodebuild test -project SpicyRPN.xcodeproj \ -scheme SpicyRPN -configuration Debug \ -destination 'platform=macOS,arch=x86_64' \ -derivedDataPath build/DerivedData-mac-rosetta
This exercises the Intel slice under translation and is useful additional coverage. It does not replace a native run on a compatible Intel Mac. The library builder does not automatically execute cross-architecture tests through Rosetta. An Intel Mac cannot execute the arm64 slice; validate it on Apple silicon.
Reading a failure report
Open the result bundle or Xcode’s Report navigator and start with the first failing test activity. Numerical UI checks retain full expected and observed strings and identify the first differing normalized decimal position. Read those details before reducing a failure to the short number visible in a display screenshot. For an input failure, establish whether the intended control was present, enabled, and hittable, and whether a sheet or keyboard focus intercepted the action.
Retain the source revision, Xcode version, destination and runtime, exact test identifier, and result bundle. Reproduce the smallest failing test, then run the related class or target after the change. Test behavior and coverage conventions are documented in Docs/UI-Testing.md and Docs/UI-Test-Coverage.md. Apple’s test-selection and results workflow is described at https://developer.apple.com/documentation/xcode/running-tests-and-interpreting-results.
Database isolation in UI tests
The UI-test harness supplies a fresh UUID through SPICYRPN_TEST_DATABASE. The app
then uses a test database under a UUID-specific temporary directory rather than its
normal Application Support database. The harness clears calculator banks through the
interface. Persistence tests can relaunch the app with the same UUID to check whether
state survived.
Do not add SPICYRPN_EPHEMERAL=1 to a persistence test run: in-memory storage takes
precedence over the UUID database and changes what that test exercises. An arbitrary
non-UUID value is not a valid isolated test-database identifier. Debug UI tests can also
supply a random seed, but the deterministic random source requires the UI-testing flag
and a valid test UUID as well as that seed. These are harness controls, not calculator
preferences.
D.11 Archiving and publishing the validated release
Before archiving, complete the native tests in section D.10 on Apple silicon and a compatible Intel Mac, and any iOS destinations being released. Keep the extracted sources unchanged and use the signing configuration prepared in section D.6. Verify the extracted source checksums again before archiving:
shasum -a 256 -c SOURCE-SHA256SUMS.txt
If a checksum no longer matches, resolve the source change and repackage before continuing.
The scheme uses Debug for running, testing, and analysis, and Release for profiling and archiving. Debug builds the selected active Mac architecture. Release builds include both arm64 and x86_64. Build a universal Mac archive and verify its executable with:
xcodebuild archive -project SpicyRPN.xcodeproj \ -scheme SpicyRPN -configuration Release \ -destination 'generic/platform=macOS' \ -archivePath build/SpicyRPN-macOS.xcarchive \ 'ARCHS=arm64 x86_64' ONLY_ACTIVE_ARCH=NO spicy_products=build/SpicyRPN-macOS.xcarchive/Products spicy_binary="$spicy_products/Applications/SpicyRPN.app" spicy_binary="$spicy_binary/Contents/MacOS/SpicyRPN" xcrun lipo -archs "$spicy_binary" xcrun lipo -verify_arch arm64 x86_64 "$spicy_binary"
The source package also supplies a bundle verifier. Pass the application bundle path, rather than its executable:
spicy_mac_app="$spicy_products/Applications/SpicyRPN.app" python3 Scripts/verify-macos-universal.py "$spicy_mac_app"
It checks Release 2.0.0/build 1, the macOS deployment minimum, and both architectures
in the main and bundled Mach-O files. The release packager can perform the same
checks with its --mac-app option; see Scripts/RELEASING.md.
The architecture check verifies that both slices are present. It does not execute either slice or validate signing. Complete the App Store archive checks, including its signing, bundled privacy manifest, and configured license terms. Then publish the exact source ZIP, manual PDF, and checksum file whose sources you validated. These files remain in the original working tree’s dist/2.0.0/; upload that set to https://spicyrpn.com/. If validation requires a source change, repackage and repeat the fresh-extraction checks before publication.
D.12 Checking independent numerical references
The included UI tests contain their expected values, so generating references is not a prerequisite for an ordinary app build or test run. The generator scripts are useful when reviewing a numerical change or adding cases. They use independent calculations rather than running SpicyRPN to obtain its own expected answers.
Use Python 3.11 or later for the documented generator workflow. The complex generator requires mpmath 1.3.0. The test documentation also records independent mpmath checks of selected scientific constants. An optional isolated environment can be prepared from the source root:
python3 -m venv build/fixture-env source build/fixture-env/bin/activate python -m pip install 'mpmath==1.3.0'
The scientific generator additionally needs an independently available MPFR shared
library that Python can load. It discovers that library through the system library
lookup unless MPFR_LIBRARY names an explicit library file. The static libmpfr.a
produced for the app is not a loadable shared library. Configure the shared
library for the Python process and host architecture on which the generator
runs.
Run the comparison modes explicitly:
python Scripts/generate-scientific-ui-fixtures.py --check python Scripts/generate-complex-ui-fixtures.py --check python Scripts/generate-financial-ui-fixtures.py --check python Scripts/generate-conversion-ui-fixtures.py --check python Scripts/generate-statistics-ui-fixtures.py deactivate
The first four commands compare independently generated references with the included
fixtures. The statistics script prints reference values for review and has no --check
mode. Its output therefore needs to be compared with the intended test cases
separately.
The scientific generator uses direct MPFR calls; complex references use mpmath; financial, statistical, and conversion references use independent high-precision decimal or exact-factor calculations. Review the mathematical convention as well as the digits, especially for cash flow signs, angle units, branch choices, and rounding.
Take care with commands that omit --check: the scientific, complex, and conversion
generators write fixture files by default. The financial generator prints by default and
writes only with --write; the statistics generator prints its results. Review any
generated diff as a source change. A generator mismatch calls for investigation before
accepting new expected values.
D.13 Building this manual
Install a TeX distribution containing LuaLaTeX, latexmk, and makeindex, together with the packages used by the manual. A full MacTeX installation is the straightforward macOS option: https://tug.org/mactex/. A suitable full TeX Live installation can also build the manual on Linux. The manual uses fonts provided by the TeX distribution and does not require the app’s numeric libraries, Python environment, or an Xcode build.
Keep only one builder or watcher for the manual’s output directory. Stop any existing watcher first, then run from the source root:
bash "SpicyRPN Manual/build.sh" --open
The resulting PDF is SpicyRPN Manual/build/SpicyRPN-Manual.pdf. Omit --open
when no PDF viewer is wanted. On macOS, the Finder launcher SpicyRPN Manual/
Build Manual.command provides the same build-and-open workflow. The build script
finds its own source directory, so it can also be invoked from elsewhere using its full path.
It adds the usual MacTeX binary directory to its search path when available and is
compatible with the Bash supplied by macOS.
For continuous rebuilding while editing:
bash "SpicyRPN Manual/build.sh" --watch --open
Stop this process with Control-C. The script first requires a successful initial build before entering watch mode; errors during later edits are reported while the watcher waits for a correction.
The build uses latexmk with LuaLaTeX, repeated passes as needed, and index-tool
support. Shell escape is disabled, external latexmk configuration is ignored, and
generated font caches are kept inside the manual’s build directory. To remove generated
manual files and rebuild, stop any watcher first. The --clean option removes this
manual’s generated PDF, intermediate files, and font cache; keep source artwork outside
that directory. It does not touch the app’s root-level build/ or math-library
installations. Then run:
bash "SpicyRPN Manual/build.sh" --clean --open
The master source is SpicyRPN Manual/SpicyRPN-Manual.tex; chapter files, appendices, front matter, and back matter are included from their respective directories. Follow the existing style and metadata files when editing. After a successful build, inspect the affected PDF pages, page breaks, wide tables or command listings, links, and cross-references. A successful TeX exit alone does not prove that the page layout is readable. On failure, start with the first substantive error in SpicyRPN Manual/build/ SpicyRPN-Manual.log.
D.14 Diagnosing a build problem
Work from the first meaningful error and the destination being built. Later linker or test errors may simply be consequences of an earlier missing dependency. The checks in table D.4 narrow the problem without changing calculator state.
|
Symptom |
Check |
|
Missing source archive |
Restore the bundled GMP, MPFR, and MPC archives from the matching release ZIP. For a working copy without bundled MPC, check its download step or verified cache. |
|
Archive checksum failure |
Compare against the matching release’s checksum file and restore the correct archive. Do not bypass the check to make the build continue. |
|
SDK or developer-tool error |
Inspect xcode-select, DEVELOPER_DIR, Xcode’s installed platforms, and xcodebuild -showsdks. Use the intended full Xcode. |
|
Missing GMP, MPFR, or MPC header or library |
Build the libraries for the selected SDK and check its build/install/ prefixes. |
|
Wrong-platform linker error |
Check macOS, simulator, and device separately. An arm64 archive from one platform cannot substitute for another. |
|
Missing Mac architecture slice |
Rebuild with the universal macOS script and check the macos-universal libraries. A Release archive must retain both arm64 and x86_64. |
|
Library edit has no effect |
Force the appropriate library rebuild, then clean and relink the app and launch the new executable. |
|
App builds but iOS tests cannot run |
Check the selected runtime or device OS against the common iOS 18.0 minimum, and check Xcode’s installed platform and test support. |
|
Signing or installation failure |
Check the selected team, bundle identifiers, all relevant targets, device pairing, and Developer Mode using Xcode’s diagnostic. |
|
UI test launches but fails on input |
Read the first failed activity; inspect the active sheet, keyboard focus, control accessibility, and exact destination before treating it as a numerical failure. |
|
Manual command or package missing |
Check for a complete, consistent TeX installation and the script’s first diagnostic. |
|
Manual cross-reference or layout problem |
Let the build complete its passes, inspect the log and referenced label, then review the affected PDF pages. |
When reporting a remaining problem, retain the source package version and local patch, tool versions, SDK and destination, exact command, and its first substantive error. Include any library-source or deployment-setting changes and, for tests, the result bundle and failing test identifier. Calculator operation and saved-state troubleshooting are covered in chapter 14.