Multi-Platform Package
This guide shows two ways to make a package behave correctly across different operating systems: overriding a command's implementation per platform (same command, different execute logic), and shipping a compiled binary per OS/architecture.
Platform-Specific Commands (Same Command, Different Implementation)
Sometimes the difference between platforms isn't a compiled binary — it's that the same shell tool behaves differently on each OS. A common example is sed: GNU sed (Linux) edits a file in place with -i, while BSD sed (macOS) requires an explicit (empty) backup suffix, -i ''.
Put a .aux4 file directly under dist/<os>/, with a "platform" field, alongside your root .aux4:
1my-package/
2├── .aux4 # root package + a default/fallback implementation
3├── LICENSE
4├── README.md
5├── RELEASE.md
6└── dist/
7 └── linux/
8 └── .aux4 # { "platform": "linux", ... }Root .aux4 — the default implementation (BSD sed, works out of the box on macOS):
1{
2 "scope": "myorg",
3 "name": "texttools",
4 "version": "1.0.0",
5 "description": "Text file utilities",
6 "license": "MIT",
7 "profiles": [
8 {
9 "name": "main",
10 "commands": [
11 {
12 "name": "trim",
13 "execute": [
14 "aux4 trim-impl run --file ${file}"
15 ],
16 "help": {
17 "text": "Remove trailing whitespace from every line of a file, in place",
18 "variables": [
19 {
20 "name": "file",
21 "text": "The file to clean",
22 "arg": true
23 }
24 ]
25 }
26 },
27 {
28 "name": "trim-impl",
29 "private": true,
30 "execute": ["profile:trim-impl"],
31 "help": {
32 "text": "Internal platform-specific implementation. Not for direct use."
33 }
34 }
35 ]
36 },
37 {
38 "name": "trim-impl",
39 "commands": [
40 {
41 "name": "run",
42 "private": true,
43 "execute": [
44 "sed -i '' -E 's/[[:space:]]+$//' ${file}"
45 ],
46 "help": {
47 "text": "BSD sed variant (default, used on macOS). The linux dist override below replaces this with the GNU sed form.",
48 "variables": [
49 {
50 "name": "file",
51 "text": "The file to clean in place"
52 }
53 ]
54 }
55 }
56 ]
57 }
58 ]
59}dist/linux/.aux4 — overrides just the trim-impl profile with the GNU sed form:
1{
2 "platform": "linux",
3 "profiles": [
4 {
5 "name": "trim-impl",
6 "commands": [
7 {
8 "name": "run",
9 "private": true,
10 "execute": [
11 "sed -i -E 's/[[:space:]]+$//' ${file}"
12 ],
13 "help": {
14 "text": "GNU sed variant (Linux) — in-place editing doesn't need the empty backup-suffix argument BSD sed requires.",
15 "variables": [
16 {
17 "name": "file",
18 "text": "The file to clean in place"
19 }
20 ]
21 }
22 }
23 ]
24 }
25 ]
26}The public trim command is identical on every platform — it always calls aux4 trim-impl run --file ${file}. Only the private trim-impl profile differs, and only on Linux. Isolating the platform-sensitive logic into its own private profile (rather than inlining it into trim itself) is what makes a clean override possible — see the next paragraph for why.
At build time, aux4 aux4 pkger build merges each dist/<platform>/.aux4 into the root .aux4. The merge works per profile, not per command: a profile in the dist file replaces a root profile of the same name in its entirety (or is added if the root doesn't define it). That's why the platform-specific run command lives alone in its own trim-impl profile — if it were bundled into a profile with other, platform-independent commands, the Linux override would have to repeat all of them just to replace the one that differs.
Installing via the hub downloads the zip already merged for the user's OS, so the rest of the package — and its users — never need to know which variant is actually installed.
This technique composes with the binary-per-platform approach below — a dist/<os>/<arch>/ binary and a dist/<os>/.aux4 override can both exist in the same package.
Platform-Specific Binaries
A multi-platform package uses the dist/ directory to organize binaries by OS and architecture:
1my-package/
2├── .aux4
3├── LICENSE
4├── README.md
5├── RELEASE.md
6└── dist/
7 ├── darwin/
8 │ ├── amd64/
9 │ │ └── my-binary
10 │ └── arm64/
11 │ └── my-binary
12 ├── linux/
13 │ ├── amd64/
14 │ │ └── my-binary
15 │ ├── arm64/
16 │ │ └── my-binary
17 │ └── 386/
18 │ └── my-binary
19 └── windows/
20 ├── amd64/
21 │ └── my-binary.exe
22 ├── arm64/
23 │ └── my-binary.exe
24 └── 386/
25 └── my-binary.exeSupported Platforms
| OS | Architectures |
|---|---|
| darwin (macOS) | amd64, arm64 |
| linux | amd64, arm64, 386 |
| windows | amd64, arm64, 386 |
Step 1: Create the Binary
This example uses Go to create a cross-platform binary. You can use any language that compiles to native executables.
Create the Go source
1// main.go
2package main
3
4import (
5 "fmt"
6 "os"
7)
8
9func main() {
10 name := "World"
11 if len(os.Args) > 1 {
12 name = os.Args[1]
13 }
14 fmt.Printf("Hello, %s!\n", name)
15}Build for all platforms
1# Create dist directories
2mkdir -p dist/darwin/{amd64,arm64}
3mkdir -p dist/linux/{amd64,arm64,386}
4mkdir -p dist/windows/{amd64,arm64,386}
5
6# Build for macOS
7GOOS=darwin GOARCH=amd64 go build -o dist/darwin/amd64/my-greeter .
8GOOS=darwin GOARCH=arm64 go build -o dist/darwin/arm64/my-greeter .
9
10# Build for Linux
11GOOS=linux GOARCH=amd64 go build -o dist/linux/amd64/my-greeter .
12GOOS=linux GOARCH=arm64 go build -o dist/linux/arm64/my-greeter .
13GOOS=linux GOARCH=386 go build -o dist/linux/386/my-greeter .
14
15# Build for Windows
16GOOS=windows GOARCH=amd64 go build -o dist/windows/amd64/my-greeter.exe .
17GOOS=windows GOARCH=arm64 go build -o dist/windows/arm64/my-greeter.exe .
18GOOS=windows GOARCH=386 go build -o dist/windows/386/my-greeter.exe .Step 2: Create the .aux4 File
Reference the binary using ${packageDir}. When installed, aux4 extracts only the binary for the user's platform:
1{
2 "scope": "myorg",
3 "name": "greeter",
4 "version": "1.0.0",
5 "description": "Cross-platform greeting tool",
6 "license": "MIT",
7 "profiles": [
8 {
9 "name": "main",
10 "commands": [
11 {
12 "name": "greet",
13 "execute": [
14 "${packageDir}/my-greeter ${name}"
15 ],
16 "help": {
17 "text": "Greet someone",
18 "variables": [
19 {
20 "name": "name",
21 "text": "Name to greet",
22 "default": "World",
23 "arg": true
24 }
25 ]
26 }
27 }
28 ]
29 }
30 ]
31}Step 3: Create Supporting Files
LICENSE
1cat > LICENSE << 'EOF'
2MIT License
3...
4EOFTip: You can also use aux4/license to generate your LICENSE file:
1aux4 license use \
2 --name mit \
3 --owner "MyOrg" \
4 --year 2024 \
5 --project "greeter"README.md
1cat > README.md << 'EOF'
2# Greeter
3
4A cross-platform greeting tool.
5
6## Supported Platforms
7
8- macOS (Intel and Apple Silicon)
9- Linux (x64, ARM64, x86)
10- Windows (x64, ARM64, x86)
11
12## Usage
13
14```bash
15aux4 greet John
16```
17EOFStep 4: Build the Package
1aux4 aux4 pkger build ./out .For multi-platform packages, the build creates multiple zip files:
1out/
2├── myorg_greeter_1.0.0.zip # Global package (contains all platforms)
3├── darwin_amd64_myorg_greeter_1.0.0.zip
4├── darwin_arm64_myorg_greeter_1.0.0.zip
5├── linux_386_myorg_greeter_1.0.0.zip
6├── linux_amd64_myorg_greeter_1.0.0.zip
7├── linux_arm64_myorg_greeter_1.0.0.zip
8├── windows_386_myorg_greeter_1.0.0.zip
9├── windows_amd64_myorg_greeter_1.0.0.zip
10└── windows_arm64_myorg_greeter_1.0.0.zipStep 5: Install from File
When installing from file, you must use the platform-specific zip file, not the main zip:
1# On macOS ARM64 (Apple Silicon)
2aux4 aux4 pkger install --fromFile ./out/darwin_arm64_myorg_greeter_1.0.0.zip
3
4# On macOS Intel
5aux4 aux4 pkger install --fromFile ./out/darwin_amd64_myorg_greeter_1.0.0.zip
6
7# On Linux x64
8aux4 aux4 pkger install --fromFile ./out/linux_amd64_myorg_greeter_1.0.0.zip
9
10# On Windows x64
11aux4 aux4 pkger install --fromFile ./out/windows_amd64_myorg_greeter_1.0.0.zipThe main zip file (myorg_greeter_1.0.0.zip) cannot be installed directly with --fromFile because it contains all platforms. Use the platform-specific zip for local installation.
Step 6: Publish
Publish the main zip file (which contains all platforms):
1aux4 aux4 login
2aux4 aux4 pkger publish ./out/myorg_greeter_1.0.0.zipStep 7: Install from aux4 Hub
When installing from the aux4 Hub, aux4 automatically downloads the correct platform-specific package:
1aux4 aux4 pkger install myorg/greeteraux4 detects the user's OS and architecture and downloads the appropriate package.
Step 8: Use the Package
1aux4 greet John1Hello, John!Building with aux4
You can automate the build process using aux4 itself. We recommend creating a build command that builds your binaries to the dist/ folder.
For multi-platform packages, we suggest creating a builder profile with commands for each platform, then having your main build command call aux4 builder all.
Create a .aux4 file in your project root:
1{
2 "profiles": [
3 {
4 "name": "main",
5 "commands": [
6 {
7 "name": "build",
8 "execute": [
9 "aux4 builder all",
10 "aux4 aux4 pkger build ./out ./package"
11 ],
12 "help": {
13 "text": "Build binaries for all platforms and create package"
14 }
15 },
16 {
17 "name": "builder",
18 "execute": [
19 "profile:builder"
20 ],
21 "help": {
22 "text": "Platform-specific build commands"
23 }
24 }
25 ]
26 },
27 {
28 "name": "builder",
29 "commands": [
30 {
31 "name": "darwin",
32 "execute": [
33 "GOOS=darwin GOARCH=amd64 go build -o package/dist/darwin/amd64/my-greeter .",
34 "GOOS=darwin GOARCH=arm64 go build -o package/dist/darwin/arm64/my-greeter ."
35 ],
36 "help": {
37 "text": "Build for macOS"
38 }
39 },
40 {
41 "name": "linux",
42 "execute": [
43 "GOOS=linux GOARCH=amd64 go build -o package/dist/linux/amd64/my-greeter .",
44 "GOOS=linux GOARCH=arm64 go build -o package/dist/linux/arm64/my-greeter .",
45 "GOOS=linux GOARCH=386 go build -o package/dist/linux/386/my-greeter ."
46 ],
47 "help": {
48 "text": "Build for Linux"
49 }
50 },
51 {
52 "name": "windows",
53 "execute": [
54 "GOOS=windows GOARCH=amd64 go build -o package/dist/windows/amd64/my-greeter.exe .",
55 "GOOS=windows GOARCH=arm64 go build -o package/dist/windows/arm64/my-greeter.exe .",
56 "GOOS=windows GOARCH=386 go build -o package/dist/windows/386/my-greeter.exe ."
57 ],
58 "help": {
59 "text": "Build for Windows"
60 }
61 },
62 {
63 "name": "all",
64 "execute": [
65 "aux4 builder darwin",
66 "aux4 builder linux",
67 "aux4 builder windows"
68 ],
69 "help": {
70 "text": "Build for all platforms"
71 }
72 }
73 ]
74 }
75 ]
76}Then build everything with:
1aux4 buildOr build for a specific platform:
1aux4 builder darwin