From a11dff51673c001626615e49ca401ee3b099ed58 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 08:33:43 +0000 Subject: [PATCH 1/4] libap: ucontext's pointer casts truncated, and a rename left an object pcc answered `conversion of pointer to shorter integer' five times in makecontext.c. The casts read (unsigned long long)(unsigned long)ptr and unsigned long is four bytes here, so the stack address, _ctxreturn and func would all have been truncated. uintptr_t now, and stack_t's ss_size is size_t rather than long, which is POSIX's type and avoids narrowing what php assigns to it. The host cross-check could not have caught it and never will: unsigned long is eight bytes under glibc, so the conversion is lossless there. That is the second long-width bug in this one port that gcc was structurally blind to, after ucontext-test's section 5, so the comment in place says to read anything that moves a pointer through an integer for it specifically rather than leave it to the host. The second error, `duplicate text symbol: _ctxreturn', is not the code at all: renaming mcontext.s to ucontext.s left mcontext.6 in libap.a. mksyslib's clean is `rm -f *.[$OS] ...', which touches the directory and never $LIB, and `ar vu' replaces members by name, so an object whose source is gone is never revisited. `ar d' on the stale member clears it. Recorded as a build-system rule, with the point that the collision was the lucky outcome: a stale object that does not collide stays linked into every program in the tree with no diagnostic from anyone. makectx-xcheck still 0, and its two frame controls still 3 and 1. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs --- CLAUDE.md | 15 +++++++++ docs/notes/libap.md | 25 +++++++++++++++ sys/include/ape/ucontext.h | 3 +- sys/src/ape/lib/ap/arch/amd64/makecontext.c | 35 ++++++++++++++------- 4 files changed, 66 insertions(+), 12 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e0b56a064..8d3fe8a99 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1488,6 +1488,21 @@ in the topic file. relink -- rounds later, with nothing nearby to blame. *The rule that a library fix can sit unused for rounds has a second edge: so can a library BREAKAGE.* +- **RENAMING a source file in a library directory leaves its OBJECT in + the archive, and `clean` does not remove it.** `mksyslib`'s `clean` + is `rm -f *.[$OS] ...`, which touches the directory and never + `$LIB`; only `nuke` removes the archive, and `ar vu` replaces + members by NAME, so an object whose source no longer exists is + simply never revisited. *Renaming `mcontext.s` to `ucontext.s` left + `mcontext.6` defining `_ctxreturn` beside the new `ucontext.6` + defining it too*, and the next build said `duplicate text symbol: + _ctxreturn`. **The loud case is the lucky one**: when the stale + object does NOT collide, its code stays linked into every program + in the tree for ever with no diagnostic from anyone. One + `ar d .$O` fixes it; `mk distclean` fixes it at the + cost of a full rebuild. *There is no instrument for "a member of + `libap.a` whose source is gone" and it would be cheap* -- `ar t` + against the directory -- but the archive exists only on the VM. - **Check every object built against a library for the flags that library was built with**, not just the ones the linker complained about. `nm -g --defined-only x.o | wc -l` is a one-second check. diff --git a/docs/notes/libap.md b/docs/notes/libap.md index 46ec67ef8..2279761e7 100644 --- a/docs/notes/libap.md +++ b/docs/notes/libap.md @@ -4098,6 +4098,31 @@ bug the reference implementation is blind to, because the difference IS the reference's width. The tree's first invariant, arriving inside a file written to check something else. +### Two things the first VM build of it said + +**`conversion of pointer to shorter integer`, five times.** The casts +read `(unsigned long long)(unsigned long)ptr`, and **`unsigned long` +is four bytes here** -- the stack address, `_ctxreturn` and `func` +would all have been truncated. `uintptr_t` now. + +*The host cross-check could not have caught it and never will*: +`unsigned long` is eight bytes under glibc, so the conversion is +lossless there. **That is the second `long`-width bug in this one port +that gcc was structurally blind to**, after `ucontext-test`'s section +5. The rule that follows is narrow and worth keeping narrow: a host +cross-check is blind to `long` by construction, so anything that moves +a POINTER through an INTEGER is read for that specifically rather than +left to the host. + +**`duplicate text symbol: _ctxreturn`.** Not the code: renaming +`mcontext.s` to `ucontext.s` left `mcontext.6` in `libap.a`, because +`mksyslib`'s `clean` removes `*.[$OS]` from the directory and never +touches the archive, and `ar vu` replaces members by name. One +`ar d` on the stale member clears it. *The collision was the lucky +outcome* -- a stale object that does not collide stays linked into +every program with no diagnostic at all. The rule is in CLAUDE.md's +build-system list. + **What neither instrument covers**: nothing exercises a context switch with signals actually blocked. And the header could not be syntax-checked against the APE headers on the host -- they reach each diff --git a/sys/include/ape/ucontext.h b/sys/include/ape/ucontext.h index 8e9a93bc1..0c26f5aee 100644 --- a/sys/include/ape/ucontext.h +++ b/sys/include/ape/ucontext.h @@ -2,6 +2,7 @@ #define __UCONTEXT_H #include +#include #include #ifdef __cplusplus @@ -32,7 +33,7 @@ extern "C" { */ typedef struct { void *ss_sp; - long ss_size; + size_t ss_size; /* POSIX's type, and `long' is 4 bytes here */ int ss_flags; } stack_t; diff --git a/sys/src/ape/lib/ap/arch/amd64/makecontext.c b/sys/src/ape/lib/ap/arch/amd64/makecontext.c index 2a51d9f01..68e3fe5a2 100644 --- a/sys/src/ape/lib/ap/arch/amd64/makecontext.c +++ b/sys/src/ape/lib/ap/arch/amd64/makecontext.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -87,7 +88,7 @@ void makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) { unsigned long long *base; - unsigned long long top; + uintptr_t top; va_list ap; int i; @@ -100,18 +101,32 @@ makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) if(ucp->uc_stack.ss_sp == 0 || ucp->uc_stack.ss_size < UC_SLOTS*8 + 64) ucdie("stack missing or too small"); - top = (unsigned long long)(unsigned long)ucp->uc_stack.ss_sp - + (unsigned long long)ucp->uc_stack.ss_size; - top &= ~(unsigned long long)15; /* 6c does not require 16; + /* + * ***EVERY POINTER HERE GOES THROUGH `uintptr_t', AND THE FIRST + * DRAFT USED `unsigned long', WHICH IS FOUR BYTES.*** `pcc' + * caught it with five `conversion of pointer to shorter integer' + * warnings and it would otherwise have truncated the stack + * address, `_ctxreturn' and `func' alike. + * + * *The host cross-check could not have caught it and never will*: + * `unsigned long' is eight bytes under glibc, so the conversion + * is lossless there. **That is the second `long'-width bug in + * this one file that gcc was structurally blind to** -- the other + * was `ucontext-test's section 5 -- so anything in these files + * that moves a pointer through an integer gets read for it + * specifically rather than left to the host. + */ + top = (uintptr_t)ucp->uc_stack.ss_sp + (uintptr_t)ucp->uc_stack.ss_size; + top &= ~(uintptr_t)15; /* 6c does not require 16; * its frames are not a * multiple of it. Free. */ - base = (unsigned long long *)(unsigned long)(top - UC_SLOTS*8); + base = (unsigned long long *)(top - UC_SLOTS*8); - base[0] = (unsigned long long)(unsigned long)_ctxreturn; + base[0] = (uintptr_t)_ctxreturn; base[1] = 0; /* 6c's reserved 0(FP) slot */ for(i = 2; i <= UC_ARGMAX; i++) base[i] = 0; - base[UC_ARGMAX+1] = (unsigned long long)(unsigned long)ucp; + base[UC_ARGMAX+1] = (uintptr_t)ucp; /* * POSIX says the arguments are `int'. They are read here as the @@ -142,10 +157,8 @@ makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) * no-stack-write form of a RET -- so the SP recorded here is one * slot BELOW the frame, and `func' begins with SP = base. */ - ucp->uc_mcontext.mc_regs[_MC_SP] = - (unsigned long long)(unsigned long)base - 8; - ucp->uc_mcontext.mc_regs[_MC_PC] = - (unsigned long long)(unsigned long)func; + ucp->uc_mcontext.mc_regs[_MC_SP] = (uintptr_t)base - 8; + ucp->uc_mcontext.mc_regs[_MC_PC] = (uintptr_t)func; /* * mc_regs[3..7] -- BX, R12..R15 -- are left exactly as they are. From de5f73010b681f010148cb60016908a6028cf9d8 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 08:36:40 +0000 Subject: [PATCH 2/4] notes: ucontext is 0 failures on the VM All six sections, including section 0 printing its PASS line twice -- the resumed path re-entering at getcontext's return, which is the thing the C wrapper could not do. php blocker 1 is closed; what remains is pointing php at it. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs --- CLAUDE.md | 15 +++++++++------ docs/notes/libap.md | 7 +++++++ docs/notes/php.md | 6 +++--- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 8d3fe8a99..02bea6d71 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1149,12 +1149,15 @@ two are the opposite of what it says — `HAVE_TM_ZONE` and `HAVE_ST_BLOCKS` are both YES, `struct tm` and `struct stat` having those members. *A sweep over function names, asked about a struct field, answers `absent` confidently.* -**What can still stop it, in order**: (1) fibers — **CLOSED on the -host, unmeasured on the VM**: `zend_fibers.c` is unconditional and -wants either boost.context's GAS assembly or ``, and APExp -now has the second (`lib/ap/arch/amd64/mcontext.s` + `ucontext.c`, -`docs/notes/libap.md`). amd64 only; the other ten follow the same -shape when wanted. +**What can still stop it, in order**: (1) fibers — **CLOSED and +MEASURED**: `zend_fibers.c` is unconditional and wants either +boost.context's GAS assembly or ``, and APExp now has the +second (`lib/ap/arch/amd64/ucontext.s` + `makecontext.c`), with +`ucontext-test` at **0 failures on the VM**. amd64 only; the other ten +follow the same shape when wanted. *php has not been pointed at it +yet* — that is `ZEND_FIBER_UCONTEXT` in the `config.h`. +`docs/notes/libap.md` has the two bugs it cost, both of them +`long`-width and both invisible to the host check. (2) **`ext/opcache` is mandatory in 8.5** — there is no `--disable-opcache`, only `--disable-opcache-jit`, which is what drops the 13-file `jit/ir` code generator; opcache only has to COMPILE, since diff --git a/docs/notes/libap.md b/docs/notes/libap.md index 2279761e7..ccf738137 100644 --- a/docs/notes/libap.md +++ b/docs/notes/libap.md @@ -4098,6 +4098,13 @@ bug the reference implementation is blind to, because the difference IS the reference's width. The tree's first invariant, arriving inside a file written to check something else. +***MEASURED ON THE VM: `ucontext-test` 0 failures, all six sections.*** +Section 0 prints its PASS line twice, which is the resumed path +re-entering at `getcontext`'s return and the thing the C wrapper could +not do. So the switch, the new stack, `uc_link`, all eight argument +slots, five round trips and a context's own locals are all behaving on +the machine as they do against glibc. + ### Two things the first VM build of it said **`conversion of pointer to shorter integer`, five times.** The casts diff --git a/docs/notes/php.md b/docs/notes/php.md index db3cfff44..47b72a1e0 100644 --- a/docs/notes/php.md +++ b/docs/notes/php.md @@ -239,9 +239,9 @@ version, then add one library at a time. ## Open, as a list -* fibers: `ucontext` is written (`docs/notes/libap.md`) and passes on - the host against glibc; **not yet run on the VM**, and php has not - been pointed at it (`ZEND_FIBER_UCONTEXT` in the `config.h`) +* fibers: **done** — `ucontext` is in libap and `ucontext-test` is 0 + failures on the VM (`docs/notes/libap.md`). What remains is pointing + php at it: `ZEND_FIBER_UCONTEXT` in the `config.h` * `main/php_config.h` not written yet; the inventory is derived, the answers are not * `memfd_create` is declared with no implementation, which is a libap From 080944b51b93f559d41f47757813ad6fd234fdf8 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 08:39:31 +0000 Subject: [PATCH 3/4] php: __x86_64__ must be defined, and the header inventory kencc defines no architecture macro, and php needs one. Zend/zend_long.h:26 selects zend_long from __x86_64__ || __LP64__ || _LP64 || _WIN64 rather than from SIZEOF_LONG, so without it php's integer type is 32 bits; ext/date/lib/timelib.h:112 has the identical test. And five arms in Zend/zend_float.h read !defined(__x86_64__), selecting x87 control-word code that is wrong for an SSE machine -- so not defining it is itself a positive, wrong choice, which is what settles it. __LP64__ is the available alternative and is a lie, since kencc is LLP64. What else it switches on was measured rather than assumed: of the 30 files mentioning it, every site emitting GCC inline assembly is separately gated on __GNUC__, on HAVE_ASM_GOTO, on an absent intrinsics header, or on the HYBRID VM kind. The three that do turn on are a plain C hash loop, unaligned-access shortcuts that are true here, and cpuinfo, whose two helpers both have a non-GCC fallback that returns zero. It goes on the compile line rather than in the config.h, because timelib.h is reached by files that have not included php_config.h yet. The header inventory is mechanical and now resolved: 39 of the 91 HAVE_*_H names exist under sys/include/ape or amd64/include/ape, including everything structural. The 52 absent are ODBC, tidy, linux/*, the SSE intrinsics, Windows and crypt.h -- php bundles its own crypt, which is why four crypt_* files are already in the object list. And one of the 39 is a trap worth the note: HAVE_DLFCN_H resolves to yes and the answer is no, because apfunc-sweep reports dlopen and dlerror as declared-only. A file-existence check answers that one confidently and wrongly, which is the clearest argument in this port for hand-answering rather than deriving. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs --- docs/notes/php.md | 67 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/docs/notes/php.md b/docs/notes/php.md index 47b72a1e0..f0d02ce38 100644 --- a/docs/notes/php.md +++ b/docs/notes/php.md @@ -217,6 +217,73 @@ memory — so the limit was Plan 9 segment slots, one spent by 10MB of heap**, long before any trimming question arose. `SEG_THRESHOLD` is 64MB now; `docs/notes/libap.md` has it. +## `__x86_64__` has to be defined, and it is the honest answer + +**kencc defines no architecture macro at all**, and php needs one. The +consequence is not a micro-optimisation: + +* `Zend/zend_long.h:26` selects `zend_long` from + `__x86_64__ || __LP64__ || _LP64 || _WIN64` -- *not* from + `SIZEOF_LONG` -- so without it php's integer type is **32 bits**. +* `ext/date/lib/timelib.h:112` has the identical test for + `timelib_sll`. +* ***And five arms in `Zend/zend_float.h` read + `!defined(__x86_64__)`***, selecting x87 control-word code + (`_controlfp`, `_FPU_SETCW`, `fpsetprec`, inline x86 asm) that is + wrong for an SSE machine. **Not defining it is itself a positive, + wrong choice**, which is the argument that settles this: there is no + neutral option. + +`__LP64__` would be the available alternative and it is a **lie** -- +kencc is LLP64, `long` is four bytes -- so anything keying on it to +mean "long is 64 bits" would be silently wrong. `__x86_64__` is simply +true of the machine. + +**The risk is what else it switches on, and that was measured rather +than assumed.** Of the 30 files mentioning it, every site that emits +GCC inline assembly is separately gated: + +| site | also needs | verdict | +|---|---|---| +| `zend_string.h:444`, `.c:394/452`, `zend_multiply.h:45/177`, `zend_execute.c:56`, `zend_cpuinfo.c:31`, `zend_vm_execute.h:364`, `TSRM.c:779` | `__GNUC__` | off | +| `zend_operators.h:566/645/731/835` | `ZEND_USE_ASM_ARITHMETIC`, which is `HAVE_ASM_GOTO` (`:547`) -- answered **0** | off | +| `zend_portability.h:561` | `HAVE_TMMINTRIN_H` / `NMMINTRIN` / `WMMINTRIN` -- all absent | off | +| `php_hash_sha.h:58` | `HAVE_IMMINTRIN_H` -- absent | off | +| `zend_vm_opcodes.h:52` | `ZEND_VM_KIND == HYBRID` -- it is CALL | off | +| `zend_cpuinfo.c:76` | nothing, but `get_xcr0_eax` and `__zend_cpuid` both have a `return 0` / zeroing fallback for a non-GCC compiler | **on, and harmless** | +| `zend_string.h:537` | nothing; a plain C multiplication hash loop | **on, and wanted** | +| `crypt_blowfish.c:56`, `md5.c:160`, murmur, xxhash | nothing; "unaligned access is cheap" | **on, and true** | + +So it goes on the compile line (`-D__x86_64__`) rather than in the +`config.h`, because `timelib.h` is reached by files that have not +included `php_config.h` yet and a macro that is defined for only some +translation units is worse than one that is defined for none. + +## The headers: 39 of 91 are present + +Mechanical, and checkable: every `HAVE_*_H` name in the generated +config resolved against `sys/include/ape` and `amd64/include/ape`. +**39 present**, including everything structural -- +`dirent`, `fcntl`, `poll`, `pwd`, `grp`, `langinfo`, `netinet/in`, +`resolv`, `syslog`, `sys/{file,ioctl,mman,param,resource,select,socket, +statvfs,stat,sysmacros,time,uio,utsname,wait}`, `utime`, `wchar`. + +The 52 absent are ODBC (14 of them), tidy, the Linux `linux/*` family, +the SSE intrinsic headers, Windows, and `crypt.h` -- php bundles its +own crypt, which is why `crypt_blowfish`, `crypt_freesec`, +`crypt_sha256` and `crypt_sha512` are already in the object list. +Three absences line up with decisions already taken: no +`sys/ipc.h` (opcache's SysV shm), no `*mmintrin.h` (every SSE path), +no `sys/mount.h`/`statfs`/`vfs` (`statvfs` is what we have). + +***BUT `HAVE_DLFCN_H` RESOLVES TO YES AND THE ANSWER IS NO.*** APE +ships a `dlfcn.h`, and `apfunc-sweep.py` reports `dlopen` and +`dlerror` as **declared-only** -- the middle state, a header promise +with nothing behind it. *A file-existence check answers this one +confidently and wrongly*, which is the clearest single argument in +this port for hand-answering rather than deriving: the mechanical +method is right 90 times and this is one of the others. + ## Extensions: the ones with a ported library The user's own framing, and the right one: enable what this tree already From 090b8233db29f2bd8db859b45e6886d21f39df28 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 08:49:59 +0000 Subject: [PATCH 4/4] php: the hand-answered config.h and the mkfile sys/src/ape/cmd/php/ holds six files and nothing in external/php is touched: the mkfile (513 objects), php_config.h, zend_config.h, timelib_config.h, build-defs.h and internal_functions_cli.c. The mkfile puts -I. first so our copies win over anything configure would have generated into the vendored tree. The object list is derived from upstream's own configure rather than transcribed, the clisp precedent. The objects keep their paths, and that is not cosmetic: sixteen basenames collide across the 43 source directories -- array.c is both ext/standard/array.c and ext/lexbor/lexbor/core/array.c, and hash, parser, state, token, url and ten more are the same -- so a flat OFILES would build one and link it twice, silently. php is a program rather than a library, so there is no archive member to collide and nested paths cost only a mkdir in the rule. Each comment inside OFILES ends with a backslash, which is mkcont-sweep's rule, and HFILES names the four hand-kept headers, because mk does not scan #includes and editing a config.h that nothing depends on rebuilds nothing. mkcont-sweep and rceq-sweep both pass; apehdr-sweep is identical with and without the new , which is a control rather than a reading. Two macros are answered no for capabilities that are present, link, and return success -- clisp's mprotect rule, twice. HAVE_MPROTECT, because plan9/mman.c:44 is `return 0'. And HAVE_MREMAP, which is worse: APExp's mremap allocates and copies, while zend_mm_chunk_extend calls it without MREMAP_MAYMOVE precisely because it needs the chunk to stay put, and treats anything that is not MAP_FAILED as success. Zend would record a chunk as extended in place while the memory had moved. A probe that compiles and links cannot tell either from the real thing. STRERROR_R_CHAR_P is unset, and copying the host answer would have been a real bug: glibc's strerror_r returns char *, APE's is POSIX's returning int, so php would have used an int as a pointer. ZEND_CHECK_STACK_LIMIT is unset with the cost recorded rather than hidden -- deep recursion will fault instead of raising an error -- and HAVE_IPV6 is unset as a choice rather than a finding, since the types exist and nothing here has ever exercised them. And one question answered itself: the sweep found 37 functions APE has that the host configure left undef, which looked like a judgement call about enabling paths upstream never compiles on Linux. grep says all 37 are referenced in 0 files of what this port builds. php is deliberately not in sys/src/ape/cmd/mkfile: one failing entry aborts the whole tree's mk, and this has never been built. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs --- docs/notes/php.md | 97 ++- sys/src/ape/cmd/php/build-defs.h | 35 + sys/src/ape/cmd/php/internal_functions_cli.c | 76 +++ sys/src/ape/cmd/php/mkfile | 674 +++++++++++++++++++ sys/src/ape/cmd/php/php_config.h | 394 +++++++++++ sys/src/ape/cmd/php/timelib_config.h | 22 + sys/src/ape/cmd/php/zend_config.h | 7 + 7 files changed, 1303 insertions(+), 2 deletions(-) create mode 100644 sys/src/ape/cmd/php/build-defs.h create mode 100644 sys/src/ape/cmd/php/internal_functions_cli.c create mode 100644 sys/src/ape/cmd/php/mkfile create mode 100644 sys/src/ape/cmd/php/php_config.h create mode 100644 sys/src/ape/cmd/php/timelib_config.h create mode 100644 sys/src/ape/cmd/php/zend_config.h diff --git a/docs/notes/php.md b/docs/notes/php.md index f0d02ce38..06f7527f6 100644 --- a/docs/notes/php.md +++ b/docs/notes/php.md @@ -304,13 +304,106 @@ was tested against and it removes a link dependency from the first build. has worked in this tree is: get the thing to compile and print its own version, then add one library at a time. +## The port directory + +`sys/src/ape/cmd/php/` holds six files and **nothing in +`sys/src/external/php` is touched** -- the vendored tree stays vendor +source, and the mkfile puts `-I.` first so our copies win: + +| file | what it is | +|---|---| +| `mkfile` | 513 objects, derived from upstream's configure | +| `php_config.h` | the hand-answered one | +| `zend_config.h` | the one line `zend_portability.h:43` wants | +| `timelib_config.h` | routes timelib through the Zend allocator | +| `build-defs.h` | the install paths | +| `internal_functions_cli.c` | the eleven built-in extension entries | + +***THE OBJECTS KEEP THEIR PATHS, AND THAT IS NOT COSMETIC.*** Sixteen +basenames collide across the 43 source directories -- `array.c` is +both `ext/standard/array.c` and `ext/lexbor/lexbor/core/array.c`, and +`hash`, `parser`, `state`, `token`, `url` and ten more are the same. +A flat `OFILES` would build one and link it twice, silently. php is a +PROGRAM rather than a library, so there is no archive member to +collide and nested paths cost only a `mkdir` in the rule -- *the +`ar`-member collision that a library would have had is the same shape +as the stale `mcontext.6` in `docs/notes/libap.md`, avoided here by +not having an archive at all.* + +Two mkfile details that are rules rather than taste. **Each comment +inside the `OFILES` list ends with a backslash**, which is +`mkcont-sweep.py`'s rule: a comment that ends a continuation ends the +variable, and the rest of the list would vanish without a word. And +**`HFILES` names the four hand-kept headers**, because mk does not +scan `#include`s -- without it, editing `php_config.h` rebuilds +nothing and the next run measures the old binary, which is how +`HELP_BUILTIN` was turned on and did not reach bash. + +`mkcont-sweep` and `rceq-sweep` both pass; `apehdr-sweep` is +**identical with and without** the new `` (151/152 +headers, the same 8 pre-existing TOGETHER errors), which is a control +rather than a reading of the messages. + +**php is deliberately NOT in `sys/src/ape/cmd/mkfile`.** One failing +entry aborts the whole tree's `mk`, and a port that has never been +built has not been measured in that position. `cd sys/src/ape/cmd/php +&& mk` is how to try it. + +## What the config.h decided, and why by hand + +The long reasoning is in the file itself; what matters as a summary: + +***TWO MACROS ARE ANSWERED NO FOR CAPABILITIES THAT ARE PRESENT, LINK, +AND RETURN SUCCESS.*** This is clisp's `mprotect` rule, twice: + +* **`HAVE_MPROTECT`** -- `plan9/mman.c:44` is `return 0`, a stub + answering success. Nothing it is asked to protect is protected. +* **`HAVE_MREMAP`** -- *and this one is worse, because the caller is + told it succeeded at something else*. APExp's `mremap` allocates and + copies: it MOVES. `zend_mm_chunk_extend` calls + `mremap(addr, old, new, 0)` with no `MREMAP_MAYMOVE` precisely + because it needs the chunk to stay put, and returns success on + anything that is not `MAP_FAILED`. Zend would record a chunk as + extended in place while the memory had moved: not a failure, a + silently wrong heap. + +A configure probe that compiles and links cannot tell either of these +from the real thing. *That is the whole argument for hand-answering, +and php supplies it twice without being asked.* + +**`STRERROR_R_CHAR_P` is unset and copying the host answer would have +been a real bug**: glibc's `strerror_r` returns `char *`, APE's is +POSIX's returning `int` (`:45`). php would have used an +`int` as a pointer. + +**`ZEND_CHECK_STACK_LIMIT` is unset, and the cost is recorded rather +than hidden**: `zend_call_stack.c` finds the stack bounds through +`pthread_getattr_np`, `pthread_attr_getstack`, `/proc`, `sysctl` or a +Windows call, and APExp has none. Deep PHP recursion will fault +instead of raising an error. + +**`HAVE_IPV6` is unset and that is a CHOICE, not a finding.** +`AF_INET6` and `struct sockaddr_in6` both exist. Nothing in this tree +has ever exercised IPv6 through APE's socket layer, and a port's first +build is the wrong place to open an unmeasured path. Revisit with a +test, not with an edit. + +***AND A QUESTION ANSWERED ITSELF.*** The sweep found **37 functions +APE has that the host configure left `#undef`** -- `clock_gettime`, +`select`, `strndup`, `times`, `utimes`, `pread`, `getlogin` and so on +-- which looked like a judgement call about enabling code paths +upstream never compiles on Linux. It is not: **`grep` says all 37 are +referenced in 0 files** of what this port builds. Nothing reads them, +so there was nothing to decide. + ## Open, as a list * fibers: **done** — `ucontext` is in libap and `ucontext-test` is 0 failures on the VM (`docs/notes/libap.md`). What remains is pointing php at it: `ZEND_FIBER_UCONTEXT` in the `config.h` -* `main/php_config.h` not written yet; the inventory is derived, the - answers are not +* the first build: `cd sys/src/ape/cmd/php && mk`. Nothing has + compiled yet, so the object list, the include paths and every + answer in the `config.h` are all unmeasured together * `memfd_create` is declared with no implementation, which is a libap trap independent of php * `sys/src/ape/lib/ap/time/asctime_r.c:30` is diff --git a/sys/src/ape/cmd/php/build-defs.h b/sys/src/ape/cmd/php/build-defs.h new file mode 100644 index 000000000..9bc09d635 --- /dev/null +++ b/sys/src/ape/cmd/php/build-defs.h @@ -0,0 +1,35 @@ +/* + * build-defs.h -- generated by configure in an upstream build; + * hand-answered here. + * + * ***THE PATHS ARE ARCHITECTURE-INDEPENDENT ON PURPOSE.*** They are + * baked into the binary as string constants, so they cannot carry + * `$objtype' -- and they do not need to: php's runtime files are + * text. `/sys/lib/ape/php' follows `cmd/bash/mkfile's + * `-DLOCALEDIR="/sys/lib/ape/locale"', which is the same shape. + * Only the BINARY is per-architecture, and the mkfile installs that + * through `$BIN'. + * + * `PHP_EXTENSION_DIR' and the shared-library names are empty because + * **Plan 9 has no dynamic linking** -- the same reason perl here has + * no XS extensions and `HAVE_LIBDL' is unset in `php_config.h'. A + * path would be a promise nothing can keep. + */ + +#define CONFIGURE_COMMAND "hand-answered for APExp; see sys/src/ape/cmd/php/mkfile" +#define PHP_PROG_SENDMAIL "" +#define PEAR_INSTALLDIR "" +#define PHP_INCLUDE_PATH ".:/sys/lib/ape/php" +#define PHP_EXTENSION_DIR "" +#define PHP_PREFIX "/sys/lib/ape/php" +#define PHP_BINDIR "/bin/ape" +#define PHP_SBINDIR "/bin/ape" +#define PHP_MANDIR "/sys/man" +#define PHP_LIBDIR "/sys/lib/ape/php" +#define PHP_DATADIR "/sys/lib/ape/php" +#define PHP_SYSCONFDIR "/sys/lib/ape/php" +#define PHP_LOCALSTATEDIR "/tmp" +#define PHP_CONFIG_FILE_PATH "/sys/lib/ape/php" +#define PHP_CONFIG_FILE_SCAN_DIR "" +#define PHP_SHLIB_SUFFIX "" +#define PHP_SHLIB_EXT_PREFIX "" diff --git a/sys/src/ape/cmd/php/internal_functions_cli.c b/sys/src/ape/cmd/php/internal_functions_cli.c new file mode 100644 index 000000000..7f9ce1f8d --- /dev/null +++ b/sys/src/ape/cmd/php/internal_functions_cli.c @@ -0,0 +1,76 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Andi Gutmans | + | Zeev Suraski | + +----------------------------------------------------------------------+ + */ + +/* + * internal_functions_cli.c -- generated by configure in an upstream + * build; kept here so `external/php' stays untouched. + * + * It is the table of extensions linked into the binary, and it is + * DERIVED rather than written: configure produced it from the flags + * in this port's mkfile. The eleven below are what `--disable-all' + * leaves, which is to say the ones php 8.5 builds unconditionally. + * **`opcache' is in the list and has to be**: there is no + * `--disable-opcache'. It only has to register, since + * `opcache.enable_cli' is off by default and the accelerator never + * starts -- which is why all three of its shared-memory macros are + * answered no in `php_config.h'. + * + * Adding an extension means adding its header, its `phpext_*_ptr' and + * its objects to the mkfile, together. + */ +#include "php.h" +#include "php_main.h" +#include "zend_modules.h" +#include "zend_compile.h" +#include +#include +#include + +#include "ext/date/php_date.h" +#include "ext/pcre/php_pcre.h" +#include "ext/hash/php_hash.h" +#include "ext/json/php_json.h" +#include "ext/lexbor/php_lexbor.h" +#include "ext/opcache/zend_accelerator_module.h" +#include "ext/random/php_random.h" +#include "ext/reflection/php_reflection.h" +#include "ext/spl/php_spl.h" +#include "ext/standard/php_standard.h" +#include "ext/uri/php_uri.h" + + +static zend_module_entry * const php_builtin_extensions[] = { + phpext_date_ptr, + phpext_pcre_ptr, + phpext_hash_ptr, + phpext_json_ptr, + phpext_lexbor_ptr, + phpext_opcache_ptr, + phpext_random_ptr, + phpext_reflection_ptr, + phpext_standard_ptr, + phpext_spl_ptr, + phpext_uri_ptr, + +}; + +#define EXTCOUNT (sizeof(php_builtin_extensions)/sizeof(zend_module_entry *)) + +PHPAPI int php_register_internal_extensions(void) +{ + return php_register_extensions(php_builtin_extensions, EXTCOUNT); +} diff --git a/sys/src/ape/cmd/php/mkfile b/sys/src/ape/cmd/php/mkfile new file mode 100644 index 000000000..2215169da --- /dev/null +++ b/sys/src/ape/cmd/php/mkfile @@ -0,0 +1,674 @@ +: long long */ + +#define ZEND_MM_ALIGNMENT (size_t)8 +#define ZEND_MM_ALIGNMENT_LOG2 (size_t)3 +#define ZEND_MM_NEED_EIGHT_BYTE_REALIGNMENT 0 + +/* ------------------------------------------------------------------ * + * Compiler features: kencc has none of them, and that is load-bearing + * rather than unfortunate. `HAVE_GCC_GLOBAL_REGS' being absent is + * what leaves `ZEND_VM_KIND' at `ZEND_VM_KIND_CALL' + * (`zend_vm_opcodes.h:40'), which is the dispatch the shipped + * `zend_vm_execute.h' can serve without a bootstrap php to regenerate + * it. `HAVE_ASM_GOTO' being absent is what keeps + * `ZEND_USE_ASM_ARITHMETIC' at 0 (`zend_operators.h:547'), which is + * what keeps four `__x86_64__' arms in that file from reaching GCC + * inline assembly. + * ------------------------------------------------------------------ */ +/* #undef HAVE_ASM_GOTO */ +/* #undef HAVE_GCC_GLOBAL_REGS */ +/* #undef HAVE_MUSTTAIL */ +/* #undef HAVE_PRESERVE_NONE */ +/* #undef HAVE_ALIGNOF */ +/* #undef HAVE_ATTRIBUTE_ALIGNED */ +/* #undef HAVE_FUNC_ATTRIBUTE_IFUNC */ +/* #undef HAVE_FUNC_ATTRIBUTE_TARGET */ +/* #undef HAVE_CPUID_COUNT */ +/* #undef HAVE_FPU_INLINE_ASM_X86 */ +/* #undef HAVE__FPU_SETCW */ +/* #undef PHP_HAVE_AVX512_SUPPORTS */ +/* #undef PHP_HAVE_AVX512_VBMI_SUPPORTS */ +/* #undef PHP_HAVE_BUILTIN_CLZ */ +/* #undef PHP_HAVE_BUILTIN_CLZL */ +/* #undef PHP_HAVE_BUILTIN_CLZLL */ +/* #undef PHP_HAVE_BUILTIN_CPU_INIT */ +/* #undef PHP_HAVE_BUILTIN_CPU_SUPPORTS */ +/* #undef PHP_HAVE_BUILTIN_CTZL */ +/* #undef PHP_HAVE_BUILTIN_CTZLL */ +/* #undef PHP_HAVE_BUILTIN_EXPECT */ +/* #undef PHP_HAVE_BUILTIN_FRAME_ADDRESS */ +/* #undef PHP_HAVE_BUILTIN_SADDL_OVERFLOW */ +/* #undef PHP_HAVE_BUILTIN_SADDLL_OVERFLOW */ +/* #undef PHP_HAVE_BUILTIN_SMULL_OVERFLOW */ +/* #undef PHP_HAVE_BUILTIN_SMULLL_OVERFLOW */ +/* #undef PHP_HAVE_BUILTIN_SSUBL_OVERFLOW */ +/* #undef PHP_HAVE_BUILTIN_SSUBLL_OVERFLOW */ +/* #undef PHP_HAVE_BUILTIN_UNREACHABLE */ +/* #undef PHP_HAVE_BUILTIN_USUB_OVERFLOW */ + +/* ------------------------------------------------------------------ * + * Headers. Mechanical: these are the 39 that exist. + * ------------------------------------------------------------------ */ +#define STDC_HEADERS 1 +#define HAVE_ALLOCA_H 1 +#define HAVE_ARPA_INET_H 1 +#define HAVE_ARPA_NAMESER_H 1 +#define HAVE_DIRENT_H 1 +#define HAVE_FCNTL_H 1 +#define HAVE_GRP_H 1 +#define HAVE_INTTYPES_H 1 +#define HAVE_LANGINFO_H 1 +#define HAVE_NETINET_IN_H 1 +#define HAVE_NET_IF_H 1 +#define HAVE_POLL_H 1 +#define HAVE_PWD_H 1 +#define HAVE_RESOLV_H 1 +#define HAVE_STDINT_H 1 +#define HAVE_STDIO_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRINGS_H 1 +#define HAVE_STRING_H 1 +#define HAVE_SYSEXITS_H 1 +#define HAVE_SYSLOG_H 1 +#define HAVE_SYS_FILE_H 1 +#define HAVE_SYS_IOCTL_H 1 +#define HAVE_SYS_MMAN_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_RESOURCE_H 1 +#define HAVE_SYS_SELECT_H 1 +#define HAVE_SYS_SOCKET_H 1 +#define HAVE_SYS_STATVFS_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_SYSMACROS_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_SYS_UIO_H 1 +#define HAVE_SYS_UTSNAME_H 1 +#define HAVE_SYS_WAIT_H 1 +#define HAVE_UNISTD_H 1 +#define HAVE_UTIME_H 1 +#define HAVE_WCHAR_H 1 +#define MAJOR_IN_SYSMACROS 1 + +/* + * ***`HAVE_DLFCN_H' IS THE EXCEPTION, AND IT IS ANSWERED NO.*** The + * header exists; `dlopen' and `dlerror' are DECLARED-ONLY, which is + * the state `apfunc-sweep' exists to find. Claiming it would cost a + * link error a long way from this line. `HAVE_LIBDL' goes with it, + * and Plan 9 has no dynamic linking at all -- the same reason perl + * here has no XS extensions. + */ +/* #undef HAVE_DLFCN_H */ +/* #undef HAVE_LIBDL */ + +/* absent: ODBC (14 names), tidy, linux/*, the SSE intrinsic headers, + * Windows, crypt.h, sys/ipc.h, sys/mount.h, sys/statfs.h, sys/vfs.h, + * pty.h, ieeefp.h, cpuid.h, io.h, dns.h, libproc.h, valgrind. */ +/* #undef HAVE_CRYPT_H */ +/* #undef HAVE_IMMINTRIN_H */ +/* #undef HAVE_TMMINTRIN_H */ +/* #undef HAVE_NMMINTRIN_H */ +/* #undef HAVE_WMMINTRIN_H */ +/* #undef HAVE_SYS_IPC_H */ +/* #undef HAVE_SYS_MOUNT_H */ +/* #undef HAVE_SYS_STATFS_H */ +/* #undef HAVE_SYS_VFS_H */ +/* #undef HAVE_SYS_POLL_H */ +/* #undef HAVE_SYS_LOADAVG_H */ +/* #undef HAVE_SYS_ACL_H */ +/* #undef HAVE_PTY_H */ +/* #undef HAVE_IEEEFP_H */ +/* #undef HAVE_CPUID_H */ + +/* ------------------------------------------------------------------ * + * The two that LIE, and they are the whole reason this file is + * hand-written. + * ------------------------------------------------------------------ */ +/* + * `mprotect' is `return 0' -- `lib/ap/plan9/mman.c:44', a stub + * answering SUCCESS. Nothing it is asked to protect is protected. + * This is the macro that cost clisp a round: there it switches on a + * generational GC whose write barrier is page protection plus SIGSEGV, + * so the barrier never fires and the collector frees live objects. + */ +/* #undef HAVE_MPROTECT */ + +/* + * ***`mremap' IS WORSE, BECAUSE THE CALLER IS TOLD IT SUCCEEDED AT + * SOMETHING ELSE.*** APExp's `mremap' allocates new memory and copies + * -- it MOVES. `Zend/zend_alloc.c's `zend_mm_chunk_extend' calls + * `mremap(addr, old, new, 0)' with no MREMAP_MAYMOVE, precisely + * because it needs the chunk to stay put, and returns 1 on anything + * that is not MAP_FAILED. So Zend would record a chunk as extended in + * place while the memory had moved: *not a failure, a silently wrong + * heap*. + */ +/* #undef HAVE_MREMAP */ + +/* + * `mmap' and `munmap' are real enough for php, and that was measured + * rather than assumed -- `sys/lib/tests/mmaptrim-probe.c'. Zend's + * allocator maps over-sized and trims head and tail to land a + * 2MB-aligned chunk; both trims survive, and `SEG_THRESHOLD' is 64MB + * so a 2MB chunk costs no Plan 9 segment slot (there are five). + */ +#define HAVE_MMAP 1 + +/* + * opcache is MANDATORY in 8.5 -- there is no `--disable-opcache' -- + * but it only has to COMPILE, since `opcache.enable_cli' is off by + * default and the accelerator never starts. All three of its shared + * memory backends are answered no, and that is deliberate: `shm_open' + * here is a file in `/tmp' (`plan9/mman.c') over a per-process `mmap', + * so it would answer a probe YES and share nothing. The + * HAVE_WORKING_MPROTECT shape a third time. + */ +/* #undef HAVE_SHM_IPC */ +/* #undef HAVE_SHM_MMAP_ANON */ +/* #undef HAVE_SHM_MMAP_POSIX */ + +/* ------------------------------------------------------------------ * + * Functions: `apfunc-sweep.py' says DEFINED for each of these. + * ------------------------------------------------------------------ */ +#define HAVE_ALLOCA 1 +#define HAVE_ALPHASORT 1 +#define HAVE_ARC4RANDOM_BUF 1 +#define HAVE_ASCTIME_R 1 +#define HAVE_ASPRINTF 1 +#define HAVE_ATOLL 1 +#define HAVE_CHROOT 1 +#define HAVE_CTIME_R 1 +#define HAVE_DN_EXPAND 1 +#define HAVE_DN_SKIPNAME 1 +#define HAVE_FLOCK 1 +#define HAVE_FNMATCH 1 +#define HAVE_FORK 1 +#define HAVE_GAI_STRERROR 1 +#define HAVE_GETADDRINFO 1 +#define HAVE_GETCWD 1 +#define HAVE_GETGRNAM_R 1 +#define HAVE_GETHOSTBYNAME_R 1 +#define HAVE_GETHOSTNAME 1 +#define HAVE_GETOPT 1 +#define HAVE_GETPID 1 +#define HAVE_GETPROTOBYNAME 1 +#define HAVE_GETPROTOBYNUMBER 1 +#define HAVE_GETPWNAM_R 1 +#define HAVE_GETPWUID_R 1 +#define HAVE_GETRANDOM 1 +#define HAVE_GETRUSAGE 1 +#define HAVE_GETSERVBYNAME 1 +#define HAVE_GETSERVBYPORT 1 +#define HAVE_GETTIMEOFDAY 1 +#define HAVE_GLOB 1 +#define HAVE_GMTIME_R 1 +#define HAVE_KILL 1 +#define HAVE_LOCALTIME_R 1 +#define HAVE_MEMMEM 1 +#define HAVE_MEMPCPY 1 +#define HAVE_MEMRCHR 1 +#define HAVE_MKSTEMP 1 +#define HAVE_NANOSLEEP 1 +#define HAVE_NL_LANGINFO 1 +#define HAVE_POLL 1 +#define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP 1 +#define HAVE_PUTENV 1 +#define HAVE_REALLOCARRAY 1 +#define HAVE_RES_SEARCH 1 +#define HAVE_SCANDIR 1 +#define HAVE_SETENV 1 +#define HAVE_SETITIMER 1 +#define HAVE_SHUTDOWN 1 +#define HAVE_SIGACTION 1 +#define HAVE_SIGPROCMASK 1 +#define HAVE_SOCKETPAIR 1 +#define HAVE_STATVFS 1 +#define HAVE_STRCASECMP 1 +#define HAVE_STRERROR_R 1 +#define HAVE_STRLCAT 1 +#define HAVE_STRLCPY 1 +#define HAVE_STRNLEN 1 +#define HAVE_STRPTIME 1 +#define HAVE_STRTOK_R 1 +#define HAVE_STRTOLL 1 +#define HAVE_SYMLINK 1 +#define HAVE_TZSET 1 +#define HAVE_UNSETENV 1 +#define HAVE_USLEEP 1 +#define HAVE_UTIME 1 +#define HAVE_VASPRINTF 1 +#define HAVE_DECL_STRERROR_R 1 +#define HAVE_DECL_STRPTIME 1 + +/* + * ***`STRERROR_R_CHAR_P' IS THE ONE TO GET RIGHT AND IT IS NOT SET.*** + * glibc's `strerror_r' returns `char *'; APE's is POSIX's, returning + * `int' (`:45', `string/strerror_r.c:4'). Defining it the + * way the host config does would have php use an `int' as a pointer. + * *Copying the Linux answer here is not a small error.* + */ +/* #undef STRERROR_R_CHAR_P */ + +/* + * Absent, each confirmed by the sweep rather than assumed. + * `explicit_bzero' is absent and php ships its own + * (`main/explicit_bzero.c', already in the object list); `fdatasync' + * falls back to `fsync'. `copy_file_range' and `memfd_create' are + * DECLARED-ONLY, which is the state that link-fails, so they are no. + */ +/* #undef HAVE_COPY_FILE_RANGE */ +/* #undef HAVE_EXPLICIT_BZERO */ +/* #undef HAVE_FDATASYNC */ +/* #undef HAVE_FOPENCOOKIE */ +/* #undef COOKIE_SEEKER_USES_OFF64_T */ +/* #undef HAVE_FTOK */ +/* #undef HAVE_FUNC_GETHOSTBYNAME_R_6 */ +/* #undef HAVE_GETIFADDRS */ +/* #undef HAVE_GETLOADAVG */ +/* #undef HAVE_GETTID */ +/* #undef HAVE_GETWD */ +/* #undef HAVE_LCHOWN */ +/* #undef HAVE_MEMFD_CREATE */ +/* #undef HAVE_NICE */ +/* #undef HAVE_OPENPTY */ +/* #undef HAVE_PRCTL */ +/* #undef HAVE_PTHREAD_ATTR_GETSTACK */ +/* #undef HAVE_PTHREAD_GETATTR_NP */ +/* #undef HAVE_RES_NSEARCH */ +/* #undef HAVE_STATFS */ +/* #undef ENABLE_CHROOT_FUNC */ + +/* ------------------------------------------------------------------ * + * Types and struct members, each read out of the APE header. + * ------------------------------------------------------------------ */ +#define HAVE_SOCKLEN_T 1 /* :30 */ +#define HAVE_STRUCT_FLOCK 1 +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 +#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 /* :24 */ +#define HAVE_STRUCT_STAT_ST_BLOCKS 1 /* :25 */ +#define HAVE_STRUCT_STAT_ST_RDEV 1 +#define HAVE_ST_BLOCKS 1 +#define HAVE_STRUCT_TM_TM_GMTOFF 1 /* :68 */ +#define HAVE_STRUCT_TM_TM_ZONE 1 /* :69 */ +#define HAVE_TM_ZONE 1 + +/* + * `AF_INET6' and `struct sockaddr_in6' both exist + * (`:115', `:193'), so this could be yes. + * **It is no for the first build and that is a choice, not a finding**: + * nothing in this tree has ever exercised IPv6 through APE's socket + * layer, and a port's first build is the wrong place to open a path + * nobody has measured. Revisit with a test, not with an edit. + */ +/* #undef HAVE_IPV6 */ + +/* ------------------------------------------------------------------ * + * php's own switches. + * ------------------------------------------------------------------ */ +#define PHP_OS "Plan9" +#define PHP_UNAME "Plan9" +#define PHP_BUILD_SYSTEM "Plan9 APExp" +#define PHP_OS_FAMILY "BSD" +#define DEFAULT_SHORT_OPEN_TAG "1" +#define PHP_SIGCHILD 0 +#define ZEND_DEBUG 0 +#define ZEND_DLIMPORT +#define PHP_WRITE_STDOUT 1 +#define PHP_USE_PHP_CRYPT_R 1 /* no crypt.h; php bundles four */ +#define HAVE_BUNDLED_PCRE 1 +#define PCRE2_CODE_UNIT_WIDTH 8 +#define HAVE_LEXBOR 1 +#define URI_ENABLE_ANSI 1 +#define URI_NO_UNICODE 1 +#define PHP_CAN_SUPPORT_PROC_OPEN 1 + +/* + * ***THE POINT OF THE LAST ROUND.*** `zend_fibers.c' is unconditional + * because `Fiber' is a language class, and it needs either + * boost.context's GAS assembly or this. libap has `' now + * (`lib/ap/arch/amd64/ucontext.s' and `makecontext.c'), measured by + * `sys/lib/tests/ucontext-test.c' at 0 failures on the machine. + */ +#define ZEND_FIBER_UCONTEXT 1 + +/* + * `zend_call_stack.c' finds the stack bounds through + * `pthread_getattr_np', `pthread_attr_getstack', `/proc', `sysctl' or + * a Windows call, and APExp has NONE of them. Answering yes would + * leave `zend_call_stack_get' returning false at run time, which is + * the same outcome by a longer route; answering no says so at compile + * time. **The cost is real and is recorded rather than hidden**: deep + * PHP recursion faults instead of raising an error. + */ +/* #undef ZEND_CHECK_STACK_LIMIT */ +/* #undef ZEND_MAX_EXECUTION_TIMERS */ +/* #undef HAVE_VALGRIND */ +/* #undef HAVE_DTRACE */ +/* #undef HAVE_HUGE_CODE_PAGES */ + +#endif /* PHP_CONFIG_H */ diff --git a/sys/src/ape/cmd/php/timelib_config.h b/sys/src/ape/cmd/php/timelib_config.h new file mode 100644 index 000000000..387e4eeae --- /dev/null +++ b/sys/src/ape/cmd/php/timelib_config.h @@ -0,0 +1,22 @@ +/* + * timelib_config.h -- generated by configure in an upstream build; + * hand-kept here. `ext/date/lib' reaches it because the mkfile + * passes `-DHAVE_TIMELIB_CONFIG_H=1'. + * + * It exists to route timelib's allocation through the Zend allocator, + * which is the whole of its content upstream as well -- this is a + * copy of what configure writes, not a port of anything. + */ +#include + +#include +#include + +#include "zend.h" + +#define timelib_malloc emalloc +#define timelib_realloc erealloc +#define timelib_calloc ecalloc +#define timelib_strdup estrdup +#define timelib_strndup estrndup +#define timelib_free efree diff --git a/sys/src/ape/cmd/php/zend_config.h b/sys/src/ape/cmd/php/zend_config.h new file mode 100644 index 000000000..868d0bd63 --- /dev/null +++ b/sys/src/ape/cmd/php/zend_config.h @@ -0,0 +1,7 @@ +/* + * zend_config.h -- the file `Zend/zend_portability.h:43' includes as + * . configure generates a one-line version of this + * into the source tree; ours is here instead, so `external/php' stays + * untouched vendor source, and the mkfile puts `-I.' first. + */ +#include