Cross-platform Compatibility
Launchpad is designed to work seamlessly across different operating systems. This guide explains how Launchpad handles platform-specific nuances and how to optimize your usage for cross-platform scenarios.
Platform Detection
Launchpad automatically detects the operating system it's running on and adjusts its behavior accordingly:
// Example of how Launchpad detects platforms internally
import { platform } from 'node:os'
const isWindows = platform() === 'win32'
const isMacOS = platform() === 'darwin'
const isLinux = platform() === 'linux'Installation Philosophy Across Platforms
Launchpad follows the pkgm approach consistently across all platforms:
Unix-like Systems (macOS, Linux)
- Primary:
/usr/localfor system-wide installations - Fallback:
~/.localfor user-specific installations - Never uses:
/opt/homebrew(Homebrew's directory) - Maintains: Clean separation from package managers like Homebrew
Windows
- Primary:
%LOCALAPPDATA%for user-specific installations - Alternative:
%PROGRAMFILES%for system-wide (requires elevation) - Avoids: Conflicting with Windows package managers
This consistent approach ensures clean coexistence with existing package managers on all platforms.
Path Handling
Windows Path Differences
On Windows, paths use backslashes (\) rather than forward slashes (/). Launchpad normalizes paths internally:
// Example of path normalization
import path from 'node:path'
const normalizedPath = path.normalize('/usr/local/bin')
// On Windows, this becomes something like 'C:\usr\local\bin'Home Directory Resolution
Launchpad resolves the ~ symbol to the user's home directory across all platforms:
// Launchpad's internal approach
const homePath = process.env.HOME || process.env.USERPROFILE || '~'Shell Integration
Each platform uses different shells by default:
- Windows: PowerShell or CMD
- macOS: Zsh (newer versions) or Bash (older versions)
- Linux: Bash, Zsh, or others
Launchpad adapts its PATH modification strategies accordingly.
Shell Message Customization by Platform
You can customize shell messages differently on each platform:
# macOS/Linux - Using ~/.zshrc or ~/.bashrc
export LAUNCHPAD_SHELL_ACTIVATION_MESSAGE="🍎 macOS environment ready: {path}"
export LAUNCHPAD_SHELL_DEACTIVATION_MESSAGE="🍎 macOS environment closed"# Windows - Using PowerShell profile
$env:LAUNCHPAD_SHELL_ACTIVATION_MESSAGE = "🪟 Windows environment ready: {path}"
$env:LAUNCHPAD_SHELL_DEACTIVATION_MESSAGE = "🪟 Windows environment closed"File System Permissions
Permission handling differs by platform:
- Unix-like Systems (macOS, Linux): Uses Unix permissions (rwx)
- Windows: Uses ACLs (Access Control Lists)
When creating shims, Launchpad sets the appropriate permissions:
// On Unix-like systems
fs.chmodSync(shimPath, 0o755) // Makes file executable
// On Windows
// No explicit chmod needed; Windows handles differentlySudo Handling
Elevated privileges are required for certain operations, and the approach varies by platform:
- Unix-like Systems: Uses
sudo - Windows: Requires running as Administrator
Launchpad's auto-sudo feature automatically adapts to the platform.
Platform-specific Example: PATH Management
macOS/Linux
# Add to PATH on Unix-like systems
echo 'export PATH="~/.local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
# Custom shell messages
echo 'export LAUNCHPAD_SHELL_ACTIVATION_MESSAGE="🔧 Dev environment: {path}"' >> ~/.zshrcWindows (PowerShell)
# Add to PATH on Windows
$currentPath = [Environment]::GetEnvironmentVariable("PATH", "User")
$newPath = "$env:USERPROFILE\.local\bin;" + $currentPath
[Environment]::SetEnvironmentVariable("PATH", $newPath, "User")
# Custom shell messages
[Environment]::SetEnvironmentVariable("LAUNCHPAD_SHELL_ACTIVATION_MESSAGE", "🔧 Dev environment: {path}", "User")Executable Detection
Different platforms use different file extensions for executables:
- Unix-like Systems: No extension required (permissions matter)
- Windows:
.exe,.bat,.cmd, etc.
Launchpad handles these differences when creating and detecting executables.
Platform-specific Installation Paths
Default installation paths vary by platform but follow consistent principles:
macOS
- System-wide:
/usr/local(preferred, like pkgm) - User-specific:
~/.local(fallback) - Never uses:
/opt/homebrew(Homebrew's directory)
Linux
- System-wide:
/usr/local(preferred, like pkgm) - User-specific:
~/.local(fallback) - Respects: Existing system package manager directories
Windows
- User-specific:
%LOCALAPPDATA%\Programs\Launchpad(preferred) - System-wide:
%PROGRAMFILES%\Launchpad(requires elevation)
NOTE
Launchpad installs packages to /usr/local (like pkgm), not to Homebrew's /opt/homebrew directory. This ensures clean separation from Homebrew-managed packages and allows peaceful coexistence.
Integration with pkgx
pkgx itself is cross-platform, and Launchpad leverages this to provide a consistent experience across operating systems.
Testing Across Platforms
When developing with Launchpad, it's good practice to test on multiple platforms:
# Basic testing on Unix-like systems
launchpad install node@22
node --version
# Verify shim creation
ls -la ~/.local/bin/node
# Test environment messages
cd my-project/ # Should show activation message
cd ../ # Should show deactivation message# Basic testing on Windows
launchpad install node@22
node --version
# Verify shim creation
dir $env:USERPROFILE\.local\bin\node.exe
# Test environment messages
cd my-project # Should show activation message
cd ..\ # Should show deactivation messageCross-platform CI/CD Integration
For CI/CD pipelines, you can use Launchpad consistently across platforms:
# Example GitHub Actions workflow
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install Launchpad
run: npm install -g @stacksjs/launchpad
- name: Install dependencies with Launchpad
run: launchpad install node@22 python@3.12
- name: Test environment activation
run: |
cd test-project
# Environment should activate automatically with shell integrationPlatform-specific Configuration
macOS Configuration
// launchpad.config.ts for macOS
export default {
installationPath: '/usr/local', // Preferred on macOS
shellActivationMessage: '🍎 macOS environment ready: {path}',
shellDeactivationMessage: '🍎 Environment closed',
// Use Homebrew paths for fallback when needed
fallbackPaths: ['/opt/homebrew/bin', '/usr/local/bin']
}Linux Configuration
// launchpad.config.ts for Linux
export default {
installationPath: '/usr/local', // Preferred on Linux
shellActivationMessage: '🐧 Linux environment ready: {path}',
shellDeactivationMessage: '🐧 Environment closed',
// Respect system package manager paths
fallbackPaths: ['/usr/bin', '/usr/local/bin']
}Windows Configuration
// launchpad.config.ts for Windows
export default {
installationPath: `${process.env.LOCALAPPDATA}\\Programs\\Launchpad`,
shellActivationMessage: '🪟 Windows environment ready: {path}',
shellDeactivationMessage: '🪟 Environment closed',
// Windows-specific paths
fallbackPaths: ['C:\\Program Files\\Git\\bin']
}Troubleshooting Cross-platform Issues
Path Separator Issues
# Use path.join() for cross-platform compatibility
const installPath = path.join(baseDir, 'bin', 'executable')Environment Variable Differences
# Unix-like systems
export LAUNCHPAD_PATH=/usr/local
# Windows
set LAUNCHPAD_PATH=C:\usr\local
# or in PowerShell
$env:LAUNCHPAD_PATH = "C:\usr\local"Shell Integration Differences
# For Bash/Zsh (Unix-like)
echo 'eval "$(launchpad dev:shellcode)"' >> ~/.zshrc
# For PowerShell (Windows)
Add-Content $PROFILE 'Invoke-Expression (& launchpad dev:shellcode)'