This commit is contained in:
crazywhalecc
2026-04-19 11:49:55 +08:00
parent a175c5862d
commit a348e838d7
120 changed files with 6346 additions and 3391 deletions

View File

@@ -55,11 +55,13 @@ jobs:
- name: "Install Locked Dependencies"
run: "composer install --no-interaction --no-progress"
- name: "Generate Extension Support List"
run: |
bin/spc dev:gen-ext-docs > docs/extensions.md
bin/spc dev:gen-ext-dep-docs > docs/deps-map-ext.md
bin/spc dev:gen-lib-dep-docs > docs/deps-map-lib.md
# TODO: Uncomment when v3 gen commands are implemented
# - name: "Generate Extension Support List"
# run: |
# bin/spc dev:gen-ext-docs > docs/en/guide/extensions.md
# bin/spc dev:gen-ext-docs > docs/zh/guide/extensions.md
# bin/spc dev:gen-ext-dep-docs > docs/en/guide/deps-map.md
# bin/spc dev:gen-ext-dep-docs > docs/zh/guide/deps-map.md
- name: Build
run: yarn docs:build

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,219 @@
<template>
<div class="contributors-container">
<div class="contributors-header">
<h2>Contributors</h2>
<p class="contributors-description">
Thanks to all the amazing people who have contributed to this project!
</p>
</div>
<div v-if="loading" class="loading-state">
<div class="spinner"></div>
<p>Loading contributors...</p>
</div>
<div v-else-if="error" class="error-state">
<p>{{ error }}</p>
</div>
<div v-else class="contributors-grid">
<a
v-for="contributor in contributors"
:key="contributor.id"
:href="contributor.html_url"
target="_blank"
rel="noopener noreferrer"
class="contributor-card"
:title="contributor.login"
>
<img
:src="contributor.avatar_url"
:alt="contributor.login"
class="contributor-avatar"
loading="lazy"
/>
<div class="contributor-name">{{ contributor.login }}</div>
</a>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
interface Contributor {
id: number;
login: string;
avatar_url: string;
html_url: string;
contributions: number;
}
const contributors = ref<Contributor[]>([]);
const loading = ref(true);
const error = ref('');
const fetchContributors = async () => {
try {
loading.value = true;
error.value = '';
const response = await fetch(
'https://api.github.com/repos/crazywhalecc/static-php-cli/contributors?per_page=24'
);
if (!response.ok) {
throw new Error('Failed to fetch contributors');
}
const data = await response.json();
contributors.value = data;
} catch (err) {
error.value = 'Failed to load contributors. Please try again later.';
console.error('Error fetching contributors:', err);
} finally {
loading.value = false;
}
};
onMounted(() => {
fetchContributors();
});
</script>
<style scoped>
.contributors-container {
margin: 48px auto;
padding: 32px 24px;
max-width: 1152px;
background: linear-gradient(135deg, var(--vp-c-bg-soft) 0%, var(--vp-c-bg) 100%);
border-radius: 16px;
border: 1px solid var(--vp-c-divider);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
}
.contributors-header {
text-align: center;
margin-bottom: 24px;
}
.contributors-header h2 {
font-size: 1.5rem;
font-weight: 700;
margin: 0 0 8px 0;
background: linear-gradient(120deg, var(--vp-c-brand-1), var(--vp-c-brand-2));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.contributors-description {
font-size: 0.95rem;
color: var(--vp-c-text-2);
margin: 0;
line-height: 1.5;
}
.loading-state,
.error-state {
text-align: center;
padding: 40px 20px;
color: var(--vp-c-text-2);
}
.spinner {
width: 40px;
height: 40px;
margin: 0 auto 16px;
border: 4px solid var(--vp-c-divider);
border-top-color: var(--vp-c-brand-1);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.contributors-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
gap: 16px;
}
.contributor-card {
display: flex;
flex-direction: column;
align-items: center;
padding: 12px;
background: var(--vp-c-bg);
border-radius: 12px;
border: 1px solid var(--vp-c-divider);
transition: all 0.3s ease;
text-decoration: none;
color: var(--vp-c-text-1);
}
.contributor-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
border-color: var(--vp-c-brand-1);
}
.contributor-avatar {
width: 60px;
height: 60px;
border-radius: 50%;
border: 2px solid var(--vp-c-divider);
transition: all 0.3s ease;
margin-bottom: 8px;
}
.contributor-card:hover .contributor-avatar {
border-color: var(--vp-c-brand-1);
transform: scale(1.05);
}
.contributor-name {
font-size: 12px;
font-weight: 500;
text-align: center;
word-break: break-word;
max-width: 100%;
}
@media (max-width: 768px) {
.contributors-container {
margin: 32px 16px;
padding: 24px 16px;
}
.contributors-header h2 {
font-size: 1.25rem;
}
.contributors-description {
font-size: 0.9rem;
}
.contributors-grid {
grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
gap: 12px;
}
.contributor-card {
padding: 8px;
}
.contributor-avatar {
width: 48px;
height: 48px;
}
.contributor-name {
font-size: 11px;
}
}
</style>

View File

@@ -0,0 +1,193 @@
export function getMetaList(meta, type, name, list_name) {
if (meta.os === 'linux') {
return meta[type][name][list_name + '-linux'] ?? meta[type][name][list_name + '-unix'] ?? meta[type][name][list_name] ?? [];
}
if (meta.os === 'macos') {
return meta[type][name][list_name + '-macos'] ?? meta[type][name][list_name + '-unix'] ?? meta[type][name][list_name] ?? [];
}
if (meta.os === 'windows') {
return meta[type][name][list_name + '-windows'] ?? meta[type][name][list_name] ?? [];
}
return [];
}
export function getExtDepends(meta, ext_name) {
return getMetaList(meta, 'ext', ext_name, 'ext-depends');
}
export function getExtSuggests(meta, ext_name) {
return getMetaList(meta, 'ext', ext_name, 'ext-suggests');
}
export function getExtLibDepends(meta, ext_name) {
const ls = getMetaList(meta, 'ext', ext_name, 'lib-depends');
return ls;
}
export function getExtLibSuggests(meta, ext_name) {
return getMetaList(meta, 'ext', ext_name, 'lib-suggests');
}
export function getLibDepends(meta, lib_name) {
return getMetaList(meta, 'lib', lib_name, 'lib-depends');
}
export function getLibSuggests(meta, lib_name) {
return getMetaList(meta, 'lib', lib_name, 'lib-suggests');
}
/**
* Obtain the dependent lib list according to the required ext list, and sort according to the dependency
* @param meta
* @param exts
*/
export function getExtLibsByDeps(meta, exts) {
const sorted = [];
const visited = new Set();
const notIncludedExts = [];
exts.forEach((ext) => {
if (!visited.has(ext)) {
visitExtDeps(meta, ext, visited, sorted);
}
});
const sortedSuggests = [];
const visitedSuggests = new Set();
const final = [];
exts.forEach((ext) => {
if (!visited.has(ext)) {
visitExtAllDeps(meta, ext, visitedSuggests, sortedSuggests);
}
});
sortedSuggests.forEach((suggest) => {
if (sorted.indexOf(suggest) !== -1) {
final.push(suggest);
}
});
const libs = [];
final.forEach((ext) => {
if (exts.indexOf(ext) === -1) {
notIncludedExts.push(ext);
}
getExtLibDepends(meta, ext).forEach((lib) => {
if (libs.indexOf(lib) === -1) {
libs.push(lib);
}
});
});
return { exts: final, libs: getLibsByDeps(meta, libs), notIncludedExts: notIncludedExts };
}
export function getAllExtLibsByDeps(meta, exts) {
const sorted = [];
const visited = new Set();
const notIncludedExts = [];
exts.forEach((ext) => {
if (!visited.has(ext)) {
visitExtAllDeps(meta, ext, visited, sorted);
}
});
const libs = [];
sorted.forEach((ext) => {
if (exts.indexOf(ext) === -1) {
notIncludedExts.push(ext);
}
const allLibs = [...getExtLibDepends(meta, ext), ...getExtLibSuggests(meta, ext)];
allLibs.forEach((dep) => {
if (libs.indexOf(dep) === -1) {
libs.push(dep);
}
});
});
return { exts: sorted, libs: getAllLibsByDeps(meta, libs), notIncludedExts: notIncludedExts };
}
export function getAllLibsByDeps(meta, libs) {
const sorted = [];
const visited = new Set();
libs.forEach((lib) => {
if (!visited.has(lib)) {
console.log('before visited');
console.log(visited);
visitLibAllDeps(meta, lib, visited, sorted);
console.log('after visited');
console.log(visited);
}
});
return sorted;
}
export function getLibsByDeps(meta, libs) {
const sorted = [];
const visited = new Set();
libs.forEach((lib) => {
if (!visited.has(lib)) {
visitLibDeps(meta, lib, visited, sorted);
}
});
const sortedSuggests = [];
const visitedSuggests = new Set();
const final = [];
libs.forEach((lib) => {
if (!visitedSuggests.has(lib)) {
visitLibAllDeps(meta, lib, visitedSuggests, sortedSuggests);
}
});
sortedSuggests.forEach((suggest) => {
if (sorted.indexOf(suggest) !== -1) {
final.push(suggest);
}
});
return final;
}
export function visitLibAllDeps(meta, lib_name, visited, sorted) {
if (visited.has(lib_name)) {
return;
}
visited.add(lib_name);
const allLibs = [...getLibDepends(meta, lib_name), ...getLibSuggests(meta, lib_name)];
allLibs.forEach((dep) => {
visitLibDeps(meta, dep, visited, sorted);
});
sorted.push(lib_name);
}
export function visitLibDeps(meta, lib_name, visited, sorted) {
if (visited.has(lib_name)) {
return;
}
visited.add(lib_name);
getLibDepends(meta, lib_name).forEach((dep) => {
visitLibDeps(meta, dep, visited, sorted);
});
sorted.push(lib_name);
}
export function visitExtDeps(meta, ext_name, visited, sorted) {
if (visited.has(visited)) {
return;
}
visited.add(ext_name);
getExtDepends(meta, ext_name).forEach((dep) => {
visitExtDeps(meta, dep, visited, sorted);
});
sorted.push(ext_name);
}
export function visitExtAllDeps(meta, ext_name, visited, sorted) {
if (visited.has(ext_name)) {
return;
}
visited.add(ext_name);
const allExts = [...getExtDepends(meta, ext_name), ...getExtSuggests(meta, ext_name)];
allExts.forEach((dep) => {
visitExtDeps(meta, dep, visited, sorted);
});
sorted.push(ext_name);
}

View File

@@ -0,0 +1,79 @@
<template>
<div>
<header class="DocSearch-SearchBar" style="padding: 0">
<form class="DocSearch-Form searchinput">
<input class="DocSearch-Input" v-model="filterText" placeholder="Filter name..." @input="doFilter" />
</form>
</header>
<table>
<thead>
<tr>
<th>Extension Name</th>
<th>Linux</th>
<th>macOS</th>
<th>FreeBSD</th>
<th>Windows</th>
</tr>
</thead>
<tbody>
<tr v-for="item in filterData">
<td v-if="!item.notes">{{ item.name }}</td>
<td v-else>
<a :href="'./extension-notes.html#' + item.name">{{ item.name }}</a>
</td>
<td>{{ item.linux }}</td>
<td>{{ item.macos }}</td>
<td>{{ item.freebsd }}</td>
<td>{{ item.windows }}</td>
</tr>
</tbody>
</table>
<div v-if="filterData.length === 0" style="margin: 0 4px 20px 4px; color: var(--vp-c-text-2); font-size: 14px">
No result, please try another keyword.
</div>
</div>
</template>
<script>
export default {
name: "SearchTable"
}
</script>
<script setup>
import {ref} from "vue";
import ext from '../../../config/ext.json';
// 将 ext 转换为列表,方便后续操作
const data = ref([]);
for (const [name, item] of Object.entries(ext)) {
data.value.push({
name,
linux: item.support?.Linux === undefined ? 'yes' : (item.support?.Linux === 'wip' ? '' : item.support?.Linux),
macos: item.support?.Darwin === undefined ? 'yes' : (item.support?.Darwin === 'wip' ? '' : item.support?.Darwin),
freebsd: item.support?.BSD === undefined ? 'yes' : (item.support?.BSD === 'wip' ? '' : item.support?.BSD),
windows: item.support?.Windows === undefined ? 'yes' : (item.support?.Windows === 'wip' ? '' : item.support?.Windows),
notes: item.notes === true,
});
}
const filterData = ref(data.value);
const filterText = ref('');
const doFilter = () => {
if (filterText.value === '') {
filterData.value = data.value;
return;
}
filterData.value = data.value.filter(item => {
return item.name.toLowerCase().includes(filterText.value.toLowerCase());
});
}
</script>
<style>
.searchinput {
border: 1px solid var(--vp-c-divider);
}
</style>

View File

@@ -0,0 +1,65 @@
import sidebarEn from "./sidebar.en";
import sidebarZh from "./sidebar.zh";
// https://vitepress.dev/reference/site-config
export default {
title: "Static PHP",
description: "Build single static PHP binary, with PHP project together, with popular extensions included.",
locales: {
en: {
label: 'English',
lang: 'en',
themeConfig: {
nav: [
{text: 'Guide', link: '/en/guide/',},
{text: 'Advanced', link: '/en/develop/'},
{text: 'Contributing', link: '/en/contributing/'},
{text: 'FAQ', link: '/en/faq/'},
],
sidebar: sidebarEn,
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2023-present crazywhalecc'
}
},
},
zh: {
label: '简体中文',
lang: 'zh', // optional, will be added as `lang` attribute on `html` tag
themeConfig: {
nav: [
{text: '构建指南', link: '/zh/guide/'},
{text: '进阶', link: '/zh/develop/'},
{text: '贡献', link: '/zh/contributing/'},
{text: 'FAQ', link: '/zh/faq/'},
],
sidebar: sidebarZh,
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2023-present crazywhalecc'
}
},
}
},
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
logo: '/images/static-php_nobg.png',
nav: [],
socialLinks: [
{icon: 'github', link: 'https://github.com/crazywhalecc/static-php-cli'}
],
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2023-present crazywhalecc'
},
search: {
provider: 'algolia',
options: {
appId: 'IHJHUB1SF1',
apiKey: '8266d31cc2ffbd0e059f1c6e5bdaf8fc',
indexName: 'static-php docs',
},
},
}
}

View File

@@ -0,0 +1,57 @@
export default {
'/en/guide/': [
{
text: 'Basic Build Guides',
items: [
{text: 'Guide', link: '/en/guide/'},
{text: 'Build (Local)', link: '/en/guide/manual-build'},
{text: 'Build (CI)', link: '/en/guide/action-build'},
{text: 'Supported Extensions', link: '/en/guide/extensions'},
{text: 'Extension Notes', link: '/en/guide/extension-notes'},
{text: 'Build Command Generator', link: '/en/guide/cli-generator'},
{text: 'Environment Variables', link: '/en/guide/env-vars', collapsed: true,},
{text: 'Dependency Table', link: '/en/guide/deps-map'},
]
},
{
text: 'Extended Build Guides',
items: [
{text: 'Troubleshooting', link: '/en/guide/troubleshooting'},
{text: 'Build on Windows', link: '/en/guide/build-on-windows'},
{text: 'Build with GNU libc', link: '/en/guide/build-with-glibc'},
],
}
],
'/en/develop/': [
{
text: 'Development',
items: [
{text: 'Get Started', link: '/en/develop/'},
{text: 'Project Structure', link: '/en/develop/structure'},
{text: 'PHP Source Modification', link: '/en/develop/php-src-changes'},
],
},
{
text: 'Module',
items: [
{text: 'Doctor ', link: '/en/develop/doctor-module'},
{text: 'Source', link: '/en/develop/source-module'},
]
},
{
text: 'Extra',
items: [
{text: 'Compilation Tools', link: '/en/develop/system-build-tools'},
{text: 'craft.yml Configuration', link: '/zh/develop/craft-yml'},
]
}
],
'/en/contributing/': [
{
text: 'Contributing',
items: [
{text: 'Contributing', link: '/en/contributing/'},
],
}
],
};

View File

@@ -0,0 +1,57 @@
export default {
'/zh/guide/': [
{
text: '构建指南',
items: [
{text: '指南', link: '/zh/guide/'},
{text: '本地构建', link: '/zh/guide/manual-build'},
{text: 'Actions 构建', link: '/zh/guide/action-build'},
{text: '扩展列表', link: '/zh/guide/extensions'},
{text: '扩展注意事项', link: '/zh/guide/extension-notes'},
{text: '编译命令生成器', link: '/zh/guide/cli-generator'},
{text: '环境变量列表', link: '/zh/guide/env-vars'},
{text: '依赖关系图表', link: '/zh/guide/deps-map'},
]
},
{
text: '扩展构建指南',
items: [
{text: '故障排除', link: '/zh/guide/troubleshooting'},
{text: '在 Windows 上构建', link: '/zh/guide/build-on-windows'},
{text: '构建 GNU libc 兼容的二进制', link: '/zh/guide/build-with-glibc'},
],
}
],
'/zh/develop/': [
{
text: '开发指南',
items: [
{text: '开发简介', link: '/zh/develop/'},
{text: '项目结构简介', link: '/zh/develop/structure'},
{text: '对 PHP 源码的修改', link: '/zh/develop/php-src-changes'},
],
},
{
text: '模块',
items: [
{text: 'Doctor 环境检查工具', link: '/zh/develop/doctor-module'},
{text: '资源模块', link: '/zh/develop/source-module'},
]
},
{
text: '其他',
items: [
{text: '系统编译工具', link: '/zh/develop/system-build-tools'},
{text: 'craft.yml 配置详解', link: '/zh/develop/craft-yml'},
]
}
],
'/zh/contributing/': [
{
text: '贡献指南',
items: [
{text: '贡献指南', link: '/zh/contributing/'},
],
}
],
};

View File

@@ -0,0 +1,17 @@
// docs/.vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
import {inBrowser, useData} from "vitepress";
import {watchEffect} from "vue";
import './style.css';
export default {
...DefaultTheme,
setup() {
const { lang } = useData()
watchEffect(() => {
if (inBrowser) {
document.cookie = `nf_lang=${lang.value}; expires=Mon, 1 Jan 2024 00:00:00 UTC; path=/`
}
})
}
}

View File

@@ -0,0 +1,24 @@
/** override default styles */
.vp-sponsor-grid-image {
max-height:36px !important;
max-width: 1000px !important;
}
.vp-doc .contributors-header h2 {
padding-top: 0;
border-top: none;
}
.vp-doc .sponsors-header h2 {
padding-top: 0;
border-top: none;
}
.dark .VPImage.logo {
filter: contrast(0.7);
}
.dark .VPImage.image-src {
filter: contrast(0.7);
}

View File

@@ -0,0 +1,63 @@
# Contributing
Thank you for being here, this project welcomes your contributions!
## Contribution Guide
If you have code or documentation to contribute, here's what you need to know first.
1. What type of code are you contributing? (new extensions, bug fixes, security issues, project framework optimizations, documentation)
2. If you contribute new files or new snippets, is your code checked by `php-cs-fixer` and `phpstan`?
3. Have you fully read the [Developer Guide](../develop/) before contributing code?
If you can answer the above questions and have made changes to the code,
you can initiate a Pull Request in the project GitHub repository in time.
After the code review is completed, the code can be modified according to the suggestion, or directly merged into the main branch.
## Contribution Type
The main purpose of this project is to compile statically linked PHP binaries,
and the command line processing function is written based on `symfony/console`.
Before development, if you are not familiar with it,
Check out the [symfony/console documentation](https://symfony.com/doc/current/components/console.html) first.
### Security Update
Because this project is basically a PHP project running locally, generally speaking, there will be no remote attacks.
But if you find such a problem, please **DO NOT submit a PR or Issue in the GitHub repository,
You need to contact the project maintainer (crazywhalecc) via [mail](mailto:admin@zhamao.me).
### Fix Bugs
Fixing bugs generally does not involve modification of the project structure and framework,
so if you can locate the wrong code and fix it directly, please submit a PR directly.
### New Extensions
For adding a new extension,
you need to understand some basic structure of the project and how to add a new extension according to the existing logic.
It will be covered in detail in the next section on this page.
In general, you will need:
1. Evaluate whether the extension can be compiled inline into PHP.
2. Evaluate whether the extension's dependent libraries (if any) can be compiled statically.
3. Write library compile commands on different platforms.
4. Verify that the extension and its dependencies are compatible with existing extensions and dependencies.
5. Verify that the extension works normally in `cli`, `micro`, `fpm`, `embed` SAPIs.
6. Write documentation and add your extension.
### Project Framework Optimization
If you are already familiar with the working principle of `symfony/console`,
and at the same time want to make some modifications or optimizations to the framework of the project,
please understand the following things first:
1. Adding extensions does not belong to project framework optimization,
but if you find that you have to optimize the framework when adding new extensions,
you need to modify the framework itself before adding extensions.
2. For some large-scale logical modifications (such as those involving LibraryBase, Extension objects, etc.),
it is recommended to submit an Issue or Draft PR for discussion first.
3. In the early stage of the project, it was a pure private development project, and there were some Chinese comments in the code.
After internationalizing your project you can submit a PR to translate these comments into English.
4. Please do not submit more useless code fragments in the code,
such as a large number of unused variables, methods, classes, and code that has been rewritten many times.

View File

@@ -0,0 +1,7 @@
---
aside: false
---
# craft.yml Configuration
<!--@include: ../../deps-craft-yml.md-->

View File

@@ -0,0 +1,70 @@
# Doctor module
The Doctor module is a relatively independent module used to check the system environment, which can be entered with the command `bin/spc doctor`, and the entry command class is in `DoctorCommand.php`.
The Doctor module is a checklist with a series of check items and automatic repair items.
These items are stored in the `src/SPC/doctor/item/` directory,
And two Attributes are used as check item tags and auto-fix item tags: `#[AsCheckItem]` and `#[AsFixItem]`.
Take the existing check item `if necessary tools are installed`,
which is used to check whether the packages necessary for compilation are installed in the macOS system.
The following is its source code:
```php
use SPC\doctor\AsCheckItem;
use SPC\doctor\AsFixItem;
use SPC\doctor\CheckResult;
#[AsCheckItem('if necessary tools are installed', limit_os: 'Darwin', level: 997)]
public function checkCliTools(): ?CheckResult
{
$missing = [];
foreach (self::REQUIRED_COMMANDS as $cmd) {
if ($this->findCommand($cmd) === null) {
$missing[] = $cmd;
}
}
if (!empty($missing)) {
return CheckResult::fail('missing system commands: ' . implode(', ', $missing), 'build-tools', [$missing]);
}
return CheckResult::ok();
}
```
The first parameter of the attribute is the name of the check item,
and the following `limit_os` parameter restricts the check item to be triggered only under the specified system,
and `level` is the priority of executing the check item, the larger the number, the higher the priority higher.
The `$this->findCommand()` method used in it is the method of `SPC\builder\traits\UnixSystemUtilTrait`,
the purpose is to find the location of the system command, and return NULL if it cannot be found.
Each check item method should return a `SPC\doctor\CheckResult`:
- When returning `CheckResult::fail()`, the first parameter is used to output the error prompt of the terminal,
and the second parameter is the name of the repair item when this check item can be automatically repaired.
- When `CheckResult::ok()` is returned, the check passed. You can also pass a parameter to return the check result, for example: `CheckResult::ok('OS supported')`.
- When returning `CheckResult::fail()`, if the third parameter is included, the array of the third parameter will be used as the parameter of `AsFixItem`.
The following is the method for automatically repairing items corresponding to this check item:
```php
#[AsFixItem('build-tools')]
public function fixBuildTools(array $missing): bool
{
foreach ($missing as $cmd) {
try {
shell(true)->exec('brew install ' . escapeshellarg($cmd));
} catch (RuntimeException) {
return false;
}
}
return true;
}
```
`#[AsFixItem()]` first parameter is the name of the fix item, and this method must return True or False.
When False is returned, the automatic repair failed and manual handling is required.
In the code here, `shell()->exec()` is the method of executing commands of the project,
which is used to replace `exec()` and `system()`, and also provides debugging, obtaining execution status,
entering directories, etc. characteristic.

View File

@@ -0,0 +1,35 @@
# Start Developing
Developing this project requires the installation and deployment of a PHP environment,
as well as some extensions and Composer commonly used in PHP projects.
The development environment and running environment of the project are almost exactly the same.
You can refer to the **Manual Build** section to install system PHP or use the pre-built static PHP of this project as the environment.
I will not go into details here.
Regardless of its purpose, this project itself is actually a `php-cli` program. You can edit and develop it as a normal PHP project.
At the same time, you need to understand the Shell languages of different systems.
The current purpose of this project is to compile statically compiled independent PHP,
but the main part also includes compiling static versions of many dependent libraries,
so you can reuse this set of compilation logic to build independent binary versions of other programs, such as Nginx, etc.
## Environment preparation
A PHP environment is required to develop this project. You can use the PHP that comes with the system,
or you can use the static PHP built by this project.
Regardless of which PHP you use, in your development environment you need to install these extensions:
```
curl,dom,filter,mbstring,openssl,pcntl,phar,posix,sodium,tokenizer,xml,xmlwriter
```
The static-php-cli project itself does not require so many extensions, but during the development process,
you will use tools such as Composer and PHPUnit, which require these extensions.
> For micro self-executing binaries built by static-php-cli itself, only `pcntl,posix,mbstring,tokenizer,phar` is required.
## Start development
Continuing down to see the project structure documentation, you can learn how `static-php-cli` works.

View File

@@ -0,0 +1,59 @@
# Modifications to PHP source code
During the static compilation process, static-php-cli made some modifications to the PHP source code
in order to achieve good compatibility, performance, and security.
The following is a description of the current modifications to the PHP source code.
## Micro related patches
Based on the patches provided by the phpmicro project,
static-php-cli has made some modifications to the PHP source code to meet the needs of static compilation.
The patches currently used by static-php-cli during compilation in the [patch list](https://github.com/easysoft/phpmicro/tree/master/patches) are:
- static_opcache
- static_extensions_win32
- cli_checks
- disable_huge_page
- vcruntime140
- win32
- zend_stream
- cli_static
- macos_iconv
- phar
## PHP <= 8.1 libxml patch
Because PHP only provides security updates for 8.1 and stops updating older versions,
static-php-cli applies the libxml compilation patch that has been applied in newer versions of PHP to PHP 8.1 and below.
## gd extension Windows patch
Compiling the gd extension under Windows requires major changes to the `config.w32` file.
static-php-cli has made some changes to the gd extension to make it easier to compile under Windows.
## YAML extension Windows patch
YAML extension needs to modify the `config.w32` file to compile under Windows.
static-php-cli has made some modifications to the YAML extension to make it easier to compile under Windows.
## static-php-cli version information insertion
When compiling, static-php-cli will insert the static-php-cli version information into the PHP version information for easy identification.
## Add option to hardcode INI
When using the `-I` parameter to hardcode INI into static PHP functionality,
static-php-cli will modify the PHP source code to insert the hardcoded content.
## Linux system repair patch
Some compilation environments may lack some system header files or libraries.
static-php-cli will automatically fix these problems during compilation, such as:
- HAVE_STRLCAT missing problem
- HAVE_STRLCPY missing problem
## Fiber issue fix patch for Windows
When compiling PHP on Windows, there will be some issues with the Fiber extension.
static-php-cli will automatically fix these issues during compilation (modify `config.w32` in php-src).

View File

@@ -0,0 +1,372 @@
# Source module
The download source module of static-php-cli is a major module.
It includes dependent libraries, external extensions, PHP source code download methods and file decompression methods.
The download configuration file mainly involves the `source.json` and `pkg.json` file, which records the download method of all downloadable sources.
The main commands involved in the download function are `bin/spc download` and `bin/spc extract`.
The `download` command is a downloader that downloads sources according to the configuration file,
and the `extract` command is an extractor that extract sources from downloaded files.
Generally speaking, downloading sources may be slow because these sources come from various official websites, GitHub,
and other different locations.
At the same time, they also occupy a large space, so you can download the sources once and reuse them.
The configuration file of the downloader is `source.json`, which contains the download methods of all sources.
You can add the source download methods you need, or modify the existing source download methods.
The download configuration structure of each source is as follows.
The following is the source download configuration corresponding to the `libevent` extension:
```json
{
"libevent": {
"type": "ghrel",
"repo": "libevent/libevent",
"match": "libevent.+\\.tar\\.gz",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
The most important field here is `type`. Currently, the types it supports are:
- `url`: Directly use URL to download, for example: `https://download.libsodium.org/libsodium/releases/libsodium-1.0.18.tar.gz`.
- `pie`: Download PHP extensions from Packagist using the PIE (PHP Installer for Extensions) standard.
- `ghrel`: Use the GitHub Release API to download, download the artifacts uploaded from the latest version released by maintainers.
- `ghtar`: Use the GitHub Release API to download.
Different from `ghrel`, `ghtar` is downloaded from the `source code (tar.gz)` in the latest Release of the project.
- `ghtagtar`: Use GitHub Release API to download.
Compared with `ghtar`, `ghtagtar` can find the latest one from the `tags` list and download the source code in `tar.gz` format
(because some projects only use `tag` release version).
- `bitbuckettag`: Download using BitBucket API, basically the same as `ghtagtar`, except this one applies to BitBucket.
- `git`: Clone the project directly from a Git address to download sources, applicable to any public Git repository.
- `filelist`: Use a crawler to crawl the Web download site that provides file index,
and get the latest version of the file name and download it.
- `custom`: If none of the above download methods are satisfactory, you can write `custom`,
create a new class under `src/SPC/store/source/`, extends `CustomSourceBase`, and write the download script yourself.
## source.json Common parameters
Each source file in source.json has the following params:
- `license`: the open source license of the source code, see **Open Source License** section below
- `type`: must be one of the types mentioned above
- `path` (optional): release the source code to the specified directory instead of `source/{name}`
- `provide-pre-built` (optional): whether to provide precompiled binary files.
If `true`, it will automatically try to download precompiled binary files when running `bin/spc download`
::: tip
The `path` parameter in `source.json` can specify a relative or absolute path. When specified as a relative path, the path is based on `source/`.
:::
## Download type - url
URL type sources refer to downloading files directly from the URL.
The parameters included are:
- `url`: The download address of the file, such as `https://example.com/file.tgz`
- `filename` (optional): The file name saved to the local area. If not specified, the file name of the url will be used.
Example (download the imagick extension and extract it to the extension storage path of the php source code):
```json
{
"ext-imagick": {
"type": "url",
"url": "https://pecl.php.net/get/imagick",
"path": "php-src/ext/imagick",
"filename": "imagick.tgz",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
## Download type - pie
PIE (PHP Installer for Extensions) type sources refer to downloading PHP extensions from Packagist that follow the PIE standard.
This method automatically fetches extension information from the Packagist repository and downloads the appropriate distribution file.
The parameters included are:
- `repo`: The Packagist vendor/package name, such as `vendor/package-name`
Example (download a PHP extension from Packagist using PIE):
```json
{
"ext-example": {
"type": "pie",
"repo": "vendor/example-extension",
"path": "php-src/ext/example",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
::: tip
The PIE download type will automatically detect the extension information from Packagist metadata,
including the download URL, version, and distribution type.
The extension must be marked as `type: php-ext` or contain `php-ext` metadata in its Packagist package definition.
:::
## Download type - ghrel
ghrel will download files from Assets uploaded in GitHub Release.
First use the GitHub Release API to get the latest version, and then download the corresponding files according to the regular matching method.
The parameters included are:
- `repo`: GitHub repository name
- `match`: regular expression matching Assets files
- `prefer-stable`: Whether to download stable versions first (default is `false`)
Example (download the libsodium library, matching the libsodium-x.y.tar.gz file in Release):
```json
{
"libsodium": {
"type": "ghrel",
"repo": "jedisct1/libsodium",
"match": "libsodium-\\d+(\\.\\d+)*\\.tar\\.gz",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
## Download type - ghtar
ghtar will download the file from the GitHub Release Tag.
Unlike `ghrel`, `ghtar` will download the `source code (tar.gz)` from the latest Release of the project.
The parameters included are:
- `repo`: GitHub repository name
- `prefer-stable`: Whether to download stable versions first (default is `false`)
Example (brotli library):
```json
{
"brotli": {
"type": "ghtar",
"repo": "google/brotli",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
## Download type - ghtagtar
Use the GitHub Release API to download.
Compared with `ghtar`, `ghtagtar` can find the latest one from the `tags` list and download the source code in `tar.gz` format
(because some projects only use the `tag` version).
The parameters included are:
- `repo`: GitHub repository name
- `prefer-stable`: Whether to download stable versions first (default is `false`)
Example (gmp library):
```json
{
"gmp": {
"type": "ghtagtar",
"repo": "alisw/GMP",
"license": {
"type": "text",
"text": "EXAMPLE LICENSE"
}
}
}
```
## Download Type - bitbuckettag
Download using BitBucket API, basically the same as `ghtagtar`, except this one works with BitBucket.
The parameters included are:
- `repo`: BitBucket repository name
## Download type - git
Clone the project directly from a Git address to download sources, applicable to any public Git repository.
The parameters included are:
- `url`: Git link (HTTPS only)
- `rev`: branch name
```json
{
"imap": {
"type": "git",
"url": "https://github.com/static-php/imap.git",
"rev": "master",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
## Download type - filelist
Use a crawler to crawl a web download site that provides a file index and get the latest version of the file name and download it.
Note that this method is only applicable to static sites with page index functions such as mirror sites and GNU official websites.
The parameters included are:
- `url`: The URL of the page to crawl the latest version of the file
- `regex`: regular expression matching file names and download links
Example (download the libiconv library from the GNU official website):
```json
{
"libiconv": {
"type": "filelist",
"url": "https://ftp.gnu.org/gnu/libiconv/",
"regex": "/href=\"(?<file>libiconv-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"license": {
"type": "file",
"path": "COPYING"
}
}
}
```
## Download type - custom
If the above downloading methods are not satisfactory, you can write `custom`,
create a new class under `src/SPC/store/source/`, extends `CustomSourceBase`, and write the download script yourself.
I wont go into details here, you can look at `src/SPC/store/source/PhpSource.php` or `src/SPC/store/source/PostgreSQLSource.php` as examples.
## pkg.json General parameters
pkg.json stores non-source-code files, such as precompiled tools musl-toolchain and UPX. It includes:
- `type`: The same type as `source.json` and different kinds of parameters.
- `extract` (optional): The path to decompress after downloading, the default is `pkgroot/{pkg_name}`.
- `extract-files` (optional): Extract only the specified files to the specified location after downloading.
It should be noted that `pkg.json` does not involve compilation, modification and distribution of source code,
so there is no `license` open source license field.
And you cannot use the `extract` and `extract-files` parameters at the same time.
Example (download nasm locally and extract only program files to PHP SDK):
```json
{
"nasm-x86_64-win": {
"type": "url",
"url": "https://www.nasm.us/pub/nasm/releasebuilds/2.16.01/win64/nasm-2.16.01-win64.zip",
"extract-files": {
"nasm-2.16.01/nasm.exe": "{php_sdk_path}/bin/nasm.exe",
"nasm-2.16.01/ndisasm.exe": "{php_sdk_path}/bin/ndisasm.exe"
}
}
}
```
The key name in `extract-files` is the file in the source folder, and the key value is the storage path. The storage path can use the following variables:
- `{php_sdk_path}`: (Windows only) PHP SDK path
- `{pkg_root_path}`: `pkgroot/`
- `{working_dir}`: current working directory
- `{download_path}`: download directory
- `{source_path}`: source code decompression directory
When `extract-files` does not use variables and is a relative path, the directory of the relative path is `{working_dir}`.
## Open source license
For `source.json`, each source file should contain an open source license.
The `license` field stores the open source license information.
Each `license` contains the following parameters:
- `type`: `file` or `text`
- `path`: the license file in the source code directory (required when `type` is `file`)
- `text`: License text (required when `type` is `text`)
Example (yaml extension source code with LICENSE file):
```json
{
"yaml": {
"type": "git",
"path": "php-src/ext/yaml",
"rev": "php7",
"url": "https://github.com/php/pecl-file_formats-yaml",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
When an open source project has multiple licenses, multiple files can be specified:
```json
{
"libuv": {
"type": "ghtar",
"repo": "libuv/libuv",
"license": [
{
"type": "file",
"path": "LICENSE"
},
{
"type": "file",
"path": "LICENSE-extra"
}
]
}
}
```
When the license of an open source project uses different files between versions,
`path` can be used as an array to list the possible license files:
```json
{
"redis": {
"type": "git",
"path": "php-src/ext/redis",
"rev": "release/6.0.2",
"url": "https://github.com/phpredis/phpredis",
"license": {
"type": "file",
"path": [
"LICENSE",
"COPYING"
]
}
}
}
```

View File

@@ -0,0 +1,180 @@
# Introduction to project structure
static-php-cli mainly contains three logical components: sources, dependent libraries, and extensions.
These components contains 4 configuration files: `source.json`, `pkg.json`, `lib.json`, and `ext.json`.
A complete process for building standalone static PHP is:
1. Use the source download module `Downloader` to download specified or all source codes.
These sources include PHP source code, dependent library source code, and extension source code.
2. Use the source decompression module `SourceExtractor` to decompress the downloaded sources to the compilation directory.
3. Use the dependency tool to calculate the dependent extensions and dependent libraries of the currently added extension,
and then compile each library that needs to be compiled in the order of dependencies.
4. After building each dependent library using `Builder` under the corresponding operating system, install it to the `buildroot` directory.
5. If external extensions are included (the source code does not contain extensions within PHP),
copy the external extensions to the `source/php-src/ext/` directory.
6. Use `Builder` to build the PHP source code and build target to the `buildroot` directory.
The project is mainly divided into several folders:
- `bin/`: used to store program entry files, including `bin/spc`, `bin/spc-alpine-docker`, `bin/setup-runtime`.
- `config/`: Contains all the extensions and dependent libraries supported by the project,
as well as the download link and download methods of these sources. It is divided into files: `lib.json`, `ext.json`, `source.json`, `pkg.json`, `pre-built.json` .
- `src/`: The core code of the project, including the entire framework and commands for compiling various extensions and libraries.
- `vendor/`: The directory that Composer depends on, you do not need to make any modifications to it.
The operating principle is to start a `ConsoleApplication` of `symfony/console`, and then parse the commands entered by the user in the terminal.
## Basic command line structure
`bin/spc` is an entry file, including the Unix common `#!/usr/bin/env php`,
which is used to allow the system to automatically execute with the PHP interpreter installed on the system.
After the project executes `new ConsoleApplication()`, the framework will automatically register them as commands.
The project does not directly use the Command registration method and command execution method recommended by Symfony. Here are small changes:
1. Each command uses the `#[AsCommand()]` Attribute to register the name and description.
2. Abstract `execute()` so that all commands are based on `BaseCommand` (which is based on `Symfony\Component\Console\Command\Command`),
and the execution code of each command itself is written in the `handle()` method .
3. Added variable `$no_motd` to `BaseCommand`, which is used to display the Figlet greeting when the command is executed.
4. `BaseCommand` saves `InputInterface` and `OutputInterface` as member variables. You can use `$this->input` and `$this->output` within the command class.
## Basic source code structure
The source code of the project is located in the `src/SPC` directory,
supports automatic loading of the PSR-4 standard, and contains the following subdirectories and classes:
- `src/SPC/builder/`: The core compilation command code used to build libraries,
PHP and related extensions under different operating systems, and also includes some compilation system tool methods.
- `src/SPC/command/`: All commands of the project are here.
- `src/SPC/doctor/`: Doctor module, which is a relatively independent module used to check the system environment.
It can be entered using the command `bin/spc doctor`.
- `src/SPC/exception/`: exception class.
- `src/SPC/store/`: Classes related to storage, files and sources are all here.
- `src/SPC/util/`: Some reusable tool methods are here.
- `src/SPC/ConsoleApplication.php`: command line program entry file.
If you have read the source code, you may find that there is also a `src/globals/` directory,
which is used to store some global variables, global methods,
and non-PSR-4 standard PHP source code that is relied upon during the build process, such as extension sanity check code etc.
## Phar application directory issue
Like other php-cli projects, spc itself has additional considerations for paths.
Because spc can run in multiple modes such as `php-cli directly`, `micro SAPI`, `php-cli with Phar`, `vendor with Phar`, etc.,
there are ambiguities in various root directories. A complete explanation is given here.
This problem is generally common in the base class path selection problem of accessing files in PHP projects, especially when used with `micro.sfx`.
Note that this may only be useful for you when developing Phar projects or PHP frameworks.
> Next, we will treat `static-php-cli` (that is, spc) as a normal `php` command line program. You can understand spc as any of your own php-cli applications for reference.
There are three basic constant theoretical values below. We recommend that you introduce these three constants when writing PHP projects:
- `WORKING_DIR`: the working directory when executing PHP scripts
- `SOURCE_ROOT_DIR` or `ROOT_DIR`: the root directory of the project folder, generally the directory where `composer.json` is located
- `FRAMEWORK_ROOT_DIR`: the root directory of the framework used, which may be used by self-developed frameworks. Generally, the framework directory is read-only
You can define these constants in your framework entry or cli applications to facilitate the use of paths in your project.
The following are PHP built-in constant values, which have been defined inside the PHP interpreter:
- `__DIR__`: the directory where the file of the currently executed script is located
- `__FILE__`: the file path of the currently executed script
### Git project mode (source)
Git project mode refers to a framework or program itself stored in plain text in the current folder, and running through `php path/to/entry.php`.
Assume that your project is stored in the `/home/example/static-php-cli/` directory, or your project is the framework itself,
which contains project files such as `composer.json`:
```
composer.json
src/App/MyCommand.app
vendor/*
bin/entry.php
```
We assume that the above constants are obtained from `src/App/MyCommand.php`:
| Constant | Value |
|----------------------|------------------------------------------------------|
| `WORKING_DIR` | `/home/example/static-php-cli` |
| `SOURCE_ROOT_DIR` | `/home/example/static-php-cli` |
| `FRAMEWORK_ROOT_DIR` | `/home/example/static-php-cli` |
| `__DIR__` | `/home/example/static-php-cli/src/App` |
| `__FILE__` | `/home/example/static-php-cli/src/App/MyCommand.php` |
In this case, the values of `WORKING_DIR`, `SOURCE_ROOT_DIR`, and `FRAMEWORK_ROOT_DIR` are exactly the same: `/home/example/static-php-cli`.
The source code of the framework and the source code of the application are both in the current path.
### Vendor library mode (vendor)
The vendor library mode generally means that your project is a framework or is installed into the project as a composer dependency by other applications,
and the storage location is in the `vendor/author/XXX` directory.
Suppose your project is `crazywhalecc/static-php-cli`, and you or others install this project in another project using `composer require`.
We assume that static-php-cli contains all files except the `vendor` directory with the same `Git mode`, and get the constant value from `src/App/MyCommand`,
Directory constant should be:
| Constant | Value |
|----------------------|--------------------------------------------------------------------------------------|
| `WORKING_DIR` | `/home/example/another-app` |
| `SOURCE_ROOT_DIR` | `/home/example/another-app` |
| `FRAMEWORK_ROOT_DIR` | `/home/example/another-app/vendor/crazywhalecc/static-php-cli` |
| `__DIR__` | `/home/example/another-app/vendor/crazywhalecc/static-php-cli/src/App` |
| `__FILE__` | `/home/example/another-app/vendor/crazywhalecc/static-php-cli/src/App/MyCommand.php` |
Here `SOURCE_ROOT_DIR` refers to the root directory of the project using `static-php-cli`.
### Git project Phar mode (source-phar)
Git project Phar mode refers to the mode of packaging the project directory of the Git project mode into a `phar` file. We assume that `/home/example/static-php-cli` will be packaged into a Phar file, and the directory has the following files:
```
composer.json
src/App/MyCommand.app
vendor/*
bin/entry.php
```
When packaged into `app.phar` and stored in the `/home/example/static-php-cli` directory, `app.phar` is executed at this time. Assuming that the `src/App/MyCommand` code is executed, the constant is obtained in the file:
| Constant | Value |
|----------------------|----------------------------------------------------------------------|
| `WORKING_DIR` | `/home/example/static-php-cli` |
| `SOURCE_ROOT_DIR` | `phar:///home/example/static-php-cli/app.phar/` |
| `FRAMEWORK_ROOT_DIR` | `phar:///home/example/static-php-cli/app.phar/` |
| `__DIR__` | `phar:///home/example/static-php-cli/app.phar/src/App` |
| `__FILE__` | `phar:///home/example/static-php-cli/app.phar/src/App/MyCommand.php` |
Because the `phar://` protocol is required to read files in the phar itself, the project root directory and the framework directory will be different from `WORKING_DIR`.
### Vendor Library Phar Mode (vendor-phar)
Vendor Library Phar Mode means that your project is installed as a framework in other projects and stored in the `vendor` directory.
We assume that your project directory structure is as follows:
```
composer.json # Composer configuration file of the current project
box.json # Configuration file for packaging Phar
another-app.php # Entry file of another project
vendor/crazywhalecc/static-php-cli/* # Your project is used as a dependent library
```
When packaging these files under the directory `/home/example/another-app/` into `app.phar`, the value of the following constant for your project should be:
| Constant | Value |
|----------------------|------------------------------------------------------------------------------------------------------|
| `WORKING_DIR` | `/home/example/another-app` |
| `SOURCE_ROOT_DIR` | `phar:///home/example/another-app/app.phar/` |
| `FRAMEWORK_ROOT_DIR` | `phar:///home/example/another-app/app.phar/vendor/crazywhalecc/static-php-cli` |
| `__DIR__` | `phar:///home/example/another-app/app.phar/vendor/crazywhalecc/static-php-cli/src/App` |
| `__FILE__` | `phar:///home/example/another-app/app.phar/vendor/crazywhalecc/static-php-cli/src/App/MyCommand.php` |

View File

@@ -0,0 +1,242 @@
# Compilation Tools
static-php-cli uses many system compilation tools when building static PHP. These tools mainly include:
- `autoconf`: used to generate `configure` scripts.
- `make`: used to execute `Makefile`.
- `cmake`: used to execute `CMakeLists.txt`.
- `pkg-config`: Used to find the installation path of dependent libraries.
- `gcc`: used to compile C/C++ projects under Linux.
- `clang`: used to compile C/C++ projects under macOS.
For Linux and macOS operating systems,
these tools can usually be installed through the package manager, which is written in the doctor module.
Theoretically we can also compile and download these tools manually,
but this will increase the complexity of compilation, so we do not recommend this.
## Linux Compilation Tools
For Linux systems, different distributions have different installation methods for compilation tools.
And for static compilation, the package management of some distributions cannot install libraries and tools for pure static compilation.
Therefore, for the Linux platform and its different distributions,
we currently provide a variety of compilation environment preparations.
### Glibc Environment
The glibc environment refers to the underlying `libc` library of the system
(that is, the C standard library that all programs written in C language are dynamically linked to) uses `glibc`,
which is the default environment for most distributions.
For example: Ubuntu, Debian, CentOS, RHEL, openSUSE, Arch Linux, etc.
In the glibc environment, the package management and compiler we use point to glibc by default,
and glibc cannot be statically linked well.
One of the reasons it cannot be statically linked is that its network library `nss` cannot be compiled statically.
For the glibc environment, in static-php-cli and spc in 2.0-RC8 and later, you can choose two ways to build static PHP:
1. Use Docker to build, you can use `bin/spc-alpine-docker` to build, it will build an Alpine Linux docker image.
2. Use `bin/spc doctor --auto-fix` to install the `musl-wrapper` and `musl-cross-make` packages, and then build directly.
([Related source code](https://github.com/crazywhalecc/static-php-cli/blob/main/src/SPC/doctor/item/LinuxMuslCheck.php))
Generally speaking, the build results in these two environments are consistent, and you can choose according to actual needs.
In the doctor module, static-php-cli will first detect the current Linux distribution.
If the current distribution is a glibc environment, you will be prompted to install the musl-wrapper and musl-cross-make packages.
The process of installing `musl-wrapper` in the glibc environment is as follows:
1. Download the specific version of [musl-wrapper source code](https://musl.libc.org/releases/) from the musl official website.
2. Use `gcc` installed from the package management to compile the musl-wrapper source code and generate `musl-libc` and other libraries: `./configure --disable-gcc-wrapper && make -j && sudo make install`.
3. The musl-wrapper related libraries will be installed in the `/usr/local/musl` directory.
The process of installing `musl-cross-make` in the glibc environment is as follows:
1. Download the precompiled [musl-cross-make](https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/) compressed package from dl.static-php.dev .
2. Unzip to the `/usr/local/musl` directory.
::: tip
In the glibc environment, static compilation can be achieved by directly installing musl-wrapper,
but musl-wrapper only contains `musl-gcc` and not `musl-g++`, which means that C++ code cannot be compiled.
So we need musl-cross-make to provide `musl-g++`.
The reason why the musl-cross-make package cannot be compiled directly locally is that
its compilation environment requirements are relatively high (requires more than 36GB of memory, compiled under Alpine Linux),
so we provide precompiled binary packages that can be used for all Linux distributions.
At the same time, the package management of some distributions provides musl-wrapper,
but musl-cross-make needs to match the corresponding musl-wrapper version,
so we do not use package management to install musl-wrapper.
Compiling musl-cross-make will be introduced in the **musl-cross-make Toolchain Compilation** section of this chapter.
:::
### Musl Environment
The musl environment refers to the system's underlying `libc` library that uses `musl`,
which is a lightweight C standard library that can be well statically linked.
For the currently popular Linux distributions, Alpine Linux uses the musl environment,
so static-php-cli can directly build static PHP under Alpine Linux.
You only need to install basic compilation tools (such as `gcc`, `cmake`, etc.) directly from the package management.
For other distributions, if your distribution uses the musl environment,
you can also use static-php-cli to build static PHP directly after installing the necessary compilation tools.
::: tip
In the musl environment, static-php-cli will automatically skip the installation of musl-wrapper and musl-cross-make.
:::
### Docker Environment
The Docker environment refers to using Docker containers to build static PHP. You can use `bin/spc-alpine-docker` to build.
Before executing this command, you need to install Docker first, and then execute `bin/spc-alpine-docker` in the project root directory.
After executing `bin/spc-alpine-docker`, static-php-cli will automatically download the Alpine Linux image and then build a `cwcc-spc-x86_64` or `cwcc-spc-aarch64` image.
Then all build process is performed within this image, which is equivalent to compiling in Alpine Linux.
## musl-cross-make Toolchain Compilation
In Linux, although you do not need to manually compile the musl-cross-make tool,
if you want to understand its compilation process, you can refer here.
Another important reason is that this may not be compiled using automated tools such as CI and Actions,
because the existing CI service compilation environment does not meet the compilation requirements of musl-cross-make,
and the configuration that meets the requirements is too expensive.
The compilation process of musl-cross-make is as follows:
Prepare an Alpine Linux environment (either directly installed or using Docker).
The compilation process requires more than **36GB** of memory,
so you need to compile on a machine with larger memory.
Without this much memory, compilation may fail.
Then write the following content into the `config.mak` file:
```makefile
STAT = -static --static
FLAG = -g0 -Os -Wno-error
ifneq ($(NATIVE),)
COMMON_CONFIG += CC="$(HOST)-gcc ${STAT}" CXX="$(HOST)-g++ ${STAT}"
else
COMMON_CONFIG += CC="gcc ${STAT}" CXX="g++ ${STAT}"
endif
COMMON_CONFIG += CFLAGS="${FLAG}" CXXFLAGS="${FLAG}" LDFLAGS="${STAT}"
BINUTILS_CONFIG += --enable-gold=yes --enable-gprofng=no
GCC_CONFIG += --enable-static-pie --disable-cet --enable-default-pie
#--enable-default-pie
CONFIG_SUB_REV = 888c8e3d5f7b
GCC_VER = 13.2.0
BINUTILS_VER = 2.40
MUSL_VER = 1.2.4
GMP_VER = 6.2.1
MPC_VER = 1.2.1
MPFR_VER = 4.2.0
LINUX_VER = 6.1.36
```
And also you need to add `gcc-13.2.0.tar.xz.sha1` file, contents here:
```
5f95b6d042fb37d45c6cbebfc91decfbc4fb493c gcc-13.2.0.tar.xz
```
If you are using Docker to build, create a new `Dockerfile` file and write the following content:
```dockerfile
FROM alpine:edge
RUN apk add --no-cache \
gcc g++ git make curl perl \
rsync patch wget libtool \
texinfo autoconf automake \
bison tar xz bzip2 zlib \
file binutils flex \
linux-headers libintl \
gettext gettext-dev icu-libs pkgconf \
pkgconfig icu-dev bash \
ccache libarchive-tools zip
WORKDIR /opt
RUN git clone https://git.zv.io/toolchains/musl-cross-make.git
WORKDIR /opt/musl-cross-make
COPY config.mak /opt/musl-cross-make
COPY gcc-13.2.0.tar.xz.sha1 /opt/musl-cross-make/hashes
RUN make TARGET=x86_64-linux-musl -j || :
RUN sed -i 's/poison calloc/poison/g' ./gcc-13.2.0/gcc/system.h
RUN make TARGET=x86_64-linux-musl -j
RUN make TARGET=x86_64-linux-musl install -j
RUN tar cvzf x86_64-musl-toolchain.tgz output/*
```
If you are using Alpine Linux in a non-Docker environment, you can directly execute the commands in the Dockerfile, for example:
```bash
apk add --no-cache \
gcc g++ git make curl perl \
rsync patch wget libtool \
texinfo autoconf automake \
bison tar xz bzip2 zlib \
file binutils flex \
linux-headers libintl \
gettext gettext-dev icu-libs pkgconf \
pkgconfig icu-dev bash \
ccache libarchive-tools zip
git clone https://git.zv.io/toolchains/musl-cross-make.git
# Copy config.mak to the working directory of musl-cross-make.
# You need to replace /path/to/config.mak with your config.mak file path.
cp /path/to/config.mak musl-cross-make/
cp /path/to/gcc-13.2.0.tar.xz.sha1 musl-cross-make/hashes
make TARGET=x86_64-linux-musl -j || :
sed -i 's/poison calloc/poison/g' ./gcc-13.2.0/gcc/system.h
make TARGET=x86_64-linux-musl -j
make TARGET=x86_64-linux-musl install -j
tar cvzf x86_64-musl-toolchain.tgz output/*
```
::: tip
All the above scripts are suitable for x86_64 architecture Linux.
If you need to build musl-cross-make for the ARM environment, just replace all `x86_64` above with `aarch64`.
:::
This compilation process may fail due to insufficient memory, network problems, etc.
You can try a few more times, or use a machine with larger memory to compile.
If you encounter problems or you have better improvement solutions, go to [Discussion](https://github.com/crazywhalecc/static-php-cli-hosted/issues/1).
## macOS Environment
For macOS systems, the main compilation tool we use is `clang`,
which is the default compiler for macOS systems and is also the compiler of Xcode.
Compiling under macOS mainly relies on Xcode or Xcode Command Line Tools.
You can download Xcode from the App Store,
or execute `xcode-select --install` in the terminal to install Xcode Command Line Tools.
In addition, in the `doctor` environment check module, static-php-cli will check whether Homebrew,
compilation tools, etc. are installed on the macOS system.
If not, you will be prompted to install them. I will not go into details here.
## FreeBSD Environment
FreeBSD is also a Unix system, and its compilation tools are similar to macOS.
You can directly use the package management `pkg` to install `clang` and other compilation tools through the `doctor` command.
## pkg-config Compilation (*nix only)
If you observe the compilation log when using static-php-cli to build static PHP, you will find that no matter what is compiled,
`pkg-config` will be compiled first. This is because `pkg-config` is a library used to find dependencies.
In earlier versions of static-php-cli, we directly used the `pkg-config` tool installed by package management,
but this would cause some problems, such as:
- Even if `PKG_CONFIG_PATH` is specified, `pkg-config` will try to find dependent packages from the system path.
- Since `pkg-config` will look for dependent packages from the system path,
if a dependent package with the same name exists in the system, compilation may fail.
In order to avoid the above problems, we compile `pkg-config` into `buildroot/bin` in user mode and use it.
We use parameters such as `--without-sysroot` to avoid looking for dependent packages from the system path.

108
docs-v2/en/faq/index.md Normal file
View File

@@ -0,0 +1,108 @@
# FAQ
Here will be some questions that you may encounter easily. There are currently many, but I need to take time to organize them.
## What is the path of php.ini ?
On Linux, macOS and FreeBSD, the path of `php.ini` is `/usr/local/etc/php/php.ini`.
On Windows, the path is `C:\windows\php.ini` or the current directory of `php.exe`.
The directory where to look for `php.ini` can be changed on *nix using the manual build option `--with-config-file-path`.
In addition, on Linux, macOS and FreeBSD, `.ini` files present in the `/usr/local/etc/php/conf.d` directory will also be loaded.
On Windows, this path is empty by default.
The directory can be changed using the manual build option `--with-config-file-scan-dir`.
`php.ini` will also be searched for in [the other standard locations](https://www.php.net/manual/configuration.file.php).
## Can statically-compiled PHP install extensions?
Because the principle of installing PHP extensions under the normal mode is to use `.so` type dynamic link library to install new extensions,
and we use the static link PHP compiled by this project. However, static linking has different definitions in different operating systems.
First of all, for Linux systems, statically linked binaries will not link the system's dynamic link library.
Purely statically linked binaries (`build with -all-static`) cannot load dynamic libraries, so new extensions cannot be added.
At the same time, in pure static mode, you cannot use extensions such as `ffi` to load external `.so` modules.
You can use the command `ldd buildroot/bin/php` to check whether the binary you built under Linux is purely statically linked.
If you [build GNU libc based PHP](../guide/build-with-glibc), you can use the `ffi` extension to load external `.so` modules and load `.so` extensions with the same ABI.
For example, you can use the following command to build a static PHP binary dynamically linked with glibc,
supporting FFI extensions and loading the `xdebug.so` extension of the same PHP version and the same TS type:
```bash
bin/spc-gnu-docker download --for-extensions=ffi,xml --with-php=8.4
bin/spc-gnu-docker build ffi,xml --build-cli --debug
buildroot/bin/php -d "zend_extension=/path/to/php{PHP_VER}-{ts/nts}/xdebug.so" --ri xdebug
```
For macOS platform, almost all binaries under macOS cannot be truly purely statically linked, and almost all binaries will link macOS system libraries: `/usr/lib/libresolv.9.dylib` and `/usr/lib/libSystem.B.dylib`.
So on macOS, you can **directly** use SPC to build statically compiled PHP binaries with dynamically linked extensions:
1. Build shared extension `xxx.so` using: `--build-shared=XXX` option. e.g. `bin/spc build bcmath,zlib --build-shared=xdebug --build-cli`
2. You will get `buildroot/modules/xdebug.so` and `buildroot/bin/php`.
3. The `xdebug.so` file could be used for php that version and thread-safe are the same.
For the Windows platform, since officially built extensions (such as `php_yaml.dll`) force the use of the `php8.dll` dynamic library as a link, and statically built PHP does not include any dynamic libraries other than system libraries,
php.exe built by static-php cannot load officially built dynamic extensions. Since static-php-cli does not yet support building dynamic extensions, there is currently no way to load dynamic extensions with static-php.
However, Windows can normally use the `FFI` extension to load other dll files and call them.
## Can it support Oracle database extension?
Some extensions that rely on closed source libraries, such as `oci8`, `sourceguardian`, etc.,
they do not provide purely statically compiled dependent library files (`.a`), only dynamic dependent library files (`.so`).
These extensions cannot be compiled into static-php-cli using source code, so this project may never support these extensions.
However, in theory you can access and use such extensions under macOS and Linux according to the above questions.
If you have a need for such extensions, or most people have needs for these closed-source extensions,
see the discussion on [standalone-php-cli](https://github.com/crazywhalecc/static-php-cli/discussions/58). Welcome to leave a message.
## Does it support Windows?
The project currently supports Windows, but the number of supported extensions is small. Windows support is not perfect. There are mainly the following problems:
1. The compilation process of Windows is different from that of *nix, and the toolchain used is also different. The compilation tools used to compile the dependent libraries of each extension are almost completely different.
2. The demand for the Windows version will also be advanced based on the needs of all people who use this project. If many people need it, I will support related extensions as soon as possible.
## Can I protect my source code with micro?
You can't. micro.sfx is essentially combining php and php code into one file,
there is no process of compiling or encrypting the PHP code.
First of all, php-src is the official interpreter of PHP code, and there is no PHP compiler compatible with mainstream branches on the market.
I saw on the Internet that there is a project called BPC (Binary PHP Compiler?) that can compile PHP into binary,
but there are many restrictions.
The direction of encrypting and protecting the code is not the same as compiling.
After compiling, the code can also be obtained through reverse engineering and other methods.
The real protection is still carried out by means of packing and encrypting the code.
Therefore, this project (static-php-cli) and related projects (lwmbs, swoole-cli) all provide a convenient compilation tool for php-src source code.
The phpmicro referenced by this project and related projects is only a package of PHP's sapi interface, not a compilation tool for PHP code.
The compiler for PHP code is a completely different project, so the extra cases are not taken into account.
If you are interested in encryption, you can consider using existing encryption technologies,
such as Swoole Compiler, Source Guardian, etc.
## Unable to use ssl
**Update: This issue has been fixed in the latest version of static-php-cli, which now reads the system's certificate file by default. If you still have problems, try the solution below.**
When using curl, pgsql, etc. to request an HTTPS website or establish an SSL connection, there may be an `error:80000002:system library::No such file or directory` error.
This error is caused by statically compiled PHP without specifying `openssl.cafile` via `php.ini`.
You can solve this problem by specifying `php.ini` before using PHP and adding `openssl.cafile=/path/to/your-cert.pem` in the INI.
For Linux systems, you can download the [cacert.pem](https://curl.se/docs/caextract.html) file from the curl official website, or you can use the certificate file that comes with the system.
For the certificate locations of different distros, please refer to [Golang docs](https://go.dev/src/crypto/x509/root_linux.go).
> INI configuration `openssl.cafile` cannot be set dynamically using the `ini_set()` function, because `openssl.cafile` is a `PHP_INI_SYSTEM` type configuration and can only be set in the `php.ini` file.
## Why don't we support older versions of PHP?
Because older versions of PHP have many problems, such as security issues, performance issues, and functional issues.
In addition, many older versions of PHP are not compatible with the latest dependency libraries,
which is one of the reasons why older versions of PHP are not supported.
You can use older versions compiled earlier by static-php-cli, such as PHP 8.0, but earlier versions will not be explicitly supported.

View File

@@ -0,0 +1,16 @@
---
aside: false
---
<script setup lang="ts">
import CliGenerator from "../../.vitepress/components/CliGenerator.vue";
</script>
# CLI Build Command Generator
::: tip
The extensions selected below may contain extensions that are not supported by the selected operating system,
which may cause compilation to fail. Please check [Supported Extensions](./extensions) first.
:::
<cli-generator lang="en" />

View File

@@ -0,0 +1,26 @@
---
outline: 'deep'
---
# Dependency Table
When compiling PHP, each extension and library has dependencies, which may be required or optional.
You can choose whether to include these optional dependencies.
For example, when compiling the `gd` extension under Linux,
the `zlib,libpng` libraries and the `zlib` extension are forced to be compiled,
while the `libavif,libwebp,libjpeg,freetype` libraries are optional libraries and will not be compiled by default
unless specified by the `--with-libs=avif,webp,jpeg,freetype` option.
- For optional extensions (optional features of extensions), you need to specify them manually at compile time, for example, to enable igbinary support for Redis: `bin/spc build redis,igbinary`.
- For optional libraries, you need to compile and specify them through the `--with-libs=XXX` option.
- If you want to enable all optional extensions, you can use `bin/spc build redis --with-suggested-exts`.
- If you want to enable all optional libraries, you can use `--with-suggested-libs`.
## Extension Dependency Table
<!--@include: ../../deps-map-ext.md-->
## Library Dependency Table
<!--@include: ../../deps-map-lib.md-->

View File

@@ -0,0 +1,121 @@
# Environment variables
All environment variables mentioned in the list on this page have default values unless otherwise noted.
You can override the default values by setting these environment variables.
## Environment variables list
Starting from version 2.3.5, we have centralized the environment variables in the `config/env.ini` file.
You can set environment variables by modifying this file.
We divide the environment variables supported by static-php-cli into three types:
- Global internal environment variables: declared after static-php-cli starts, you can use `getenv()` to get them internally in static-php-cli, and you can override them before starting static-php-cli.
- Fixed environment variables: declared after static-php-cli starts, you can only use `getenv()` to get them, but you cannot override them through shell scripts.
- Config file environment variables: declared before static-php-cli build, you can set these environment variables by modifying the `config/env.ini` file or through shell scripts.
You can read the comments for each parameter in [config/env.ini](https://github.com/crazywhalecc/static-php-cli/blob/main/config/env.ini) to understand its purpose.
## Custom environment variables
Generally, you don't need to modify any of the following environment variables as they are already set to optimal values.
However, if you have special needs, you can set these environment variables to meet your needs
(for example, you need to debug PHP performance under different compilation parameters).
If you want to use custom environment variables, you can use the `export` command in the terminal or set the environment variables directly before the command, for example:
```shell
# export first
export SPC_CONCURRENCY=4
bin/spc build mbstring,pcntl --build-cli
# or direct use
SPC_CONCURRENCY=4 bin/spc build mbstring,pcntl --build-cli
```
Or, if you need to modify an environment variable for a long time, you can modify the `config/env.ini` file.
`config/env.ini` is divided into three sections, `[global]` is globally effective, `[windows]`, `[macos]`, `[linux]` are only effective for the corresponding operating system.
For example, if you need to modify the `./configure` command for compiling PHP, you can find the `SPC_CMD_PREFIX_PHP_CONFIGURE` environment variable in the `config/env.ini` file, and then modify its value.
If your build conditions are more complex and require multiple `env.ini` files to switch,
we recommend that you use the `config/env.custom.ini` file.
In this way, you can specify your environment variables by writing additional override items
without modifying the default `config/env.ini` file.
```ini
; This is an example of `config/env.custom.ini` file,
; we modify the `SPC_CONCURRENCY` and linux default CFLAGS passing to libs and PHP
[global]
SPC_CONCURRENCY=4
[linux]
SPC_DEFAULT_C_FLAGS="-O3"
```
## Library environment variables (Unix only)
Starting from 2.2.0, static-php-cli supports custom environment variables for all compilation dependent library commands of macOS, Linux, FreeBSD and other Unix systems.
In this way, you can adjust the behavior of compiling dependent libraries through environment variables at any time.
For example, you can set the optimization parameters for compiling the xxx library through `xxx_CFLAGS=-O0`.
Of course, not every library supports the injection of environment variables.
We currently provide three wildcard environment variables with the suffixes:
- `_CFLAGS`: CFLAGS for the compiler
- `_LDFLAGS`: LDFLAGS for the linker
- `_LIBS`: LIBS for the linker
The prefix is the name of the dependent library, and the specific name of the library is subject to `lib.json`.
Among them, the library name with `-` needs to replace `-` with `_`.
Here is an example of an optimization option that replaces the openssl library compilation:
```shell
openssl_CFLAGS="-O0"
```
The library name uses the same name listed in `lib.json` and is case-sensitive.
::: tip
When no relevant environment variables are specified, except for the following variables, the remaining values are empty by default:
| var name | var default value |
|-----------------------|-------------------------------------------------------------------------------------------------|
| `pkg_config_CFLAGS` | macOS: `$SPC_DEFAULT_C_FLAGS -Wimplicit-function-declaration -Wno-int-conversion`, Other: empty |
| `pkg_config_LDFLAGS` | Linux: `--static`, Other: empty |
| `imagemagick_LDFLAGS` | Linux: `-static`, Other: empty |
| `imagemagick_LIBS` | macOS: `-liconv`, Other: empty |
| `ldap_LDFLAGS` | `-L$BUILD_LIB_PATH` |
| `openssl_CFLAGS` | Linux: `$SPC_DEFAULT_C_FLAGS`, Other: empty |
| others... | empty |
:::
The following table is a list of library names that support customizing the above three variables:
| lib name |
|-------------|
| brotli |
| bzip |
| curl |
| freetype |
| gettext |
| gmp |
| imagemagick |
| ldap |
| libargon2 |
| libavif |
| libcares |
| libevent |
| openssl |
::: tip
Because adapting custom environment variables to each library is a particularly tedious task,
and in most cases you do not need custom environment variables for these libraries,
so we currently only support custom environment variables for some libraries.
If the library you need to customize environment variables is not listed above,
you can submit your request through [GitHub Issue](https://github.com/crazywhalecc/static-php-cli/issues).
:::

View File

@@ -0,0 +1,168 @@
# Extension Notes
Because it is a static compilation, extensions will not compile 100% perfectly,
and different extensions have different requirements for PHP and the environment,
which will be listed one by one here.
## curl
HTTP3 support is not enabled by default, compile with `--with-libs="nghttp2,nghttp3,ngtcp2"` to enable HTTP3 support for PHP >= 8.4.
When using curl to request HTTPS, there may be an `error:80000002:system library::No such file or directory` error.
For details on the solution, see [FAQ - Unable to use ssl](../faq/#unable-to-use-ssl).
## phpmicro
1. Only PHP >= 8.0 is supported.
## swoole
1. swoole >= 5.0 Only PHP >= 8.0 is supported.
2. swoole Currently, curl hooks are not supported for PHP 8.0.x (which may be fixed in the future).
3. When compiling, if only `swoole` extension is included, the supported Swoole database coroutine hook will not be fully enabled.
If you need to use it, please add the corresponding `swoole-hook-xxx` extension.
4. The `zend_mm_heap corrupted` problem may occur in swoole under some extension combinations. The cause has not yet been found.
## swoole-hook-pgsql
swoole-hook-pgsql is not an extension, it's a Hook feature of Swoole.
If you use `swoole,swoole-hook-pgsql`, you will enable Swoole's PostgreSQL client and the coroutine mode of the `pdo_pgsql` extension.
swoole-hook-pgsql conflicts with the `pdo_pgsql` extension. If you want to use Swoole and `pdo_pgsql`, please delete the pdo_pgsql extension and enable `swoole` and `swoole-hook-pgsql`.
This extension contains an implementation of the coroutine environment for `pdo_pgsql`.
On macOS systems, `pdo_pgsql` may not be able to connect to the postgresql server normally, please use it with caution.
## swoole-hook-mysql
swoole-hook-mysql is not an extension, it's a Hook feature of Swoole.
If you use `swoole,swoole-hook-mysql`, you will enable the coroutine mode of Swoole's `mysqlnd` and `pdo_mysql`.
## swoole-hook-sqlite
swoole-hook-sqlite is not an extension, it's a Hook feature of Swoole.
If you use `swoole,swoole-hook-sqlite`, you will enable the coroutine mode of Swoole's `pdo_sqlite` (Swoole must be 5.1 or above).
swoole-hook-sqlite conflicts with the `pdo_sqlite` extension. If you want to use Swoole and `pdo_sqlite`, please delete the pdo_sqlite extension and enable `swoole` and `swoole-hook-sqlite`.
This extension contains an implementation of the coroutine environment for `pdo_sqlite`.
## swoole-hook-odbc
swoole-hook-odbc is not an extension, it's a Hook feature of Swoole.
If you use `swoole,swoole-hook-odbc`, you will enable the coroutine mode of Swoole's `odbc` extension.
swoole-hook-odbc conflicts with the `pdo_odbc` extension. If you want to use Swoole and `pdo_odbc`, please delete the `pdo_odbc` extension and enable `swoole` and `swoole-hook-odbc`.
This extension contains an implementation of the coroutine environment for `pdo_odbc`.
## swow
1. Only PHP 8.0+ is supported.
## imagick
1. OpenMP support is disabled, this is recommended by the maintainers and also the case system packages.
## imap
1. Kerberos is not supported
2. ext-imap is not thread safe due to the underlying c-client. It's not possible to use it in `--enable-zts` builds.
3. The extension was dropped from php 8.4, we recommend you look for an alternative implementation, such as [Webklex/php-imap](https://github.com/Webklex/php-imap)
## gd
1. gd Extension relies on more additional Graphics library. By default,
using `bin/spc build gd` directly will not support some Graphics library, such as `libjpeg`, `libavif`, etc.
Currently, it supports four libraries: `freetype,libjpeg,libavif,libwebp`.
Therefore, the following command can be used to introduce them into the gd library:
```bash
bin/spc build gd --with-libs=freetype,libjpeg,libavif,libwebp --build-cli
```
## mcrypt
1. Currently not supported, and this extension will not be supported in the future. [#32](https://github.com/crazywhalecc/static-php-cli/issues/32)
## oci8
1. oci8 is an extension of the Oracle database, because the library on which the extension provided by Oracle does not provide a statically compiled version (`.a`) or source code,
and this extension cannot be compiled into php by static linking, so it cannot be supported.
## xdebug
1. Xdebug is only buildable as a shared extension. On Linux, you'll need to use a SPC_TARGET like `native-native -dynamic` or `native-native-gnu`.
2. When using Linux/glibc or macOS, you can compile Xdebug as a shared extension using --build-shared="xdebug".
The compiled `./php` binary can be configured and run by specifying the INI, eg `./php -d 'zend_extension=/path/to/xdebug.so' your-code.php`.
## xml
1. xml includes xml, xmlreader, xmlwriter, xsl, dom, simplexml, etc.
When adding xml extensions, it is best to enable these extensions at the same time.
2. libxml is included in xml extension. Enabling xml is equivalent to enabling libxml.
## glfw
1. glfw depends on OpenGL, and linux environment also needs X11, which cannot be linked statically.
2. macOS platform, we can compile and link system builtin OpenGL and related libraries dynamically.
## rar
1. The rar extension currently has a problem when compiling phpmicro with the `common` extension collection in the macOS x86_64 environment.
## pgsql
~~pgsql ssl connection is not compatible with openssl 3.2.0. See:~~
- ~~<https://github.com/Homebrew/homebrew-core/issues/155651>~~
- ~~<https://github.com/Homebrew/homebrew-core/pull/155699>~~
- ~~<https://github.com/postgres/postgres/commit/c82207a548db47623a2bfa2447babdaa630302b9>~~
pgsql 16.2 has fixed this bug, now it's working.
When pgsql uses SSL connection, there may be `error:80000002:system library::No such file or directory` error,
For details on the solution, see [FAQ - Unable to use ssl](../faq/#unable-to-use-ssl).
## openssl
When using openssl-based extensions (such as curl, pgsql and other network libraries),
there may be an `error:80000002:system library::No such file or directory` error.
For details on the solution, see [FAQ - Unable to use ssl](../faq/#unable-to-use-ssl).
## password-argon2
1. password-argon2 is not a standard extension. The algorithm `PASSWORD_ARGON2ID` for the `password_hash` function needs libsodium or libargon2 to work.
2. using password-argon2 enables multithread support for this.
## ffi
1. Due to the limitation of musl libc's static linkage, you cannot use ffi because dynamic libraries cannot be loaded.
If you need to use the ffi extension, see [Compile PHP with GNU libc](./build-with-glibc).
2. macOS supports the ffi extension, but errors will occur when some kernels do not contain debugging symbols.
3. Windows x64 supports the ffi extension.
## xhprof
The xhprof extension consists of three parts: `xhprof_extension`, `xhprof_html`, `xhprof_libs`.
Only `xhprof_extension` is included in the compiled binary.
If you need to use xhprof,
please download the source code from [pecl.php.net/package/xhprof](http://pecl.php.net/package/xhprof) and specify the `xhprof_libs` and `xhprof_html` paths for use.
## event
If you enable event extension on macOS, the `openpty` will be disabled due to issue:
- [static-php-cli#335](https://github.com/crazywhalecc/static-php-cli/issues/335)
## parallel
Parallel is only supported on PHP 8.0 ZTS and above.
## spx
1. SPX does not support Windows, and the official repository does not support static compilation. static-php-cli uses a [modified version](https://github.com/static-php/php-spx).
## mimalloc
1. This is not technically an extension, but a library.
2. Building with `--with-libs="mimalloc"` on Linux or macOS will override the default allocator.
3. This is experimental for now, but is recommended in threaded environments.

View File

@@ -0,0 +1,23 @@
<script setup>
import SearchTable from "../../.vitepress/components/SearchTable.vue";
</script>
# Extensions
> - `yes`: supported
> - _blank_: not supported yet, or WIP
> - `no` with issue link: confirmed to be unavailable due to issue
> - `partial` with issue link: supported but not perfect due to issue
<search-table />
::: tip
If an extension you need is missing, you can create a [Feature Request](https://github.com/crazywhalecc/static-php-cli/issues).
Some extensions or libraries that the extension depends on will have some optional features.
For example, the gd library optionally supports libwebp, freetype, etc.
If you only use `bin/spc build gd --build-cli` they will not be included (static-php-cli defaults to the minimum dependency principle).
For more information about optional libraries, see [Extensions, Library Dependency Map](./deps-map).
For optional libraries, you can also select an extension from the [Command Generator](./cli-generator) and then select optional libraries.
:::

50
docs-v2/en/guide/index.md Normal file
View File

@@ -0,0 +1,50 @@
# Guide
Static php cli is a tool used to build statically compiled PHP binaries,
currently supporting Linux and macOS systems.
In the guide section, you will learn how to use static php cli to build standalone PHP programs.
- [Build (local)](./manual-build)
- [Build (GitHub Actions)](./action-build)
- [Supported Extensions](./extensions)
## Compilation Environment
The following is the architecture support situation, where :gear: represents support for GitHub Action build,
:computer: represents support for local manual build, and empty represents temporarily not supported.
| | x86_64 | aarch64 |
|---------|-------------------|-------------------|
| macOS | :gear: :computer: | :gear: :computer: |
| Linux | :gear: :computer: | :gear: :computer: |
| Windows | :gear: :computer: | |
| FreeBSD | :computer: | :computer: |
Current supported PHP versions for compilation:
> :warning: Partial support, there may be issues with new beta versions and old versions.
>
> :heavy_check_mark: Supported
>
> :x: Not supported
| PHP Version | Status | Comment |
|-------------|--------------------|-------------------------------------------------------------------------------------------------------------------------|
| 7.2 | :x: | |
| 7.3 | :x: | phpmicro and many extensions do not support 7.3, 7.4 versions |
| 7.4 | :x: | phpmicro and many extensions do not support 7.3, 7.4 versions |
| 8.0 | :warning: | PHP official has stopped maintaining 8.0, we no longer handle 8.0 related backport support |
| 8.1 | :warning: | PHP official only provides security updates for 8.1, we no longer handle 8.1 related backport support after 8.5 release |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |
| 8.4 | :heavy_check_mark: | |
| 8.5 (beta) | :warning: | PHP 8.5 is currently in beta stage |
> This table shows the support status of static-php-cli for building corresponding versions, not the PHP official support status for that version.
## PHP Support Versions
Currently, static-php-cli supports PHP versions 8.2 ~ 8.5, and theoretically supports PHP 8.1 and earlier versions, just select the earlier version when downloading.
However, due to some extensions and special components that have stopped supporting earlier versions of PHP, static-php-cli will not explicitly support earlier versions.
We recommend that you compile the latest PHP version possible for a better experience.

View File

@@ -0,0 +1,42 @@
# Troubleshooting
Various failures may be encountered in the process of using static-php-cli,
here will describe how to check the errors by yourself and report Issue.
## Download Failure
Problems with downloading resources are one of the most common problems with spc.
The main reason is that the addresses used for SPC download resources are generally the official website of the corresponding project or GitHub, etc.,
and these websites may occasionally go down and block IP addresses.
After encountering a download failure,
you can try to call the download command multiple times.
When downloading extensions, you may eventually see errors like `curl: (56) The requested URL returned error: 403` which are often caused by github rate limiting.
You can verify this by adding `--debug` to the command and will see something like `[DEBU] Running command (no output) : curl -sfSL "https://api.github.com/repos/openssl/openssl/releases"`.
To fix this, [create](https://github.com/settings/tokens) a personal access token on GitHub and set it as an environment variable `GITHUB_TOKEN=<XXX>`.
If you confirm that the address is indeed inaccessible,
you can submit an Issue or PR to update the url or download type.
## Doctor Can't Fix Something
In most cases, the doctor module can automatically repair and install missing system environments,
but there are also special circumstances where the automatic repair function cannot be used normally.
Due to system limitations (for example, software such as Visual Studio cannot be automatically installed under Windows),
the automatic repair function cannot be used for some projects.
When encountering a function that cannot be automatically repaired,
if you encounter the words `Some check items can not be fixed`,
it means that it cannot be automatically repaired.
Please submit an issue according to the method displayed on the terminal or repair the environment yourself.
## Compile Error
When you encounter a compilation error, if the `--debug` log is not enabled, please enable the debug log first,
and then determine the command that reported the error.
The error terminal output is very important for fixing compilation errors.
When submitting an issue, please upload the last error fragment of the terminal log (or the entire terminal log output),
and include the `spc` command and parameters used.
If you are rebuilding, please refer to the [Local Build - Multiple Builds](./manual-build#multiple-builds) section.

145
docs-v2/en/index.md Normal file
View File

@@ -0,0 +1,145 @@
---
# https://vitepress.dev/reference/default-theme-home-page
layout: home
hero:
name: "StaticPHP"
tagline: "StaticPHP is a powerful tool designed for building portable executables including PHP, extensions, and more."
image:
src: /images/static-php_nobg.png
alt: StaticPHP Logo
actions:
- theme: brand
text: Get Started
link: /en/guide/
- theme: alt
text: 中文文档
link: /zh/
features:
- title: Static PHP Binary
details: You can easily compile a standalone php binary for general use. Including cli, fpm, cgi, frankenphp SAPI.
- title: Micro Self-Extracted Executable
details: You can compile a self-extracted executable and build with your php source code using micro SAPI.
- title: Dependency Management
details: StaticPHP comes with dependency management and supports installation of different types of PHP extensions, packages and libraries.
---
<script setup>
import {VPSponsors} from "vitepress/theme";
import Contributors from '../.vitepress/components/Contributors.vue';
const sponsors = [
{ name: 'Beyond Code', img: '/images/beyondcode-seeklogo.png', url: 'https://beyondco.de/' },
{ name: 'NativePHP', img: '/images/nativephp-logo.svg', url: 'https://nativephp.com/' },
];
</script>
<div class="sponsors-section">
<div class="sponsors-header">
<h2>Special Sponsors</h2>
<p class="sponsors-description">
Thank you to our amazing sponsors for supporting this project!
</p>
</div>
<VPSponsors :data="sponsors"/>
</div>
<style scoped>
.sponsors-section {
margin: 48px auto;
padding: 32px 24px;
max-width: 1152px;
background: linear-gradient(135deg, var(--vp-c-bg-soft) 0%, var(--vp-c-bg) 100%);
border-radius: 16px;
border: 1px solid var(--vp-c-divider);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
}
.sponsors-section:hover {
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
.sponsors-header {
text-align: center;
margin-bottom: 24px;
}
.sponsors-header h2 {
font-size: 1.5rem;
font-weight: 700;
margin: 0 0 8px 0;
background: linear-gradient(120deg, var(--vp-c-brand-1), var(--vp-c-brand-2));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.sponsors-description {
font-size: 0.95rem;
color: var(--vp-c-text-2);
margin: 0;
line-height: 1.5;
}
@media (max-width: 768px) {
.sponsors-section {
margin: 32px 16px;
padding: 24px 16px;
}
.sponsors-header h2 {
font-size: 1.25rem;
}
.sponsors-description {
font-size: 0.9rem;
}
}
/* Hero logo styling */
:deep(.VPImage.image-src) {
border-radius: 20px;
background: linear-gradient(135deg, var(--vp-c-bg-soft) 0%, var(--vp-c-default-soft) 100%);
padding: 40px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
:deep(.VPImage.image-src:hover) {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
}
/* Dark mode adjustments for logo */
.dark :deep(.VPImage.image-src) {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
opacity: 0.9;
}
.dark :deep(.VPImage.image-src:hover) {
opacity: 1;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.7);
}
/* Additional styling for the logo image itself */
:deep(.VPImage.image-src img) {
max-height: 280px;
width: auto;
}
@media (max-width: 768px) {
:deep(.VPImage.image-src) {
padding: 24px;
}
:deep(.VPImage.image-src img) {
max-height: 200px;
}
}
</style>
<Contributors />

147
docs-v2/index.md Normal file
View File

@@ -0,0 +1,147 @@
---
# https://vitepress.dev/reference/default-theme-home-page
layout: home
hero:
name: "StaticPHP"
tagline: "StaticPHP is a powerful tool designed for building portable executables including PHP, extensions, and more."
image:
src: /images/static-php_nobg.png
alt: StaticPHP Logo
actions:
- theme: brand
text: Get Started
link: /en/guide/
- theme: alt
text: 中文文档
link: /zh/
features:
- title: Static PHP Binary
details: You can easily compile a standalone php binary for general use. Including cli, fpm, cgi, frankenphp SAPI.
- title: Micro Self-Extracted Executable
details: You can compile a self-extracted executable and build with your php source code using micro SAPI.
- title: Dependency Management
details: StaticPHP comes with dependency management and supports installation of different types of PHP extensions, packages and libraries.
---
<script setup>
import {VPSponsors} from "vitepress/theme";
import Contributors from './.vitepress/components/Contributors.vue';
const sponsors = [
{ name: 'Beyond Code', img: '/images/beyondcode-seeklogo.png', url: 'https://beyondco.de/' },
{ name: 'NativePHP', img: '/images/nativephp-logo.svg', url: 'https://nativephp.com/' },
];
</script>
<div class="sponsors-section">
<div class="sponsors-header">
<h2>Special Sponsors</h2>
<p class="sponsors-description">
Thank you to our amazing sponsors for supporting this project!
</p>
</div>
<VPSponsors :data="sponsors"/>
</div>
<style scoped>
.sponsors-section {
margin: 48px auto;
padding: 32px 24px;
max-width: 1152px;
background: linear-gradient(135deg, var(--vp-c-bg-soft) 0%, var(--vp-c-bg) 100%);
border-radius: 16px;
border: 1px solid var(--vp-c-divider);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
}
.sponsors-section:hover {
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
.sponsors-header {
text-align: center;
margin-bottom: 24px;
}
.sponsors-header h2 {
font-size: 1.5rem;
font-weight: 700;
margin: 0 0 8px 0;
background: linear-gradient(120deg, var(--vp-c-brand-1), var(--vp-c-brand-2));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.sponsors-description {
font-size: 0.95rem;
color: var(--vp-c-text-2);
margin: 0;
line-height: 1.5;
}
@media (max-width: 768px) {
.sponsors-section {
margin: 32px 16px;
padding: 24px 16px;
}
.sponsors-header h2 {
font-size: 1.25rem;
}
.sponsors-description {
font-size: 0.9rem;
}
}
/* Hero logo styling */
:deep(.VPImage.image-src) {
border-radius: 20px;
background: linear-gradient(135deg, var(--vp-c-bg-soft) 0%, var(--vp-c-default-soft) 100%);
padding: 40px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
:deep(.VPImage.image-src:hover) {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
}
/* Dark mode adjustments for logo */
.dark :deep(.VPImage.image-src) {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
opacity: 0.9;
}
.dark :deep(.VPImage.image-src:hover) {
opacity: 1;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.7);
}
/* Additional styling for the logo image itself */
:deep(.VPImage.image-src img) {
max-height: 280px;
width: auto;
}
@media (max-width: 768px) {
:deep(.VPImage.image-src) {
padding: 24px;
}
:deep(.VPImage.image-src img) {
max-height: 200px;
}
}
</style>
<Contributors />

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 764 100">
<path fill="#505b93" d="M29.5,98.4H0V1.2h29.5V98.4z"/>
<path fill="#00aaa6" d="M96.7,98.4H67.2V1.2h29.5V98.4z"/>
<path fill="#272d48" d="M96.7,98.4H29.5V1.2L96.7,98.4z"/>
<path fill="#272d48" d="M102.6,54.5c0-6.2,1.3-11.8,4.1-16.7c2.7-5,6.7-8.8,11.9-11.6c5.2-2.8,11.4-4.2,18.6-4.2c1.1,0,2.8,0.1,5.2,0.3 c4.9,0.4,9.1,1.3,12.5,2.8c3.4,1.5,6.4,3.4,9.1,5.9v-7.2h25.8v74.7h-25.8v-7.2c-2.5,2.6-5.6,4.6-9.4,6.1c-3.8,1.5-7.9,2.4-12.1,2.6 c-0.9,0.1-2.3,0.1-4.1,0.1c-7.2,0-13.4-1.4-18.8-4.1c-5.4-2.7-9.5-6.6-12.4-11.5c-2.9-4.9-4.3-10.5-4.3-16.6V54.5z M128.4,63.9 c0,9.2,5.9,13.8,17.7,13.8c11.8,0,17.7-4.6,17.7-13.8v-5.6c0-9.3-5.9-14-17.7-14c-11.8,0-17.7,4.7-17.7,14V63.9z M208.3,98.4V47h-12.8V23.7l12.8-0.2V1.2h25.9l0.1,22.4h18.3V47h-18.4v51.4 M287.3,98.4h-25.9V23.6h25.9V98.4z M351,98.4H325l-31-74.8H320L338,68l18-44.5h25.9L351,98.4z M454.9,87.6c-4.1,4.2-8.8,7.3-14.1,9.3c-5.3,2-11.8,2.9-19.5,2.9c-8,0-15.1-1.4-21.3-4.2 c-6.2-2.8-11.1-6.7-14.7-11.6c-3.5-5-5.3-10.6-5.3-17V54.6c0-6.5,1.7-12.2,5.2-17.1c3.4-4.9,8.2-8.7,14.2-11.3c6-2.7,12.7-4,20-4 c8,0,15,1.5,21.2,4.3c6.1,2.9,10.9,7,14.4,12.4c3.4,5.4,5.2,11.6,5.2,18.7c0,1.7-0.2,4.2-0.7,7.7l-54.2,0.1v2.1 c0,4.1,1.5,7.3,4.4,9.4c2.9,2.2,6.9,3.2,11.8,3.2c4.6,0,8.5-0.6,11.8-1.8c3.2-1.2,6.4-3.5,9.4-6.8L454.9,87.6z M434.4,51.4 c0-3.1-1.4-5.5-4.2-7.1c-2.8-1.6-6.4-2.4-10.8-2.4s-7.9,0.8-10.5,2.4c-2.6,1.6-3.8,4-3.8,7.1H434.4z M466,98.4V1.2h56c9.9,0,17.8,1.9,23.7,5.6c5.9,3.7,10,8.2,12.2,13.3c2.3,5.1,3.4,10.1,3.4,15 c0,4.8-1.2,9.7-3.5,14.7c-2.3,5-6.4,9.2-12.2,12.8c-5.8,3.6-13.7,5.4-23.7,5.4h-30.2v30.5H466z M522,44.6c9,0,13.6-3.3,13.6-9.9 c0-6.9-4.6-10.3-13.7-10.3h-30.1v20.2H522z M593,98.4h-25.8V1.2H593v38h43.9v-38h25.8v97.2h-25.8V59.9H593V98.4z M668.6,98.4V1.2h56c9.9,0,17.8,1.9,23.7,5.6c5.9,3.7,10,8.2,12.2,13.3c2.3,5.1,3.4,10.1,3.4,15 c0,4.8-1.2,9.7-3.5,14.7c-2.3,5-6.4,9.2-12.2,12.8c-5.8,3.6-13.7,5.4-23.7,5.4h-30.2v30.5H668.6z M724.6,44.6c9,0,13.6-3.3,13.6-9.9 c0-6.9-4.6-10.3-13.7-10.3h-30.1v20.2H724.6z M291.1,20.2h-33.5V0h33.5V20.2z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 965 KiB

View File

@@ -0,0 +1,51 @@
# 贡献指南
感谢你能够看到这里,本项目非常欢迎你的贡献!
## 贡献方法
如果你有代码或文档要贡献,以下是你需要首先了解的内容。
1. 你要贡献什么类型的代码?(新扩展、修复 Bug、安全问题、项目框架优化、文档
2. 如果你贡献了新文件或新片段,你的代码是否经过 `php-cs-fixer``phpstan` 的检查?
3. 在贡献代码前是否充分阅读了 [开发指南](../develop/)
如果你能回答上述问题并对代码进行了修改,可以及时在项目 GitHub 仓库发起 Pull Request。
代码审查完成后,可以根据建议修改代码,或直接合并到主分支。
## 贡献类型
本项目的主要目的是编译静态链接的 PHP 二进制文件,命令行处理功能基于 `symfony/console` 编写。
在开发之前,如果你对它不够熟悉,请先查看 [symfony/console 文档](https://symfony.com/doc/current/components/console.html)。
### 安全更新
因为本项目基本上是一个本地运行的 PHP 项目,一般来说不会有远程攻击。
但如果你发现此类问题,请**不要**在 GitHub 仓库提交 PR 或 Issue
你需要通过 [邮件](mailto:admin@zhamao.me) 联系项目维护者crazywhalecc
### 修复 Bug
修复 Bug 一般不涉及项目结构和框架的修改,所以如果你能定位到错误代码并直接修复它,请直接提交 PR。
### 新扩展
对于添加新扩展,你需要了解项目的一些基本结构以及如何根据现有逻辑添加新扩展。
这将在本页的下一节中详细介绍。
总的来说,你需要:
1. 评估扩展是否可以内联编译到 PHP 中。
2. 评估扩展的依赖库(如果有)是否可以静态编译。
3. 编写不同平台的库编译命令。
4. 验证扩展及其依赖项与现有扩展和依赖项兼容。
5. 验证扩展在 `cli``micro``fpm``embed` SAPIs 中正常工作。
6. 编写文档并添加你的扩展。
### 项目框架优化
如果你已经熟悉 `symfony/console` 的工作原理,并同时要对项目的框架进行一些修改或优化,请先了解以下事情:
1. 添加扩展不属于项目框架优化,但如果你在添加新扩展时发现必须优化框架,则需要先修改框架本身,然后再添加扩展。
2. 对于一些大规模逻辑修改(例如涉及 LibraryBase、Extension 对象等的修改),建议先提交 Issue 或 Draft PR 进行讨论。
3. 在项目早期,它是一个纯私有开发项目,代码中有一些中文注释。项目国际化后,你可以提交 PR 将这些注释翻译为英语。
4. 请不要在代码中提交更多无用的代码片段,例如大量未使用的变量、方法、类以及多次重写的代码。

View File

@@ -0,0 +1,7 @@
---
aside: false
---
# craft.yml 配置
<!--@include: ../../deps-craft-yml.md-->

View File

@@ -0,0 +1,60 @@
# Doctor 模块
Doctor 模块是一个较为独立的用于检查系统环境的模块,可使用命令 `bin/spc doctor` 进入,入口的命令类在 `DoctorCommand.php` 中。
Doctor 模块是一个检查单,里面有一系列的检查项目和自动修复项目。这些项目都存放在 `src/SPC/doctor/item/` 目录中,
并且使用了两种 Attribute 用作检查项标记和自动修复项目标记:`#[AsCheckItem]``#[AsFixItem]`
以现有的检查项 `if necessary tools are installed`,它是用于检查编译必需的包是否安装在 macOS 系统内,下面是它的源码:
```php
use SPC\doctor\AsCheckItem;
use SPC\doctor\AsFixItem;
use SPC\doctor\CheckResult;
#[AsCheckItem('if necessary tools are installed', limit_os: 'Darwin', level: 997)]
public function checkCliTools(): ?CheckResult
{
$missing = [];
foreach (self::REQUIRED_COMMANDS as $cmd) {
if ($this->findCommand($cmd) === null) {
$missing[] = $cmd;
}
}
if (!empty($missing)) {
return CheckResult::fail('missing system commands: ' . implode(', ', $missing), 'build-tools', [$missing]);
}
return CheckResult::ok();
}
```
属性的第一个参数就是检查项目的名称,后面的 `limit_os` 参数是限制了该检查项仅在指定的系统下触发,`level` 是执行该检查项的优先级,数字越大,优先级越高。
里面用到的 `$this->findCommand()` 方法为 `SPC\builder\traits\UnixSystemUtilTrait` 的方法,用途是查找系统命令所在位置,找不到时返回 NULL。
每个检查项的方法都应该返回一个 `SPC\doctor\CheckResult`
- 在返回 `CheckResult::fail()` 时,第一个参数用于输出终端的错误提示,第二个参数是在这个检查项可自动修复时的修复项目名称。
- 在返回 `CheckResult::ok()` 时,表明检查通过。你也可以传递一个参数,用于返回检查结果,例如:`CheckResult::ok('OS supported')`
- 在返回 `CheckResult::fail()` 时,如果包含了第三个参数,第三个参数的数组将被当作 `AsFixItem` 的参数。
下面是这个检查项对应的自动修复项的方法:
```php
#[AsFixItem('build-tools')]
public function fixBuildTools(array $missing): bool
{
foreach ($missing as $cmd) {
try {
shell(true)->exec('brew install ' . escapeshellarg($cmd));
} catch (RuntimeException) {
return false;
}
}
return true;
}
```
`#[AsFixItem()]` 属性传入的参数即修复项的名称,该方法必须返回 True 或 False。当返回 False 时,表明自动修复失败,需要手动处理。
此处的代码中 `shell()->exec()` 是项目的执行命令的方法,用于替代 `exec()``system()`,同时提供了 debug、获取执行状态、进入目录等特性。

View File

@@ -0,0 +1,27 @@
# 开发简介
开发本项目需要安装部署 PHP 环境,以及一些 PHP 项目常用的扩展和 Composer。
项目的开发环境和运行环境几乎完全一致。你可以参照 **手动构建** 部分安装系统 PHP 或使用本项目预构建的静态 PHP 作为环境。这里不再赘述。
抛开用途,本项目本身其实就是一个 `php-cli` 程序,你可以将它当作一个正常的 PHP 项目进行编辑和开发,同时你需要了解不同系统的 Shell 命令行。
本项目目前的目的就是为了编译静态编译的独立 PHP但主体部分也包含编译很多依赖库的静态版本所以你可以复用这套编译逻辑用于构建其他程序的独立二进制版本例如 Nginx 等。
## 环境准备
开发本项目需要 PHP 环境。你可以使用系统自带的 PHP也可以使用本项目构建的静态 PHP。
无论是使用哪种 PHP在开发环境你需要安装这些扩展
```
curl,dom,filter,mbstring,openssl,pcntl,phar,posix,sodium,tokenizer,xml,xmlwriter
```
static-php-cli 项目本身不需要这么多扩展,但在开发过程中,你会用到 Composer 和 PHPUnit 等工具,它们需要这些扩展。
> 对于 static-php-cli 自身构建的 micro 自执行二进制,仅需要 `pcntl,posix,mbstring,tokenizer,phar`。
## 开始开发
继续向下查看项目结构文档,你可以学习 `static-php-cli` 是如何工作的。

View File

@@ -0,0 +1,51 @@
# 对 PHP 源码的修改
由于 static-php-cli 在静态编译过程中为了实现良好的兼容性、性能和安全性,对 PHP 源码进行了一些修改。下面是目前对 PHP 源码修改的说明。
## micro 相关补丁
基于 phpmicro 项目提供的补丁static-php-cli 对 PHP 源码进行了一些修改,以适应静态编译的需求。[补丁列表](https://github.com/easysoft/phpmicro/tree/master/patches) 包含:
目前 static-php-cli 在编译时用到的补丁有:
- static_opcache
- static_extensions_win32
- cli_checks
- disable_huge_page
- vcruntime140
- win32
- zend_stream
- cli_static
- macos_iconv
- phar
## PHP <= 8.1 libxml 补丁
因为 PHP 官方仅对 8.1 进行安全更新,旧版本停止更新,所以 static-php-cli 对 PHP 8.1 及以下版本应用了在新版本 PHP 中已经应用的 libxml 编译补丁。
## gd 扩展 Windows 补丁
在 Windows 下编译 gd 扩展需要大幅改动 `config.w32` 文件static-php-cli 对 gd 扩展进行了一些修改,使其在 Windows 下编译更加方便。
## yaml 扩展 Windows 补丁
yaml 扩展在 Windows 下编译需要修改 `config.w32` 文件static-php-cli 对 yaml 扩展进行了一些修改,使其在 Windows 下编译更加方便。
## static-php-cli 版本信息插入
static-php-cli 在编译时会在 PHP 版本信息中插入 static-php-cli 的版本信息,以便于识别。
## 加入硬编码 INI 的选项
在使用 `-I` 参数硬编码 INI 到静态 PHP 的功能中static-php-cli 会修改 PHP 源码以插入硬编码内容。
## Linux 系统修复补丁
部分编译环境可能缺少一些头文件或库static-php-cli 会在编译时自动修复这些问题,如:
- HAVE_STRLCAT missing problem
- HAVE_STRLCPY missing problem
## Windows 系统下 Fiber 问题修复补丁
在 Windows 下编译 PHP 时Fiber 扩展会出现一些问题static-php-cli 会在编译时自动修复这些问题(修改 php-src 的 `config.w32`)。

View File

@@ -0,0 +1,350 @@
# 资源模块
static-php-cli 的下载资源模块是一个主要的功能它包含了所依赖的库、外部扩展、PHP 源码的下载方式和资源解压方式。
下载的配置文件主要涉及 `source.json``pkg.json` 文件,这个文件记录了所有可下载的资源的下载方式。
下载功能主要涉及的命令有 `bin/spc download``bin/spc extract`。其中 `download` 命令是一个下载器,它会根据配置文件下载资源;
`extract` 命令是一个解压器,它会根据配置文件解压资源。
一般来说下载资源可能会比较慢因为这些资源来源于各个官网、GitHub 等不同位置,同时它们也占用了较大空间,所以你可以在一次下载资源后,可重复使用。
下载器的配置文件是 `source.json`,它包含了所有资源的下载方式,你可以在其中添加你需要的资源下载方式,也可以修改已有的资源下载方式。
每个资源的下载配置结构如下,下面是 `libevent` 扩展对应的资源下载配置:
```json
{
"libevent": {
"type": "ghrel",
"repo": "libevent/libevent",
"match": "libevent.+\\.tar\\.gz",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
这里最主要的字段是 `type`,目前它支持的类型有:
- `url`: 直接使用 URL 下载,例如:`https://download.libsodium.org/libsodium/releases/libsodium-1.0.18.tar.gz`
- `pie`: 使用 PIEPHP Installer for Extensions标准从 Packagist 下载 PHP 扩展。
- `ghrel`: 使用 GitHub Release API 下载,即从 GitHub 项目发布的最新版本中上传的附件下载。
- `ghtar`: 使用 GitHub Release API 下载,与 `ghrel` 不同的是,`ghtar` 是从项目的最新 Release 中找 `source code (tar.gz)` 下载的。
- `ghtagtar`: 使用 GitHub Release API 下载,与 `ghtar` 相比,`ghtagtar` 可以从 `tags` 列表找最新的,并下载 `tar.gz` 格式的源码(因为有些项目只使用了 `tag` 发布版本)。
- `bitbuckettag`: 使用 BitBucket API 下载,基本和 `ghtagtar` 相同,只是这个适用于 BitBucket。
- `git`: 直接从一个 Git 地址克隆项目来下载资源,适用于任何公开 Git 仓库。
- `filelist`: 使用爬虫爬取提供文件索引的 Web 下载站点,并获取最新版本的文件名并下载。
- `custom`: 如果以上下载方式都不能满足,你可以编写 `custom` 后,在 `src/SPC/store/source/` 下新建一个类,并继承 `CustomSourceBase`,自己编写下载脚本。
## source.json 通用参数
source.json 中每个源文件拥有以下字段:
- `license`: 源代码的开源许可证,见下方 **开源许可证** 章节
- `type`: 必须为上面提到的类型之一
- `path`(可选): 释放源码到指定目录而非 `source/{name}`
- `provide-pre-built`(可选): 是否提供预编译的二进制文件,如果为 `true`,则会在 `bin/spc download` 时尝试自动下载预编译的二进制文件
::: tip
`source.json` 中的 `path` 参数可指定相对路径或绝对路径。当指定为相对路径时,路径基于 `source/`
:::
## 下载类型 - url
url 类型的资源指的是从 URL 直接下载文件。
包含的参数有:
- `url`: 文件的下载地址,如 `https://example.com/file.tgz`
- `filename`(可选): 保存到本地的文件名,如不指定,则使用 url 的文件名
例子(下载 imagick 扩展,并解压缩到 php 源码的扩展存放路径):
```json
{
"ext-imagick": {
"type": "url",
"url": "https://pecl.php.net/get/imagick",
"path": "php-src/ext/imagick",
"filename": "imagick.tgz",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
## 下载类型 - pie
PIEPHP Installer for Extensions类型的资源是从 Packagist 下载遵循 PIE 标准的 PHP 扩展。
该方法会自动从 Packagist 仓库获取扩展信息,并下载相应的分发文件。
包含的参数有:
- `repo`: Packagist 的 vendor/package 名称,如 `vendor/package-name`
例子(使用 PIE 从 Packagist 下载 PHP 扩展):
```json
{
"ext-example": {
"type": "pie",
"repo": "vendor/example-extension",
"path": "php-src/ext/example",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
::: tip
PIE 下载类型会自动从 Packagist 元数据中检测扩展信息,包括下载 URL、版本和分发类型。
扩展必须在其 Packagist 包定义中标记为 `type: php-ext` 或包含 `php-ext` 元数据。
:::
## 下载类型 - ghrel
ghrel 会从 GitHub Release 中上传的 Assets 下载文件。首先使用 GitHub Release API 获取最新版本,然后根据正则匹配方式下载相应的文件。
包含的参数有:
- `repo`: GitHub 仓库名称
- `match`: 匹配 Assets 文件的正则表达式
- `prefer-stable`: 是否优先下载稳定版本(默认为 `false`
例子(下载 libsodium 库,匹配 Release 中的 libsodium-x.y.tar.gz 文件):
```json
{
"libsodium": {
"type": "ghrel",
"repo": "jedisct1/libsodium",
"match": "libsodium-\\d+(\\.\\d+)*\\.tar\\.gz",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
## 下载类型 - ghtar
ghtar 会从 GitHub Release Tag 下载文件,与 `ghrel` 不同的是,`ghtar` 是从项目的最新 Release 中找 `source code (tar.gz)` 下载的。
包含的参数有:
- `repo`: GitHub 仓库名称
- `prefer-stable`: 是否优先下载稳定版本(默认为 `false`
例子brotli 库):
```json
{
"brotli": {
"type": "ghtar",
"repo": "google/brotli",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
## 下载类型 - ghtagtar
使用 GitHub Release API 下载,与 `ghtar` 相比,`ghtagtar` 可以从 `tags` 列表找最新的,并下载 `tar.gz` 格式的源码(因为有些项目只使用了 `tag` 发布版本)。
包含的参数有:
- `repo`: GitHub 仓库名称
- `prefer-stable`: 是否优先下载稳定版本(默认为 `false`
例子gmp 库):
```json
{
"gmp": {
"type": "ghtagtar",
"repo": "alisw/GMP",
"license": {
"type": "text",
"text": "EXAMPLE LICENSE"
}
}
}
```
## 下载类型 - bitbuckettag
使用 BitBucket API 下载,基本和 `ghtagtar` 相同,只是这个适用于 BitBucket。
包含的参数有:
- `repo`: BitBucket 仓库名称
## 下载类型 - git
直接从一个 Git 地址克隆项目来下载资源,适用于任何公开 Git 仓库。
包含的参数有:
- `url`: Git 链接(仅限 HTTPS
- `rev`: 分支名称
```json
{
"imap": {
"type": "git",
"url": "https://github.com/static-php/imap.git",
"rev": "master",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
## 下载类型 - filelist
使用爬虫爬取提供文件索引的 Web 下载站点,并获取最新版本的文件名并下载。
注意该方法仅限于镜像站、GNU 官网等具有页面 index 功能的静态站点使用。
包含的参数有:
- `url`: 要爬取文件最新版本的页面 URL
- `regex`: 匹配文件名及下载链接的正则表达式
例子(从 GNU 官网下载 libiconv 库):
```json
{
"libiconv": {
"type": "filelist",
"url": "https://ftp.gnu.org/gnu/libiconv/",
"regex": "/href=\"(?<file>libiconv-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"license": {
"type": "file",
"path": "COPYING"
}
}
}
```
## 下载类型 - custom
如果以上下载方式都不能满足,你可以编写 `custom` 后,在 `src/SPC/store/source/` 下新建一个类,并继承 `CustomSourceBase`,自己编写下载脚本。
这里不再赘述,你可以查看 `src/SPC/store/source/PhpSource.php``src/SPC/store/source/PostgreSQLSource.php` 作为例子。
## pkg.json 通用参数
pkg.json 存放的是非源码类型的文件资源,例如 musl-toolchain、UPX 等预编译的工具。它的使用包含:
- `type`: 与 `source.json` 相同的类型及不同种类的参数。
- `extract`(可选): 下载后解压缩的路径,默认为 `pkgroot/{pkg_name}`
- `extract-files`(可选): 下载后仅解压指定的文件到指定位置。
需要注意的是,`pkg.json` 不涉及源代码的编译和修改分发,所以没有 `license` 开源许可证字段。并且你不能同时使用 `extract``extract-files` 参数。
例子(下载 nasm 到本地,并只提取程序文件到 PHP SDK
```json
{
"nasm-x86_64-win": {
"type": "url",
"url": "https://www.nasm.us/pub/nasm/releasebuilds/2.16.01/win64/nasm-2.16.01-win64.zip",
"extract-files": {
"nasm-2.16.01/nasm.exe": "{php_sdk_path}/bin/nasm.exe",
"nasm-2.16.01/ndisasm.exe": "{php_sdk_path}/bin/ndisasm.exe"
}
}
}
```
`extract-files` 中的键名为源文件夹下的文件,键值为存放的路径。存放的路径可以使用以下变量:
- `{php_sdk_path}`: (仅限 WindowsPHP SDK 路径
- `{pkg_root_path}`: `pkgroot/`
- `{working_dir}`: 当前工作目录
- `{download_path}`: 下载目录
- `{source_path}`: 源码解压缩目录
`extract-files` 不使用变量且为相对路径时,相对路径的目录为 `{working_dir}`
## 开源许可证
对于 `source.json` 而言,每个源文件都应包含开源许可证。`license` 字段存放了开源许可证的信息。
每个 `license` 包含的参数有:
- `type`: `file``text`
- `path`: 源代码目录中的许可证文件(当 `type``file` 时,此项必填)
- `text`: 许可证文本(当 `type``text` 时,此项必填)
例子yaml 扩展的源代码中带有 LICENSE 文件):
```json
{
"yaml": {
"type": "git",
"path": "php-src/ext/yaml",
"rev": "php7",
"url": "https://github.com/php/pecl-file_formats-yaml",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
当开源项目拥有多个许可证时,可指定多个文件:
```json
{
"libuv": {
"type": "ghtar",
"repo": "libuv/libuv",
"license": [
{
"type": "file",
"path": "LICENSE"
},
{
"type": "file",
"path": "LICENSE-extra"
}
]
}
}
```
当一个开源项目的许可证在不同版本间使用不同的文件,`path` 参数可以使用数组将可能的许可证文件列出:
```json
{
"redis": {
"type": "git",
"path": "php-src/ext/redis",
"rev": "release/6.0.2",
"url": "https://github.com/phpredis/phpredis",
"license": {
"type": "file",
"path": [
"LICENSE",
"COPYING"
]
}
}
}
```

View File

@@ -0,0 +1,163 @@
# 项目结构简介
static-php-cli 主要包含三种逻辑组件:资源、依赖库、扩展。这三种组件四个配置文件:`source.json``lib.json``ext.json``pkg.json`
一个完整的构建静态 PHP 流程是:
1. 使用资源下载模块 `Downloader` 下载指定或所有资源,这些资源包含 PHP 源码、依赖库源码、扩展源码。
2. 使用资源解压模块 `SourceExtractor` 解压下载的资源到编译目录。
3. 使用依赖工具计算出当前加入的扩展的依赖扩展、依赖库,然后对每个需要编译的依赖库进行编译,按照依赖顺序。
4. 使用对应操作系统下的 `Builder` 构建每个依赖库后,将其安装到 `buildroot` 目录。
5. 如果包含外部扩展(源码没有包含在 PHP 内的扩展),将外部扩展拷贝到 `source/php-src/ext/` 目录。
6. 使用 `Builder` 构建 PHP 源码,将其安装到 `buildroot` 目录。
项目主要分为几个文件夹:
- `bin/`: 用于存放程序入口文件,包含 `bin/spc``bin/spc-alpine-docker``bin/setup-runtime`
- `config/`: 包含了所有项目支持的扩展、依赖库以及这些资源下载的地址、下载方式等,:`lib.json``ext.json``source.json``pkg.json``pre-built.json`
- `src/SPC/`: 项目的核心代码,包含了整个框架以及编译各种扩展和库的命令。
- `src/globals/`: 项目的全局方法和常量、运行时需要的测试文件(例如:扩展的可用性检查代码)。
- `vendor/`: Composer 依赖的目录,你无需对它做出任何修改。
其中运行原理就是启动一个 `symfony/console``ConsoleApplication`,然后解析用户在终端输入的命令。
## 基本命令行结构
`bin/spc` 是一个 PHP 代码入口文件,包含了 Unix 通用的 `#!/usr/bin/env php` 用来让系统自动以系统安装好的 PHP 解释器执行。
在项目执行了 `new ConsoleApplication()` 后,框架会自动使用反射的方式,解析 `src/SPC/command` 目录下的所有类,并将其注册成为命令。
项目并没有直接使用 Symfony 推荐的 Command 注册方式和命令执行方式,这里做出了一点小变动:
1. 每个命令都使用 `#[AsCommand()]` Attribute 来注册名称和简介。
2.`execute()` 抽象化,让所有命令基于 `BaseCommand`(它基于 `Symfony\Component\Console\Command\Command`),每个命令本身的执行代码写到了 `handle()` 方法中。
3. `BaseCommand` 添加了变量 `$no_motd`,用于是否在该命令执行时显示 Figlet 欢迎词。
4. `BaseCommand``InputInterface``OutputInterface` 保存为成员变量,你可以在命令的类内使用 `$this->input``$this->output`
## 基本源码结构
项目的源码位于 `src/SPC` 目录,支持 PSR-4 标准的自动加载,包含以下子目录和类:
- `src/SPC/builder/`: 用于不同操作系统下构建依赖库、PHP 及相关扩展的核心编译命令代码,还包含了一些编译的系统工具方法。
- `src/SPC/command/`: 项目的所有命令都在这里。
- `src/SPC/doctor/`: Doctor 模块,它是一个较为独立的用于检查系统环境的模块,可使用命令 `bin/spc doctor` 进入。
- `src/SPC/exception/`: 异常类。
- `src/SPC/store/`: 有关存储、文件和资源的类都在这里。
- `src/SPC/util/`: 一些可以复用的工具方法都在这里。
- `src/SPC/ConsoleApplication.php`: 命令行程序入口文件。
如果你阅读过源码,你可能会发现还有一个 `src/globals/` 目录,它是用于存放一些全局变量、全局方法、构建过程中依赖的非 PSR-4 标准的 PHP 源码,例如测试扩展代码等。
## Phar 应用目录问题
和其他 php-cli 项目一样spc 自身对路径有额外的考虑。
因为 spc 可以在 `php-cli directly``micro SAPI``php-cli with Phar``vendor with Phar` 等多种模式下运行,各类根目录存在歧义。这里会进行一个完整的说明。
此问题一般常见于 PHP 项目中存取文件的基类路径选择问题,尤其是在配合 `micro.sfx` 使用时容易出现路径问题。
注意,此处仅对你在开发 Phar 项目或 PHP 框架时可能有用。
> 接下来我们都将 `static-php-cli`(也就是 spc当作一个普通的 `php` 命令行程序来看,你可以将 spc 理解为你自己的任何 php-cli 应用以参考。
下面主要有三个基本的常量理论值,我们建议你在编写 php 项目时引入这三种常量:
- `WORKING_DIR`:执行 PHP 脚本时的工作目录
- `SOURCE_ROOT_DIR``ROOT_DIR`:项目文件夹的根目录,一般为 `composer.json` 所在目录
- `FRAMEWORK_ROOT_DIR`:使用框架的根目录,自行开发的框架可能会用到,一般框架目录为只读
你可以在你的框架或者 cli 应用程序入口中定义这些常量,以方便在你的项目中使用路径。
下面是 PHP 内置的常量值,在 PHP 解释器内部已被定义:
- `__DIR__`:当前执行脚本的文件所在目录
- `__FILE__`:当前执行脚本的文件路径
### Git 项目模式source
Git 项目模式指的是一个框架或程序本身在当前文件夹以纯文本形式存放,运行通过 `php path/to/entry.php` 方式。
假设你的项目存放在 `/home/example/static-php-cli/` 目录下,或你的项目就是框架本身,里面包含 `composer.json` 等项目文件:
```
composer.json
src/App/MyCommand.app
vendor/*
bin/entry.php
```
我们假设从 `src/App/MyCommand.php` 中获取以上常量:
| Constant | Value |
|----------------------|------------------------------------------------------|
| `WORKING_DIR` | `/home/example/static-php-cli` |
| `SOURCE_ROOT_DIR` | `/home/example/static-php-cli` |
| `FRAMEWORK_ROOT_DIR` | `/home/example/static-php-cli` |
| `__DIR__` | `/home/example/static-php-cli/src/App` |
| `__FILE__` | `/home/example/static-php-cli/src/App/MyCommand.php` |
这种情况下,`WORKING_DIR``SOURCE_ROOT_DIR``FRAMEWORK_ROOT_DIR` 的值是完全一致的:`/home/example/static-php-cli`
框架的源码和应用的源码都在当前路径下。
### Vendor 库模式vendor
Vendor 库模式一般是指你的项目为框架类或者被其他应用作为 composer 依赖项安装到项目中,存放位置在 `vendor/author/XXX` 目录。
假设你的项目是 `crazywhalecc/static-php-cli`,你或其他人在另一个项目使用 `composer require` 安装了这个项目。
我们假设 static-php-cli 中包含同 `Git 模式` 的除 `vendor` 目录外的所有文件,并从 `src/App/MyCommand` 中获取常量值,
目录常量应该是:
| Constant | Value |
|----------------------|--------------------------------------------------------------------------------------|
| `WORKING_DIR` | `/home/example/another-app` |
| `SOURCE_ROOT_DIR` | `/home/example/another-app` |
| `FRAMEWORK_ROOT_DIR` | `/home/example/another-app/vendor/crazywhalecc/static-php-cli` |
| `__DIR__` | `/home/example/another-app/vendor/crazywhalecc/static-php-cli/src/App` |
| `__FILE__` | `/home/example/another-app/vendor/crazywhalecc/static-php-cli/src/App/MyCommand.php` |
这里的 `SOURCE_ROOT_DIR` 就指的是使用 `static-php-cli` 的项目的根目录。
### Git 项目 Phar 模式source-phar
Git 项目 Phar 模式指的是将 Git 项目模式的项目目录打包为一个 `phar` 文件的模式。我们假设 `/home/example/static-php-cli` 将打包为一个 Phar 文件,目录有以下文件:
```
composer.json
src/App/MyCommand.app
vendor/*
bin/entry.php
```
打包为 `app.phar` 并存放到 `/home/example/static-php-cli` 目录下时,此时执行 `app.phar`,假设执行了 `src/App/MyCommand` 代码,常量在该文件内获取:
| Constant | Value |
|----------------------|----------------------------------------------------------------------|
| `WORKING_DIR` | `/home/example/static-php-cli` |
| `SOURCE_ROOT_DIR` | `phar:///home/example/static-php-cli/app.phar/` |
| `FRAMEWORK_ROOT_DIR` | `phar:///home/example/static-php-cli/app.phar/` |
| `__DIR__` | `phar:///home/example/static-php-cli/app.phar/src/App` |
| `__FILE__` | `phar:///home/example/static-php-cli/app.phar/src/App/MyCommand.php` |
因为在 phar 内读取自身 phar 的文件需要 `phar://` 协议进行,所以项目根目录和框架目录将会和 `WORKING_DIR` 不同。
### Vendor 库 Phar 模式vendor-phar
Vendor 库 Phar 模式指的是你的项目作为框架安装在其他项目内,存储于 `vendor` 目录下。
我们假设你的项目目录结构如下:
```
composer.json # 当前项目的 Composer 配置文件
box.json # 打包 Phar 的配置文件
another-app.php # 另一个项目的入口文件
vendor/crazywhalecc/static-php-cli/* # 你的项目被作为依赖库
```
将该目录 `/home/example/another-app/` 下的这些文件打包为 `app.phar` 时,对于你的项目而言,下面常量的值应为:
| Constant | Value |
|----------------------|------------------------------------------------------------------------------------------------------|
| `WORKING_DIR` | `/home/example/another-app` |
| `SOURCE_ROOT_DIR` | `phar:///home/example/another-app/app.phar/` |
| `FRAMEWORK_ROOT_DIR` | `phar:///home/example/another-app/app.phar/vendor/crazywhalecc/static-php-cli` |
| `__DIR__` | `phar:///home/example/another-app/app.phar/vendor/crazywhalecc/static-php-cli/src/App` |
| `__FILE__` | `phar:///home/example/another-app/app.phar/vendor/crazywhalecc/static-php-cli/src/App/MyCommand.php` |

View File

@@ -0,0 +1,204 @@
# 系统编译工具
static-php-cli 在构建静态 PHP 时使用了许多系统编译工具,这些工具主要包括:
- `autoconf`: 用于生成 `configure` 脚本。
- `make`: 用于执行 `Makefile`
- `cmake`: 用于执行 `CMakeLists.txt`
- `pkg-config`: 用于查找依赖库的安装路径。
- `gcc`: 用于在 Linux 下编译 C/C++ 语言代码。
- `clang`: 用于在 macOS 下编译 C/C++ 语言代码。
对于 Linux 和 macOS 操作系统,这些工具通常可以通过包管理安装,这部分在 doctor 模块中编写了。
理论上我们也可以通过编译和手动下载这些工具,但这样会增加编译的复杂度,所以我们不推荐这样做。
## Linux 环境编译工具
对于 Linux 系统来说,不同发行版的编译工具安装方式不同。而且对于静态编译来说,某些发行版的包管理无法安装用于纯静态编译的库和工具,
所以对于 Linux 平台及其不同发行版,我们目前提供了多种编译环境的部署措施。
### glibc 环境
glibc 环境指的是系统底层的 `libc` 库(即所有 C 语言编写的程序动态链接的 C 标准库)使用的是 `glibc`,这是大多数发行版的默认环境。
例如Ubuntu、Debian、CentOS、RHEL、openSUSE、Arch Linux 等。
而 glibc 环境下,我们使用的包管理、编译器都是默认指向 glibc 的glibc 不能被良好地静态链接。它不能被静态链接的原因之一是它的网络库 `nss` 无法静态编译。
对于 glibc 环境,在 2.0 RC8 及以后的 static-php-cli 及 spc 中,你可以选择两种方式来构建静态 PHP
1. 使用 Docker 构建,这是最简单的方式,你可以使用 `bin/spc-alpine-docker` 来构建,它会在 Alpine Linux 环境下构建。
2. 使用 `bin/spc doctor` 安装 musl-wrapper 和 musl-cross-make 套件,然后直接正常构建。([相关源码](https://github.com/crazywhalecc/static-php-cli/blob/main/src/SPC/doctor/item/LinuxMuslCheck.php)
一般来说,这两种构建方式的构建结果是一致的,你可以根据实际需求选择。
在 doctor 模块中static-php-cli 会先检测当前的 Linux 发行版。如果当前发行版是 glibc 环境,会提示需要安装 musl-wrapper 和 musl-cross-make 套件。
在 glibc 环境下安装 musl-wrapper 的过程如下:
1. 从 musl 官网下载特定版本的 [musl-wrapper 源码](https://musl.libc.org/releases/)。
2. 使用从包管理安装的 `gcc` 编译 musl-wrapper 源码,生成 `musl-libc` 等库:`./configure --disable-gcc-wrapper && make -j && sudo make install`
3. musl-wrapper 相关库将被安装在 `/usr/local/musl` 目录。
在 glibc 环境下安装 musl-cross-make 的过程如下:
1. 从 dl.static-php.dev 下载预编译好的 [musl-cross-make](https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/) 压缩包。
2. 解压到 `/usr/local/musl` 目录。
::: tip
在 glibc 环境下,静态编译可以通过直接安装 musl-wrapper 来实现,但是 musl-wrapper 仅包含了 `musl-gcc`,而没有 `musl-g++`,这也就意味着无法编译 C++ 代码。
所以我们需要 musl-cross-make 来提供 `musl-g++`
而 musl-cross-make 套件无法在本地直接编译的原因是它的编译环境要求比较高(需要 36GB 以上内存Alpine Linux 下编译),所以我们提供了预编译好的二进制包,可用于所有 Linux 发行版。
同时,部分发行版的包管理提供了 musl-wrapper但 musl-cross-make 需要匹配对应的 musl-wrapper 版本,所以我们不使用包管理安装 musl-wrapper。
对于如何编译 musl-cross-make将在本章节内的 **编译 musl-cross-make** 小节中介绍。
:::
### musl 环境
musl 环境指的是系统底层的 `libc` 库使用的是 `musl`,这是一种轻量级的 C 标准库,它的特点是可以被良好地静态链接。
对于目前流行的 Linux 发行版Alpine Linux 使用的就是 musl 环境,所以 static-php-cli 在 Alpine Linux 下可以直接构建静态 PHP仅需直接从包管理安装基础编译工具如 gcc、cmake 等)即可。
对于其他发行版,如果你的发行版使用的是 musl 环境,那么你也可以在安装必要的编译工具后直接使用 static-php-cli 构建静态 PHP。
::: tip
在 musl 环境下static-php-cli 会自动跳过 musl-wrapper 和 musl-cross-make 的安装。
:::
### Docker 环境
Docker 环境指的是使用 Docker 容器来构建静态 PHP你可以使用 `bin/spc-alpine-docker` 来构建。
执行这个命令前需要先安装 Docker然后在项目根目录执行 `bin/spc-alpine-docker` 即可。
在执行 `bin/spc-alpine-docker`static-php-cli 会自动下载 Alpine Linux 镜像,然后构建一个 `cwcc-spc-x86_64``cwcc-spc-aarch64` 的镜像。
然后一切的构建都在这个镜像内进行,相当于在 Alpine Linux 内编译。总的来说Docker 环境就是 musl 环境。
## musl-cross-make 工具链编译
在 Linux 中,尽管你不需要手动编译 musl-cross-make 工具,但是如果你想了解它的编译过程,可以参考这里。
还有一个重要的原因就是,这个可能无法使用 CI、Actions 等自动化工具编译,因为现有的 CI 服务编译环境不满足 musl-cross-make 的编译要求,满足要求的配置价格太高。
musl-cross-make 的编译过程如下:
准备一个 Alpine Linux 环境(直接安装或使用 Docker 均可),编译的过程需要 36GB 以上内存,所以你需要在内存较大的机器上编译。如果没有这么多内存,可能会导致编译失败。
然后将以下内容写入 `config.mak` 文件内:
```makefile
STAT = -static --static
FLAG = -g0 -Os -Wno-error
ifneq ($(NATIVE),)
COMMON_CONFIG += CC="$(HOST)-gcc ${STAT}" CXX="$(HOST)-g++ ${STAT}"
else
COMMON_CONFIG += CC="gcc ${STAT}" CXX="g++ ${STAT}"
endif
COMMON_CONFIG += CFLAGS="${FLAG}" CXXFLAGS="${FLAG}" LDFLAGS="${STAT}"
BINUTILS_CONFIG += --enable-gold=yes --enable-gprofng=no
GCC_CONFIG += --enable-static-pie --disable-cet --enable-default-pie
#--enable-default-pie
CONFIG_SUB_REV = 888c8e3d5f7b
GCC_VER = 13.2.0
BINUTILS_VER = 2.40
MUSL_VER = 1.2.4
GMP_VER = 6.2.1
MPC_VER = 1.2.1
MPFR_VER = 4.2.0
LINUX_VER = 6.1.36
```
同时,你需要新建一个 `gcc-13.2.0.tar.xz.sha1` 文件,文件内容如下:
```
5f95b6d042fb37d45c6cbebfc91decfbc4fb493c gcc-13.2.0.tar.xz
```
如果你使用的是 Docker 构建,新建一个 `Dockerfile` 文件,写入以下内容:
```dockerfile
FROM alpine:edge
RUN apk add --no-cache \
gcc g++ git make curl perl \
rsync patch wget libtool \
texinfo autoconf automake \
bison tar xz bzip2 zlib \
file binutils flex \
linux-headers libintl \
gettext gettext-dev icu-libs pkgconf \
pkgconfig icu-dev bash \
ccache libarchive-tools zip
WORKDIR /opt
RUN git clone https://git.zv.io/toolchains/musl-cross-make.git
WORKDIR /opt/musl-cross-make
COPY config.mak /opt/musl-cross-make
COPY gcc-13.2.0.tar.xz.sha1 /opt/musl-cross-make/hashes
RUN make TARGET=x86_64-linux-musl -j || :
RUN sed -i 's/poison calloc/poison/g' ./gcc-13.2.0/gcc/system.h
RUN make TARGET=x86_64-linux-musl -j
RUN make TARGET=x86_64-linux-musl install -j
RUN tar cvzf x86_64-musl-toolchain.tgz output/*
```
如果你使用的是非 Docker 环境的 Alpine Linux可以直接执行 Dockerfile 中的命令,例如:
```bash
apk add --no-cache \
gcc g++ git make curl perl \
rsync patch wget libtool \
texinfo autoconf automake \
bison tar xz bzip2 zlib \
file binutils flex \
linux-headers libintl \
gettext gettext-dev icu-libs pkgconf \
pkgconfig icu-dev bash \
ccache libarchive-tools zip
git clone https://git.zv.io/toolchains/musl-cross-make.git
# 将 config.mak 拷贝到 musl-cross-make 的工作目录内,你需要将 /path/to/config.mak 替换为你的 config.mak 文件路径
cp /path/to/config.mak musl-cross-make/
cp /path/to/gcc-13.2.0.tar.xz.sha1 musl-cross-make/hashes
make TARGET=x86_64-linux-musl -j || :
sed -i 's/poison calloc/poison/g' ./gcc-13.2.0/gcc/system.h
make TARGET=x86_64-linux-musl -j
make TARGET=x86_64-linux-musl install -j
tar cvzf x86_64-musl-toolchain.tgz output/*
```
::: tip
以上所有脚本都适用于 x86_64 架构的 Linux。如果你需要构建 ARM 环境的 musl-cross-make只需要将上方所有 `x86_64` 替换为 `aarch64` 即可。
:::
这个编译过程可能会因为内存不足、网络问题等原因导致编译失败,你可以多尝试几次,或者使用更大内存的机器来编译。
如果遇到了问题,或者你有更好的改进方案,可以在 [讨论](https://github.com/crazywhalecc/static-php-cli-hosted/issues/1) 中提出。
## macOS 环境编译工具
对于 macOS 系统来说,我们使用的编译工具主要是 `clang`,它是 macOS 系统默认的编译器,同时也是 Xcode 的编译器。
在 macOS 下编译,主要依赖于 Xcode 或 Xcode Command Line Tools你可以在 App Store 下载 Xcode或者在终端执行 `xcode-select --install` 来安装 Xcode Command Line Tools。
此外,在 `doctor` 环境检查模块中static-php-cli 会检查 macOS 系统是否安装了 Homebrew、编译工具等如果没有会提示你安装这里不再赘述。
## FreeBSD 环境编译工具
FreeBSD 也是 Unix 系统,它的编译工具和 macOS 类似,你可以直接使用包管理 `pkg` 安装 `clang` 等编译工具,通过 `doctor` 命令。
## pkg-config 编译
如果你在使用 static-php-cli 构建静态 PHP 时仔细观察编译的日志,你会发现无论编译什么,都会先编译 `pkg-config`,这是因为 `pkg-config` 是一个用于查找依赖库的工具。
在早期的 static-php-cli 版本中,我们直接使用了包管理安装的 `pkg-config` 工具,但是这样会导致一些问题,例如:
- 即使指定了 `PKG_CONFIG_PATH``pkg-config` 也会尝试从系统路径中查找依赖包。
- 由于 `pkg-config` 会从系统路径中查找依赖包,所以如果系统中存在同名的依赖包,可能会导致编译失败。
为了避免以上问题,我们将 `pkg-config` 编译到用户态的 `buildroot/bin` 内并使用,使用了 `--without-sysroot` 等参数来避免从系统路径中查找依赖包。

96
docs-v2/zh/faq/index.md Normal file
View File

@@ -0,0 +1,96 @@
# 常见问题
这里将会编写一些你容易遇到的问题。目前有很多,但是我需要花时间来整理一下。
## php.ini 的路径是什么?
在 Linux、macOS 和 FreeBSD 上,`php.ini` 的路径是 `/usr/local/etc/php/php.ini`
在 Windows 中,路径是 `C:\windows\php.ini``php.exe` 所在的当前目录。
可以在 *nix 系统中使用手动构建选项 `--with-config-file-path` 来更改查找 `php.ini` 的目录。
此外,在 Linux、macOS 和 FreeBSD 上,`/usr/local/etc/php/conf.d` 目录中的 `.ini` 文件也会被加载。
在 Windows 中,该路径默认为空。
可以使用手动构建选项 `--with-config-file-scan-dir` 更改该目录。
PHP 默认也会从 [其他标准位置](https://www.php.net/manual/zh/configuration.file.php) 中搜索 `php.ini`
## 静态编译的 PHP 可以安装扩展吗?
因为传统架构下的 PHP 安装扩展的原理是使用 `.so` 类型的动态链接的库方式安装新扩展,而使用本项目编译的静态链接的 PHP。但是静态链接在不同操作系统有不同的定义。
首先,对于 Linux 系统,静态链接的二进制文件不会链接系统的动态链接库。纯静态链接的二进制文件(`-all-static`)无法加载动态库,因此无法添加新扩展。
同时,在纯静态模式下,你也不能使用 `ffi` 等扩展来加载外部 `.so` 模块。
你可以使用命令 `ldd buildroot/bin/php` 来检查你在 Linux 下构建的二进制文件是否为纯静态链接。
如果你 [构建基于 GNU libc 的 PHP](../guide/build-with-glibc),你可以使用 `ffi` 扩展来加载外部 `.so` 模块,并加载具有相同 ABI 的 `.so` 扩展。
例如,你可以使用以下命令构建一个与 glibc 动态链接的静态 PHP 二进制文件,支持 FFI 扩展并加载相同 PHP 版本和相同 TS 类型的 `xdebug.so` 扩展:
```bash
bin/spc-gnu-docker download --for-extensions=ffi,xml --with-php=8.4
bin/spc-gnu-docker build ffi,xml --build-cli --debug
buildroot/bin/php -d "zend_extension=/path/to/php{PHP_VER}-{ts/nts}/xdebug.so" --ri xdebug
```
对于 macOS 平台macOS 下的几乎所有二进制文件都无法真正纯静态链接,几乎所有二进制文件都会链接 macOS 系统库:`/usr/lib/libresolv.9.dylib``/usr/lib/libSystem.B.dylib`
因此,在 macOS 上,你可以**直接**使用 SPC 构建具有动态链接扩展的静态编译 PHP 二进制文件:
1. 使用 `--build-shared=XXX` 选项构建共享扩展 `xxx.so`。例如:`bin/spc build bcmath,zlib --build-shared=xdebug --build-cli`
2. 你将获得 `buildroot/modules/xdebug.so``buildroot/bin/php`
3. `xdebug.so` 文件可用于版本和线程安全相同的 php。
对于 Windows 平台,由于官方构建的扩展(如 `php_yaml.dll`)强制使用了 `php8.dll` 动态库作为链接,静态构建的 PHP 不包含任何系统库以外的动态库,
所以 Windows 下无法加载官方构建的动态扩展。 由于 static-php-cli 还暂未支持构建动态扩展,所以目前还没有让 static-php 加载动态扩展的方法。
不过Windows 可以正常使用 `FFI` 扩展加载其他的 dll 文件并调用。
## 可以支持 Oracle 数据库扩展吗?
部分依赖库闭源的扩展,如 `oci8``sourceguardian` 等,它们没有提供纯静态编译的依赖库文件(`.a`),仅提供了动态依赖库文件(`.so`
这些扩展无法使用源码的形式编译到 static-php-cli 中,所以本项目可能永远也不会支持这些扩展。不过,理论上你可以根据上面的问题在 macOS 和 Linux 下接入和使用这类扩展。
如果你对此类扩展有需求,或者大部分人都对这些闭源扩展使用有需求,
可以看看有关 [standalone-php-cli](https://github.com/crazywhalecc/static-php-cli/discussions/58) 的讨论。欢迎留言。
## 支持 Windows 吗?
该项目目前支持 Windows但支持的扩展数量较少。Windows 支持并不完美。主要有以下问题:
1. Windows 的编译过程与 *nix 不同,使用的工具链也不同。用于编译每个扩展依赖库的编译工具也几乎完全不同。
2. Windows 版本的需求也会根据所有使用本项目的人的需求推进。如果很多人需要,我会尽快支持相关扩展。
## 我可以使用 micro 保护我的源代码吗?
不可以。micro.sfx 本质上是将 php 和 php 代码合并为一个文件,没有编译或加密 PHP 代码的过程。
首先php-src 是 PHP 代码的官方解释器,市场上没有与主流分支兼容的 PHP 编译器。
我在网上看到一个名为 BPCBinary PHP Compiler的项目可以将 PHP 编译为二进制,但有很多限制。
加密和保护代码的方向与编译不同。编译后,也可以通过逆向工程等方法获得代码。真正的保护仍然通过打包和加密代码等手段进行。
因此本项目static-php-cli和相关项目lwmbs、swoole-cli都提供了 php-src 源代码的便捷编译工具。
本项目和相关项目引用的 phpmicro 只是 PHP 的 sapi 接口封装,而不是 PHP 代码的编译工具。
PHP 代码的编译器是一个完全不同的项目,因此不考虑额外的情况。
如果你对加密感兴趣,可以考虑使用现有的加密技术,如 Swoole Compiler、Source Guardian 等。
## 无法使用 ssl
**更新:该问题已在最新版本的 static-php-cli 中修复,现在默认读取系统的证书文件。如果你仍然遇到问题,请尝试下面的解决方案。**
使用 curl、pgsql 等请求 HTTPS 网站或建立 SSL 连接时,可能会出现 `error:80000002:system library::No such file or directory` 错误。
此错误是由于静态编译的 PHP 未通过 `php.ini` 指定 `openssl.cafile` 导致的。
你可以通过在使用 PHP 前指定 `php.ini` 并在 INI 中添加 `openssl.cafile=/path/to/your-cert.pem` 来解决此问题。
对于 Linux 系统,你可以从 curl 官方网站下载 [cacert.pem](https://curl.se/docs/caextract.html) 文件,也可以使用系统自带的证书文件。
有关不同发行版的证书位置,请参考 [Golang 文档](https://go.dev/src/crypto/x509/root_linux.go)。
> INI 配置 `openssl.cafile` 不能使用 `ini_set()` 函数动态设置,因为 `openssl.cafile` 是 `PHP_INI_SYSTEM` 类型的配置,只能在 `php.ini` 文件中设置。
## 为什么不支持旧版本的 PHP
因为旧版本的 PHP 有很多问题,如安全问题、性能问题和功能问题。此外,许多旧版本的 PHP 与最新的依赖库不兼容,这也是不支持旧版本 PHP 的原因之一。
你可以使用 static-php-cli 早期编译的旧版本,如 PHP 8.0,但不会明确支持早期版本。

View File

@@ -0,0 +1,15 @@
---
aside: false
---
<script setup lang="ts">
import CliGenerator from "../../.vitepress/components/CliGenerator.vue";
</script>
# CLI 编译命令生成器
::: tip
下面选择扩展可能包含所选操作系统不支持的扩展,这可能导致编译失败。请先查阅 [支持的扩展](./extensions)。
:::
<cli-generator lang="zh" />

View File

@@ -0,0 +1,22 @@
---
outline: 'deep'
---
# 依赖关系图表
在编译 PHP 时,每个扩展、库都有依赖关系,这些依赖关系可能是必需的,也可能是可选的。在编译 PHP 时,可以选择是否包含这些可选的依赖关系。
例如,在 Linux 下编译 `gd` 扩展时,会强制编译 `zlib,libpng` 库和 `zlib` 扩展,而 `libavif,libwebp,libjpeg,freetype` 库都是可选的库,默认不会编译,除非通过 `--with-libs=avif,webp,jpeg,freetype` 选项指定。
- 对于可选扩展(扩展的可选特性),需手动在编译时指定,例如启用 Redis 的 igbinary 支持:`bin/spc build redis,igbinary`
- 对于可选库,需通过 `--with-libs=XXX` 选项编译指定。
- 如果想启用所有的可选扩展,可以使用 `bin/spc build redis --with-suggested-exts` 参数。
- 如果想启用所有的可选库,可以使用 `--with-suggested-libs` 参数。
## 扩展的依赖图
<!--@include: ../../deps-map-ext.md-->
## 库的依赖表
<!--@include: ../../deps-map-lib.md-->

View File

@@ -0,0 +1,112 @@
# 环境变量
本页面的环境变量列表中所提到的所有环境变量都具有默认值,除非另有说明。你可以通过设置这些环境变量来覆盖默认值。
## 环境变量列表
在 2.3.5 版本之后,我们将环境变量集中到了 `config/env.ini` 文件中,你可以通过修改这个文件来设置环境变量。
我们将 static-php-cli 支持的环境变量分为三种:
- 全局内部环境变量:在 static-php-cli 启动后即声明,你可以在 static-php-cli 的内部使用 `getenv()` 来获取他们,也可以在启动 static-php-cli 前覆盖。
- 固定环境变量:在 static-php-cli 启动后声明,你仅可使用 `getenv()` 获取,但无法通过 shell 脚本对其覆盖。
- 配置文件环境变量:在 static-php-cli 构建前声明,你可以通过修改 `config/env.ini` 文件或通过 shell 脚本来设置这些环境变量。
你可以阅读 [config/env.ini](https://github.com/crazywhalecc/static-php-cli/blob/main/config/env.ini) 中每项参数的注释来了解其作用(仅限英文版)。
## 自定义环境变量
一般情况下,你不需要修改任何以下环境变量,因为它们已经被设置为最佳值。
但是,如果你有特殊需求,你可以通过设置这些环境变量来满足你的需求(比如你需要调试不同编译参数下的 PHP 性能表现)。
如需使用自定义环境变量,你可以在终端中使用 `export` 命令或者在命令前直接设置环境变量,例如:
```shell
# export 方式
export SPC_CONCURRENCY=4
bin/spc build mbstring,pcntl --build-cli
# 直接设置方式
SPC_CONCURRENCY=4 bin/spc build mbstring,pcntl --build-cli
```
或者,如果你需要长期修改某个环境变量,你可以通过修改 `config/env.ini` 文件来实现。
`config/env.ini` 分为三段,其中 `[global]` 全局有效,`[windows]``[macos]``[linux]` 仅对应的操作系统有效。
例如,你需要修改编译 PHP 的 `./configure` 命令,你可以在 `config/env.ini` 文件中找到 `SPC_CMD_PREFIX_PHP_CONFIGURE` 环境变量,然后修改其值即可。
但如果你的构建条件比较复杂,需要多种 env.ini 进行切换,我们推荐你使用 `config/env.custom.ini` 文件,这样你可以在不修改默认的 `config/env.ini` 文件的情况下,
通过写入额外的重载项目指定你的环境变量。
```ini
; This is an example of `config/env.custom.ini` file,
; we modify the `SPC_CONCURRENCY` and linux default CFLAGS passing to libs and PHP
[global]
SPC_CONCURRENCY=4
[linux]
SPC_DEFAULT_C_FLAGS="-O3"
```
## 编译依赖库的环境变量(仅限 Unix 系统)
从 2.2.0 开始static-php-cli 对所有 macOS、Linux、FreeBSD 等 Unix 系统的编译依赖库的命令均支持自定义环境变量。
这样你就可以随时通过环境变量来调整编译依赖库的行为。例如你可以通过 `xxx_CFLAGS=-O0` 来设置编译 xxx 库的优化参数。
当然,不是每个依赖库都支持注入环境变量,我们目前提供了三个通配的环境变量,后缀分别为:
- `_CFLAGS`: C 编译器的参数
- `_LDFLAGS`: 链接器的参数
- `_LIBS`: 额外的链接库
前缀为依赖库的名称,具体依赖库的名称以 `lib.json` 为准。其中,带有 `-` 的依赖库名称需要将 `-` 替换为 `_`
下面是一个替换 openssl 库编译的优化选项示例:
```shell
openssl_CFLAGS="-O0"
```
库名称使用同 `lib.json` 中列举的名称,区分大小写。
::: tip
当未指定相关环境变量时,除以下变量外,其余值均默认为空:
| var name | var default value |
|-----------------------|-------------------------------------------------------------------------------------------------|
| `pkg_config_CFLAGS` | macOS: `$SPC_DEFAULT_C_FLAGS -Wimplicit-function-declaration -Wno-int-conversion`, Other: empty |
| `pkg_config_LDFLAGS` | Linux: `--static`, Other: empty |
| `imagemagick_LDFLAGS` | Linux: `-static`, Other: empty |
| `imagemagick_LIBS` | macOS: `-liconv`, Other: empty |
| `ldap_LDFLAGS` | `-L$BUILD_LIB_PATH` |
| `openssl_CFLAGS` | Linux: `$SPC_DEFAULT_C_FLAGS`, Other: empty |
| others... | empty |
:::
下表是支持自定义以上三种变量的依赖库名称列表:
| lib name |
|-------------|
| brotli |
| bzip |
| curl |
| freetype |
| gettext |
| gmp |
| imagemagick |
| ldap |
| libargon2 |
| libavif |
| libcares |
| libevent |
| openssl |
::: tip
因为给每个库适配自定义环境变量是一项特别繁琐的工作,且大部分情况下你都不需要这些库的自定义环境变量,所以我们目前只支持了部分库的自定义环境变量。
如果你需要自定义环境变量的库不在上方列表,可以通过 [GitHub Issue](https://github.com/crazywhalecc/static-php-cli/issues)
来提出需求。
:::

View File

@@ -0,0 +1,158 @@
# 扩展注意事项
因为是静态编译,扩展不会 100% 完美编译,而且不同扩展对 PHP、环境都有不同的要求这里将一一列举。
## curl
HTTP3 支持默认未启用,需在编译时添加 `--with-libs="nghttp2,nghttp3,ngtcp2"` 以启用 PHP 8.4 及以上版本的 HTTP3 支持。
使用 curl 请求 HTTPS 时,可能存在 `error:80000002:system library::No such file or directory` 错误,
解决办法详见 [FAQ - 无法使用 ssl](../faq/#无法使用-ssl)。
## phpmicro
1. phpmicro SAPI 仅支持 PHP >= 8.0 版本。
## swoole
1. swoole >= 5.0 版本仅支持 PHP >= 8.0 版本。
2. swoole 目前不支持 PHP 8.0 版本 curl 的 hook后续有可能会修复
3. 编译时只包含 `swoole` 扩展时不会完整开启支持的 Swoole 数据库协程 hook如需使用请加入对应的 `swoole-hook-xxx` 扩展。
4. swoole 在部分扩展组合下可能出现 `zend_mm_heap corrupted` 问题,暂未找到是什么原因导致的。
## swoole-hook-pgsql
swoole-hook-pgsql 不是一个扩展,而是 Swoole 的 Hook 特性。
如果你在编译时添加了 `swoole,swoole-hook-pgsql`,你将启用 Swoole 的 PostgreSQL 客户端和 `pdo_pgsql` 扩展的协程模式。
swoole-hook-pgsql 与 `pdo_pgsql` 扩展冲突。如需使用 Swoole 和 `pdo_pgsql`,请删除 pdo_pgsql 扩展,启用 `swoole``swoole-hook-pgsql` 即可。
该扩展包含了 `pdo_pgsql` 的协程环境的实现。
在 macOS 系统,`pdo_pgsql` 可能无法正常连接到 postgresql 服务器,请谨慎使用。
## swoole-hook-mysql
swoole-hook-mysql 不是一个扩展,而是 Swoole 的 Hook 特性。
如果你在编译时添加了 `swoole,swoole-hook-mysql`,你将启用 Swoole 的 `mysqlnd``pdo_mysql` 的协程模式。
## swoole-hook-sqlite
swoole-hook-sqlite 不是一个扩展,而是 Swoole 的 Hook 特性。
如果你在编译时添加了 `swoole,swoole-hook-sqlite`,你将启用 Swoole 的 `pdo_sqlite` 的协程模式Swoole 必须为 5.1 以上)。
swoole-hook-sqlite 与 `pdo_sqlite` 扩展冲突。如需使用 Swoole 和 `pdo_sqlite`,请删除 pdo_sqlite 扩展,启用 `swoole``swoole-hook-sqlite` 即可。
该扩展包含了 `pdo_sqlite` 的协程环境的实现。
## swoole-hook-odbc
swoole-hook-odbc 不是一个扩展,而是 Swoole 的 Hook 特性。
如果你在编译时添加了 `swoole,swoole-hook-odbc`,你将启用 Swoole 的 `odbc` 扩展的协程模式。
swoole-hook-odbc 与 `pdo_odbc` 扩展冲突。如需使用 Swoole 和 `pdo_odbc`,请删除 `pdo_odbc` 扩展,启用 `swoole``swoole-hook-odbc` 即可。
该扩展包含了 `pdo_odbc` 的协程环境的实现。
## swow
1. swow 仅支持 PHP 8.0+ 版本。
## imagick
1. OpenMP 支持已被禁用,这是维护者推荐的做法,系统软件包也是如此配置。
## imap
1. 该扩展目前不支持 Kerberos。
2. 由于底层的 c-client、ext-imap 不是线程安全的。 无法在 `--enable-zts` 构建中使用它。
3. 该扩展已在 PHP 8.4 中被移除,因此我们建议您寻找替代实现,例如 [Webklex/php-imap](https://github.com/Webklex/php-imap)。
## gd
1. gd 扩展依赖了较多的额外图形库,默认情况下,直接使用 `bin/spc build gd` 不会引入和支持部分图形库,例如 `libjpeg``libavif` 等,
需要使用 `--with-libs` 参数补全。目前支持 `freetype,libjpeg,libavif,libwebp` 四个库的支持,所以这里可以使用以下命令来让 gd 库引入它们:
```bash
bin/spc build gd --with-libs=freetype,libjpeg,libavif,libwebp --build-cli
```
## mcrypt
1. 目前未支持,未来也不计划支持此扩展。[#32](https://github.com/crazywhalecc/static-php-cli/issues/32)
## oci8
1. oci8 是 Oracle 数据库的扩展,因为 Oracle 提供的扩展所依赖的库未提供静态编译版本(`.a`)或源代码,无法使用静态链接的方式将此扩展编译到 php 内,故无法支持。
## xdebug
1. Xdebug 只能作为共享扩展进行构建。您需要使用除了 `musl-static` 外的其他 `SPC_TARGET` 构建目标。
2. 使用 Linux/glibc 或 macOS 时,您可以使用 `--build-shared=xdebug` 将 Xdebug 编译为共享扩展。
编译后的 `./php` 二进制文件可以通过指定 INI 文件进行配置和运行,例如 `./php -d 'zend_extension=/path/to/xdebug.so' your-code.php`
## xml
1. xml包括 xmlreader、xmlwriter、dom、simplexml 等,添加 xml 扩展时最好同时启用这些扩展。
2. libxml 包含在 xml 扩展中。 启用 xml 相当于启用 libxml。
## glfw
1. glfw 扩展依赖 OpenGL在 Linux 平台还依赖 X11 等环境,这些库都无法被轻易地动态链接。
2. 在 macOS 系统下,我们可以动态链接系统的 OpenGL 和一些相关的库。
## rar
1. rar 扩展目前在 macOS x86_64 环境下与 `common` 扩展集合编译 phpmicro 存在问题。
## pgsql
~~pgsql ssl 连接与 openssl 3.2.0 不兼容。相关链接:~~
- ~~<https://github.com/Homebrew/homebrew-core/issues/155651>~~
- ~~<https://github.com/Homebrew/homebrew-core/pull/155699>~~
- ~~<https://github.com/postgres/postgres/commit/c82207a548db47623a2bfa2447babdaa630302b9>~~
pgsql 16.2 修复了这个 Bug现在正常工作了。
在 pgsql 使用 SSL 连接时,可能存在 `error:80000002:system library::No such file or directory` 错误,
解决办法详见 [FAQ - 无法使用 ssl](../faq/#无法使用-ssl)。
## openssl
使用基于 openssl 的扩展(如 curl、pgsql 等网络库)时,可能存在 `error:80000002:system library::No such file or directory` 错误,
解决办法详见 [FAQ - 无法使用 ssl](../faq/#无法使用-ssl)。
## password-argon2
1. password-argon2不是一个标准的扩展。`password_hash` 函数的 `PASSWORD_ARGON2ID` 算法需要 libsodium 或 libargon2 才能工作。
2. 使用 password-argon2 可以为此启用多线程支持。
## ffi
1. 由于 musl libc 静态链接的限制,无法加载动态库,因此无法使用 ffi。
如果您需要使用 ffi 扩展,请参阅 [使用 GNU libc 编译 PHP](./build-with-glibc)。
2. macOS 支持 ffi 扩展,但某些内核不包含调试符号时会出现错误。
3. Windows x64 支持 ffi 扩展。
## xhprof
xhprof 扩展包含三部分:`xhprof_extension``xhprof_html``xhprof_libs`。编译的二进制中只包含 `xhprof_extension`
如果需要使用 xhprof请到 [pecl.php.net/package/xhprof](http://pecl.php.net/package/xhprof) 下载源码,指定 `xhprof_libs``xhprof_html` 路径来使用。
## event
event 扩展在 macOS 系统下编译后暂无法使用 `openpty` 特性。相关 Issue
- [static-php-cli#335](https://github.com/crazywhalecc/static-php-cli/issues/335)
## parallel
parallel 扩展只支持 PHP 8.0 及以上版本,并只支持 ZTS 构建(`--enable-zts`)。
## spx
1. SPX 目前不支持 Windows且官方仓库也不支持静态编译static-php-cli 使用了 [修改版本](https://github.com/static-php/php-spx)。
## mimalloc
1. 从技术上讲,这不是扩展,而是一个库。
2. 在 Linux 或 macOS 上使用 `--with-libs="mimalloc"` 进行构建将覆盖默认分配器。
3. 目前,这还处于实验阶段,但建议在线程环境中使用。

View File

@@ -0,0 +1,22 @@
<script setup>
import SearchTable from "../../.vitepress/components/SearchTable.vue";
</script>
# 扩展列表
> - `yes`: 已支持
> - 空白: 目前还不支持,或正在支持中
> - `no` with issue link: 确定不支持或无法支持
> - `partial` with issue link: 已支持,但是无法完美工作
<search-table />
::: tip
如果缺少您需要的扩展,您可以创建 [功能请求](https://github.com/crazywhalecc/static-php-cli/issues)。
有些扩展或扩展依赖的库会有一些可选的特性,例如 gd 库可选支持 libwebp、freetype 等。
如果你只使用 `bin/spc build gd --build-cli` 是不会包含它们static-php-cli 默认为最小依赖原则)。
有关编译可选库,请参考 [扩展、库的依赖关系图表](./deps-map)。对于可选的库,你也可以从 [编译命令生成器](./cli-generator) 中选择扩展后展开选择可选库。
:::

48
docs-v2/zh/guide/index.md Normal file
View File

@@ -0,0 +1,48 @@
# 指南
static-php-cli 是一个用于构建静态编译的 PHP 二进制的工具,目前支持 Linux 和 macOS 系统。
在指南章节中,你将了解到如何使用 static-php-cli 构建独立的 php 程序。
- [本地构建](./manual-build)
- [Action 构建](./action-build)
- [扩展列表](./extensions)
## 编译环境
下面是架构支持情况,:gear: 代表支持 GitHub Action 构建,:computer: 代表支持本地构建,空 代表暂不支持。
| | x86_64 | aarch64 |
|---------|-------------------|-------------------|
| macOS | :gear: :computer: | :gear: :computer: |
| Linux | :gear: :computer: | :gear: :computer: |
| Windows | :gear: :computer: | |
| FreeBSD | :computer: | :computer: |
当前支持编译的 PHP 版本:
> :warning: 部分支持,对于新的测试版和旧版本可能存在问题。
>
> :heavy_check_mark: 支持
>
> :x: 不支持
| PHP Version | Status | Comment |
|-------------|--------------------|---------------------------------------------------------|
| 7.2 | :x: | |
| 7.3 | :x: | phpmicro 和许多扩展不支持 7.3、7.4 版本 |
| 7.4 | :x: | phpmicro 和许多扩展不支持 7.3、7.4 版本 |
| 8.0 | :warning: | PHP 官方已停止 8.0 的维护,我们不再处理 8.0 相关的 backport 支持 |
| 8.1 | :warning: | PHP 官方仅对 8.1 提供安全更新,在 8.5 发布后我们不再处理 8.1 相关的 backport 支持 |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |
| 8.4 | :heavy_check_mark: | |
| 8.5 (beta) | :warning: | PHP 8.5 目前处于 beta 阶段 |
> 这个表格的支持状态是 static-php-cli 对构建对应版本的支持情况,不是 PHP 官方对该版本的支持情况。
## PHP 支持版本
目前static-php-cli 对 PHP 8.2 ~ 8.5 版本是支持的,对于 PHP 8.1 及更早版本理论上支持,只需下载时选择早期版本即可。
但由于部分扩展和特殊组件已对早期版本的 PHP 停止了支持,所以 static-php-cli 不会明确支持早期版本。
我们推荐你编译尽可能新的 PHP 版本,以获得更好的体验。

View File

@@ -0,0 +1,31 @@
# 故障排除
使用 static-php-cli 过程中可能会碰到各种各样的故障,这里将讲述如何自行查看错误并反馈 Issue。
## 下载失败问题
下载资源问题是 spc 最常见的问题之一。主要是由于 spc 下载资源使用的地址一般均为对应项目的官方网站或 GitHub 等,而这些网站可能偶尔会宕机、屏蔽 IP 地址。
在遇到下载失败后,可以多次尝试调用下载命令。
当下载资源时,你可能最终会看到类似 `curl: (56) The requested URL returned error: 403` 的错误,这通常是由于 GitHub 限制导致的。
你可以通过在命令中添加 `--debug` 来验证,会看到类似 `[DEBU] Running command (no output) : curl -sfSL "https://api.github.com/repos/openssl/openssl/releases"` 的输出。
要解决这个问题,可以在 GitHub 上 [创建](https://github.com/settings/tokens) 一个个人访问令牌,并将其设置为环境变量 `GITHUB_TOKEN=<XXX>`
如果确认地址确实无法正常访问,可以提交 Issue 或 PR 更新地址或下载类型。
## Doctor 无法修复某些问题
在绝大部分情况下doctor 模块都可以对缺失的系统环境进行自动修复和安装,但也存在特殊的环境无法正常使用自动修复功能。
由于系统限制例如Windows 下无法自动安装 Visual Studio 等软件),自动修复功能无法用于某些项目。
在遇到无法自动修复功能时,如果遇到 `Some check items can not be fixed` 字样,则表明无法自动修复。
请根据终端显示的方法提交 Issue 或自行修复环境。
## 编译错误
遇到编译错误时,如果没有开启 `--debug` 日志,请先开启调试日志,然后确定报错的命令。
报错的终端输出对于修复编译错误非常重要。
在提交 Issue 时,请上传终端日志的最后报错片段(或整个终端日志输出),并且包含使用的 `spc` 命令和参数。
如果你是重复构建,请参考 [本地构建 - 多次构建](./manual-build#多次构建) 章节。

145
docs-v2/zh/index.md Normal file
View File

@@ -0,0 +1,145 @@
---
# https://vitepress.dev/reference/default-theme-home-page
layout: home
hero:
name: "StaticPHP"
tagline: "StaticPHP 是一款强大的工具,旨在构建包含 PHP、扩展等在内的可移植可执行文件。"
image:
src: /images/static-php_nobg.png
alt: StaticPHP Logo
actions:
- theme: brand
text: 开始使用
link: /zh/guide/
- theme: alt
text: English Docs
link: /en/
features:
- title: 静态 CLI 二进制
details: 您可以轻松编译一个可独立运行的 PHP 二进制文件用于通用场景,支持 CLI、FPM、CGI、FrankenPHP SAPI。
- title: Micro 自解压可执行文件
details: 您可以编译一个自解压可执行文件,并通过 Micro SAPI 将其与 PHP 源代码一起构建。
- title: 依赖管理
details: StaticPHP 内置依赖管理,支持安装不同类型的 PHP 扩展、包和库。
---
<script setup>
import {VPSponsors} from "vitepress/theme";
import Contributors from '../.vitepress/components/Contributors.vue';
const sponsors = [
{ name: 'Beyond Code', img: '/images/beyondcode-seeklogo.png', url: 'https://beyondco.de/' },
{ name: 'NativePHP', img: '/images/nativephp-logo.svg', url: 'https://nativephp.com/' },
];
</script>
<div class="sponsors-section">
<div class="sponsors-header">
<h2>特别赞助商</h2>
<p class="sponsors-description">
感谢我们出色的赞助商对本项目的支持!
</p>
</div>
<VPSponsors :data="sponsors"/>
</div>
<style scoped>
.sponsors-section {
margin: 48px auto;
padding: 32px 24px;
max-width: 1152px;
background: linear-gradient(135deg, var(--vp-c-bg-soft) 0%, var(--vp-c-bg) 100%);
border-radius: 16px;
border: 1px solid var(--vp-c-divider);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
}
.sponsors-section:hover {
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
.sponsors-header {
text-align: center;
margin-bottom: 24px;
}
.sponsors-header h2 {
font-size: 1.5rem;
font-weight: 700;
margin: 0 0 8px 0;
background: linear-gradient(120deg, var(--vp-c-brand-1), var(--vp-c-brand-2));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.sponsors-description {
font-size: 0.95rem;
color: var(--vp-c-text-2);
margin: 0;
line-height: 1.5;
}
@media (max-width: 768px) {
.sponsors-section {
margin: 32px 16px;
padding: 24px 16px;
}
.sponsors-header h2 {
font-size: 1.25rem;
}
.sponsors-description {
font-size: 0.9rem;
}
}
/* Hero logo styling */
:deep(.VPImage.image-src) {
border-radius: 20px;
background: linear-gradient(135deg, var(--vp-c-bg-soft) 0%, var(--vp-c-default-soft) 100%);
padding: 40px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
:deep(.VPImage.image-src:hover) {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
}
/* Dark mode adjustments for logo */
.dark :deep(.VPImage.image-src) {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
opacity: 0.9;
}
.dark :deep(.VPImage.image-src:hover) {
opacity: 1;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.7);
}
/* Additional styling for the logo image itself */
:deep(.VPImage.image-src img) {
max-height: 280px;
width: auto;
}
@media (max-width: 768px) {
:deep(.VPImage.image-src) {
padding: 24px;
}
:deep(.VPImage.image-src img) {
max-height: 200px;
}
}
</style>
<Contributors />

View File

@@ -1,57 +1,69 @@
import sidebarEn from "./sidebar.en";
import sidebarZh from "./sidebar.zh";
// https://vitepress.dev/reference/site-config
export default {
title: "Static PHP",
description: "Build single static PHP binary, with PHP project together, with popular extensions included.",
title: "StaticPHP",
description: "A powerful tool designed for building portable executables including PHP, extensions, and more.",
locales: {
en: {
label: 'English',
lang: 'en',
themeConfig: {
nav: [
{text: 'Guide', link: '/en/guide/',},
{text: 'Advanced', link: '/en/develop/'},
{text: 'Contributing', link: '/en/contributing/'},
{text: 'FAQ', link: '/en/faq/'},
{ text: 'Guide', link: '/en/guide/' },
{ text: 'Develop', link: '/en/develop/' },
{ text: 'Contributing', link: '/en/contributing/' },
{ text: 'FAQ', link: '/en/faq/' },
{
text: 'v3 (alpha)',
items: [
{ text: 'v3 (alpha)', link: '/en/' },
{ text: 'v2', link: '/v2/en/guide/' },
],
},
],
sidebar: sidebarEn,
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2023-present crazywhalecc'
}
copyright: 'Copyright © 2023-present crazywhalecc',
},
},
},
zh: {
label: '简体中文',
lang: 'zh', // optional, will be added as `lang` attribute on `html` tag
lang: 'zh',
themeConfig: {
nav: [
{text: '构建指南', link: '/zh/guide/'},
{text: '进阶', link: '/zh/develop/'},
{text: '贡献', link: '/zh/contributing/'},
{text: 'FAQ', link: '/zh/faq/'},
{ text: '构建指南', link: '/zh/guide/' },
{ text: '开发者', link: '/zh/develop/' },
{ text: '贡献', link: '/zh/contributing/' },
{ text: 'FAQ', link: '/zh/faq/' },
{
text: 'v3 (alpha)',
items: [
{ text: 'v3 (alpha)', link: '/zh/' },
{ text: 'v2', link: '/v2/zh/guide/' },
],
},
],
sidebar: sidebarZh,
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2023-present crazywhalecc'
}
copyright: 'Copyright © 2023-present crazywhalecc',
},
},
}
},
},
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
logo: '/images/static-php_nobg.png',
nav: [],
socialLinks: [
{icon: 'github', link: 'https://github.com/crazywhalecc/static-php-cli'}
{ icon: 'github', link: 'https://github.com/crazywhalecc/static-php-cli' },
],
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2023-present crazywhalecc'
copyright: 'Copyright © 2023-present crazywhalecc',
},
search: {
provider: 'algolia',
@@ -59,7 +71,13 @@ export default {
appId: 'IHJHUB1SF1',
apiKey: '8266d31cc2ffbd0e059f1c6e5bdaf8fc',
indexName: 'static-php docs',
askAi: {
assistantId: 'b72369b2-60a5-461d-902c-5c18d8c05902',
agentStudio: true,
sidePanel: true,
},
},
},
}
},
}

View File

@@ -1,57 +1,82 @@
export default {
'/en/guide/': [
{
text: 'Basic Build Guides',
items: [
{text: 'Guide', link: '/en/guide/'},
{text: 'Build (Local)', link: '/en/guide/manual-build'},
{text: 'Build (CI)', link: '/en/guide/action-build'},
{text: 'Supported Extensions', link: '/en/guide/extensions'},
{text: 'Extension Notes', link: '/en/guide/extension-notes'},
{text: 'Build Command Generator', link: '/en/guide/cli-generator'},
{text: 'Environment Variables', link: '/en/guide/env-vars', collapsed: true,},
{text: 'Dependency Table', link: '/en/guide/deps-map'},
]
},
{
text: 'Extended Build Guides',
items: [
{text: 'Troubleshooting', link: '/en/guide/troubleshooting'},
{text: 'Build on Windows', link: '/en/guide/build-on-windows'},
{text: 'Build with GNU libc', link: '/en/guide/build-with-glibc'},
],
}
],
'/en/develop/': [
{
text: 'Development',
items: [
{text: 'Get Started', link: '/en/develop/'},
{text: 'Project Structure', link: '/en/develop/structure'},
{text: 'PHP Source Modification', link: '/en/develop/php-src-changes'},
],
},
{
text: 'Module',
items: [
{text: 'Doctor ', link: '/en/develop/doctor-module'},
{text: 'Source', link: '/en/develop/source-module'},
]
},
{
text: 'Extra',
items: [
{text: 'Compilation Tools', link: '/en/develop/system-build-tools'},
{text: 'craft.yml Configuration', link: '/zh/develop/craft-yml'},
]
}
],
'/en/contributing/': [
{
text: 'Contributing',
items: [
{text: 'Contributing', link: '/en/contributing/'},
],
}
],
'/en/guide/': [
{
text: 'Getting Started',
items: [
{ text: 'Overview', link: '/en/guide/' },
{ text: 'Installation', link: '/en/guide/installation' },
{ text: 'First Build', link: '/en/guide/first-build' },
{ text: 'CLI Reference', link: '/en/guide/cli-reference' },
],
},
{
text: 'Extensions',
items: [
{ text: 'Supported Extensions', link: '/en/guide/extensions' },
{ text: 'Extension Notes', link: '/en/guide/extension-notes' },
{ text: 'Build Command Generator', link: '/en/guide/cli-generator' },
],
},
{
text: 'Reference',
items: [
{ text: 'Environment Variables', link: '/en/guide/env-vars' },
{ text: 'Dependency Table', link: '/en/guide/deps-map' },
{ text: 'Troubleshooting', link: '/en/guide/troubleshooting' },
],
},
],
'/en/develop/': [
{
text: 'Developer Guide',
items: [
{ text: 'Get Started', link: '/en/develop/' },
{ text: 'Project Structure', link: '/en/develop/structure' },
{ text: 'PHP Source Modifications', link: '/en/develop/php-src-changes' },
],
},
{
text: 'Concepts',
items: [
{ text: 'Package Model', link: '/en/develop/package-model' },
{ text: 'Registry & Plugin System', link: '/en/develop/registry' },
{ text: 'Build Lifecycle', link: '/en/develop/build-lifecycle' },
],
},
{
text: 'Modules',
items: [
{ text: 'Doctor', link: '/en/develop/doctor-module' },
{ text: 'Source', link: '/en/develop/source-module' },
{ text: 'craft.yml', link: '/en/develop/craft-yml' },
{ text: 'Compilation Tools', link: '/en/develop/system-build-tools' },
],
},
{
text: 'Vendor Mode',
items: [
{ text: 'Introduction', link: '/en/develop/vendor-mode/' },
{ text: 'Writing Package Classes', link: '/en/develop/vendor-mode/package-classes' },
{ text: 'Annotations Reference', link: '/en/develop/vendor-mode/annotations' },
{ text: 'Dependency Injection', link: '/en/develop/vendor-mode/dependency-injection' },
{ text: 'Lifecycle Hooks', link: '/en/develop/vendor-mode/lifecycle-hooks' },
],
},
],
'/en/contributing/': [
{
text: 'Contributing',
items: [
{ text: 'Contributing Guide', link: '/en/contributing/' },
],
},
],
'/en/faq/': [
{
text: 'FAQ',
items: [
{ text: 'Frequently Asked Questions', link: '/en/faq/' },
],
},
],
};

View File

@@ -1,57 +1,82 @@
export default {
'/zh/guide/': [
{
text: '构建指南',
items: [
{text: '指南', link: '/zh/guide/'},
{text: '本地构建', link: '/zh/guide/manual-build'},
{text: 'Actions 构建', link: '/zh/guide/action-build'},
{text: '扩展列表', link: '/zh/guide/extensions'},
{text: '扩展注意事项', link: '/zh/guide/extension-notes'},
{text: '编译命令生成器', link: '/zh/guide/cli-generator'},
{text: '环境变量列表', link: '/zh/guide/env-vars'},
{text: '依赖关系图表', link: '/zh/guide/deps-map'},
]
},
{
text: '扩展构建指南',
items: [
{text: '故障排除', link: '/zh/guide/troubleshooting'},
{text: '在 Windows 上构建', link: '/zh/guide/build-on-windows'},
{text: '构建 GNU libc 兼容的二进制', link: '/zh/guide/build-with-glibc'},
],
}
],
'/zh/develop/': [
{
text: '开发指南',
items: [
{text: '开发简介', link: '/zh/develop/'},
{text: '项目结构简介', link: '/zh/develop/structure'},
{text: '对 PHP 源码的修改', link: '/zh/develop/php-src-changes'},
],
},
{
text: '模块',
items: [
{text: 'Doctor 环境检查工具', link: '/zh/develop/doctor-module'},
{text: '资源模块', link: '/zh/develop/source-module'},
]
},
{
text: '其他',
items: [
{text: '系统编译工具', link: '/zh/develop/system-build-tools'},
{text: 'craft.yml 配置详解', link: '/zh/develop/craft-yml'},
]
}
],
'/zh/contributing/': [
{
text: '贡献指南',
items: [
{text: '贡献指南', link: '/zh/contributing/'},
],
}
],
'/zh/guide/': [
{
text: '快速上手',
items: [
{ text: '概览', link: '/zh/guide/' },
{ text: '安装', link: '/zh/guide/installation' },
{ text: '第一次构建', link: '/zh/guide/first-build' },
{ text: '命令行参考', link: '/zh/guide/cli-reference' },
],
},
{
text: '扩展',
items: [
{ text: '支持的扩展列表', link: '/zh/guide/extensions' },
{ text: '扩展注意事项', link: '/zh/guide/extension-notes' },
{ text: '命令生成器', link: '/zh/guide/cli-generator' },
],
},
{
text: '参考',
items: [
{ text: '环境变量', link: '/zh/guide/env-vars' },
{ text: '依赖关系图', link: '/zh/guide/deps-map' },
{ text: '故障排除', link: '/zh/guide/troubleshooting' },
],
},
],
'/zh/develop/': [
{
text: '开发者指南',
items: [
{ text: '开发简介', link: '/zh/develop/' },
{ text: '项目结构', link: '/zh/develop/structure' },
{ text: '对 PHP 源码的修改', link: '/zh/develop/php-src-changes' },
],
},
{
text: '核心概念',
items: [
{ text: 'Package 模型', link: '/zh/develop/package-model' },
{ text: 'Registry 与插件系统', link: '/zh/develop/registry' },
{ text: '构建生命周期', link: '/zh/develop/build-lifecycle' },
],
},
{
text: '模块',
items: [
{ text: 'Doctor 环境检查', link: '/zh/develop/doctor-module' },
{ text: '资源模块', link: '/zh/develop/source-module' },
{ text: 'craft.yml 配置', link: '/zh/develop/craft-yml' },
{ text: '编译工具', link: '/zh/develop/system-build-tools' },
],
},
{
text: 'Vendor 模式',
items: [
{ text: '简介', link: '/zh/develop/vendor-mode/' },
{ text: '编写 Package 类', link: '/zh/develop/vendor-mode/package-classes' },
{ text: '注解参考', link: '/zh/develop/vendor-mode/annotations' },
{ text: '依赖注入', link: '/zh/develop/vendor-mode/dependency-injection' },
{ text: '生命周期 Hook', link: '/zh/develop/vendor-mode/lifecycle-hooks' },
],
},
],
'/zh/contributing/': [
{
text: '贡献指南',
items: [
{ text: '贡献指南', link: '/zh/contributing/' },
],
},
],
'/zh/faq/': [
{
text: 'FAQ',
items: [
{ text: '常见问题', link: '/zh/faq/' },
],
},
],
};

View File

@@ -1,63 +1,5 @@
# Contributing
Thank you for being here, this project welcomes your contributions!
## Contribution Guide
If you have code or documentation to contribute, here's what you need to know first.
1. What type of code are you contributing? (new extensions, bug fixes, security issues, project framework optimizations, documentation)
2. If you contribute new files or new snippets, is your code checked by `php-cs-fixer` and `phpstan`?
3. Have you fully read the [Developer Guide](../develop/) before contributing code?
If you can answer the above questions and have made changes to the code,
you can initiate a Pull Request in the project GitHub repository in time.
After the code review is completed, the code can be modified according to the suggestion, or directly merged into the main branch.
## Contribution Type
The main purpose of this project is to compile statically linked PHP binaries,
and the command line processing function is written based on `symfony/console`.
Before development, if you are not familiar with it,
Check out the [symfony/console documentation](https://symfony.com/doc/current/components/console.html) first.
### Security Update
Because this project is basically a PHP project running locally, generally speaking, there will be no remote attacks.
But if you find such a problem, please **DO NOT submit a PR or Issue in the GitHub repository,
You need to contact the project maintainer (crazywhalecc) via [mail](mailto:admin@zhamao.me).
### Fix Bugs
Fixing bugs generally does not involve modification of the project structure and framework,
so if you can locate the wrong code and fix it directly, please submit a PR directly.
### New Extensions
For adding a new extension,
you need to understand some basic structure of the project and how to add a new extension according to the existing logic.
It will be covered in detail in the next section on this page.
In general, you will need:
1. Evaluate whether the extension can be compiled inline into PHP.
2. Evaluate whether the extension's dependent libraries (if any) can be compiled statically.
3. Write library compile commands on different platforms.
4. Verify that the extension and its dependencies are compatible with existing extensions and dependencies.
5. Verify that the extension works normally in `cli`, `micro`, `fpm`, `embed` SAPIs.
6. Write documentation and add your extension.
### Project Framework Optimization
If you are already familiar with the working principle of `symfony/console`,
and at the same time want to make some modifications or optimizations to the framework of the project,
please understand the following things first:
1. Adding extensions does not belong to project framework optimization,
but if you find that you have to optimize the framework when adding new extensions,
you need to modify the framework itself before adding extensions.
2. For some large-scale logical modifications (such as those involving LibraryBase, Extension objects, etc.),
it is recommended to submit an Issue or Draft PR for discussion first.
3. In the early stage of the project, it was a pure private development project, and there were some Chinese comments in the code.
After internationalizing your project you can submit a PR to translate these comments into English.
4. Please do not submit more useless code fragments in the code,
such as a large number of unused variables, methods, classes, and code that has been rewritten many times.
<!-- TODO: v3 contribution guide.
Sections: code style (php-cs-fixer, phpstan), adding a new library/extension,
adding a doctor check, submitting PRs, security disclosures. -->

View File

@@ -0,0 +1,6 @@
# Build Lifecycle
<!-- TODO: Describe the full build pipeline stage sequence.
When each hook fires: #[BeforeStage], #[AfterStage], #[PatchBeforeBuild].
How platform selection (#[BuildFor]) works at runtime.
Diagram of stage order for a typical library and extension build. -->

View File

@@ -4,4 +4,4 @@ aside: false
# craft.yml Configuration
<!--@include: ../../deps-craft-yml.md-->
<!-- TODO: Full reference for craft.yml fields. -->

View File

@@ -1,70 +1,4 @@
# Doctor module
# Doctor Module
The Doctor module is a relatively independent module used to check the system environment, which can be entered with the command `bin/spc doctor`, and the entry command class is in `DoctorCommand.php`.
The Doctor module is a checklist with a series of check items and automatic repair items.
These items are stored in the `src/SPC/doctor/item/` directory,
And two Attributes are used as check item tags and auto-fix item tags: `#[AsCheckItem]` and `#[AsFixItem]`.
Take the existing check item `if necessary tools are installed`,
which is used to check whether the packages necessary for compilation are installed in the macOS system.
The following is its source code:
```php
use SPC\doctor\AsCheckItem;
use SPC\doctor\AsFixItem;
use SPC\doctor\CheckResult;
#[AsCheckItem('if necessary tools are installed', limit_os: 'Darwin', level: 997)]
public function checkCliTools(): ?CheckResult
{
$missing = [];
foreach (self::REQUIRED_COMMANDS as $cmd) {
if ($this->findCommand($cmd) === null) {
$missing[] = $cmd;
}
}
if (!empty($missing)) {
return CheckResult::fail('missing system commands: ' . implode(', ', $missing), 'build-tools', [$missing]);
}
return CheckResult::ok();
}
```
The first parameter of the attribute is the name of the check item,
and the following `limit_os` parameter restricts the check item to be triggered only under the specified system,
and `level` is the priority of executing the check item, the larger the number, the higher the priority higher.
The `$this->findCommand()` method used in it is the method of `SPC\builder\traits\UnixSystemUtilTrait`,
the purpose is to find the location of the system command, and return NULL if it cannot be found.
Each check item method should return a `SPC\doctor\CheckResult`:
- When returning `CheckResult::fail()`, the first parameter is used to output the error prompt of the terminal,
and the second parameter is the name of the repair item when this check item can be automatically repaired.
- When `CheckResult::ok()` is returned, the check passed. You can also pass a parameter to return the check result, for example: `CheckResult::ok('OS supported')`.
- When returning `CheckResult::fail()`, if the third parameter is included, the array of the third parameter will be used as the parameter of `AsFixItem`.
The following is the method for automatically repairing items corresponding to this check item:
```php
#[AsFixItem('build-tools')]
public function fixBuildTools(array $missing): bool
{
foreach ($missing as $cmd) {
try {
shell(true)->exec('brew install ' . escapeshellarg($cmd));
} catch (RuntimeException) {
return false;
}
}
return true;
}
```
`#[AsFixItem()]` first parameter is the name of the fix item, and this method must return True or False.
When False is returned, the automatic repair failed and manual handling is required.
In the code here, `shell()->exec()` is the method of executing commands of the project,
which is used to replace `exec()` and `system()`, and also provides debugging, obtaining execution status,
entering directories, etc. characteristic.
<!-- TODO: Migrate and update from v2 doctor-module.md.
Cover v3 changes: --auto-fix, .spc-doctor.lock, new check items for v3 toolchain. -->

View File

@@ -1,35 +1,4 @@
# Start Developing
Developing this project requires the installation and deployment of a PHP environment,
as well as some extensions and Composer commonly used in PHP projects.
The development environment and running environment of the project are almost exactly the same.
You can refer to the **Manual Build** section to install system PHP or use the pre-built static PHP of this project as the environment.
I will not go into details here.
Regardless of its purpose, this project itself is actually a `php-cli` program. You can edit and develop it as a normal PHP project.
At the same time, you need to understand the Shell languages of different systems.
The current purpose of this project is to compile statically compiled independent PHP,
but the main part also includes compiling static versions of many dependent libraries,
so you can reuse this set of compilation logic to build independent binary versions of other programs, such as Nginx, etc.
## Environment preparation
A PHP environment is required to develop this project. You can use the PHP that comes with the system,
or you can use the static PHP built by this project.
Regardless of which PHP you use, in your development environment you need to install these extensions:
```
curl,dom,filter,mbstring,openssl,pcntl,phar,posix,sodium,tokenizer,xml,xmlwriter
```
The static-php-cli project itself does not require so many extensions, but during the development process,
you will use tools such as Composer and PHPUnit, which require these extensions.
> For micro self-executing binaries built by static-php-cli itself, only `pcntl,posix,mbstring,tokenizer,phar` is required.
## Start development
Continuing down to see the project structure documentation, you can learn how `static-php-cli` works.
<!-- TODO: Developer introduction, environment setup, required PHP extensions.
Link to Vendor Mode for library authors, and Contributing for code contributors. -->

View File

@@ -0,0 +1,6 @@
# Package Model
<!-- TODO: Explain the unified package model: library / php-extension / target types.
Cover the per-package YAML format (config/pkg/), the `depends` field,
platform overrides (@windows / @unix notation), artifact.source and artifact.binary.
Show annotated example YAML for a library and an extension. -->

View File

@@ -1,59 +1,4 @@
# Modifications to PHP source code
# PHP Source Modifications
During the static compilation process, static-php-cli made some modifications to the PHP source code
in order to achieve good compatibility, performance, and security.
The following is a description of the current modifications to the PHP source code.
## Micro related patches
Based on the patches provided by the phpmicro project,
static-php-cli has made some modifications to the PHP source code to meet the needs of static compilation.
The patches currently used by static-php-cli during compilation in the [patch list](https://github.com/easysoft/phpmicro/tree/master/patches) are:
- static_opcache
- static_extensions_win32
- cli_checks
- disable_huge_page
- vcruntime140
- win32
- zend_stream
- cli_static
- macos_iconv
- phar
## PHP <= 8.1 libxml patch
Because PHP only provides security updates for 8.1 and stops updating older versions,
static-php-cli applies the libxml compilation patch that has been applied in newer versions of PHP to PHP 8.1 and below.
## gd extension Windows patch
Compiling the gd extension under Windows requires major changes to the `config.w32` file.
static-php-cli has made some changes to the gd extension to make it easier to compile under Windows.
## YAML extension Windows patch
YAML extension needs to modify the `config.w32` file to compile under Windows.
static-php-cli has made some modifications to the YAML extension to make it easier to compile under Windows.
## static-php-cli version information insertion
When compiling, static-php-cli will insert the static-php-cli version information into the PHP version information for easy identification.
## Add option to hardcode INI
When using the `-I` parameter to hardcode INI into static PHP functionality,
static-php-cli will modify the PHP source code to insert the hardcoded content.
## Linux system repair patch
Some compilation environments may lack some system header files or libraries.
static-php-cli will automatically fix these problems during compilation, such as:
- HAVE_STRLCAT missing problem
- HAVE_STRLCPY missing problem
## Fiber issue fix patch for Windows
When compiling PHP on Windows, there will be some issues with the Fiber extension.
static-php-cli will automatically fix these issues during compilation (modify `config.w32` in php-src).
<!-- TODO: Migrate and update from v2 php-src-changes.md.
Add v3-specific patches (FrankenPHP embed, Windows fiber fix, etc.). -->

View File

@@ -0,0 +1,6 @@
# Registry & Plugin System
<!-- TODO: Explain spc.registry.yml structure.
How to add an external registry via SPC_REGISTRIES env var.
Vendor-specific configurations, overriding core packages.
Registry resolution order and conflict rules. -->

View File

@@ -1,372 +1,5 @@
# Source module
# Source Module
The download source module of static-php-cli is a major module.
It includes dependent libraries, external extensions, PHP source code download methods and file decompression methods.
The download configuration file mainly involves the `source.json` and `pkg.json` file, which records the download method of all downloadable sources.
The main commands involved in the download function are `bin/spc download` and `bin/spc extract`.
The `download` command is a downloader that downloads sources according to the configuration file,
and the `extract` command is an extractor that extract sources from downloaded files.
Generally speaking, downloading sources may be slow because these sources come from various official websites, GitHub,
and other different locations.
At the same time, they also occupy a large space, so you can download the sources once and reuse them.
The configuration file of the downloader is `source.json`, which contains the download methods of all sources.
You can add the source download methods you need, or modify the existing source download methods.
The download configuration structure of each source is as follows.
The following is the source download configuration corresponding to the `libevent` extension:
```json
{
"libevent": {
"type": "ghrel",
"repo": "libevent/libevent",
"match": "libevent.+\\.tar\\.gz",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
The most important field here is `type`. Currently, the types it supports are:
- `url`: Directly use URL to download, for example: `https://download.libsodium.org/libsodium/releases/libsodium-1.0.18.tar.gz`.
- `pie`: Download PHP extensions from Packagist using the PIE (PHP Installer for Extensions) standard.
- `ghrel`: Use the GitHub Release API to download, download the artifacts uploaded from the latest version released by maintainers.
- `ghtar`: Use the GitHub Release API to download.
Different from `ghrel`, `ghtar` is downloaded from the `source code (tar.gz)` in the latest Release of the project.
- `ghtagtar`: Use GitHub Release API to download.
Compared with `ghtar`, `ghtagtar` can find the latest one from the `tags` list and download the source code in `tar.gz` format
(because some projects only use `tag` release version).
- `bitbuckettag`: Download using BitBucket API, basically the same as `ghtagtar`, except this one applies to BitBucket.
- `git`: Clone the project directly from a Git address to download sources, applicable to any public Git repository.
- `filelist`: Use a crawler to crawl the Web download site that provides file index,
and get the latest version of the file name and download it.
- `custom`: If none of the above download methods are satisfactory, you can write `custom`,
create a new class under `src/SPC/store/source/`, extends `CustomSourceBase`, and write the download script yourself.
## source.json Common parameters
Each source file in source.json has the following params:
- `license`: the open source license of the source code, see **Open Source License** section below
- `type`: must be one of the types mentioned above
- `path` (optional): release the source code to the specified directory instead of `source/{name}`
- `provide-pre-built` (optional): whether to provide precompiled binary files.
If `true`, it will automatically try to download precompiled binary files when running `bin/spc download`
::: tip
The `path` parameter in `source.json` can specify a relative or absolute path. When specified as a relative path, the path is based on `source/`.
:::
## Download type - url
URL type sources refer to downloading files directly from the URL.
The parameters included are:
- `url`: The download address of the file, such as `https://example.com/file.tgz`
- `filename` (optional): The file name saved to the local area. If not specified, the file name of the url will be used.
Example (download the imagick extension and extract it to the extension storage path of the php source code):
```json
{
"ext-imagick": {
"type": "url",
"url": "https://pecl.php.net/get/imagick",
"path": "php-src/ext/imagick",
"filename": "imagick.tgz",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
## Download type - pie
PIE (PHP Installer for Extensions) type sources refer to downloading PHP extensions from Packagist that follow the PIE standard.
This method automatically fetches extension information from the Packagist repository and downloads the appropriate distribution file.
The parameters included are:
- `repo`: The Packagist vendor/package name, such as `vendor/package-name`
Example (download a PHP extension from Packagist using PIE):
```json
{
"ext-example": {
"type": "pie",
"repo": "vendor/example-extension",
"path": "php-src/ext/example",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
::: tip
The PIE download type will automatically detect the extension information from Packagist metadata,
including the download URL, version, and distribution type.
The extension must be marked as `type: php-ext` or contain `php-ext` metadata in its Packagist package definition.
:::
## Download type - ghrel
ghrel will download files from Assets uploaded in GitHub Release.
First use the GitHub Release API to get the latest version, and then download the corresponding files according to the regular matching method.
The parameters included are:
- `repo`: GitHub repository name
- `match`: regular expression matching Assets files
- `prefer-stable`: Whether to download stable versions first (default is `false`)
Example (download the libsodium library, matching the libsodium-x.y.tar.gz file in Release):
```json
{
"libsodium": {
"type": "ghrel",
"repo": "jedisct1/libsodium",
"match": "libsodium-\\d+(\\.\\d+)*\\.tar\\.gz",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
## Download type - ghtar
ghtar will download the file from the GitHub Release Tag.
Unlike `ghrel`, `ghtar` will download the `source code (tar.gz)` from the latest Release of the project.
The parameters included are:
- `repo`: GitHub repository name
- `prefer-stable`: Whether to download stable versions first (default is `false`)
Example (brotli library):
```json
{
"brotli": {
"type": "ghtar",
"repo": "google/brotli",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
## Download type - ghtagtar
Use the GitHub Release API to download.
Compared with `ghtar`, `ghtagtar` can find the latest one from the `tags` list and download the source code in `tar.gz` format
(because some projects only use the `tag` version).
The parameters included are:
- `repo`: GitHub repository name
- `prefer-stable`: Whether to download stable versions first (default is `false`)
Example (gmp library):
```json
{
"gmp": {
"type": "ghtagtar",
"repo": "alisw/GMP",
"license": {
"type": "text",
"text": "EXAMPLE LICENSE"
}
}
}
```
## Download Type - bitbuckettag
Download using BitBucket API, basically the same as `ghtagtar`, except this one works with BitBucket.
The parameters included are:
- `repo`: BitBucket repository name
## Download type - git
Clone the project directly from a Git address to download sources, applicable to any public Git repository.
The parameters included are:
- `url`: Git link (HTTPS only)
- `rev`: branch name
```json
{
"imap": {
"type": "git",
"url": "https://github.com/static-php/imap.git",
"rev": "master",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
## Download type - filelist
Use a crawler to crawl a web download site that provides a file index and get the latest version of the file name and download it.
Note that this method is only applicable to static sites with page index functions such as mirror sites and GNU official websites.
The parameters included are:
- `url`: The URL of the page to crawl the latest version of the file
- `regex`: regular expression matching file names and download links
Example (download the libiconv library from the GNU official website):
```json
{
"libiconv": {
"type": "filelist",
"url": "https://ftp.gnu.org/gnu/libiconv/",
"regex": "/href=\"(?<file>libiconv-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"license": {
"type": "file",
"path": "COPYING"
}
}
}
```
## Download type - custom
If the above downloading methods are not satisfactory, you can write `custom`,
create a new class under `src/SPC/store/source/`, extends `CustomSourceBase`, and write the download script yourself.
I wont go into details here, you can look at `src/SPC/store/source/PhpSource.php` or `src/SPC/store/source/PostgreSQLSource.php` as examples.
## pkg.json General parameters
pkg.json stores non-source-code files, such as precompiled tools musl-toolchain and UPX. It includes:
- `type`: The same type as `source.json` and different kinds of parameters.
- `extract` (optional): The path to decompress after downloading, the default is `pkgroot/{pkg_name}`.
- `extract-files` (optional): Extract only the specified files to the specified location after downloading.
It should be noted that `pkg.json` does not involve compilation, modification and distribution of source code,
so there is no `license` open source license field.
And you cannot use the `extract` and `extract-files` parameters at the same time.
Example (download nasm locally and extract only program files to PHP SDK):
```json
{
"nasm-x86_64-win": {
"type": "url",
"url": "https://www.nasm.us/pub/nasm/releasebuilds/2.16.01/win64/nasm-2.16.01-win64.zip",
"extract-files": {
"nasm-2.16.01/nasm.exe": "{php_sdk_path}/bin/nasm.exe",
"nasm-2.16.01/ndisasm.exe": "{php_sdk_path}/bin/ndisasm.exe"
}
}
}
```
The key name in `extract-files` is the file in the source folder, and the key value is the storage path. The storage path can use the following variables:
- `{php_sdk_path}`: (Windows only) PHP SDK path
- `{pkg_root_path}`: `pkgroot/`
- `{working_dir}`: current working directory
- `{download_path}`: download directory
- `{source_path}`: source code decompression directory
When `extract-files` does not use variables and is a relative path, the directory of the relative path is `{working_dir}`.
## Open source license
For `source.json`, each source file should contain an open source license.
The `license` field stores the open source license information.
Each `license` contains the following parameters:
- `type`: `file` or `text`
- `path`: the license file in the source code directory (required when `type` is `file`)
- `text`: License text (required when `type` is `text`)
Example (yaml extension source code with LICENSE file):
```json
{
"yaml": {
"type": "git",
"path": "php-src/ext/yaml",
"rev": "php7",
"url": "https://github.com/php/pecl-file_formats-yaml",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
When an open source project has multiple licenses, multiple files can be specified:
```json
{
"libuv": {
"type": "ghtar",
"repo": "libuv/libuv",
"license": [
{
"type": "file",
"path": "LICENSE"
},
{
"type": "file",
"path": "LICENSE-extra"
}
]
}
}
```
When the license of an open source project uses different files between versions,
`path` can be used as an array to list the possible license files:
```json
{
"redis": {
"type": "git",
"path": "php-src/ext/redis",
"rev": "release/6.0.2",
"url": "https://github.com/phpredis/phpredis",
"license": {
"type": "file",
"path": [
"LICENSE",
"COPYING"
]
}
}
}
```
<!-- TODO: Migrate and update from v2 source-module.md.
Document v3 source types: url, ghrel, ghtar, ghtagtar, git, pecl (new), filelist, custom.
Per-package YAML source block format. Parallel download (--parallel N). -->

View File

@@ -1,180 +1,5 @@
# Introduction to project structure
# Project Structure
static-php-cli mainly contains three logical components: sources, dependent libraries, and extensions.
These components contains 4 configuration files: `source.json`, `pkg.json`, `lib.json`, and `ext.json`.
A complete process for building standalone static PHP is:
1. Use the source download module `Downloader` to download specified or all source codes.
These sources include PHP source code, dependent library source code, and extension source code.
2. Use the source decompression module `SourceExtractor` to decompress the downloaded sources to the compilation directory.
3. Use the dependency tool to calculate the dependent extensions and dependent libraries of the currently added extension,
and then compile each library that needs to be compiled in the order of dependencies.
4. After building each dependent library using `Builder` under the corresponding operating system, install it to the `buildroot` directory.
5. If external extensions are included (the source code does not contain extensions within PHP),
copy the external extensions to the `source/php-src/ext/` directory.
6. Use `Builder` to build the PHP source code and build target to the `buildroot` directory.
The project is mainly divided into several folders:
- `bin/`: used to store program entry files, including `bin/spc`, `bin/spc-alpine-docker`, `bin/setup-runtime`.
- `config/`: Contains all the extensions and dependent libraries supported by the project,
as well as the download link and download methods of these sources. It is divided into files: `lib.json`, `ext.json`, `source.json`, `pkg.json`, `pre-built.json` .
- `src/`: The core code of the project, including the entire framework and commands for compiling various extensions and libraries.
- `vendor/`: The directory that Composer depends on, you do not need to make any modifications to it.
The operating principle is to start a `ConsoleApplication` of `symfony/console`, and then parse the commands entered by the user in the terminal.
## Basic command line structure
`bin/spc` is an entry file, including the Unix common `#!/usr/bin/env php`,
which is used to allow the system to automatically execute with the PHP interpreter installed on the system.
After the project executes `new ConsoleApplication()`, the framework will automatically register them as commands.
The project does not directly use the Command registration method and command execution method recommended by Symfony. Here are small changes:
1. Each command uses the `#[AsCommand()]` Attribute to register the name and description.
2. Abstract `execute()` so that all commands are based on `BaseCommand` (which is based on `Symfony\Component\Console\Command\Command`),
and the execution code of each command itself is written in the `handle()` method .
3. Added variable `$no_motd` to `BaseCommand`, which is used to display the Figlet greeting when the command is executed.
4. `BaseCommand` saves `InputInterface` and `OutputInterface` as member variables. You can use `$this->input` and `$this->output` within the command class.
## Basic source code structure
The source code of the project is located in the `src/SPC` directory,
supports automatic loading of the PSR-4 standard, and contains the following subdirectories and classes:
- `src/SPC/builder/`: The core compilation command code used to build libraries,
PHP and related extensions under different operating systems, and also includes some compilation system tool methods.
- `src/SPC/command/`: All commands of the project are here.
- `src/SPC/doctor/`: Doctor module, which is a relatively independent module used to check the system environment.
It can be entered using the command `bin/spc doctor`.
- `src/SPC/exception/`: exception class.
- `src/SPC/store/`: Classes related to storage, files and sources are all here.
- `src/SPC/util/`: Some reusable tool methods are here.
- `src/SPC/ConsoleApplication.php`: command line program entry file.
If you have read the source code, you may find that there is also a `src/globals/` directory,
which is used to store some global variables, global methods,
and non-PSR-4 standard PHP source code that is relied upon during the build process, such as extension sanity check code etc.
## Phar application directory issue
Like other php-cli projects, spc itself has additional considerations for paths.
Because spc can run in multiple modes such as `php-cli directly`, `micro SAPI`, `php-cli with Phar`, `vendor with Phar`, etc.,
there are ambiguities in various root directories. A complete explanation is given here.
This problem is generally common in the base class path selection problem of accessing files in PHP projects, especially when used with `micro.sfx`.
Note that this may only be useful for you when developing Phar projects or PHP frameworks.
> Next, we will treat `static-php-cli` (that is, spc) as a normal `php` command line program. You can understand spc as any of your own php-cli applications for reference.
There are three basic constant theoretical values below. We recommend that you introduce these three constants when writing PHP projects:
- `WORKING_DIR`: the working directory when executing PHP scripts
- `SOURCE_ROOT_DIR` or `ROOT_DIR`: the root directory of the project folder, generally the directory where `composer.json` is located
- `FRAMEWORK_ROOT_DIR`: the root directory of the framework used, which may be used by self-developed frameworks. Generally, the framework directory is read-only
You can define these constants in your framework entry or cli applications to facilitate the use of paths in your project.
The following are PHP built-in constant values, which have been defined inside the PHP interpreter:
- `__DIR__`: the directory where the file of the currently executed script is located
- `__FILE__`: the file path of the currently executed script
### Git project mode (source)
Git project mode refers to a framework or program itself stored in plain text in the current folder, and running through `php path/to/entry.php`.
Assume that your project is stored in the `/home/example/static-php-cli/` directory, or your project is the framework itself,
which contains project files such as `composer.json`:
```
composer.json
src/App/MyCommand.app
vendor/*
bin/entry.php
```
We assume that the above constants are obtained from `src/App/MyCommand.php`:
| Constant | Value |
|----------------------|------------------------------------------------------|
| `WORKING_DIR` | `/home/example/static-php-cli` |
| `SOURCE_ROOT_DIR` | `/home/example/static-php-cli` |
| `FRAMEWORK_ROOT_DIR` | `/home/example/static-php-cli` |
| `__DIR__` | `/home/example/static-php-cli/src/App` |
| `__FILE__` | `/home/example/static-php-cli/src/App/MyCommand.php` |
In this case, the values of `WORKING_DIR`, `SOURCE_ROOT_DIR`, and `FRAMEWORK_ROOT_DIR` are exactly the same: `/home/example/static-php-cli`.
The source code of the framework and the source code of the application are both in the current path.
### Vendor library mode (vendor)
The vendor library mode generally means that your project is a framework or is installed into the project as a composer dependency by other applications,
and the storage location is in the `vendor/author/XXX` directory.
Suppose your project is `crazywhalecc/static-php-cli`, and you or others install this project in another project using `composer require`.
We assume that static-php-cli contains all files except the `vendor` directory with the same `Git mode`, and get the constant value from `src/App/MyCommand`,
Directory constant should be:
| Constant | Value |
|----------------------|--------------------------------------------------------------------------------------|
| `WORKING_DIR` | `/home/example/another-app` |
| `SOURCE_ROOT_DIR` | `/home/example/another-app` |
| `FRAMEWORK_ROOT_DIR` | `/home/example/another-app/vendor/crazywhalecc/static-php-cli` |
| `__DIR__` | `/home/example/another-app/vendor/crazywhalecc/static-php-cli/src/App` |
| `__FILE__` | `/home/example/another-app/vendor/crazywhalecc/static-php-cli/src/App/MyCommand.php` |
Here `SOURCE_ROOT_DIR` refers to the root directory of the project using `static-php-cli`.
### Git project Phar mode (source-phar)
Git project Phar mode refers to the mode of packaging the project directory of the Git project mode into a `phar` file. We assume that `/home/example/static-php-cli` will be packaged into a Phar file, and the directory has the following files:
```
composer.json
src/App/MyCommand.app
vendor/*
bin/entry.php
```
When packaged into `app.phar` and stored in the `/home/example/static-php-cli` directory, `app.phar` is executed at this time. Assuming that the `src/App/MyCommand` code is executed, the constant is obtained in the file:
| Constant | Value |
|----------------------|----------------------------------------------------------------------|
| `WORKING_DIR` | `/home/example/static-php-cli` |
| `SOURCE_ROOT_DIR` | `phar:///home/example/static-php-cli/app.phar/` |
| `FRAMEWORK_ROOT_DIR` | `phar:///home/example/static-php-cli/app.phar/` |
| `__DIR__` | `phar:///home/example/static-php-cli/app.phar/src/App` |
| `__FILE__` | `phar:///home/example/static-php-cli/app.phar/src/App/MyCommand.php` |
Because the `phar://` protocol is required to read files in the phar itself, the project root directory and the framework directory will be different from `WORKING_DIR`.
### Vendor Library Phar Mode (vendor-phar)
Vendor Library Phar Mode means that your project is installed as a framework in other projects and stored in the `vendor` directory.
We assume that your project directory structure is as follows:
```
composer.json # Composer configuration file of the current project
box.json # Configuration file for packaging Phar
another-app.php # Entry file of another project
vendor/crazywhalecc/static-php-cli/* # Your project is used as a dependent library
```
When packaging these files under the directory `/home/example/another-app/` into `app.phar`, the value of the following constant for your project should be:
| Constant | Value |
|----------------------|------------------------------------------------------------------------------------------------------|
| `WORKING_DIR` | `/home/example/another-app` |
| `SOURCE_ROOT_DIR` | `phar:///home/example/another-app/app.phar/` |
| `FRAMEWORK_ROOT_DIR` | `phar:///home/example/another-app/app.phar/vendor/crazywhalecc/static-php-cli` |
| `__DIR__` | `phar:///home/example/another-app/app.phar/vendor/crazywhalecc/static-php-cli/src/App` |
| `__FILE__` | `phar:///home/example/another-app/app.phar/vendor/crazywhalecc/static-php-cli/src/App/MyCommand.php` |
<!-- TODO: v3 directory layout (bin/, config/pkg/, src/StaticPHP/, src/Package/, etc.).
Explain the role of each top-level directory. Internal class structure kept brief;
deep dives belong in the Concepts pages. -->

View File

@@ -1,242 +1,4 @@
# Compilation Tools
static-php-cli uses many system compilation tools when building static PHP. These tools mainly include:
- `autoconf`: used to generate `configure` scripts.
- `make`: used to execute `Makefile`.
- `cmake`: used to execute `CMakeLists.txt`.
- `pkg-config`: Used to find the installation path of dependent libraries.
- `gcc`: used to compile C/C++ projects under Linux.
- `clang`: used to compile C/C++ projects under macOS.
For Linux and macOS operating systems,
these tools can usually be installed through the package manager, which is written in the doctor module.
Theoretically we can also compile and download these tools manually,
but this will increase the complexity of compilation, so we do not recommend this.
## Linux Compilation Tools
For Linux systems, different distributions have different installation methods for compilation tools.
And for static compilation, the package management of some distributions cannot install libraries and tools for pure static compilation.
Therefore, for the Linux platform and its different distributions,
we currently provide a variety of compilation environment preparations.
### Glibc Environment
The glibc environment refers to the underlying `libc` library of the system
(that is, the C standard library that all programs written in C language are dynamically linked to) uses `glibc`,
which is the default environment for most distributions.
For example: Ubuntu, Debian, CentOS, RHEL, openSUSE, Arch Linux, etc.
In the glibc environment, the package management and compiler we use point to glibc by default,
and glibc cannot be statically linked well.
One of the reasons it cannot be statically linked is that its network library `nss` cannot be compiled statically.
For the glibc environment, in static-php-cli and spc in 2.0-RC8 and later, you can choose two ways to build static PHP:
1. Use Docker to build, you can use `bin/spc-alpine-docker` to build, it will build an Alpine Linux docker image.
2. Use `bin/spc doctor --auto-fix` to install the `musl-wrapper` and `musl-cross-make` packages, and then build directly.
([Related source code](https://github.com/crazywhalecc/static-php-cli/blob/main/src/SPC/doctor/item/LinuxMuslCheck.php))
Generally speaking, the build results in these two environments are consistent, and you can choose according to actual needs.
In the doctor module, static-php-cli will first detect the current Linux distribution.
If the current distribution is a glibc environment, you will be prompted to install the musl-wrapper and musl-cross-make packages.
The process of installing `musl-wrapper` in the glibc environment is as follows:
1. Download the specific version of [musl-wrapper source code](https://musl.libc.org/releases/) from the musl official website.
2. Use `gcc` installed from the package management to compile the musl-wrapper source code and generate `musl-libc` and other libraries: `./configure --disable-gcc-wrapper && make -j && sudo make install`.
3. The musl-wrapper related libraries will be installed in the `/usr/local/musl` directory.
The process of installing `musl-cross-make` in the glibc environment is as follows:
1. Download the precompiled [musl-cross-make](https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/) compressed package from dl.static-php.dev .
2. Unzip to the `/usr/local/musl` directory.
::: tip
In the glibc environment, static compilation can be achieved by directly installing musl-wrapper,
but musl-wrapper only contains `musl-gcc` and not `musl-g++`, which means that C++ code cannot be compiled.
So we need musl-cross-make to provide `musl-g++`.
The reason why the musl-cross-make package cannot be compiled directly locally is that
its compilation environment requirements are relatively high (requires more than 36GB of memory, compiled under Alpine Linux),
so we provide precompiled binary packages that can be used for all Linux distributions.
At the same time, the package management of some distributions provides musl-wrapper,
but musl-cross-make needs to match the corresponding musl-wrapper version,
so we do not use package management to install musl-wrapper.
Compiling musl-cross-make will be introduced in the **musl-cross-make Toolchain Compilation** section of this chapter.
:::
### Musl Environment
The musl environment refers to the system's underlying `libc` library that uses `musl`,
which is a lightweight C standard library that can be well statically linked.
For the currently popular Linux distributions, Alpine Linux uses the musl environment,
so static-php-cli can directly build static PHP under Alpine Linux.
You only need to install basic compilation tools (such as `gcc`, `cmake`, etc.) directly from the package management.
For other distributions, if your distribution uses the musl environment,
you can also use static-php-cli to build static PHP directly after installing the necessary compilation tools.
::: tip
In the musl environment, static-php-cli will automatically skip the installation of musl-wrapper and musl-cross-make.
:::
### Docker Environment
The Docker environment refers to using Docker containers to build static PHP. You can use `bin/spc-alpine-docker` to build.
Before executing this command, you need to install Docker first, and then execute `bin/spc-alpine-docker` in the project root directory.
After executing `bin/spc-alpine-docker`, static-php-cli will automatically download the Alpine Linux image and then build a `cwcc-spc-x86_64` or `cwcc-spc-aarch64` image.
Then all build process is performed within this image, which is equivalent to compiling in Alpine Linux.
## musl-cross-make Toolchain Compilation
In Linux, although you do not need to manually compile the musl-cross-make tool,
if you want to understand its compilation process, you can refer here.
Another important reason is that this may not be compiled using automated tools such as CI and Actions,
because the existing CI service compilation environment does not meet the compilation requirements of musl-cross-make,
and the configuration that meets the requirements is too expensive.
The compilation process of musl-cross-make is as follows:
Prepare an Alpine Linux environment (either directly installed or using Docker).
The compilation process requires more than **36GB** of memory,
so you need to compile on a machine with larger memory.
Without this much memory, compilation may fail.
Then write the following content into the `config.mak` file:
```makefile
STAT = -static --static
FLAG = -g0 -Os -Wno-error
ifneq ($(NATIVE),)
COMMON_CONFIG += CC="$(HOST)-gcc ${STAT}" CXX="$(HOST)-g++ ${STAT}"
else
COMMON_CONFIG += CC="gcc ${STAT}" CXX="g++ ${STAT}"
endif
COMMON_CONFIG += CFLAGS="${FLAG}" CXXFLAGS="${FLAG}" LDFLAGS="${STAT}"
BINUTILS_CONFIG += --enable-gold=yes --enable-gprofng=no
GCC_CONFIG += --enable-static-pie --disable-cet --enable-default-pie
#--enable-default-pie
CONFIG_SUB_REV = 888c8e3d5f7b
GCC_VER = 13.2.0
BINUTILS_VER = 2.40
MUSL_VER = 1.2.4
GMP_VER = 6.2.1
MPC_VER = 1.2.1
MPFR_VER = 4.2.0
LINUX_VER = 6.1.36
```
And also you need to add `gcc-13.2.0.tar.xz.sha1` file, contents here:
```
5f95b6d042fb37d45c6cbebfc91decfbc4fb493c gcc-13.2.0.tar.xz
```
If you are using Docker to build, create a new `Dockerfile` file and write the following content:
```dockerfile
FROM alpine:edge
RUN apk add --no-cache \
gcc g++ git make curl perl \
rsync patch wget libtool \
texinfo autoconf automake \
bison tar xz bzip2 zlib \
file binutils flex \
linux-headers libintl \
gettext gettext-dev icu-libs pkgconf \
pkgconfig icu-dev bash \
ccache libarchive-tools zip
WORKDIR /opt
RUN git clone https://git.zv.io/toolchains/musl-cross-make.git
WORKDIR /opt/musl-cross-make
COPY config.mak /opt/musl-cross-make
COPY gcc-13.2.0.tar.xz.sha1 /opt/musl-cross-make/hashes
RUN make TARGET=x86_64-linux-musl -j || :
RUN sed -i 's/poison calloc/poison/g' ./gcc-13.2.0/gcc/system.h
RUN make TARGET=x86_64-linux-musl -j
RUN make TARGET=x86_64-linux-musl install -j
RUN tar cvzf x86_64-musl-toolchain.tgz output/*
```
If you are using Alpine Linux in a non-Docker environment, you can directly execute the commands in the Dockerfile, for example:
```bash
apk add --no-cache \
gcc g++ git make curl perl \
rsync patch wget libtool \
texinfo autoconf automake \
bison tar xz bzip2 zlib \
file binutils flex \
linux-headers libintl \
gettext gettext-dev icu-libs pkgconf \
pkgconfig icu-dev bash \
ccache libarchive-tools zip
git clone https://git.zv.io/toolchains/musl-cross-make.git
# Copy config.mak to the working directory of musl-cross-make.
# You need to replace /path/to/config.mak with your config.mak file path.
cp /path/to/config.mak musl-cross-make/
cp /path/to/gcc-13.2.0.tar.xz.sha1 musl-cross-make/hashes
make TARGET=x86_64-linux-musl -j || :
sed -i 's/poison calloc/poison/g' ./gcc-13.2.0/gcc/system.h
make TARGET=x86_64-linux-musl -j
make TARGET=x86_64-linux-musl install -j
tar cvzf x86_64-musl-toolchain.tgz output/*
```
::: tip
All the above scripts are suitable for x86_64 architecture Linux.
If you need to build musl-cross-make for the ARM environment, just replace all `x86_64` above with `aarch64`.
:::
This compilation process may fail due to insufficient memory, network problems, etc.
You can try a few more times, or use a machine with larger memory to compile.
If you encounter problems or you have better improvement solutions, go to [Discussion](https://github.com/crazywhalecc/static-php-cli-hosted/issues/1).
## macOS Environment
For macOS systems, the main compilation tool we use is `clang`,
which is the default compiler for macOS systems and is also the compiler of Xcode.
Compiling under macOS mainly relies on Xcode or Xcode Command Line Tools.
You can download Xcode from the App Store,
or execute `xcode-select --install` in the terminal to install Xcode Command Line Tools.
In addition, in the `doctor` environment check module, static-php-cli will check whether Homebrew,
compilation tools, etc. are installed on the macOS system.
If not, you will be prompted to install them. I will not go into details here.
## FreeBSD Environment
FreeBSD is also a Unix system, and its compilation tools are similar to macOS.
You can directly use the package management `pkg` to install `clang` and other compilation tools through the `doctor` command.
## pkg-config Compilation (*nix only)
If you observe the compilation log when using static-php-cli to build static PHP, you will find that no matter what is compiled,
`pkg-config` will be compiled first. This is because `pkg-config` is a library used to find dependencies.
In earlier versions of static-php-cli, we directly used the `pkg-config` tool installed by package management,
but this would cause some problems, such as:
- Even if `PKG_CONFIG_PATH` is specified, `pkg-config` will try to find dependent packages from the system path.
- Since `pkg-config` will look for dependent packages from the system path,
if a dependent package with the same name exists in the system, compilation may fail.
In order to avoid the above problems, we compile `pkg-config` into `buildroot/bin` in user mode and use it.
We use parameters such as `--without-sysroot` to avoid looking for dependent packages from the system path.
<!-- TODO: Migrate and update from v2 system-build-tools.md.
Cover v3 additions: WindowsCMakeExecutor, vswhere.exe detection, LLVM/Clang for FrankenPHP. -->

View File

@@ -0,0 +1,6 @@
# Annotations Reference
<!-- TODO: Complete reference for all v3 PHP attributes.
#[Library], #[Extension], #[BuildFor], #[BeforeStage], #[AfterStage],
#[PatchBeforeBuild], #[CustomPhpConfigureArg], #[AsCheckItem], #[AsFixItem].
Per-attribute: parameters, types, allowed targets, example. -->

View File

@@ -0,0 +1,6 @@
# Dependency Injection
<!-- TODO: How PHP-DI autowiring works in v3.
ApplicationContext::get() usage.
Registering custom services.
Injecting into command classes, build classes, and stage methods. -->

View File

@@ -0,0 +1,6 @@
# Vendor Mode
<!-- TODO: What vendor mode is and when to use it.
Installation: `composer require crazywhalecc/static-php-cli`.
How to register an external registry pointing to your custom package classes.
Minimal working example: one Library class, one config YAML, run spc. -->

View File

@@ -0,0 +1,6 @@
# Lifecycle Hooks
<!-- TODO: Detailed explanation of hook execution order and method signatures.
#[BeforeStage('lib-name', 'build')], #[AfterStage(...)], #[PatchBeforeBuild].
How hooks from different packages are merged and ordered.
Common patterns: patching config.m4, injecting compile flags, post-install fixups. -->

View File

@@ -0,0 +1,6 @@
# Writing Package Classes
<!-- TODO: Step-by-step guide to writing a Library class and an Extension class.
Full annotated code examples using #[Library], #[Extension], #[BuildFor].
UnixAutoconfExecutor / UnixCmakeExecutor / WindowsCMakeExecutor usage.
File placement (src/Package/Library/, src/Package/Extension/) and autoloading. -->

View File

@@ -1,108 +1,10 @@
# FAQ
# Frequently Asked Questions
Here will be some questions that you may encounter easily. There are currently many, but I need to take time to organize them.
## What is the path of php.ini ?
On Linux, macOS and FreeBSD, the path of `php.ini` is `/usr/local/etc/php/php.ini`.
On Windows, the path is `C:\windows\php.ini` or the current directory of `php.exe`.
The directory where to look for `php.ini` can be changed on *nix using the manual build option `--with-config-file-path`.
In addition, on Linux, macOS and FreeBSD, `.ini` files present in the `/usr/local/etc/php/conf.d` directory will also be loaded.
On Windows, this path is empty by default.
The directory can be changed using the manual build option `--with-config-file-scan-dir`.
`php.ini` will also be searched for in [the other standard locations](https://www.php.net/manual/configuration.file.php).
## Can statically-compiled PHP install extensions?
Because the principle of installing PHP extensions under the normal mode is to use `.so` type dynamic link library to install new extensions,
and we use the static link PHP compiled by this project. However, static linking has different definitions in different operating systems.
First of all, for Linux systems, statically linked binaries will not link the system's dynamic link library.
Purely statically linked binaries (`build with -all-static`) cannot load dynamic libraries, so new extensions cannot be added.
At the same time, in pure static mode, you cannot use extensions such as `ffi` to load external `.so` modules.
You can use the command `ldd buildroot/bin/php` to check whether the binary you built under Linux is purely statically linked.
If you [build GNU libc based PHP](../guide/build-with-glibc), you can use the `ffi` extension to load external `.so` modules and load `.so` extensions with the same ABI.
For example, you can use the following command to build a static PHP binary dynamically linked with glibc,
supporting FFI extensions and loading the `xdebug.so` extension of the same PHP version and the same TS type:
```bash
bin/spc-gnu-docker download --for-extensions=ffi,xml --with-php=8.4
bin/spc-gnu-docker build ffi,xml --build-cli --debug
buildroot/bin/php -d "zend_extension=/path/to/php{PHP_VER}-{ts/nts}/xdebug.so" --ri xdebug
```
For macOS platform, almost all binaries under macOS cannot be truly purely statically linked, and almost all binaries will link macOS system libraries: `/usr/lib/libresolv.9.dylib` and `/usr/lib/libSystem.B.dylib`.
So on macOS, you can **directly** use SPC to build statically compiled PHP binaries with dynamically linked extensions:
1. Build shared extension `xxx.so` using: `--build-shared=XXX` option. e.g. `bin/spc build bcmath,zlib --build-shared=xdebug --build-cli`
2. You will get `buildroot/modules/xdebug.so` and `buildroot/bin/php`.
3. The `xdebug.so` file could be used for php that version and thread-safe are the same.
For the Windows platform, since officially built extensions (such as `php_yaml.dll`) force the use of the `php8.dll` dynamic library as a link, and statically built PHP does not include any dynamic libraries other than system libraries,
php.exe built by static-php cannot load officially built dynamic extensions. Since static-php-cli does not yet support building dynamic extensions, there is currently no way to load dynamic extensions with static-php.
However, Windows can normally use the `FFI` extension to load other dll files and call them.
## Can it support Oracle database extension?
Some extensions that rely on closed source libraries, such as `oci8`, `sourceguardian`, etc.,
they do not provide purely statically compiled dependent library files (`.a`), only dynamic dependent library files (`.so`).
These extensions cannot be compiled into static-php-cli using source code, so this project may never support these extensions.
However, in theory you can access and use such extensions under macOS and Linux according to the above questions.
If you have a need for such extensions, or most people have needs for these closed-source extensions,
see the discussion on [standalone-php-cli](https://github.com/crazywhalecc/static-php-cli/discussions/58). Welcome to leave a message.
## Does it support Windows?
The project currently supports Windows, but the number of supported extensions is small. Windows support is not perfect. There are mainly the following problems:
1. The compilation process of Windows is different from that of *nix, and the toolchain used is also different. The compilation tools used to compile the dependent libraries of each extension are almost completely different.
2. The demand for the Windows version will also be advanced based on the needs of all people who use this project. If many people need it, I will support related extensions as soon as possible.
## Can I protect my source code with micro?
You can't. micro.sfx is essentially combining php and php code into one file,
there is no process of compiling or encrypting the PHP code.
First of all, php-src is the official interpreter of PHP code, and there is no PHP compiler compatible with mainstream branches on the market.
I saw on the Internet that there is a project called BPC (Binary PHP Compiler?) that can compile PHP into binary,
but there are many restrictions.
The direction of encrypting and protecting the code is not the same as compiling.
After compiling, the code can also be obtained through reverse engineering and other methods.
The real protection is still carried out by means of packing and encrypting the code.
Therefore, this project (static-php-cli) and related projects (lwmbs, swoole-cli) all provide a convenient compilation tool for php-src source code.
The phpmicro referenced by this project and related projects is only a package of PHP's sapi interface, not a compilation tool for PHP code.
The compiler for PHP code is a completely different project, so the extra cases are not taken into account.
If you are interested in encryption, you can consider using existing encryption technologies,
such as Swoole Compiler, Source Guardian, etc.
## Unable to use ssl
**Update: This issue has been fixed in the latest version of static-php-cli, which now reads the system's certificate file by default. If you still have problems, try the solution below.**
When using curl, pgsql, etc. to request an HTTPS website or establish an SSL connection, there may be an `error:80000002:system library::No such file or directory` error.
This error is caused by statically compiled PHP without specifying `openssl.cafile` via `php.ini`.
You can solve this problem by specifying `php.ini` before using PHP and adding `openssl.cafile=/path/to/your-cert.pem` in the INI.
For Linux systems, you can download the [cacert.pem](https://curl.se/docs/caextract.html) file from the curl official website, or you can use the certificate file that comes with the system.
For the certificate locations of different distros, please refer to [Golang docs](https://go.dev/src/crypto/x509/root_linux.go).
> INI configuration `openssl.cafile` cannot be set dynamically using the `ini_set()` function, because `openssl.cafile` is a `PHP_INI_SYSTEM` type configuration and can only be set in the `php.ini` file.
## Why don't we support older versions of PHP?
Because older versions of PHP have many problems, such as security issues, performance issues, and functional issues.
In addition, many older versions of PHP are not compatible with the latest dependency libraries,
which is one of the reasons why older versions of PHP are not supported.
You can use older versions compiled earlier by static-php-cli, such as PHP 8.0, but earlier versions will not be explicitly supported.
<!-- TODO: Categorized FAQ.
Sections:
- Build Issues (common compile errors, missing tools)
- Extensions (dynamic loading, closed-source deps, oci8)
- Windows (icon embedding, DLL loading, FFI)
- Version Compatibility (PHP versions, glibc vs musl)
- Source Protection (micro, encryption)
Migrate and expand from v2 faq/index.md. -->

View File

@@ -2,15 +2,6 @@
aside: false
---
<script setup lang="ts">
import CliGenerator from "../../.vitepress/components/CliGenerator.vue";
</script>
# Build Command Generator
# CLI Build Command Generator
::: tip
The extensions selected below may contain extensions that are not supported by the selected operating system,
which may cause compilation to fail. Please check [Supported Extensions](./extensions) first.
:::
<cli-generator lang="en" />
<!-- TODO: Embed CliGenerator Vue component. -->

View File

@@ -0,0 +1,6 @@
# CLI Reference
<!-- TODO: Full reference for every spc command and option.
One ## section per command: download, build, craft, doctor, check-update, dev:*.
Each option: type, default, description, example.
Covers platform-specific options (e.g., --embed-icon on Windows). -->

View File

@@ -1,26 +1,4 @@
---
outline: 'deep'
---
# Dependency Table
When compiling PHP, each extension and library has dependencies, which may be required or optional.
You can choose whether to include these optional dependencies.
For example, when compiling the `gd` extension under Linux,
the `zlib,libpng` libraries and the `zlib` extension are forced to be compiled,
while the `libavif,libwebp,libjpeg,freetype` libraries are optional libraries and will not be compiled by default
unless specified by the `--with-libs=avif,webp,jpeg,freetype` option.
- For optional extensions (optional features of extensions), you need to specify them manually at compile time, for example, to enable igbinary support for Redis: `bin/spc build redis,igbinary`.
- For optional libraries, you need to compile and specify them through the `--with-libs=XXX` option.
- If you want to enable all optional extensions, you can use `bin/spc build redis --with-suggested-exts`.
- If you want to enable all optional libraries, you can use `--with-suggested-libs`.
## Extension Dependency Table
<!--@include: ../../deps-map-ext.md-->
## Library Dependency Table
<!--@include: ../../deps-map-lib.md-->
<!-- TODO: Auto-generated by `bin/spc dev:gen-ext-dep-docs` and `dev:gen-lib-dep-docs`.
Placeholder until commands are implemented in v3. -->

View File

@@ -1,121 +1,4 @@
# Environment variables
# Environment Variables
All environment variables mentioned in the list on this page have default values unless otherwise noted.
You can override the default values by setting these environment variables.
## Environment variables list
Starting from version 2.3.5, we have centralized the environment variables in the `config/env.ini` file.
You can set environment variables by modifying this file.
We divide the environment variables supported by static-php-cli into three types:
- Global internal environment variables: declared after static-php-cli starts, you can use `getenv()` to get them internally in static-php-cli, and you can override them before starting static-php-cli.
- Fixed environment variables: declared after static-php-cli starts, you can only use `getenv()` to get them, but you cannot override them through shell scripts.
- Config file environment variables: declared before static-php-cli build, you can set these environment variables by modifying the `config/env.ini` file or through shell scripts.
You can read the comments for each parameter in [config/env.ini](https://github.com/crazywhalecc/static-php-cli/blob/main/config/env.ini) to understand its purpose.
## Custom environment variables
Generally, you don't need to modify any of the following environment variables as they are already set to optimal values.
However, if you have special needs, you can set these environment variables to meet your needs
(for example, you need to debug PHP performance under different compilation parameters).
If you want to use custom environment variables, you can use the `export` command in the terminal or set the environment variables directly before the command, for example:
```shell
# export first
export SPC_CONCURRENCY=4
bin/spc build mbstring,pcntl --build-cli
# or direct use
SPC_CONCURRENCY=4 bin/spc build mbstring,pcntl --build-cli
```
Or, if you need to modify an environment variable for a long time, you can modify the `config/env.ini` file.
`config/env.ini` is divided into three sections, `[global]` is globally effective, `[windows]`, `[macos]`, `[linux]` are only effective for the corresponding operating system.
For example, if you need to modify the `./configure` command for compiling PHP, you can find the `SPC_CMD_PREFIX_PHP_CONFIGURE` environment variable in the `config/env.ini` file, and then modify its value.
If your build conditions are more complex and require multiple `env.ini` files to switch,
we recommend that you use the `config/env.custom.ini` file.
In this way, you can specify your environment variables by writing additional override items
without modifying the default `config/env.ini` file.
```ini
; This is an example of `config/env.custom.ini` file,
; we modify the `SPC_CONCURRENCY` and linux default CFLAGS passing to libs and PHP
[global]
SPC_CONCURRENCY=4
[linux]
SPC_DEFAULT_C_FLAGS="-O3"
```
## Library environment variables (Unix only)
Starting from 2.2.0, static-php-cli supports custom environment variables for all compilation dependent library commands of macOS, Linux, FreeBSD and other Unix systems.
In this way, you can adjust the behavior of compiling dependent libraries through environment variables at any time.
For example, you can set the optimization parameters for compiling the xxx library through `xxx_CFLAGS=-O0`.
Of course, not every library supports the injection of environment variables.
We currently provide three wildcard environment variables with the suffixes:
- `_CFLAGS`: CFLAGS for the compiler
- `_LDFLAGS`: LDFLAGS for the linker
- `_LIBS`: LIBS for the linker
The prefix is the name of the dependent library, and the specific name of the library is subject to `lib.json`.
Among them, the library name with `-` needs to replace `-` with `_`.
Here is an example of an optimization option that replaces the openssl library compilation:
```shell
openssl_CFLAGS="-O0"
```
The library name uses the same name listed in `lib.json` and is case-sensitive.
::: tip
When no relevant environment variables are specified, except for the following variables, the remaining values are empty by default:
| var name | var default value |
|-----------------------|-------------------------------------------------------------------------------------------------|
| `pkg_config_CFLAGS` | macOS: `$SPC_DEFAULT_C_FLAGS -Wimplicit-function-declaration -Wno-int-conversion`, Other: empty |
| `pkg_config_LDFLAGS` | Linux: `--static`, Other: empty |
| `imagemagick_LDFLAGS` | Linux: `-static`, Other: empty |
| `imagemagick_LIBS` | macOS: `-liconv`, Other: empty |
| `ldap_LDFLAGS` | `-L$BUILD_LIB_PATH` |
| `openssl_CFLAGS` | Linux: `$SPC_DEFAULT_C_FLAGS`, Other: empty |
| others... | empty |
:::
The following table is a list of library names that support customizing the above three variables:
| lib name |
|-------------|
| brotli |
| bzip |
| curl |
| freetype |
| gettext |
| gmp |
| imagemagick |
| ldap |
| libargon2 |
| libavif |
| libcares |
| libevent |
| openssl |
::: tip
Because adapting custom environment variables to each library is a particularly tedious task,
and in most cases you do not need custom environment variables for these libraries,
so we currently only support custom environment variables for some libraries.
If the library you need to customize environment variables is not listed above,
you can submit your request through [GitHub Issue](https://github.com/crazywhalecc/static-php-cli/issues).
:::
<!-- TODO: Full table of all env vars supported by config/env.ini and config/env.custom.ini.
Migrate and update from v2 env-vars.md. -->

View File

@@ -1,168 +1,3 @@
# Extension Notes
Because it is a static compilation, extensions will not compile 100% perfectly,
and different extensions have different requirements for PHP and the environment,
which will be listed one by one here.
## curl
HTTP3 support is not enabled by default, compile with `--with-libs="nghttp2,nghttp3,ngtcp2"` to enable HTTP3 support for PHP >= 8.4.
When using curl to request HTTPS, there may be an `error:80000002:system library::No such file or directory` error.
For details on the solution, see [FAQ - Unable to use ssl](../faq/#unable-to-use-ssl).
## phpmicro
1. Only PHP >= 8.0 is supported.
## swoole
1. swoole >= 5.0 Only PHP >= 8.0 is supported.
2. swoole Currently, curl hooks are not supported for PHP 8.0.x (which may be fixed in the future).
3. When compiling, if only `swoole` extension is included, the supported Swoole database coroutine hook will not be fully enabled.
If you need to use it, please add the corresponding `swoole-hook-xxx` extension.
4. The `zend_mm_heap corrupted` problem may occur in swoole under some extension combinations. The cause has not yet been found.
## swoole-hook-pgsql
swoole-hook-pgsql is not an extension, it's a Hook feature of Swoole.
If you use `swoole,swoole-hook-pgsql`, you will enable Swoole's PostgreSQL client and the coroutine mode of the `pdo_pgsql` extension.
swoole-hook-pgsql conflicts with the `pdo_pgsql` extension. If you want to use Swoole and `pdo_pgsql`, please delete the pdo_pgsql extension and enable `swoole` and `swoole-hook-pgsql`.
This extension contains an implementation of the coroutine environment for `pdo_pgsql`.
On macOS systems, `pdo_pgsql` may not be able to connect to the postgresql server normally, please use it with caution.
## swoole-hook-mysql
swoole-hook-mysql is not an extension, it's a Hook feature of Swoole.
If you use `swoole,swoole-hook-mysql`, you will enable the coroutine mode of Swoole's `mysqlnd` and `pdo_mysql`.
## swoole-hook-sqlite
swoole-hook-sqlite is not an extension, it's a Hook feature of Swoole.
If you use `swoole,swoole-hook-sqlite`, you will enable the coroutine mode of Swoole's `pdo_sqlite` (Swoole must be 5.1 or above).
swoole-hook-sqlite conflicts with the `pdo_sqlite` extension. If you want to use Swoole and `pdo_sqlite`, please delete the pdo_sqlite extension and enable `swoole` and `swoole-hook-sqlite`.
This extension contains an implementation of the coroutine environment for `pdo_sqlite`.
## swoole-hook-odbc
swoole-hook-odbc is not an extension, it's a Hook feature of Swoole.
If you use `swoole,swoole-hook-odbc`, you will enable the coroutine mode of Swoole's `odbc` extension.
swoole-hook-odbc conflicts with the `pdo_odbc` extension. If you want to use Swoole and `pdo_odbc`, please delete the `pdo_odbc` extension and enable `swoole` and `swoole-hook-odbc`.
This extension contains an implementation of the coroutine environment for `pdo_odbc`.
## swow
1. Only PHP 8.0+ is supported.
## imagick
1. OpenMP support is disabled, this is recommended by the maintainers and also the case system packages.
## imap
1. Kerberos is not supported
2. ext-imap is not thread safe due to the underlying c-client. It's not possible to use it in `--enable-zts` builds.
3. The extension was dropped from php 8.4, we recommend you look for an alternative implementation, such as [Webklex/php-imap](https://github.com/Webklex/php-imap)
## gd
1. gd Extension relies on more additional Graphics library. By default,
using `bin/spc build gd` directly will not support some Graphics library, such as `libjpeg`, `libavif`, etc.
Currently, it supports four libraries: `freetype,libjpeg,libavif,libwebp`.
Therefore, the following command can be used to introduce them into the gd library:
```bash
bin/spc build gd --with-libs=freetype,libjpeg,libavif,libwebp --build-cli
```
## mcrypt
1. Currently not supported, and this extension will not be supported in the future. [#32](https://github.com/crazywhalecc/static-php-cli/issues/32)
## oci8
1. oci8 is an extension of the Oracle database, because the library on which the extension provided by Oracle does not provide a statically compiled version (`.a`) or source code,
and this extension cannot be compiled into php by static linking, so it cannot be supported.
## xdebug
1. Xdebug is only buildable as a shared extension. On Linux, you'll need to use a SPC_TARGET like `native-native -dynamic` or `native-native-gnu`.
2. When using Linux/glibc or macOS, you can compile Xdebug as a shared extension using --build-shared="xdebug".
The compiled `./php` binary can be configured and run by specifying the INI, eg `./php -d 'zend_extension=/path/to/xdebug.so' your-code.php`.
## xml
1. xml includes xml, xmlreader, xmlwriter, xsl, dom, simplexml, etc.
When adding xml extensions, it is best to enable these extensions at the same time.
2. libxml is included in xml extension. Enabling xml is equivalent to enabling libxml.
## glfw
1. glfw depends on OpenGL, and linux environment also needs X11, which cannot be linked statically.
2. macOS platform, we can compile and link system builtin OpenGL and related libraries dynamically.
## rar
1. The rar extension currently has a problem when compiling phpmicro with the `common` extension collection in the macOS x86_64 environment.
## pgsql
~~pgsql ssl connection is not compatible with openssl 3.2.0. See:~~
- ~~<https://github.com/Homebrew/homebrew-core/issues/155651>~~
- ~~<https://github.com/Homebrew/homebrew-core/pull/155699>~~
- ~~<https://github.com/postgres/postgres/commit/c82207a548db47623a2bfa2447babdaa630302b9>~~
pgsql 16.2 has fixed this bug, now it's working.
When pgsql uses SSL connection, there may be `error:80000002:system library::No such file or directory` error,
For details on the solution, see [FAQ - Unable to use ssl](../faq/#unable-to-use-ssl).
## openssl
When using openssl-based extensions (such as curl, pgsql and other network libraries),
there may be an `error:80000002:system library::No such file or directory` error.
For details on the solution, see [FAQ - Unable to use ssl](../faq/#unable-to-use-ssl).
## password-argon2
1. password-argon2 is not a standard extension. The algorithm `PASSWORD_ARGON2ID` for the `password_hash` function needs libsodium or libargon2 to work.
2. using password-argon2 enables multithread support for this.
## ffi
1. Due to the limitation of musl libc's static linkage, you cannot use ffi because dynamic libraries cannot be loaded.
If you need to use the ffi extension, see [Compile PHP with GNU libc](./build-with-glibc).
2. macOS supports the ffi extension, but errors will occur when some kernels do not contain debugging symbols.
3. Windows x64 supports the ffi extension.
## xhprof
The xhprof extension consists of three parts: `xhprof_extension`, `xhprof_html`, `xhprof_libs`.
Only `xhprof_extension` is included in the compiled binary.
If you need to use xhprof,
please download the source code from [pecl.php.net/package/xhprof](http://pecl.php.net/package/xhprof) and specify the `xhprof_libs` and `xhprof_html` paths for use.
## event
If you enable event extension on macOS, the `openpty` will be disabled due to issue:
- [static-php-cli#335](https://github.com/crazywhalecc/static-php-cli/issues/335)
## parallel
Parallel is only supported on PHP 8.0 ZTS and above.
## spx
1. SPX does not support Windows, and the official repository does not support static compilation. static-php-cli uses a [modified version](https://github.com/static-php/php-spx).
## mimalloc
1. This is not technically an extension, but a library.
2. Building with `--with-libs="mimalloc"` on Linux or macOS will override the default allocator.
3. This is experimental for now, but is recommended in threaded environments.
<!-- TODO: Migrate and update from v2 extension-notes.md. Per-extension special compilation notes. -->

View File

@@ -1,23 +1,3 @@
<script setup>
import SearchTable from "../../.vitepress/components/SearchTable.vue";
</script>
# Supported Extensions
# Extensions
> - `yes`: supported
> - _blank_: not supported yet, or WIP
> - `no` with issue link: confirmed to be unavailable due to issue
> - `partial` with issue link: supported but not perfect due to issue
<search-table />
::: tip
If an extension you need is missing, you can create a [Feature Request](https://github.com/crazywhalecc/static-php-cli/issues).
Some extensions or libraries that the extension depends on will have some optional features.
For example, the gd library optionally supports libwebp, freetype, etc.
If you only use `bin/spc build gd --build-cli` they will not be included (static-php-cli defaults to the minimum dependency principle).
For more information about optional libraries, see [Extensions, Library Dependency Map](./deps-map).
For optional libraries, you can also select an extension from the [Command Generator](./cli-generator) and then select optional libraries.
:::
<!-- TODO: Auto-generated by `bin/spc dev:gen-ext-docs`. Placeholder until command is implemented in v3. -->

View File

@@ -0,0 +1,190 @@
# Your First Build
This page walks you through building a static PHP binary from scratch, end to end.
::: tip
If you installed spc as a pre-built binary, replace every `spc` in this page with `./spc` (or `.\spc.exe` on Windows).
If you installed from source, use `bin/spc` instead.
:::
## Two Approaches
StaticPHP supports two build workflows — pick the one that fits your situation:
| Approach | When to use |
|---|---|
| `craft` (one-shot) | Everyday use, getting started quickly |
| Step-by-step | CI/CD pipelines, when you need to separate download and build phases |
## Option 1: One-Shot Build with `craft` (Recommended)
The `craft` command reads a `craft.yml` file and handles everything automatically — downloading dependencies, compiling libraries, and building PHP — in a single run.
### Write craft.yml
Create a `craft.yml` in your working directory and declare the PHP version, extensions, and target SAPIs:
```yaml
php-version: 8.4
extensions: bcmath,posix,phar,zlib,openssl,curl,fileinfo,tokenizer
sapi:
- cli
- micro
```
Not sure which extensions you need? Use the [command generator](./cli-generator) to produce a `craft.yml` automatically.
### Run the Build
```bash
spc craft
```
The build pipeline runs in order: download dependencies → compile libraries → compile PHP. No interaction required.
To see more detail, pass `-v`, `-vv`, or `-vvv`:
```bash
spc craft -v
```
### Inspect the Output
On success, binaries land in `buildroot/bin/`:
| SAPI | Output path |
|---|---|
| cli | `buildroot/bin/php` (Windows: `buildroot/bin/php.exe`) |
| fpm | `buildroot/bin/php-fpm` |
| micro | `buildroot/bin/micro.sfx` |
| embed | `buildroot/lib/libphp.a` |
| frankenphp | `buildroot/bin/frankenphp` |
Give the CLI binary a quick smoke-test:
```bash
./buildroot/bin/php -v
./buildroot/bin/php -m
```
## Option 2: Step-by-Step Build
This approach lets you run download and compile as separate steps — useful when you want to cache downloads in CI and reuse them across builds.
### Step 1: Download Dependencies
```bash
# Download only what the chosen extensions need (recommended)
spc download --for-extensions=bcmath,posix,phar,zlib,openssl,curl,fileinfo,tokenizer --with-php=8.4
# Download by specific libraries
spc download --for-libs=curl,openssl --with-php=8.4
```
Downloads are cached in `downloads/` and reused across builds automatically.
```bash
# Slow connection? Increase parallelism and retries
spc download --for-extensions=bcmath,openssl,curl -P 4 --retry=3
# Use pre-built binaries where available — skips compiling those dependencies
spc download --for-extensions=bcmath,openssl,curl --prefer-binary
```
### Step 2: Build PHP
```bash
# Build the cli SAPI
spc build:php bcmath,posix,phar,zlib,openssl,curl,fileinfo,tokenizer --build-cli
# Build multiple SAPIs in one go
spc build:php bcmath,posix,phar,zlib,openssl,curl --build-cli --build-micro
# Build all SAPIs
spc build:php bcmath,posix,phar,zlib,openssl,curl --build-all
```
`build:php` will automatically fetch any missing dependencies before building. If you already ran `download`, pass `--no-download` to skip that step:
```bash
spc build:php bcmath,openssl,curl --build-cli --no-download
```
#### Common Build Options
| Option | Description |
|---|---|
| `--build-cli` | Build the cli SAPI |
| `--build-fpm` | Build php-fpm (not available on Windows) |
| `--build-micro` | Build micro.sfx |
| `--build-embed` | Build the embed SAPI (not available on Windows) |
| `--build-frankenphp` | Build FrankenPHP (not available on Windows) |
| `--build-all` | Build all SAPIs |
| `--enable-zts` | Enable thread-safe (ZTS) mode |
| `--no-strip` | Keep debug symbols; do not strip the binary |
| `-I key=value` | Hard-compile an INI option into PHP |
| `--with-upx-pack` | Compress output with UPX (run `spc install-pkg upx` first) |
Example — baking in a larger memory limit and disabling the `system` function:
```bash
spc build:php bcmath,pcntl,posix --build-all -I "memory_limit=4G" -I "disable_functions=system"
```
## Packaging a micro App
Once you have `micro.sfx`, use `micro:combine` to bundle your PHP code into a single self-contained executable:
```bash
echo "<?php echo 'Hello, World!' . PHP_EOL;" > hello.php
spc micro:combine hello.php --output=hello
./hello
```
Works with `.phar` files too, and you can inject INI settings at packaging time:
```bash
# Bundle a phar
spc micro:combine your-app.phar --output=your-app
# Inject INI via command-line options
spc micro:combine your-app.phar --output=your-app -I "memory_limit=512M"
# Inject INI from a file
spc micro:combine your-app.phar --output=your-app -N /path/to/custom.ini
```
## Debugging and Rebuilding
If a build fails or you want to trace what's happening, use `-v` / `-vv` / `-vvv`:
```bash
spc build:php bcmath,openssl --build-cli -vv
```
- `-v` shows `INFO`-level logs: which modules are running and what build commands are being executed.
- `-vv` shows `DEBUG`-level logs: all internal debug output from StaticPHP.
- `-vvv` shows `DEBUG`-level logs and also pipes the stdout of every shell command directly to your terminal.
To wipe compiled artifacts and start fresh without re-downloading, run `reset`:
```bash
spc reset
# Then rebuild
spc build:php bcmath,openssl --build-cli
```
::: tip
`reset` only removes `buildroot/` and `source/`. Your `downloads/` cache is preserved.
Add `--with-download` if you also want to clear the download cache.
:::
If you're stuck, open an [Issue](https://github.com/static-php/static-php-cli/issues) and include your `craft.yml` (if any) and a zip of the `log/` directory.
## What's Next
- [CLI Reference](./cli-reference) — Full documentation for every command and option
- [Extensions](./extensions) — Browse supported extensions and their dependencies
- [Troubleshooting](./troubleshooting) — Diagnose common build failures

View File

@@ -1,50 +1,45 @@
# Guide
Static php cli is a tool used to build statically compiled PHP binaries,
currently supporting Linux and macOS systems.
## What is StaticPHP?
In the guide section, you will learn how to use static php cli to build standalone PHP programs.
StaticPHP is a build tool that compiles the PHP interpreter together with any extensions you need into a single self-contained binary. The target system doesn't need PHP or any runtime libraries installed — just copy the binary and run it. Builds target Linux, macOS, and Windows.
- [Build (local)](./manual-build)
- [Build (GitHub Actions)](./action-build)
- [Supported Extensions](./extensions)
## Why bother with a static PHP binary?
## Compilation Environment
A typical PHP installation is tightly coupled to the system: you install PHP, then extensions, then spend time dealing with version mismatches across distros. A static binary sidesteps all of that — what you get is a single executable that runs on any machine of the same architecture, no setup required.
The following is the architecture support situation, where :gear: represents support for GitHub Action build,
:computer: represents support for local manual build, and empty represents temporarily not supported.
Common use cases:
| | x86_64 | aarch64 |
|---------|-------------------|-------------------|
| macOS | :gear: :computer: | :gear: :computer: |
| Linux | :gear: :computer: | :gear: :computer: |
| Windows | :gear: :computer: | |
| FreeBSD | :computer: | :computer: |
- **Distributing CLI tools** — Ship tools like Composer, PHPStan, or your own CLI as a single file. Users don't need PHP installed.
- **Leaner containers** — Replace a bloated `php:8.x` base image with a minimal image (or even `FROM scratch`) carrying just a static binary.
- **Server applications** — Build a static binary with FPM or FrankenPHP baked in. Deployment becomes a file copy, with no dependency on the host environment.
Current supported PHP versions for compilation:
## phpmicro: ship PHP and your code as one file
> :warning: Partial support, there may be issues with new beta versions and old versions.
>
> :heavy_check_mark: Supported
>
> :x: Not supported
[phpmicro](https://github.com/easysoft/phpmicro) is a third-party PHP SAPI that StaticPHP supports out of the box. It merges the PHP interpreter with your `.php` source or `.phar` archive into a single self-extracting executable (`.sfx`).
| PHP Version | Status | Comment |
|-------------|--------------------|-------------------------------------------------------------------------------------------------------------------------|
| 7.2 | :x: | |
| 7.3 | :x: | phpmicro and many extensions do not support 7.3, 7.4 versions |
| 7.4 | :x: | phpmicro and many extensions do not support 7.3, 7.4 versions |
| 8.0 | :warning: | PHP official has stopped maintaining 8.0, we no longer handle 8.0 related backport support |
| 8.1 | :warning: | PHP official only provides security updates for 8.1, we no longer handle 8.1 related backport support after 8.5 release |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |
| 8.4 | :heavy_check_mark: | |
| 8.5 (beta) | :warning: | PHP 8.5 is currently in beta stage |
```
micro.sfx + your-app.phar = your-app # one file, zero dependencies
```
> This table shows the support status of static-php-cli for building corresponding versions, not the PHP official support status for that version.
This is ideal for distributing PHP-based CLI tools: the end user just gets an ordinary executable with no idea PHP is involved.
## PHP Support Versions
## Improving how you ship and deploy PHP projects
Currently, static-php-cli supports PHP versions 8.2 ~ 8.5, and theoretically supports PHP 8.1 and earlier versions, just select the earlier version when downloading.
However, due to some extensions and special components that have stopped supporting earlier versions of PHP, static-php-cli will not explicitly support earlier versions.
We recommend that you compile the latest PHP version possible for a better experience.
**Drop the heavy Docker base image**
The official `php:8.x` image can be hundreds of megabytes, most of which is just the PHP runtime. Swap it for a static PHP binary with a minimal base image — or `FROM scratch` — and you can get container sizes down to single-digit megabytes with noticeably faster startup times.
**Ship PHP CLI tools like native binaries**
Build your CLI with [symfony/console](https://symfony.com/doc/current/components/console.html) or [Laravel Zero](https://laravel-zero.com), bundle it into a `.phar` with [Box](https://github.com/box-project/box), then merge it with phpmicro. The result is a single distributable executable — the same experience users expect from Go or Rust tools, with no PHP runtime required on their end.
**Single-file web apps with FrankenPHP**
[FrankenPHP](https://frankenphp.dev) is a modern PHP app server with built-in HTTP/2, HTTP/3, and automatic HTTPS. StaticPHP can compile FrankenPHP together with your chosen extensions into one binary. The result is a complete web server in a single file — no Nginx, no PHP-FPM, just deploy and run.
## Next steps
- [Installation](./installation) — Get the StaticPHP build tool
- [First Build](./first-build) — Full walkthrough: from downloading sources to a working executable
- [CLI Reference](./cli-reference) — Every command and option, in one place

View File

@@ -0,0 +1,121 @@
# Installation
## Requirements
| Platform | Architecture | Notes |
|---|---|---|
| Linux | x86_64, aarch64 | Major distros supported (Alpine, Debian/Ubuntu, RHEL/CentOS, etc.) |
| macOS | x86_64 (Intel), arm64 (Apple Silicon) | macOS 12 or later |
| Windows | x86_64 | Windows 10 Build 17063 or later |
::: tip
Both glibc-based distros (Debian, Ubuntu, Arch, etc.) and musl-based ones (Alpine) are supported on Linux.
The `doctor` command will detect your environment and guide you through installing the right toolchain if needed.
:::
Pick the installation method that fits your use case:
| Method | Best for |
|---|---|
| Pre-built binary | Most users — download and run, no dependencies |
| From source | Contributors, or anyone who needs to modify core build logic |
| Vendor mode | Integrating StaticPHP into an existing PHP project |
## Pre-built binary
`spc` has no runtime dependencies — download the binary for your platform and it's ready to go.
> Fun fact: `spc` itself is a static PHP binary built with StaticPHP. We use StaticPHP to build StaticPHP's own build tool.
```shell
# Linux x86_64
curl -#fSL https://dl.static-php.dev/v3/spc-bin/latest/spc-linux-x86_64 -o spc
# Linux arm64
curl -#fSL https://dl.static-php.dev/v3/spc-bin/latest/spc-linux-aarch64 -o spc
# macOS x86_64 (Intel)
curl -#fSL https://dl.static-php.dev/v3/spc-bin/latest/spc-macos-x86_64 -o spc
# macOS arm64 (Apple Silicon)
curl -#fSL https://dl.static-php.dev/v3/spc-bin/latest/spc-macos-aarch64 -o spc
# Windows x86_64 (PowerShell)
curl.exe -#fSL https://dl.static-php.dev/v3/spc-bin/latest/spc-windows-x86_64.exe -o spc.exe
```
On Linux and macOS, mark the binary as executable before running it:
```bash
chmod +x spc && ./spc --version
```
## From source
This is the right path if you want to contribute to StaticPHP, or need to modify the core registry and build scripts. You'll need PHP >= 8.4, Composer, and the `mbstring,posix,pcntl,iconv,phar,zlib` extensions.
```bash
git clone https://github.com/crazywhalecc/static-php-cli.git --branch v3
cd static-php-cli
composer install
```
If you don't have PHP or Composer installed, use the bundled setup script to install a self-contained runtime:
::: code-group
```bash [Linux / macOS]
bin/setup-runtime
```
```powershell [Windows]
.\bin\setup-runtime.ps1
.\bin\setup-runtime.ps1 add-path # add runtime/ to PATH
```
:::
The script downloads `php` and `composer` into a `runtime/` subdirectory. You then have two options:
1. **Call them directly** (no PATH changes needed):
```bash
runtime/php bin/spc --help
runtime/php runtime/composer install
```
2. **Add `runtime/` to your PATH** so you can use `php`, `composer`, and `bin/spc` without prefixes:
```bash
export PATH="/path/to/static-php-cli/runtime:$PATH"
# Add this to ~/.bashrc or ~/.zshrc to make it permanent
```
::: tip
In regions with restricted access to GitHub or getcomposer.org, pass `--mirror china` to use a mirror:
```bash
bin/setup-runtime --mirror china
```
:::
## Vendor mode
If you already have a PHP project and want to call StaticPHP's build APIs directly, or use a custom registry to support private libraries and extensions, pull it in as a Composer dependency:
```bash
composer require crazywhalecc/static-php-cli
```
See the [Vendor Mode guide](../develop/vendor-mode/) for details.
## Verify your build environment
> **Vendor mode users can skip this step.**
Once installed, run `doctor` to check that your system has the required build tools (cmake, make, a C compiler, etc.):
```bash
# Using the spc binary
./spc doctor
# From source
bin/spc doctor
```
If anything is missing, `--auto-fix` will attempt to install it for you:
```bash
./spc doctor --auto-fix
```
Once `doctor` reports everything is good, head over to [First Build](./first-build).

View File

@@ -1,42 +1,5 @@
# Troubleshooting
Various failures may be encountered in the process of using static-php-cli,
here will describe how to check the errors by yourself and report Issue.
## Download Failure
Problems with downloading resources are one of the most common problems with spc.
The main reason is that the addresses used for SPC download resources are generally the official website of the corresponding project or GitHub, etc.,
and these websites may occasionally go down and block IP addresses.
After encountering a download failure,
you can try to call the download command multiple times.
When downloading extensions, you may eventually see errors like `curl: (56) The requested URL returned error: 403` which are often caused by github rate limiting.
You can verify this by adding `--debug` to the command and will see something like `[DEBU] Running command (no output) : curl -sfSL "https://api.github.com/repos/openssl/openssl/releases"`.
To fix this, [create](https://github.com/settings/tokens) a personal access token on GitHub and set it as an environment variable `GITHUB_TOKEN=<XXX>`.
If you confirm that the address is indeed inaccessible,
you can submit an Issue or PR to update the url or download type.
## Doctor Can't Fix Something
In most cases, the doctor module can automatically repair and install missing system environments,
but there are also special circumstances where the automatic repair function cannot be used normally.
Due to system limitations (for example, software such as Visual Studio cannot be automatically installed under Windows),
the automatic repair function cannot be used for some projects.
When encountering a function that cannot be automatically repaired,
if you encounter the words `Some check items can not be fixed`,
it means that it cannot be automatically repaired.
Please submit an issue according to the method displayed on the terminal or repair the environment yourself.
## Compile Error
When you encounter a compilation error, if the `--debug` log is not enabled, please enable the debug log first,
and then determine the command that reported the error.
The error terminal output is very important for fixing compilation errors.
When submitting an issue, please upload the last error fragment of the terminal log (or the entire terminal log output),
and include the `spc` command and parameters used.
If you are rebuilding, please refer to the [Local Build - Multiple Builds](./manual-build#multiple-builds) section.
<!-- TODO: Categorized common build failures and fixes.
Sections: Download issues / Compilation errors / Extension conflicts / Windows-specific / glibc Linux.
Migrate and expand from v2 troubleshooting.md. -->

View File

@@ -1,51 +1,5 @@
# 贡献指南
感谢你能够看到这里,本项目非常欢迎你的贡献!
## 贡献方法
如果你有代码或文档要贡献,以下是你需要首先了解的内容。
1. 你要贡献什么类型的代码?(新扩展、修复 Bug、安全问题、项目框架优化、文档
2. 如果你贡献了新文件或新片段,你的代码是否经过 `php-cs-fixer``phpstan` 的检查?
3. 在贡献代码前是否充分阅读了 [开发指南](../develop/)
如果你能回答上述问题并对代码进行了修改,可以及时在项目 GitHub 仓库发起 Pull Request。
代码审查完成后,可以根据建议修改代码,或直接合并到主分支。
## 贡献类型
本项目的主要目的是编译静态链接的 PHP 二进制文件,命令行处理功能基于 `symfony/console` 编写。
在开发之前,如果你对它不够熟悉,请先查看 [symfony/console 文档](https://symfony.com/doc/current/components/console.html)。
### 安全更新
因为本项目基本上是一个本地运行的 PHP 项目,一般来说不会有远程攻击。
但如果你发现此类问题,请**不要**在 GitHub 仓库提交 PR 或 Issue
你需要通过 [邮件](mailto:admin@zhamao.me) 联系项目维护者crazywhalecc
### 修复 Bug
修复 Bug 一般不涉及项目结构和框架的修改,所以如果你能定位到错误代码并直接修复它,请直接提交 PR。
### 新扩展
对于添加新扩展,你需要了解项目的一些基本结构以及如何根据现有逻辑添加新扩展。
这将在本页的下一节中详细介绍。
总的来说,你需要:
1. 评估扩展是否可以内联编译到 PHP 中。
2. 评估扩展的依赖库(如果有)是否可以静态编译。
3. 编写不同平台的库编译命令。
4. 验证扩展及其依赖项与现有扩展和依赖项兼容。
5. 验证扩展在 `cli``micro``fpm``embed` SAPIs 中正常工作。
6. 编写文档并添加你的扩展。
### 项目框架优化
如果你已经熟悉 `symfony/console` 的工作原理,并同时要对项目的框架进行一些修改或优化,请先了解以下事情:
1. 添加扩展不属于项目框架优化,但如果你在添加新扩展时发现必须优化框架,则需要先修改框架本身,然后再添加扩展。
2. 对于一些大规模逻辑修改(例如涉及 LibraryBase、Extension 对象等的修改),建议先提交 Issue 或 Draft PR 进行讨论。
3. 在项目早期,它是一个纯私有开发项目,代码中有一些中文注释。项目国际化后,你可以提交 PR 将这些注释翻译为英语。
4. 请不要在代码中提交更多无用的代码片段,例如大量未使用的变量、方法、类以及多次重写的代码。
<!-- TODO: v3 贡献指南。
章节代码风格php-cs-fixer、phpstan、新增 library/extension、
新增 doctor 检查项、提交 PR、安全漏洞披露。 -->

View File

@@ -0,0 +1,5 @@
# 构建生命周期
<!-- TODO: 完整构建流水线阶段顺序说明。
各 Hook 触发时机:#[BeforeStage]、#[AfterStage]、#[PatchBeforeBuild]。
#[BuildFor] 运行时平台选择机制。典型 library 和 extension 构建的阶段顺序图示。 -->

View File

@@ -2,6 +2,6 @@
aside: false
---
# craft.yml 配置
# craft.yml 配置详解
<!--@include: ../../deps-craft-yml.md-->
<!-- TODO: craft.yml 字段完整参考。 -->

View File

@@ -1,60 +1,4 @@
# Doctor 模块
# Doctor 环境检查
Doctor 模块是一个较为独立的用于检查系统环境的模块,可使用命令 `bin/spc doctor` 进入,入口的命令类在 `DoctorCommand.php`
Doctor 模块是一个检查单,里面有一系列的检查项目和自动修复项目。这些项目都存放在 `src/SPC/doctor/item/` 目录中,
并且使用了两种 Attribute 用作检查项标记和自动修复项目标记:`#[AsCheckItem]``#[AsFixItem]`
以现有的检查项 `if necessary tools are installed`,它是用于检查编译必需的包是否安装在 macOS 系统内,下面是它的源码:
```php
use SPC\doctor\AsCheckItem;
use SPC\doctor\AsFixItem;
use SPC\doctor\CheckResult;
#[AsCheckItem('if necessary tools are installed', limit_os: 'Darwin', level: 997)]
public function checkCliTools(): ?CheckResult
{
$missing = [];
foreach (self::REQUIRED_COMMANDS as $cmd) {
if ($this->findCommand($cmd) === null) {
$missing[] = $cmd;
}
}
if (!empty($missing)) {
return CheckResult::fail('missing system commands: ' . implode(', ', $missing), 'build-tools', [$missing]);
}
return CheckResult::ok();
}
```
属性的第一个参数就是检查项目的名称,后面的 `limit_os` 参数是限制了该检查项仅在指定的系统下触发,`level` 是执行该检查项的优先级,数字越大,优先级越高。
里面用到的 `$this->findCommand()` 方法为 `SPC\builder\traits\UnixSystemUtilTrait` 的方法,用途是查找系统命令所在位置,找不到时返回 NULL。
每个检查项的方法都应该返回一个 `SPC\doctor\CheckResult`
- 在返回 `CheckResult::fail()` 时,第一个参数用于输出终端的错误提示,第二个参数是在这个检查项可自动修复时的修复项目名称。
- 在返回 `CheckResult::ok()` 时,表明检查通过。你也可以传递一个参数,用于返回检查结果,例如:`CheckResult::ok('OS supported')`
- 在返回 `CheckResult::fail()` 时,如果包含了第三个参数,第三个参数的数组将被当作 `AsFixItem` 的参数。
下面是这个检查项对应的自动修复项的方法:
```php
#[AsFixItem('build-tools')]
public function fixBuildTools(array $missing): bool
{
foreach ($missing as $cmd) {
try {
shell(true)->exec('brew install ' . escapeshellarg($cmd));
} catch (RuntimeException) {
return false;
}
}
return true;
}
```
`#[AsFixItem()]` 属性传入的参数即修复项的名称,该方法必须返回 True 或 False。当返回 False 时,表明自动修复失败,需要手动处理。
此处的代码中 `shell()->exec()` 是项目的执行命令的方法,用于替代 `exec()``system()`,同时提供了 debug、获取执行状态、进入目录等特性。
<!-- TODO: 从 v2 doctor-module.md 迁移并更新
涵盖 v3 变化:--auto-fix、.spc-doctor.lock、v3 工具链新增检查项。 -->

View File

@@ -1,27 +1,4 @@
# 开发简介
开发本项目需要安装部署 PHP 环境,以及一些 PHP 项目常用的扩展和 Composer
项目的开发环境和运行环境几乎完全一致。你可以参照 **手动构建** 部分安装系统 PHP 或使用本项目预构建的静态 PHP 作为环境。这里不再赘述。
抛开用途,本项目本身其实就是一个 `php-cli` 程序,你可以将它当作一个正常的 PHP 项目进行编辑和开发,同时你需要了解不同系统的 Shell 命令行。
本项目目前的目的就是为了编译静态编译的独立 PHP但主体部分也包含编译很多依赖库的静态版本所以你可以复用这套编译逻辑用于构建其他程序的独立二进制版本例如 Nginx 等。
## 环境准备
开发本项目需要 PHP 环境。你可以使用系统自带的 PHP也可以使用本项目构建的静态 PHP。
无论是使用哪种 PHP在开发环境你需要安装这些扩展
```
curl,dom,filter,mbstring,openssl,pcntl,phar,posix,sodium,tokenizer,xml,xmlwriter
```
static-php-cli 项目本身不需要这么多扩展,但在开发过程中,你会用到 Composer 和 PHPUnit 等工具,它们需要这些扩展。
> 对于 static-php-cli 自身构建的 micro 自执行二进制,仅需要 `pcntl,posix,mbstring,tokenizer,phar`。
## 开始开发
继续向下查看项目结构文档,你可以学习 `static-php-cli` 是如何工作的。
<!-- TODO: 开发者简介、环境准备、所需 PHP 扩展
Vendor 模式链接到 vendor-mode/,代码贡献链接到 contributing/。 -->

View File

@@ -0,0 +1,5 @@
# Package 模型
<!-- TODO: 统一 Package 模型说明library / php-extension / target 类型。
config/pkg/ 下 per-package YAML 格式、depends 字段、平台覆盖(@windows / @unix 写法)。
artifact.source 和 artifact.binary 字段。附注释的 library 和 extension YAML 示例。 -->

View File

@@ -1,51 +1,3 @@
# 对 PHP 源码的修改
由于 static-php-cli 在静态编译过程中为了实现良好的兼容性、性能和安全性,对 PHP 源码进行了一些修改。下面是目前对 PHP 源码修改的说明。
## micro 相关补丁
基于 phpmicro 项目提供的补丁static-php-cli 对 PHP 源码进行了一些修改,以适应静态编译的需求。[补丁列表](https://github.com/easysoft/phpmicro/tree/master/patches) 包含:
目前 static-php-cli 在编译时用到的补丁有:
- static_opcache
- static_extensions_win32
- cli_checks
- disable_huge_page
- vcruntime140
- win32
- zend_stream
- cli_static
- macos_iconv
- phar
## PHP <= 8.1 libxml 补丁
因为 PHP 官方仅对 8.1 进行安全更新,旧版本停止更新,所以 static-php-cli 对 PHP 8.1 及以下版本应用了在新版本 PHP 中已经应用的 libxml 编译补丁。
## gd 扩展 Windows 补丁
在 Windows 下编译 gd 扩展需要大幅改动 `config.w32` 文件static-php-cli 对 gd 扩展进行了一些修改,使其在 Windows 下编译更加方便。
## yaml 扩展 Windows 补丁
yaml 扩展在 Windows 下编译需要修改 `config.w32` 文件static-php-cli 对 yaml 扩展进行了一些修改,使其在 Windows 下编译更加方便。
## static-php-cli 版本信息插入
static-php-cli 在编译时会在 PHP 版本信息中插入 static-php-cli 的版本信息,以便于识别。
## 加入硬编码 INI 的选项
在使用 `-I` 参数硬编码 INI 到静态 PHP 的功能中static-php-cli 会修改 PHP 源码以插入硬编码内容。
## Linux 系统修复补丁
部分编译环境可能缺少一些头文件或库static-php-cli 会在编译时自动修复这些问题,如:
- HAVE_STRLCAT missing problem
- HAVE_STRLCPY missing problem
## Windows 系统下 Fiber 问题修复补丁
在 Windows 下编译 PHP 时Fiber 扩展会出现一些问题static-php-cli 会在编译时自动修复这些问题(修改 php-src 的 `config.w32`)。
<!-- TODO: 从 v2 php-src-changes.md 迁移并更新。补充 v3 新增 patchFrankenPHP embed、Windows fiber 修复等)。 -->

View File

@@ -0,0 +1,5 @@
# Registry 与插件系统
<!-- TODO: spc.registry.yml 结构说明。
通过 SPC_REGISTRIES 环境变量添加外部 Registry。
Vendor 特定配置、覆盖核心包。Registry 解析顺序与冲突规则。 -->

Some files were not shown because too many files have changed in this diff Show More