Skip to content

Commit c858bf4

Browse files
Add installation packaging script for FreeBSD
Swift should be distributed to FreeBSD users as a .pkg file which can be installed using pkg, the system package manager. This allows for a better user experience because it handles installing all of the required dependencies as well as placing the compiler in the user's PATH. To create a FreeBSD package, we should have a script that automates the process of creating one. This commit adds such a script. It is designed to be invoked by the CI system, but can also be invoked by an end user.
1 parent 49821e7 commit c858bf4

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed

platforms/FreeBSD/Readme.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# FreeBSD Swift Package Builder Script
2+
3+
## Description
4+
5+
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.
6+
7+
## Summary
8+
9+
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.
10+
11+
The script performs the following key operations:
12+
13+
- Validation: Ensures the current platform is FreeBSD and validates command-line arguments
14+
- Directory Setup: Creates temporary staging areas for package files and metadata
15+
- Toolchain Processing: Copies the Swift toolchain to the appropriate directory structure (`/usr/local/swift`)
16+
- Symlink Creation: Creates symbolic links in `/usr/local/bin` for `swift` and `swiftc` commands
17+
- Package Manifest Generation: Creates a FreeBSD package manifest with metadata including version, description, and maintainer information
18+
- File List Generation: Builds a complete list of files and symlinks to include in the package
19+
- Package Creation: Uses FreeBSD's `pkg create` command to build the final package with Zstandard compression
20+
- Cleanup: Removes temporary staging directories
21+
22+
The resulting package installs Swift to `/usr/local/swift` with convenient symlinks in `/usr/local/bin`, making Swift commands available in the standard path.
23+
24+
## Usage Examples
25+
26+
### Basic Usage
27+
28+
```
29+
# Package a Swift 6.2 toolchain
30+
./makePackage /home/user/swift-6.2-RELEASE-freebsd /usr/local/packages/swift-6.2.pkg
31+
```
32+
33+
### Complete Workflow Example
34+
35+
```
36+
# 1. Create the package
37+
./makePackage ./swift-6.2-RELEASE-freebsd ./swift-6.2.pkg
38+
39+
# 2. Install the package (as root)
40+
pkg install ./swift-6.2.pkg
41+
42+
# 3. Verify installation
43+
swift --version
44+
swiftc --help
45+
```

platforms/FreeBSD/makePackage

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#!/bin/sh -e
2+
#
3+
# Builds a FreeBSD package out of a toolchain.
4+
# Usage: makePackage /path/to/toolchain /path/to/final/package
5+
6+
# Validate the command line arguments.
7+
if [ "$#" -ne 2 ]; then
8+
echo "Usage: $0 /path/to/toolchain /path/to/final/package" >/dev/stderr
9+
exit 1
10+
fi
11+
12+
# Create some variables for ease of use.
13+
PLATFORM="$(uname)"
14+
CURRENT_DIRECTORY="$(pwd)"
15+
TOOLCHAIN_PATH="$1"
16+
PACKAGE_PATH="$2"
17+
PACKAGE_STAGING="$(mktemp -d)"
18+
METADATA_STAGING="$(mktemp -d)"
19+
SWIFT_TOOLCHAIN_HOME="$PACKAGE_STAGING/usr/local/swift"
20+
21+
# Check the platform and exit if we aren't running on FreeBSD.
22+
if [ ! "$PLATFORM" = "FreeBSD" ]; then
23+
echo "Platform $PLATFORM is not supported" >/dev/stderr
24+
exit 1
25+
fi
26+
27+
# Create necessary directories on disk.
28+
mkdir -p "$METADATA_STAGING"
29+
mkdir -p "$PACKAGE_STAGING/usr/local/bin"
30+
echo "Staging Swift package files in $PACKAGE_STAGING..."
31+
32+
# Check the path that we were provided. We want to ensure that the
33+
# path that we were given is the root of the produced toolchain.
34+
# In other words, directly below the directory that we were passed
35+
# should be another directory named `usr`.
36+
if [ ! -d "$TOOLCHAIN_PATH/usr" ]; then
37+
echo "error: Directory provided was not the root directory of a toolchain" >/dev/stderr
38+
exit 1
39+
fi
40+
41+
# Stage the package files, dropping the initial usr/ directory
42+
# that is at the root of the provided toolchain from the path
43+
# but keeping everything after it.
44+
# So, the directory structure relative to the root of the staging
45+
# area will be
46+
# - ./usr/local/swift/bin
47+
# - ./usr/local/swift/lib
48+
# and so on.
49+
mkdir -p "$SWIFT_TOOLCHAIN_HOME"
50+
cp -R "$TOOLCHAIN_PATH/usr/" "$SWIFT_TOOLCHAIN_HOME"
51+
echo "Copied toolchain into $SWIFT_TOOLCHAIN_HOME."
52+
53+
# Because the Swift toolchain will be installed to /usr/local/swift,
54+
# we need to create symlinks to the actual Swift binaries. This is
55+
# because users expect the installed binaries to be in the path at
56+
# /usr/local/bin.
57+
echo "Creating symlinks to Swift tools..."
58+
echo "Entering $PACKAGE_STAGING/usr/local/bin"
59+
cd "$PACKAGE_STAGING/usr/local/bin"
60+
ln -s "../swift/bin/swift" "swift"
61+
ln -s "../swift/bin/swiftc" "swiftc"
62+
echo "Returning to $CURRENT_DIRECTORY"
63+
64+
# Once the symlink structure has been created, then we must generate
65+
# the list of files to store in the package. To do so, we iterate over
66+
# the staging area, and generate the list of files. These paths need
67+
# to be relative to ./usr/local since that is the prefix that we indicate
68+
# below in the manifest file.
69+
#
70+
# When the package is created using `pkg create`, pkg will handle the
71+
# process of generating the file hashes, etc. for everything here.
72+
echo "Generate package list..."
73+
cd "$PACKAGE_STAGING/usr/local"
74+
find "." -type l > "$METADATA_STAGING/pkg-plist"
75+
find "." -type f >> "$METADATA_STAGING/pkg-plist"
76+
cd "$CURRENT_DIRECTORY"
77+
78+
SWIFT_VERSION="$("$SWIFT_TOOLCHAIN_HOME/bin/swift" --version | grep -Eo 'version [0-9.]+' | sed 's/version //')"
79+
echo "Swift version being packaged is $SWIFT_VERSION"
80+
81+
# Create the manifest file. All fields below are required. pkg_create(3)
82+
# will add additional fields as part of generating the package.
83+
echo "Generating manifest..."
84+
cat > "$METADATA_STAGING/manifest" <<EOF
85+
{
86+
"name": "swift",
87+
"version": "$SWIFT_VERSION",
88+
"desc": "The Swift programming language",
89+
"arch": "$(uname -m)",
90+
"prefix": "/usr/local",
91+
"origin": "",
92+
"comment": "",
93+
"maintainer": "Apple Inc.",
94+
"www": "https://www.swift.org"
95+
}
96+
EOF
97+
98+
# Log where we wrote the metadata files.
99+
echo "Wrote manifest file to $METADATA_STAGING/manifest"
100+
echo "Wrote package file list to $METADATA_STAGING/pkg-plist"
101+
102+
# Generate the package. FreeBSD will helpfully determine the required
103+
# dependencies for us based on the shared libraries that the binaries
104+
# in the toolchain require. We should call `pkg update` beforehand to
105+
# ensure this package database of dependencies is updated, just for
106+
# good measure.
107+
echo "Building package..."
108+
PACKAGE_FILE_NAME="$METADATA_STAGING/swift-$SWIFT_VERSION.pkg"
109+
mkdir -p "$(dirname $PACKAGE_PATH)"
110+
pkg update
111+
pkg create -f tzst -M "$METADATA_STAGING/manifest" -r "$PACKAGE_STAGING" -p "$METADATA_STAGING/pkg-plist" -o "$METADATA_STAGING"
112+
mv "$PACKAGE_FILE_NAME" "$PACKAGE_PATH"
113+
114+
# Cleanup.
115+
rm -rf "$PACKAGE_STAGING" "$METADATA_STAGING"

0 commit comments

Comments
 (0)