Skip to content

Add installation packaging script for FreeBSD #431

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions platforms/FreeBSD/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# FreeBSD Swift Package Builder Script

## Description

This shell script automates the creation of FreeBSD packages (.pkg files) for Swift programming language toolchains. It takes a compiled Swift toolchain directory as input and produces a properly structured FreeBSD package that can be installed using the `pkg` package manager.

## Summary

The script is specifically designed for FreeBSD systems and requires a properly structured Swift toolchain with a `usr/` subdirectory containing the Swift binaries and libraries.

The script performs the following key operations:

- Validation: Ensures the current platform is FreeBSD and validates command-line arguments
- Directory Setup: Creates temporary staging areas for package files and metadata
- Toolchain Processing: Copies the Swift toolchain to the appropriate directory structure (`/usr/local/swift`)
- Symlink Creation: Creates symbolic links in `/usr/local/bin` for `swift` and `swiftc` commands
- Package Manifest Generation: Creates a FreeBSD package manifest with metadata including version, description, and maintainer information
- File List Generation: Builds a complete list of files and symlinks to include in the package
- Package Creation: Uses FreeBSD's `pkg create` command to build the final package with Zstandard compression
- Cleanup: Removes temporary staging directories

The resulting package installs Swift to `/usr/local/swift` with convenient symlinks in `/usr/local/bin`, making Swift commands available in the standard path.

## Usage Examples

### Basic Usage

```
# Package a Swift 6.2 toolchain
./makePackage /home/user/swift-6.2-RELEASE-freebsd /usr/local/packages/swift-6.2.pkg
```

### Complete Workflow Example

```
# 1. Create the package
./makePackage ./swift-6.2-RELEASE-freebsd ./swift-6.2.pkg

# 2. Install the package (as root)
pkg install ./swift-6.2.pkg

# 3. Verify installation
swift --version
swiftc --help
```
115 changes: 115 additions & 0 deletions platforms/FreeBSD/makePackage
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/bin/sh -e
#
# Builds a FreeBSD package out of a toolchain.
# Usage: makePackage /path/to/toolchain /path/to/final/package

# Validate the command line arguments.
if [ "$#" -ne 2 ]; then
echo "Usage: $0 /path/to/toolchain /path/to/final/package" >/dev/stderr
exit 1
fi

# Create some variables for ease of use.
PLATFORM="$(uname)"
CURRENT_DIRECTORY="$(pwd)"
TOOLCHAIN_PATH="$1"
PACKAGE_PATH="$2"
PACKAGE_STAGING="$(mktemp -d)"
METADATA_STAGING="$(mktemp -d)"
SWIFT_TOOLCHAIN_HOME="$PACKAGE_STAGING/usr/local/swift"

# Check the platform and exit if we aren't running on FreeBSD.
if [ ! "$PLATFORM" = "FreeBSD" ]; then
echo "Platform $PLATFORM is not supported" >/dev/stderr
exit 1
fi

# Create necessary directories on disk.
mkdir -p "$METADATA_STAGING"
mkdir -p "$PACKAGE_STAGING/usr/local/bin"
echo "Staging Swift package files in $PACKAGE_STAGING..."

# Check the path that we were provided. We want to ensure that the
# path that we were given is the root of the produced toolchain.
# In other words, directly below the directory that we were passed
# should be another directory named `usr`.
if [ ! -d "$TOOLCHAIN_PATH/usr" ]; then
echo "error: Directory provided was not the root directory of a toolchain" >/dev/stderr
exit 1
fi

# Stage the package files, dropping the initial usr/ directory
# that is at the root of the provided toolchain from the path
# but keeping everything after it.
# So, the directory structure relative to the root of the staging
# area will be
# - ./usr/local/swift/bin
# - ./usr/local/swift/lib
# and so on.
mkdir -p "$SWIFT_TOOLCHAIN_HOME"
cp -R "$TOOLCHAIN_PATH/usr/" "$SWIFT_TOOLCHAIN_HOME"
echo "Copied toolchain into $SWIFT_TOOLCHAIN_HOME."

# Because the Swift toolchain will be installed to /usr/local/swift,
# we need to create symlinks to the actual Swift binaries. This is
# because users expect the installed binaries to be in the path at
# /usr/local/bin.
echo "Creating symlinks to Swift tools..."
echo "Entering $PACKAGE_STAGING/usr/local/bin"
cd "$PACKAGE_STAGING/usr/local/bin"
ln -s "../swift/bin/swift" "swift"
ln -s "../swift/bin/swiftc" "swiftc"
echo "Returning to $CURRENT_DIRECTORY"

# Once the symlink structure has been created, then we must generate
# the list of files to store in the package. To do so, we iterate over
# the staging area, and generate the list of files. These paths need
# to be relative to ./usr/local since that is the prefix that we indicate
# below in the manifest file.
#
# When the package is created using `pkg create`, pkg will handle the
# process of generating the file hashes, etc. for everything here.
echo "Generate package list..."
cd "$PACKAGE_STAGING/usr/local"
find "." -type l > "$METADATA_STAGING/pkg-plist"
find "." -type f >> "$METADATA_STAGING/pkg-plist"
cd "$CURRENT_DIRECTORY"

SWIFT_VERSION="$("$SWIFT_TOOLCHAIN_HOME/bin/swift" --version | grep -Eo 'version [0-9.]+' | sed 's/version //')"
echo "Swift version being packaged is $SWIFT_VERSION"

# Create the manifest file. All fields below are required. pkg_create(3)
# will add additional fields as part of generating the package.
echo "Generating manifest..."
cat > "$METADATA_STAGING/manifest" <<EOF
{
"name": "swift",
"version": "$SWIFT_VERSION",
"desc": "The Swift programming language",
"arch": "$(uname -m)",
"prefix": "/usr/local",
"origin": "",
"comment": "",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this should be a one-liner description that will show up in pkg info

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the description field, we already have “the Swift programming language.” Any suggestions on what a short, succinct comment about the package could be?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it can just duplicate what we have in description

"maintainer": "Apple Inc.",
Copy link
Member

@michael-yuji michael-yuji Jun 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maintainer should be a email address. see pkg-create(8)

"www": "https://www.swift.org"
}
EOF

# Log where we wrote the metadata files.
echo "Wrote manifest file to $METADATA_STAGING/manifest"
echo "Wrote package file list to $METADATA_STAGING/pkg-plist"

# Generate the package. FreeBSD will helpfully determine the required
# dependencies for us based on the shared libraries that the binaries
# in the toolchain require. We should call `pkg update` beforehand to
# ensure this package database of dependencies is updated, just for
# good measure.
echo "Building package..."
PACKAGE_FILE_NAME="$METADATA_STAGING/swift-$SWIFT_VERSION.pkg"
mkdir -p "$(dirname $PACKAGE_PATH)"
pkg update
pkg create -f tzst -M "$METADATA_STAGING/manifest" -r "$PACKAGE_STAGING" -p "$METADATA_STAGING/pkg-plist" -o "$METADATA_STAGING"
mv "$PACKAGE_FILE_NAME" "$PACKAGE_PATH"

# Cleanup.
rm -rf "$PACKAGE_STAGING" "$METADATA_STAGING"