Configuration
Complete reference for Porters configuration files.
Global Configuration
Porters maintains a global configuration file at ~/.porters/config.toml for user-wide settings and preferences.
Location:
- Windows:
C:\Users\<YourName>\.porters\config.toml - Linux/macOS:
~/.porters/config.toml
Automatic Creation:
The global config is automatically created on first run. Porters will:
- Create the
~/.porters/directory - Generate
config.tomlwith default settings - Run system requirements check
- Save detected compilers and build tools
Global Config Structure
[porters]
version = "0.1.0"
config_version = "1"
[user]
# Default author information for new projects
name = "Your Name"
email = "you@example.com"
default_license = "MIT" # Default license for new projects
[cache]
# Global cache directory for compiled executables
dir = "~/.porters/cache"
max_size_mb = 1024
auto_clean = true
[system]
# Last system requirements check
last_check = "2024-01-15T10:30:00Z"
[system.compilers]
# Detected C/C++ compilers (auto-populated)
gcc = "/usr/bin/gcc"
gpp = "/usr/bin/g++"
clang = "/usr/bin/clang"
clangpp = "/usr/bin/clang++"
[system.build_tools]
# Detected build systems (auto-populated)
cmake = "/usr/bin/cmake"
make = "/usr/bin/make"
xmake = "/usr/local/bin/xmake"
meson = "/usr/bin/meson"
ninja = "/usr/bin/ninja"
[preferences]
# User preferences
default_build_system = "cmake"
default_language = "cpp"
auto_add_to_path = true
check_updates = true
Configuration Fields
[porters] Section
version- Porters version that created this configconfig_version- Configuration file format version
[user] Section
name- Default author name for new projectsemail- Default email for new projectsdefault_license- Default license (MIT, Apache-2.0, GPL-3.0, etc.)
[cache] Section
dir- Directory for temporary build files and executablesmax_size_mb- Maximum cache size in megabytesauto_clean- Automatically clean old cache filescache_dir- Custom global cache directory path (optional)
Example:
[cache]
enabled = true
max_size_mb = 2048
auto_clean = true
cache_dir = "~/.porters/cache" # Optional custom path
[registry] Section
url- Registry repository URL (default: https://github.com/muhammad-fiaz/porters)auto_update- Automatically update registry indexindex_path- Local registry index directorylast_update- Timestamp of last registry update
Example:
[registry]
url = "https://github.com/muhammad-fiaz/porters"
auto_update = true
index_path = "~/.porters/registry-index"
last_update = "2024-01-15T10:30:00Z"
Global Offline Mode
Enable offline mode globally to prevent all network operations:
# In ~/.porters/config.toml
offline = true
When offline mode is enabled:
- ✅ Uses only cached dependencies
- ✅ Uses local registry index
- ❌ No network requests
- ❌ Cannot download new packages
Use case: Working in environments without internet access or wanting to ensure reproducible builds.
[system] Section
last_check- Timestamp of last system requirements checkcompilers- Detected compiler paths (auto-populated)build_tools- Detected build system paths (auto-populated)
[preferences] Section
default_build_system- Preferred build system (cmake, xmake, meson, make)default_language- Preferred language (c, cpp, both)auto_add_to_path- Automatically add Cargo bin to PATH on first runcheck_updates- Check for Porters updates automatically
System Requirements Check
On first run (or when running porters --check-system), Porters will:
-
Check for C/C++ Compilers:
- gcc, g++
- clang, clang++
- MSVC (Windows)
- MinGW (Windows)
-
Check for Build Systems:
- CMake
- Make
- XMake
- Meson
- Ninja
-
Display Results:
- ✅ Found tools with version numbers
- ❌ Missing tools with installation instructions
-
Save to Config:
- Detected tool paths saved to
~/.porters/config.toml - Used for faster detection in future runs
- Detected tool paths saved to
Example Output:
╭──────────────────────────────────────────────────╮
│ System Requirements Check │
╰──────────────────────────────────────────────────╯
Compilers
─────────
✅ g++ (version 11.4.0)
✅ gcc (version 11.4.0)
❌ clang++ (not found)
Build Systems
─────────────
✅ cmake (version 3.22.1)
✅ make (version 4.3)
Status: ✅ System ready!
Installation Instructions:
If tools are missing, Porters displays platform-specific installation commands:
Windows:
Install C/C++ compiler:
- MSVC: Install Visual Studio Build Tools
- MinGW: choco install mingw
- Clang: choco install llvm
Install build tools:
- CMake: choco install cmake
Linux (Debian/Ubuntu):
sudo apt-get update
sudo apt-get install gcc g++ clang cmake make
macOS:
xcode-select --install
brew install cmake
Manual Configuration
You can manually edit ~/.porters/config.toml to customize settings:
[user]
name = "Jane Developer"
email = "jane@example.com"
default_license = "Apache-2.0"
[preferences]
default_build_system = "xmake"
default_language = "cpp"
check_updates = true
[cache]
max_size_mb = 2048
auto_clean = true
After editing, run any Porters command to apply changes.
porters.toml
Main project configuration file.
Complete Example
[project]
name = "my-project"
version = "1.0.0"
description = "My awesome C++ project"
license = "Apache-2.0"
authors = ["Your Name <you@example.com>"]
repository = "https://github.com/username/my-project"
project-type = "application" # or "library"
entry_point = "src/main"
platforms = ["windows", "macos", "linux"]
keywords = ["application", "c", "cpp"]
readme = "README.md"
offline = false # Enable offline mode for this project
# Tool version requirements (like Python's requirements.txt)
[requires]
cpp = ">=17" # C++ standard version
cmake = ">=3.20" # CMake version
gcc = ">=9.0" # GCC version
clang = ">=12.0" # Clang version (alternative to gcc)
ninja = ">=1.10" # Ninja build tool version
make = ">=4.0" # Make version
meson = ">=0.60" # Meson version
bazel = ">=5.0" # Bazel version
conan = ">=1.50" # Conan version
vcpkg = "*" # Any version of vcpkg
# Extensions to auto-install from crates.io
extensions = [
"porters-format", # Code formatter extension
"porters-lint", # Linting extension
"porters-doc" # Documentation generator
]
[dependencies]
fmt = { git = "https://github.com/fmtlib/fmt", tag = "10.1.1" }
spdlog = { git = "https://github.com/gabime/spdlog", branch = "v1.x" }
mylib = { path = "../mylib" }
[dev-dependencies]
catch2 = { git = "https://github.com/catchorg/Catch2" }
benchmark = { git = "https://github.com/google/benchmark" }
[optional-dependencies]
zlib = { git = "https://github.com/madler/zlib" }
[build]
system = "cmake"
options = ["-DBUILD_SHARED_LIBS=ON"]
[build.env]
CC = "clang"
CXX = "clang++"
# Build lifecycle scripts
[build.scripts]
pre-build = "echo Building..."
post-build = "strip build/myapp"
pre-install = "echo Installing..."
post-install = "echo Done!"
# Custom CLI commands
[[commands]]
name = "format"
description = "Format source code"
script = "clang-format -i src/**/*.cpp"
[[commands]]
name = "docs"
description = "Generate documentation"
script = "doxygen Doxyfile"
[commands.env]
DOXYGEN_OUTPUT = "docs/html"
# Named script shortcuts
[scripts]
test-all = "cargo build && cargo test"
deploy = "./deploy.sh production"
Project Section
Required fields:
name- Project nameversion- Semantic version (e.g., "1.0.0")
Optional fields:
description- Project descriptionlicense- SPDX license identifierauthors- List of authorsrepository- Git repository URLproject-type- "application" or "library"entry_point- Main entry pointplatforms- Target platformskeywords- Search keywordsreadme- README file path
Dependencies Section
Dependency sources:
Git (HTTPS):
fmt = { git = "https://github.com/fmtlib/fmt" }
Git (SSH):
spdlog = { git = "git@github.com:gabime/spdlog.git" }
With version constraints:
fmt = { git = "https://github.com/fmtlib/fmt", tag = "10.1.1" }
boost = { git = "https://github.com/boostorg/boost", branch = "boost-1.80.0" }
Local path:
mylib = { path = "../mylib" }
Build Section
[build]
system = "cmake" # cmake, xmake, meson, make, custom
options = ["-DCMAKE_BUILD_TYPE=Release"]
[build.env]
CMAKE_PREFIX_PATH = "/usr/local"
Run Section - Direct File Execution (COMPLETELY OPTIONAL)
⚠️ YOU DON'T NEED THIS SECTION!
The porters execute command works 100% automatically without any configuration. This section only exists for advanced manual overrides.
What Works Automatically (No [run] Section Needed):
- ✅ Compiler Detection - Finds gcc/clang/g++/clang++ in your PATH
- ✅ Dependency Resolution - Reads dependencies from
[dependencies] - ✅ Include Paths - Automatically adds
-Ifor all dependency includes - ✅ Library Paths - Automatically adds
-Lfor all dependency libraries - ✅ File Type Detection -
.c→ C compiler,.cpp→ C++ compiler - ✅ Supported Extensions -
.c,.cpp,.cxx,.cc,.c++,.cp,.C,.CPP
Zero Configuration Example:
# No porters.toml needed at all!
porters execute hello.c
# With dependencies - automatically resolved
porters execute my_app.cpp
Optional Manual Overrides (Only If You Need Custom Behavior):
[run]
# Extra include directories (beyond automatic dependency includes)
include-dirs = ["./include", "./extra/include"]
# Exclude patterns (rarely needed)
exclude-patterns = ["test_*", "*_backup.c"]
# Compiler flags (only if you want warnings, optimizations, etc.)
compiler-flags = ["-Wall", "-O2", "-std=c17"]
# Linker flags (only if you need extra libraries)
linker-flags = ["-lm", "-lpthread"]
# Override compiler (only if you need a specific one)
c-compiler = "clang" # Default: auto-detect
cpp-compiler = "clang++" # Default: auto-detect
# Execution mode settings (default: false for both)
use-external-terminal = false # Open programs in new external terminal window
no-console = false # Run without console window (Windows GUI apps)
Execution Mode Settings:
Configure how porters execute runs your programs:
-
use-external-terminal(default:false)- When
true: Opens program in new external terminal window - Useful for: GUI applications, interactive programs needing separate window
- CLI override:
--externalflag - Example use cases:
- Interactive TUI applications that manage terminal state
- Games that need full terminal control
- Programs that should run independently of IDE/editor
- When
-
no-console(default:false)- When
true: Runs program without console window (Windows only) - Useful for: Pure GUI applications with no console output
- CLI override:
--no-consoleflag - Example use cases:
- Windows GUI applications using Win32 API, SDL, SFML
- Applications where console window would be distracting
- Release builds of GUI apps
- When
Example Configurations:
# For GUI game development
[run]
use-external-terminal = true # Run in separate window
no-console = true # No console clutter
linker-flags = ["-lSDL2"] # Link SDL library
# For interactive terminal application
[run]
use-external-terminal = true # Needs dedicated terminal
compiler-flags = ["-Wall", "-Wextra"]
# For standard CLI tool (defaults are fine, no [run] needed)
# Just use: porters execute main.c
Note: CLI flags (--external, --no-console) always override config settings.
When You Might Use [run]:
- Adding project-specific include paths not in dependencies
- Setting custom compiler warnings or optimizations
- Linking additional system libraries
- Using a specific compiler version
- Configuring default execution mode for GUI apps
- Setting up consistent behavior for team development
Tool Version Requirements
Specify minimum versions for build tools and compilers. Porters will validate these before building.
Supported version operators:
*- Any version>=1.2.3- Greater than or equal<=1.2.3- Less than or equal>1.2.3- Greater than<1.2.3- Less than^1.2.3- Compatible (allows patch and minor updates, ~= caret in Cargo)~1.2.3- Tilde (allows patch updates only)1.2.3or==1.2.3- Exact version
Example:
[requires]
c = ">=11" # C11 or later
cpp = ">=17" # C++17 or later
cmake = ">=3.20" # CMake 3.20+
gcc = ">=9.0" # GCC 9.0+
clang = "^12.0" # Clang 12.x (allows 12.1, 12.2, but not 13.0)
ninja = "~1.10.0" # Ninja 1.10.x (allows 1.10.1, but not 1.11)
make = "*" # Any Make version
meson = ">=0.60" # Meson 0.60+
bazel = ">=5.0" # Bazel 5.0+
conan = ">=1.50" # Conan 1.50+
vcpkg = "*" # Any vcpkg version
xmake = ">=2.7" # XMake 2.7+
msvc = ">=19.30" # MSVC 19.30+ (Visual Studio 2022)
Version check output:
$ porters build
✓ Checking tool version requirements...
✓ C++ Compiler: requires >=17, found 20
✓ CMake: requires >=3.20, found 3.25.1
✓ GCC: requires >=9.0, found 11.3.0
✓ All tool requirements satisfied ✓
If requirements not met:
$ porters build
✓ Checking tool version requirements...
🤔 Oops! Unsatisfied version requirements:
❌ C++: requires >=17, found 14
❌ CMake: requires >=3.20, found 3.15.0
❌ GCC: requires >=9.0, but tool not found in PATH
Please install or upgrade the required tools to continue.
See: https://github.com/muhammad-fiaz/porters#requirements
Extension Auto-Install
Automatically install extensions from crates.io when running porters sync.
Example:
extensions = [
"porters-format", # Code formatter
"porters-lint", # Linter
"porters-doc", # Documentation generator
"porters-test-runner" # Test runner
]
Extensions are always installed in the dev category and can be published to crates.io by anyone.
During sync:
$ porters sync
✓ Syncing dependencies from porters.toml
ℹ Auto-installing 3 extensions from config...
📦 Installing extension 'porters-format'...
✓ Extension 'porters-format' installed successfully! 🔌
📦 Extension 'porters-lint' already installed, skipping
📦 Installing extension 'porters-doc'...
✓ Extension 'porters-doc' installed successfully! 🔌
Custom Commands
Define custom CLI commands in your porters.toml for project-specific tasks.
Example:
[[commands]]
name = "format"
description = "Format all C++ source files"
script = "clang-format -i src/**/*.cpp include/**/*.hpp"
[[commands]]
name = "lint"
description = "Run clang-tidy linter"
script = "clang-tidy src/*.cpp -- -Iinclude"
[[commands]]
name = "docs"
description = "Generate Doxygen documentation"
script = "doxygen Doxyfile"
[commands.env]
DOXYGEN_OUTPUT = "docs/html"
OUTPUT_DIR = "build/docs"
Usage:
$ porters format # Runs clang-format
$ porters lint # Runs clang-tidy
$ porters docs # Generates documentation
Named Scripts
Quick script shortcuts for common tasks.
Example:
[scripts]
test-all = "cargo build && cargo test --all"
deploy-prod = "./scripts/deploy.sh production"
clean-all = "rm -rf build ports .porters-cache"
bench = "cargo build --release && ./build/benchmark"
Usage:
$ porters run-script test-all
$ porters run-script deploy-prod
$ porters run-script bench
Dependency Checksums
Verify dependency integrity with SHA-256 checksums (automatically managed by lockfile).
Example:
[dependencies]
fmt = {
git = "https://github.com/fmtlib/fmt",
tag = "10.1.1",
checksum = "sha256:a1b2c3d4e5f6..." # Optional, auto-calculated if omitted
}
Porters automatically:
- Calculates checksums on first download
- Stores checksums in
porters.lock - Verifies checksums on subsequent builds
Checksum mismatch:
⚠️ Dependency hash mismatch for 'fmt':
Expected: abc123...
Found: def456...
This may indicate tampering or corruption. Please verify the source.
Global Configuration
Location:
- Linux/macOS:
~/.porters/config.toml - Windows:
C:\Users\<username>\.porters\config.toml
Example
[settings]
parallel_jobs = 8
cache_enabled = true
[packages.fmt]
name = "fmt"
version = "10.1.1"
source = "https://github.com/fmtlib/fmt"
install_path = "/home/user/.porters/packages/fmt"
installed_at = "2024-01-15T10:30:00Z"
Lock File (porters.lock)
Auto-generated file ensuring reproducible builds.
Format
version = "1"
updated_at = "2024-01-15T10:30:00Z"
[dependencies.fmt]
name = "fmt"
version = "10.1.1"
source = { Git = { url = "https://github.com/fmtlib/fmt", rev = "a1b2c3d" } }
checksum = "sha256:..."
dependencies = []
[dependencies.spdlog]
name = "spdlog"
version = "1.12.0"
source = { Git = { url = "https://github.com/gabime/spdlog", rev = "e4f5678" } }
dependencies = ["fmt"]
Do not edit manually. Use porters lock to regenerate.
Transitive Dependencies
Porters automatically resolves dependencies-of-dependencies recursively.
How it works:
- When you add a dependency, Porters checks if it has its own
porters.toml - If found, Porters reads the dependency's dependencies
- This process repeats recursively to build a full dependency graph
- Circular dependencies are detected and reported as errors
- Version conflicts are detected and must be manually resolved
Example:
Your project's porters.toml:
[dependencies]
mylib = { path = "../mylib" }
mylib's porters.toml (transitive dependencies):
[dependencies]
fmt = { git = "https://github.com/fmtlib/fmt", tag = "10.1.1" }
spdlog = { git = "https://github.com/gabime/spdlog" }
When you run porters sync, Porters will:
- Install
mylib(your direct dependency) - Detect
mylibhas dependencies onfmtandspdlog - Automatically install
fmtandspdlog(transitive dependencies) - Build them in the correct order:
fmt→spdlog→mylib→your-project
Dependency graph visualization:
porters graph
# Output:
📦 Resolved dependency build order: fmt → spdlog → mylib
Circular dependency detection:
❌ Circular dependency detected involving: mylib
This means there's a circular dependency chain. Check your dependency tree.
Version conflict detection:
❌ Dependency conflicts detected:
fmt requires versions: 10.1.1, 9.0.0
Two dependencies require different versions of 'fmt'. You must manually resolve this conflict.
Offline Mode
Porters supports working entirely offline using only cached dependencies and local registry index. This is useful for:
- 🔒 Secure environments without internet access
- ✈️ Air-gapped networks
- 🏗️ Reproducible builds
- 📦 CI/CD pipelines with pre-populated cache
Enabling Offline Mode
Global offline mode (affects all projects):
# ~/.porters/config.toml
offline = true
Project offline mode (project-specific):
# porters.toml
[project]
offline = true
Temporary offline mode (command-line):
porters build --offline
porters add <dep> --offline
porters sync --offline
How Offline Mode Works
When offline mode is enabled:
-
Network Operations Blocked:
- ❌ No Git clones/fetches
- ❌ No registry updates from GitHub
- ❌ No package downloads
-
Cache-First Resolution:
- ✅ Uses global cache (
~/.porters/cache/) - ✅ Uses local cache (
.porters/cache/) - ✅ Uses local registry index (
~/.porters/registry-index/)
- ✅ Uses global cache (
-
Error Handling:
- If dependency not in cache → clear error message
- Suggests running without
--offlineto download
Preparing for Offline Mode
Before going offline, ensure all dependencies are cached:
# 1. Sync all dependencies (downloads if needed)
porters sync
# 2. Verify cache contents
porters cache list
# 3. Enable offline mode
porters config set offline true
# 4. Test that build works offline
porters build --offline
Offline Mode Example Workflow
Setup (with internet):
# Initialize project
porters init
# Add dependencies
porters add https://github.com/fmtlib/fmt
porters add https://github.com/gabime/spdlog
# Sync (downloads and caches)
porters sync
# Verify cache
porters cache stats
# Output: Packages: 2, Total Size: 15.2 MB
Work offline (no internet):
# Enable offline mode
export PORTERS_OFFLINE=1
# or add offline=true to porters.toml
# Build works entirely from cache
porters build --offline
# ✅ Using globally cached fmt
# ✅ Using globally cached spdlog
# 🔨 Building project...
Offline Mode with Registry
The registry can be used offline with a local index:
# 1. Update registry index (with internet)
porters registry update
# 2. Work offline
porters search fmt --offline
# Searches local registry index
porters info spdlog --offline
# Shows info from local index
Troubleshooting Offline Mode
"Package not found in cache":
# Temporarily disable offline to download
porters sync
# Then re-enable offline
"Registry index not found":
# Update registry index first
porters registry update
# Then work offline
Check what's cached:
# List all cached packages
porters cache list
# Show cache statistics
porters cache stats
Best Practices
-
Pre-populate cache before going offline:
porters sync porters cache verify -
Use lock file for reproducibility:
porters lock # Commit porters.lock to version control -
Periodic cache updates:
# Weekly: update registry and dependencies porters registry update porters update -
CI/CD offline builds:
# .github/workflows/build.yml - name: Restore cache uses: actions/cache@v3 with: path: ~/.porters/cache key: ${{ runner.os }}-porters-${{ hashFiles('**/porters.lock') }} - name: Build offline run: porters build --offline