Docker One-Liner Compiles PHP to Native Binaries: Zero-Dependency Go-Style Distribution
This guide shows how to use TypePHP's Docker images to compile PHP code into standalone native Linux binaries without installing C++ or PHP toolchains locally, covering the compilation workflow, a common linker error caused by directory name conflicts, and advanced options like static compilation for scratch containers.
Introduction
Go's ability to produce a single, dependency-free native binary makes deployment trivial. Traditional PHP deployment, by contrast, requires a runtime, extensions, and code directories, leading to environment inconsistencies. TypePHP, an open-source Ahead-of-Time (AOT) compiler from the Swoole team, translates PHP directly into native machine code, giving PHP Go-like startup speed and single-file distribution. However, setting up the local C++17, PHP 8.5 ZTS/Embed, and GCC/Clang toolchain is a significant barrier. This article demonstrates how to bypass that setup entirely using pre-built Docker images.
Quick Start
Step 1: Prepare the PHP Entry File
Create main.php in your working directory. The entry point must be a function main(): int and use printf() for standard output:
declare(strict_types=1);
function main(): int {
printf("Hello World from TypePHP Docker AOT!
");
return 0;
}Step 2: One-Line Compilation Command
Run the appropriate Docker command for your shell. The command mounts the current directory to /app inside the container and uses the tinywan/typephp-linux-x64:v0.7.0 image.
Windows PowerShell:
docker run --rm -v "${PWD}:/app" tinywan/typephp-linux-x64:v0.7.0Linux / macOS / Git Bash:
docker run --rm -v "$(pwd):/app" tinywan/typephp-linux-x64:v0.7.0Windows CMD:
docker run --rm -v "%cd%:/app" tinywan/typephp-linux-x64:v0.7.0The container automatically detects the environment, transpiles PHP to C++, and compiles with GCC. The terminal streams the full build log, for example:
[TypePHP] Working directory: /app
[TypePHP] Detected PHP entrypoint: main.php
[TypePHP] Auto-generating project.yml for app...
[TypePHP] Generated project.yml:
name: app
bin: app.bin
sources:
- main.php
----------------------------------------
[TypePHP] Starting AOT compilation via tpc...
Initialized platform/backend: Linux + GCC (g++)
prepare: main.php
prepare completed: 1 source files in total
convert: main.php
generate arginfo file: main.php
[pch] built: opt/typephp/vendor/swoole/typephp/build/cache/pch/31e80de1e5c0ecccc9195c7b/typephp_pch.hpp.gch
Starting parallel compilation with 4 jobs for 6 files
Compiling [████████████████████████████████] 100% (6/6)
Successfully compiled 6 files
g++ '@./app.rsp' -o 'app.bin' -L '/opt/typephp/vendor/swoole/phpx/lib' -L '/usr/lib' -lphpx -lphp -lgmp -lgmpxx -lmpfr -lstdc++
[TypePHP] Build successful: app.binWithin seconds, a native Linux ELF binary app.bin appears in the current directory.
Step 3: Run the Compiled Binary
The resulting app.bin is a standalone Linux executable. Verify it by running it inside the same Docker image:
docker run --rm -v "${PWD}:/app" tinywan/typephp-linux-x64:v0.7.0 ./app.binOutput:
Hello World from TypePHP Docker AOT!Troubleshooting: Linker Error "Is a directory"
Error Phenomenon
The linker fails with:
g++ '@./app.rsp' -o 'app' -L '/opt/typephp/vendor/swoole/phpx/lib' -L '/usr/lib' -lphpx -lphp ...
/usr/bin/ld: cannot open output file app: Is a directory
collect2: error: ld returned 1 exit statusRoot Cause Analysis
Many PHP projects have an app/ directory for business logic. When project.yml sets name: app, the linker defaults the output executable to ./app. Because a directory with that name already exists, the linker cannot create a regular file, producing the "Is a directory" error.
Solution
Explicitly set the bin field in project.yml to a filename that does not clash with an existing directory:
name: app
bin: app.bin # Explicitly specify binary name (e.g., server, demo)
sources:
- app/index.phpRe-run the compilation command; the binary will be generated successfully.
Advanced Usage
1. Compile a Single Script
If the directory contains multiple PHP files, specify the target script as an argument to the Docker command:
docker run --rm -v "${PWD}:/app" tinywan/typephp-linux-x64:v0.7.0 your_script.php2. Fully Static, Single-File Binary (~6 MB)
To run on any Linux distribution or inside a FROM scratch container without glibc dependencies, switch to the static image based on Alpine/musl:
docker run --rm -v "${PWD}:/app" tinywan/typephp-linux-x64-static:v0.7.0This produces a completely self-contained binary suitable for production distribution and minimal container deployment.
Docker Image Reference
Dynamic Compilation (Ubuntu / glibc) : tinywan/typephp-linux-x64:v0.7.0 — General development, local testing
Fully Static Single-File (Alpine / musl) : tinywan/typephp-linux-x64-static:v0.7.0 — Production distribution, cross-distro execution, scratch image deployment
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Open Source Tech Hub
Sharing cutting-edge internet technologies and practical AI resources.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
