Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,16 @@ that the instrument notices.*
nothing declares), `apehdr-sweep.py` (every `sys/include/ape` header
standalone, plus a TOGETHER case for collisions only a combination can
show), `rceq-sweep.py` (**gates**: a bare `=` in an mkfile recipe cannot
parse), `mkcont-sweep.py` (**gates**: a comment ending a continuation),
parse), `mkcont-sweep.py` (**gates**: a logical line mk cannot parse. TWO
shapes, and *the second was added after the first reported 0 over
it*: a comment ending a continuation, and an INDENTED line that is
not a recipe — `cmd/php/mkfile` ended its `OFILES` at an ordinary
entry and left a tab-indented one orphaned five comment lines later.
**Recipes are the whole difficulty**, since every recipe body is
indented and has no `:` or `=`, so the discriminator is what the last
non-indented logical line was; `--control` carries one of each shape
*and a real recipe*, because a control without one would pass for a
version that reports every mkfile),
`ishadow-sweep.py` (does NOT gate — most hits are deliberate),
`hosthelper-sweep.py` (**does NOT gate, on purpose**: which mkfile
recipes run a binary the same mkfile builds, and whether it was built
Expand Down
35 changes: 35 additions & 0 deletions docs/notes/php.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,46 @@ Which maps to: `mbstring` (oniguruma), `openssl` (libressl), `curl`,
`zlib`, `bz2`, `libxml`/`dom`/`simplexml`/`xml`/`xmlreader`/`xmlwriter`,
`sqlite3` + `pdo_sqlite`, `zip`, `readline`, `gd` (png only), `intl`.

***THESE ARE A DIFFERENT RISK CLASS FROM ANYTHING ON PECL, AND THAT IS
THE DISTINCTION TO KEEP.*** Every one of them SHIPS WITH php 8.5, is
tested by upstream against this exact version, and is turned on with a
`--with-X` against a library this tree already has. A PECL package is
a separate source tree with its own maintenance state and its own
target php version. *The first is a flag; the second is a port.*

**`ext/pcre` bundles its own pcre2 and that is what the 29 objects are.**
`--with-external-pcre` would use `sys/src/ape/lib/pcre2` instead; the
bundled copy is the better starting point, because it is the version php
was tested against and it removes a link dependency from the first build.

### php-lua and php-tk: a different risk class, and the answer is no for now

Asked directly, so recorded rather than left to be re-asked. **Neither
is vendored and neither ships with php** -- `sys/src/external/lua` and
`external/tk` are the LIBRARIES, and `php/ext/` has no `lua` or `tk`.
Both would be PECL packages to bring in, and PECL extensions build as
shared modules by default, which Plan 9 cannot load at all; they would
have to be linked statically and listed in the mkfile and
`internal_functions_cli.c` by hand. *That part is mechanical and the
port directory is already arranged for it.* The problem is upstream.

**`tk` is PECL 0.1.1 beta, dated 2004-11-14, and its own page says the
package is unmaintained and invites someone to take it over.** That is
the PHP 4 extension API: no `zend_string`, the PHP 7 zval rework, the
arginfo requirements and the TSRMLS removal all postdate it. This is
not an extension to enable, it is a rewrite -- *bigger than most of
what this tree has ported* -- and a GUI binding additionally needs an
event loop married to php's request lifecycle, on top of our own
`external/tk/plan9` backend. No.

**`lua` is less clear and still not first.** The PECL `lua` package
looks PHP 7-era; **LuaSandbox** is the one actually packaged for PHP
8.0 through 8.5. *Which also means it is a different extension with a
different API*, and it is worth checking before any work whether it
wants Lua **5.1** -- it comes from MediaWiki's Scribunto, which
standardised there -- because this tree ships **5.5.0**. A version
mismatch would be its own port.

**No extension should be enabled in the first build.** The order that
has worked in this tree is: get the thing to compile and print its own
version, then add one library at a time.
Expand Down
116 changes: 114 additions & 2 deletions sys/lib/tests/mkcont-sweep.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#!/usr/bin/env python3
"""
mkcont-sweep -- which mkfile has a COMMENT that silently ends a
continued assignment, leaving the rest of the list as a bare word?
mkcont-sweep -- which mkfile has a logical line mk cannot parse,
because a continuation ended where nobody meant it to?

Two shapes, and the second was added after the first missed it.

python3 sys/lib/tests/mkcont-sweep.py

Expand Down Expand Up @@ -41,6 +43,28 @@
because mk accepts it. It is still wrong -- the dropped entries are
silently not built -- but it has no symptom this can see, so this is a
LOWER BOUND like every other sweep here.

------------------------------------------------------------------
SHAPE TWO: AN ORPHAN INDENTED LINE, AND THIS SWEEP REPORTED 0 OVER IT.

`cmd/php/mkfile' ended its `OFILES' at the last generated entry and
then had a blank line, five comment lines and a tab-indented
`internal_functions_cli.$O' that was meant to be part of the list. mk
answered `mkfile:612: syntax error; expected one of :<=' -- and **the
check above never fired, because the continuation was ended by an
ordinary entry rather than by a comment.**

The generalisation is the one mk itself uses, and it covers both: a
logical line that starts with a bare word -- no `:', `=' or leading
`<' -- is a syntax error WHEREVER it came from. An INDENTED one is a
syntax error unless it is a recipe, which means the rule above it had
a `:'. So this now also reports an indented logical line that follows
an ASSIGNMENT rather than a rule.

*Recipes are the whole difficulty*: every recipe body line is indented
and has no `:' or `=', so a naive version of this check reports the
entire tree. The discriminator is what the last non-indented logical
line was.
"""

import os
Expand All @@ -53,6 +77,37 @@
"report 0 findings from the wrong tree" % ROOT)


def logical(lines):
"""yield (start_line_index, joined_text, first_raw) per logical line"""
i = 0
while i < len(lines):
start = i
parts = [lines[i].rstrip()]
while parts[-1].endswith("\\") and i + 1 < len(lines):
i += 1
parts.append(lines[i].rstrip())
yield start, "\n".join(parts), lines[start]
i += 1


def orphans(path):
"""shape two: an indented logical line that is not a recipe"""
lines = open(path, encoding="latin1").read().split("\n")
out = []
in_recipe = False
for start, text, raw in logical(lines):
bare = raw.strip()
if not bare or bare.startswith("#"):
continue # blank and comment end nothing, deliberately
if raw[:1] in (" ", "\t"):
if not in_recipe:
out.append((start + 1, bare))
continue
# a non-indented logical line: does a recipe follow it?
in_recipe = ":" in text.split("\n")[0]
return out


def check(path):
lines = open(path, encoding="latin1").read().split("\n")
out = []
Expand All @@ -73,7 +128,59 @@ def check(path):
return out


CONTROL_ONE = """\
OFILES=\\
\ta.$O\\
# a comment that forgets its backslash
\tb.$O\\
\tc.$O
"""

CONTROL_TWO = """\
OFILES=\\
\ta.$O\\
\tb.$O

# a comment block, and then an entry meant to be part of the list
\tc.$O

install:V:
\techo this recipe must NOT be reported
"""


def control():
"""Both shapes, because a sweep that only proves it can say one
thing has not been shown to say the other. CONTROL_TWO carries a
real recipe as well: the discriminator between an orphan and a
recipe body is the whole difficulty, so a control that omits the
recipe would pass for a version that reports every mkfile."""
import tempfile
ok = True
with tempfile.TemporaryDirectory() as d:
for name, body, fn, want in (
("one", CONTROL_ONE, lambda p: check(p), 1),
("two", CONTROL_TWO, lambda p: orphans(p), 1)):
p = os.path.join(d, "mkfile")
open(p, "w").write(body)
got = len(fn(p))
print("control %s: %d finding(s), want %d -- %s"
% (name, got, want, "ok" if got == want else "FAILED"))
if got != want:
ok = False
# and the recipe in CONTROL_TWO must not be among them
p = os.path.join(d, "mkfile")
open(p, "w").write(CONTROL_TWO)
for (ln, text) in orphans(p):
if "echo" in text:
print("control two: REPORTED A RECIPE BODY -- FAILED")
ok = False
return 0 if ok else 1


def main():
if "--control" in sys.argv:
return control()
findings = 0
for base in ("sys/src/ape", "sys/src/cmd", "sys/src/cmd2"):
top = os.path.join(ROOT, base)
Expand All @@ -90,6 +197,11 @@ def main():
print(" %s" % text.strip()[:68])
print(" :%d is then a bare word mk cannot parse:" % nl)
print(" %s" % nxt.strip()[:68])
for (ln, text) in orphans(p):
findings += 1
print("%s:%d indented line that is not a recipe:" %
(os.path.relpath(p, ROOT), ln))
print(" %s" % text[:68])
print()
print("%d broken continuation(s)." % findings)
if findings:
Expand Down
17 changes: 10 additions & 7 deletions sys/src/ape/cmd/php/mkfile
Original file line number Diff line number Diff line change
Expand Up @@ -601,13 +601,16 @@ OFILES=\
sapi/cli/php_cli_process_title.$O\
sapi/cli/php_cli_server.$O\
sapi/cli/php_http_parser.$O\
sapi/cli/ps_title.$O

# `internal_functions_cli.c' is generated by configure -- it is the
# table of built-in extension entries -- and ours is beside this
# mkfile rather than in `external/php', so the vendored tree stays
# untouched. Same for `php_config.h', `zend_config.h',
# `timelib_config.h' and `build-defs.h'.
sapi/cli/ps_title.$O\
# `internal_functions_cli.c' is generated by configure -- it is the\
# table of built-in extension entries -- and ours is beside this\
# mkfile rather than in `external/php', so the vendored tree stays\
# untouched. Same for `php_config.h', `zend_config.h',\
# `timelib_config.h' and `build-defs.h'. ***IT IS ALSO THE LAST\
# ENTRY, AND THE ONLY LINE IN THIS LIST WITHOUT A TRAILING\
# BACKSLASH*** -- the first version ended the list one line above and\
# left this tab-indented line orphaned, which mk answered with\
# `mkfile:612: syntax error; expected one of :<='.\
internal_functions_cli.$O

# ***WITHOUT THIS LINE, EDITING `php_config.h' REBUILDS NOTHING.***
Expand Down
Loading