Building from source

~2 min read

Building from source

Lettuce is a SwiftPM project. The source is available via private repo invite during the 0.x series and goes open-source (MIT) at 1.0 — repo: github.com/DrBaher/lettuce.

Pre-requisites

Clone

git clone https://github.com/DrBaher/lettuce.git
cd lettuce

Build

There’s intentionally no .xcodeproj — everything is SwiftPM. The repo’s main entry point is ./Scripts/run.sh:

./Scripts/run.sh

This:

  1. Sets DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer

  2. Runs swift build -c debug

  3. Bundles the result into a runnable .app

  4. Launches it

For a release build:

./Scripts/run.sh --release

For headless (no app launch — useful in CI):

DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer swift build -c release

Run the CLI

After a build:

.build/arm64-apple-macosx/release/Lettuce --help

Or use the run.sh shortcut:

./Scripts/run.sh --cli docs path

Run tests

DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer swift test

This takes ~30 seconds for the full suite. To run a subset:

swift test --filter DocsVault
swift test --filter SuggestionsModeTests

Build the QuickLook plugin

The .qlgenerator is built by a separate script because SwiftPM doesn’t know about .appex bundles:

./Scripts/build-quicklook.sh

Output: .build/Lettuce.qlgenerator/. To install for testing:

./Scripts/install-quicklook.sh
qlmanage -r

Package for distribution

The full release flow (build, sign, notarise, bundle DMG, deploy site):

./Scripts/package.sh --version 0.6.1

You’ll need:

This script is also the spec for what the CI does — read it for the canonical flow.

Toolchain pinning

Lettuce pins to Swift 6.0 (with language mode 5 for transitions). The toolchain comes from Xcode (whatever version is at DEVELOPER_DIR). To use a different one:

xcode-select -p                          # current
sudo xcode-select -s /path/to/Xcode-16.4.app

Common gotchas

“DEVELOPER_DIR” required

SwiftPM needs Xcode’s SDK. Set:

export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer

Add to ~/.zshrc to make permanent.

Build fails with “missing required module”

A package dependency didn’t resolve. Try:

swift package resolve
swift package update

“Bundle.module” returns nil at runtime

You added a resource file but didn’t tell SwiftPM. Add to the target’s resources: list in Package.swift:

resources: [.process("Resources"), .copy("Docs")],

.process is for files SwiftPM should handle (xib, strings, …); .copy is for arbitrary files (especially when you need subdirectory structure preserved — see For developers/04 Architecture map).

Tests fail with “fatal error: nil”

Usually a missing resource. Run swift build first, check .build/.../Lettuce_LettuceKit.bundle/ for expected files.