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/local
for system-wide installations - Fallback:
~/.local
for 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 differently
Sudo 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}"' >> ~/.zshrc
Windows (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 message
Cross-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 integration
Platform-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)'