Imported from trodemaster/blakeports (
.claude/skills/macports/SKILL.md). Install upstream withnpx skills add trodemaster/blakeports --skill macports. Copyright stays with the author.
MacPorts Development
Overview
Comprehensive guide for MacPorts port development workflows: creating and updating Portfiles, testing ports, debugging build failures, and mastering the port command-line tool.
Core Workflows
1. Checking for Updates
Check if any GitHub-hosted or SVN-hosted ports have new versions available:
bash scripts/check-updates.sh # Check all ports in current directory
The script will:
- Find all Portfiles using GitHub PortGroup or SVN fetch
- Skip ports where @trodemaster is not listed as a maintainer
- Query GitHub API for latest releases
- Query SourceForge RSS feeds for SVN release commits
- Compare current version/revision with latest
- Display color-coded results (✓ up to date, ✗ update available)
Supported sources:
- GitHub-hosted ports (via GitHub API)
- SourceForge SVN ports (via RSS feed parsing for "Releasing" commits)
Script available: scripts/check-updates.sh (in repo root scripts/) automates version checking.
Native alternative: port -v livecheck maintainer:<handle> checks every port you
maintain in one pass. scripts/check-updates.sh predates this and additionally parses
SourceForge SVN release RSS, which livecheck does not do. In a Portfile:
livecheck.url ${github.homepage}/releases/latest— track the latest GitHub release (skips pre-releases the default git-tag check would catch)livecheck.type none— for archived/dead upstreams, and in subports to suppress duplicate livecheck hits
2. Testing a Port
Prefer CI over local builds for verification. Run portindex and port lint --nitpick <portname> locally (fast, no build), update checksums locally (required to
even fetch the source), then push and trigger the Build <portname> GitHub Actions
workflow rather than running sudo port install -sv <portname> on this machine:
portindex # Regenerate port index
port lint --nitpick <portname> # Strict compliance check
git add <portname-portfile> && git commit -m "..." && git push
gh workflow run "Build <Portname>" # e.g. "Build netatalk"
gh run watch # or: gh run list -L 5
Reserve a local sudo port install -sv <portname> for when CI itself is failing and
you need to reproduce/debug the failure interactively on this machine — not as the
default verification step for an ordinary version bump.
Local test sequence (only when actually debugging on this machine):
portindex # Regenerate port index
port lint --nitpick <portname> # Strict compliance check
sudo port uninstall <portname> # Remove existing installation
sudo port clean --dist <portname> # Clear downloaded files
sudo port install -sv <portname> # Install with verbose output
Script available: scripts/test-port.sh <portname> (in repo root scripts/) automates this sequence.
Force a source build when the version is unchanged: port install pulls a prebuilt
binary archive whenever version/revision/epoch match an existing archive, so it can
silently skip your local Portfile change. Force it to build from source:
sudo port clean <portname> && sudo port -s install <portname>
Or validate destroot staging in isolation: sudo port destroot <portname>.
3. Updating Port Version
When bumping version number:
- Update
versionfield in Portfile - Keep existing checksums (do NOT delete)
- Run
sudo port checksum <portname> - MacPorts will fail and output correct checksums
- Copy checksum line from error output
- Update Portfile with new checksums
- Run
sudo port checksum <portname>again to verify - Test the build
Why keep old checksums: MacPorts needs them present to fetch the new file and calculate correct checksums.
Script available: scripts/update-checksums.sh <portname> (in repo root scripts/) guides this workflow.
4. Creating New Port
# 1. Create directory structure
mkdir -p category/portname
cd category/portname
# 2. Create Portfile (use template from assets/Portfile.template)
# 3. Generate checksums
portindex
sudo port checksum portname
# 4. Test
port lint --nitpick portname
sudo port install -sv portname
Template available: assets/Portfile.template provides standard structure.
5. Submitting to MacPorts (Creating PRs)
CRITICAL REQUIREMENTS:
- STOP AND WAIT before running
gh pr create— always show the full PR description to the user and wait for explicit approval. This is a strict rule with no exceptions. - STOP AND WAIT before committing — always show the commit message to the user and wait for explicit approval.
- MacPorts PRs must contain exactly ONE commit - squash/amend if needed
- Port lint must pass with 0 errors and 0 warnings (use
--nitpick) - GitHub pull requests are STRONGLY PREFERRED over Trac tickets (faster workflow)
Reference: https://guide.macports.org/chunked/project.contributing.html
Commit Message Format (Official MacPorts Guidelines)
Reference: https://trac.macports.org/wiki/CommitMessages
Subject line (50-55 characters, max 60):
- List modified ports first, followed by colon
- Be specific - avoid vague subjects like "Update to latest version"
- Include version numbers when updating
- Use glob notation for multiple related ports (e.g., "py3*-numpy:", "clang-3.[6-9]:")
Examples:
portname: update to 3.0.3
autoconf, libtool: fix build on arm64
py3*-numpy: add maintainer handle
Blank line - Required between subject and body
Body (wrap at 72 characters):
- Say what the commit itself cannot - provide context
- What was previous behavior, why incorrect, how this changes it
- Don't just translate the diff into English
- Use full URLs for Trac tickets: https://trac.macports.org/ticket/12345
- For GitHub PRs: full URL or #n syntax
- Do NOT mention checksums updates (always required, redundant)
Keywords (for Trac integration):
- "References", "Addresses", "See": adds comment to ticket
- "Closes", "Fixes": closes ticket and adds comment
Example:
portname: update to 3.0.3
* update to version 3.0.3
* add maintainer's github handle
* remove obsolete patches
Closes: https://trac.macports.org/ticket/12345
What to avoid:
- ❌ Revision numbers (SVN r1234, git SHA)
- ❌ "Update checksums" (always required)
- ❌ Overly detailed implementation explanations
- ❌ Describing what the software does
PR Description Format
ALWAYS use the official MacPorts PR template as the starting point.
📋 Template: See pr-template.md for the complete official template.
Key requirements:
- Use the template structure (Description, Type(s), Tested on, Verification)
- Fill in system info using the provided shell command
- Check all applicable verification items
- Omit the entire Type(s) section if none apply - update/submission are auto-detected from title, only include Type(s) if bugfix/enhancement/security fix applies
- Keep description concise and focused
- Do NOT repeat commit message verbatim
- Do NOT mention checksums (redundant)
- Do NOT describe software functionality
Workflow:
- Run lint check:
port lint --nitpick category/portname - Fix all warnings and errors
- Fetch upstream and create branch from
upstream/master(not fork master, which may lag):git fetch upstream master git checkout -b category/portname-update-X.Y.Z upstream/master - Copy/modify files from blakeports to macports-ports
- Stage changes:
git add category/portname/ - Draft commit message (following guidelines above)
- SHOW commit message to user — STOP and wait for explicit approval before proceeding
- Commit after approval:
git commit -m "message" - Rebase onto latest upstream/master before pushing (catches any commits that landed since branch creation):
git fetch upstream master git rebase upstream/master - Push to fork:
git push -u origin branch-name - Extract "Tested on" system info from CI runner logs (see pr-template.md) — do NOT use local machine info
- Draft PR description using the official template with CI-sourced system info
- SHOW PR description to user — STOP and wait for explicit approval before proceeding
- Create PR only after approval:
gh pr create --repo macports/macports-ports - If reviewer feedback requires changes: apply fix to blakeports → run CI (both modern and legacy runners) → verify all passing → THEN amend commit and force push to macports-ports
- If PR doesn't receive attention within a few days, email macports-dev@lists.macports.org
For new ports:
- Set ticket type to "submission" (if using Trac)
- Attach Portfile and any required patchfiles
For port updates/enhancements:
- Set ticket type to "enhancement" (misc), "defect" (bug fix), or "update" (version update)
- Cc the maintainer (get via
port info --maintainer portname) - Do NOT Cc openmaintainer@macports.org or nomaintainer@macports.org (not real addresses)
Note: Feature branches can be force-pushed after amendments. Master branch commits are immutable.
6. Debugging Build Failures
When builds fail:
# View build log
cat $(port logfile <portname>)
# Search for errors
grep -i error $(port logfile <portname>)
# Inspect work directory
cd $(port work <portname>)
# Test individual phases
sudo port configure <portname>
sudo port build <portname>
See debugging.md for comprehensive debugging techniques.
7. Creating Patches
CRITICAL: MacPorts applies patches with patch -p0. This means paths in the diff must be bare — no a//b/ prefixes. Using git diff without --no-prefix produces a/foo.go/b/foo.go paths that -p0 cannot resolve, causing "No file to patch" failures.
From a git branch (upstream PR candidates)
Always use --no-prefix when generating patches from git branches:
git diff --no-prefix origin/master..upstream-pr/<branch> -- [files...] > files/patch-name.diff
Verify the patch header looks like this (no a//b/):
diff --git pkg/foo/bar.go pkg/foo/bar.go
--- pkg/foo/bar.go
+++ pkg/foo/bar.go
Never edit patch files directly — always make the fix on the branch in the fork, then regenerate:
# 1. Fix on the branch
git -C /path/to/repo checkout upstream-pr/<branch>
# ... make changes, commit ...
# 2. Regenerate patch
git -C /path/to/repo diff --no-prefix origin/master..upstream-pr/<branch> -- [files] \
> sysutils/<port>/files/patch-name.diff
# 3. Bump the patch revision variable in the Portfile (e.g. set b1_rev 2)
From plain file edits
For simple single-file patches not tracked in a branch:
diff -u original.txt modified.txt > files/patch-name.diff
diff -u does not add a//b/ prefixes, so it is -p0 compatible by default.
git format-patch --no-prefix -<n> (or git diff --no-prefix HEAD) is the equivalent
when the fix is already committed on a branch.
If a patch must stay -p1
MacPorts defaults to patch -p0. Prefer regenerating with --no-prefix, but when
carrying a patch verbatim from an upstream PR that uses a/…b/ paths:
patch.pre_args-replace -p0 -p1
Verifying patches after a version bump
sudo port clean <portname>
sudo port -v patch <portname> # applies patchfiles against the new source
If a hunk no longer applies, fix it on the fork branch and regenerate — never hand-edit
the .diff. For large distfiles, skip port clean, manually revert the partially
applied hunks, then re-run port patch.
Adding to Portfile
patchfiles patch-name.diff
MacPorts approach: Use system libraries in place, avoid bundling.
Port Command Usage
Essential Commands
Installation:
sudo port install -sv <portname> # Verbose install (recommended)
sudo port install -d <portname> # Debug mode
Cleanup:
sudo port uninstall <portname> # Remove port
sudo port clean --dist <portname> # Clear downloads (important!)
sudo port clean --all <portname> # Clean everything (work dir + downloads)
Clean rebuild after source changes (preferred):
sudo port uninstall stash && sudo port clean --all stash && sudo port install stash
port clean --all must come after uninstall to clear the cached work directory so the next install re-fetches and rebuilds from scratch.
Rebuild only the port, skip dependency processing:
sudo port -n upgrade --force <portname>
The -n flag skips all dependency processing. Use this when dependencies are already up to date and you only want to rebuild the target port itself.
Avoid: sudo port upgrade --force <portname> without -n — this forces a rebuild of the port AND its outdated dependencies, which can trigger a large cascade of rebuilds.
Quality Checks:
port lint --nitpick <portname> # Strict compliance (use before PR)
port checksum <portname> # Verify checksums
Information:
port info <portname> # Port information
port deps <portname> # Show dependencies
port variants <portname> # Available variants
port work <portname> # Work directory path
port dir <portname> # Portfile directory path
port logfile <portname> # Build log path
Development:
portindex # Regenerate port index (after edits)
port test <portname> # Run test suite
Full reference: See port-commands.md for comprehensive command documentation.
Portfile Structure
IMPORTANT: When creating or modifying Portfiles, consult the official Port Phases reference:
📚 https://guide.macports.org/chunked/reference.phases.html
This comprehensive reference covers all available keywords for each phase:
- Fetch Phase - master_sites, distfiles, fetch.type (git/svn/etc)
- Checksum Phase - checksums format (rmd160, sha256, size)
- Extract Phase - compression formats (use_zip, use_xz, etc)
- Patch Phase - patchfiles, patch.args, patch.dir
- Configure Phase - configure.args, compiler flags (configure.cflags-append), environment variables
- Build Phase - build.cmd, build.args, use_parallel_build
- Test Phase - test.run, test.target, test.env
- Destroot Phase - destroot.args, destroot.destdir, destroot.keepdirs
Use this reference to:
- Choose appropriate configure options and compiler flags
- Set build/configure environment variables correctly
- Handle non-standard build systems (CMake, SCons, etc)
- Debug phase-specific failures
- Understand keyword modifiers (-append, -delete, -replace)
Minimal Portfile
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
PortSystem 1.0
PortGroup github 1.0
github.setup owner repo 1.2.3
revision 0
categories category
maintainers {@username provider} openmaintainer
license MIT
description Short description
long_description {*}${description}. Extended details.
checksums rmd160 HASH \
sha256 HASH \
size SIZE
depends_lib-append port:dependency
Key Sections
Dependencies:
depends_build- Build-time only (compilers, build tools)depends_lib- Runtime libraries (linked)depends_run- Runtime only (not linked)
Configuration:
configure.args --prefix=${prefix} \
--enable-feature
Variants:
variant feature description {
configure.args-append --with-feature
depends_lib-append port:feature-lib
}
Full syntax reference: See portfile-syntax.md for complete Portfile documentation.
Build Phase Debugging
Phase Order
fetch- Download sourcechecksum- Verify integrityextract- Unpack archivepatch- Apply patchesconfigure- Run configure scriptbuild- Compile sourcetest- Run tests (optional)destroot- Stage installationinstall- Install to system
Test Individual Phases
sudo port configure <portname> # Test configure only
sudo port build <portname> # Test build only
sudo port destroot <portname> # Test destroot only
Inspect Work Directory
cd $(port work <portname>) # Navigate to work directory
cd $(port work <portname>)/<portname>-<version> # Source directory
cat config.log # Configure output
Common Issues and Solutions
Checksum Mismatch
sudo port clean --dist <portname> # Clear cached download
sudo port checksum <portname> # Get correct checksums
Missing Dependencies
error: 'some_header.h' file not found
Solution: Find providing port and add to depends_lib:
port provides /path/to/header.h
Build Errors
cat $(port logfile <portname>) # Read full log
grep -B 5 -A 10 error $(port logfile <portname>) # Error context
Lint Warnings
Fix before submitting:
port lint --nitpick <portname>
Common issues:
- Line length >80 characters
- Missing long_description
- Inconsistent indentation
Quick Reference
Standard Test Workflow
portindex && \
port lint --nitpick <portname> && \
sudo port clean --dist <portname> && \
sudo port uninstall <portname> && \
sudo port install -sv <portname>
Clean Rebuild After Source Changes
sudo port uninstall <portname> && sudo port clean --all <portname> && sudo port install <portname>
Rebuild Only This Port (dependencies already installed)
sudo port -n upgrade --force <portname>
Checksum Update Workflow
# 1. Update version in Portfile (keep old checksums)
sudo port checksum <portname> # Shows correct checksums
# 2. Copy checksum line from error output to Portfile
sudo port checksum <portname> # Verify
Debug Build Failure
sudo port install -sv <portname> # Verbose install
cat $(port logfile <portname>) | less # Read log
cd $(port work <portname>) # Inspect source
Resources
Scripts (scripts/ in repo root)
All scripts live in the scripts/ directory in the repository root.
scripts/test-port.sh - Automate standard port testing workflow
scripts/update-checksums.sh - Guide checksum update process
scripts/check-updates.sh - Check ports for available updates; only reports ports where @trodemaster is a maintainer
Execute without reading into context for efficiency.
References (references/)
port-commands.md - Comprehensive port CLI reference with all commands, options, and workflows. Load when working with port commands or needing command syntax.
debugging.md - Build failure debugging techniques including log analysis, common error patterns, a catalog of common upstream build fixes (-Werror, missing includes, DESTDIR, racy builds), finding undeclared dependencies (trace mode, otool -L), work directory inspection, and environment troubleshooting. Load when diagnosing build failures.
portfile-syntax.md - Complete Portfile syntax reference covering structure, PortGroups (github/cmake/python/meson/legacysupport/obsolete/stub/makefile/conflicts_build/select), dependencies, variants, platform checks (compiler.cxx_standard, known_fail), distfile handling (stealth updates, multiple distfiles, dist_subdir), Tcl techniques, and style guide. Load when writing or modifying Portfiles.
pr-template.md - Official MacPorts PR template. ALWAYS use as the starting point when creating pull requests. Includes verification checklist and system info helper command.
Assets (assets/)
Portfile.template - Standard Portfile template for new ports
Best Practices
- Always run
portindexafter modifying Portfiles - Use
port lint --nitpickbefore submitting - must pass with 0 errors and 0 warnings - Clean distribution files (
--dist) when updating versions - Keep old checksums during version updates (MacPorts needs them)
- Test with verbose output (
-svflag) for debugging - Inspect build logs (
port logfile) when builds fail - Check work directory for build artifacts and logs
- Test individual phases to isolate failures
- Use 4 spaces for indentation in Portfiles (no tabs)
- Align continuation lines for readability
- ALWAYS stop and show commit messages and PR descriptions for explicit user approval — never commit or create a PR without approval
- Follow official commit message format - see https://trac.macports.org/wiki/CommitMessages
- Subject line: 50-55 characters, max 60 - list ports first with colon
- Body: wrap at 72 characters - provide context, not implementation details
- Use full URLs for Trac tickets and GitHub PRs in commit messages
- Don't mention checksums updates - always required, redundant
- Don't mention revision numbers (SVN r1234, git SHA) in commits
- MacPorts PRs must contain exactly ONE commit - squash or amend if needed
- Feature branches can be force-pushed - use
--force-with-leaseafter amends - Use system libraries in place - avoid bundling frameworks in MacPorts builds
platform darwinversion blocks: sort highestos.majorthreshold first (affects most systems), down to lowest; merge multiple blocks with the same threshold into one- Never update the upstream macports-ports PR before CI passes — always fix in blakeports, run CI, verify green, then amend upstream
- Always branch from
upstream/master, not from fork master — fork master can lag behind, causing conflicts when upstream merges a concurrent change to the same port before your PR lands - Revisions: local blakeports iteration and MacPorts submissions follow different rules.
- In blakeports / local dev MacPorts: do NOT bump
revisionfor minor Portfile changes while the upstream distfile is unchanged. Clean and rebuild to pick up the change:sudo port uninstall <port> && sudo port clean --all <port> && sudo port install <port>. - In a macports-ports submission: bump
revisionwhen a change alters the installed binary without a version change — adding or removing a dependency, changing configure args, adding a patch, or an ABI-incompatible dependency bump. - A build fix that only makes a broken port compile is not a revbump — no user has a working install at the old revision to protect.
- Reset
revisionto 0 wheneverversionorepochincreases.
- In blakeports / local dev MacPorts: do NOT bump
- Use path-style dependencies (
path:file:portname) forpkgconfigandglib2—path:bin/pkg-config:pkgconfigandpath:lib/pkgconfig/glib-2.0.pc:glib2, notport:pkgconfig/port:glib2. This is the dominant convention across macports-ports and what reviewers (e.g. reneeotten) flag in review. See portfile-syntax.md for the mechanism and rationale. - Don't manually declare
depends_buildfor autoconf/automake/libtool whenuse_autoreconf/use_autoconf/use_automakeis set — MacPorts base (portconfigure.tcl) adds those deps automatically. Manually listing them is redundant and gets flagged in review. - Prefer CI (
gh workflow run "Build <Portname>") over localsudo port installfor verifying a version bump or Portfile change. Local builds tie up this machine and don't match the runner matrix; push and let CI build across all configured platforms. Only build locally when actively debugging a CI failure that needs interactive reproduction. - Prefer
compiler.blacklist-append {clang < N}over hardcodingconfigure.compilerto a specific toolchain (e.g.macports-clang-11) when the real requirement is "system clang below version X lacks feature Y." The blacklist lets MacPorts' own fallback chain pick a working replacement instead of pinning one exact compiler — the idiomatic pattern across macports-ports and what reviewers flag in review (e.g. netatalk PR #34827, replacing a 10.7-10.9os.majorversion check + pinnedmacports-clang-11withcompiler.blacklist-append {clang < 700}). - Keep Portfile comments terse — state the fact and the reason in one line, not a multi-line paragraph. A reviewer or future editor can find the full story in the commit message or PR discussion; the inline comment only needs to answer "why is this line here."
- blakeports'
Build <Portname>workflow has oneworkflow_dispatchboolean input per platform —run_macos26,run_macos27_beta,run_macos15,run_leopard_ppc,run_leopard,run_snowleopard,run_lion,run_mountainlion,run_mavericks,run_yosemite,run_elcapitan— there is no singlerun_legacyflag. Pass-ffor each platform you want to include, e.g.:gh workflow run "Build netatalk" \ -f run_leopard_ppc=true -f run_leopard=true -f run_snowleopard=true \ -f run_lion=true -f run_mountainlion=true -f run_mavericks=true -Wno-error=incompatible-pointer-types, not the-function-variant — the-function-form is clang-only and breaks on gcc and on old clang that predates the diagnostic name (unknown-flag error, not just an ignored warning). The non--function-form is older, portable across clang/gcc, and needs no compiler/platform guard. Precedent:graphics/feh/Portfilehits the identicalscandir-comparator error and fixes it this way, unconditionally.- Don't trust a third-party fork's Portfile "fix" without checking it does something — a suggested fix borrowed from a community fork (e.g. macos-powerpc/powerpc-ports) may define a macro or flag that the upstream source doesn't actually reference. Grep the real upstream source for the macro/guard before adopting; a plausible-looking define can be a no-op.