Skip to content
Open
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
38 changes: 37 additions & 1 deletion build/gen_stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -1299,6 +1299,19 @@ public function generateVersionDependentFlagCode(
}
}

class IncludeInfo {
public /* readonly */ ?string $cond;
public /* readonly */ string $include;

public function __construct(
string $include,
?string $cond,
) {
$this->include = $include;
$this->cond = $cond;
}
}

class FuncInfo {
public /* readonly */ FunctionOrMethodName $name;
private /* readonly */ int $classFlags;
Expand Down Expand Up @@ -4189,6 +4202,8 @@ class FileInfo {
public array $funcInfos = [];
/** @var ClassInfo[] */
public array $classInfos = [];
/** @var IncludeInfo[] */
public array $includeInfos = [];
public bool $generateFunctionEntries = false;
public string $declarationPrefix = "";
public bool $generateClassEntries = false;
Expand Down Expand Up @@ -4337,6 +4352,16 @@ private function handleStatements(array $stmts, PrettyPrinterAbstract $prettyPri
$conds = [];
foreach ($stmts as $stmt) {
$cond = self::handlePreprocessorConditions($conds, $stmt);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think using declare() is the right approach here, it adds a new declaration in stubs that isn't valid in normal PHP code, meaning that stubs would no longer be valid PHP:

Warning: Unsupported declare 'c_include' in /in/oj65h on line 3

can I suggest instead just using a C preprocessor macro, #include <stdint.h>
this would be a comment, so it would get skipped in the next block, and you would just add handling to handlePreprocessorConditions to ensure that for #include a new IncludeInfo is added (make the handlePreprocessorConditions method non-static)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree that this is somewhat abusing the existing PHP syntax.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

meaning that stubs would no longer be valid PHP:

This is just a warning. It's valid PHP code.

can I suggest instead just using a C preprocessor macro,

I initially tried that, but it got pretty ugly: The existing logic to handle #if / #endif is “statement-based”. Since the #include would not be a statement, special handling would be required.

Also the declare nicely forces the #include to appear at the top of the file, avoiding random includes from appearing somewhere in the middle of the stub.

if ($stmt instanceof Stmt\Declare_) {
foreach ($stmt->declares as $declare) {
if ($declare->key->name !== 'c_include') {
throw new Exception("Unexpected declare {$declare->key->name}");
}
$this->includeInfos[] = new IncludeInfo((string)EvaluatedValue::createFromExpression($declare->value, null, null, [])->value, $cond);
}
continue;
}

if ($stmt instanceof Stmt\Nop) {
continue;
Expand Down Expand Up @@ -5111,7 +5136,7 @@ function generateCodeWithConditions(
continue;
}

if ($info->cond && $info->cond !== $parentCond) {
if ($info->cond !== null && $info->cond !== $parentCond) {
if ($openCondition !== null
&& $info->cond !== $openCondition
) {
Expand Down Expand Up @@ -5162,6 +5187,17 @@ function generateArgInfoCode(

$generatedFuncInfos = [];

$argInfoCode = generateCodeWithConditions(
$fileInfo->includeInfos, "\n",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't need both a "\n" at the end of each line and a "\n" when combining them, that leads to blank lines between the inclusions

static function (IncludeInfo $includeInfo) {
return sprintf("#include %s\n", $includeInfo->include);
}
);

if ($argInfoCode !== "") {
$code .= "$argInfoCode\n";
}

$argInfoCode = generateCodeWithConditions(
$fileInfo->getAllFuncInfos(), "\n",
static function (FuncInfo $funcInfo) use (&$generatedFuncInfos, $fileInfo) {
Expand Down
8 changes: 8 additions & 0 deletions ext/zend_test/test.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@
* @generate-legacy-arginfo 80000
* @undocumentable
*/

#if 0
declare(
c_include='<stdint.h>',
c_include='"zend_attributes.h"'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My 2 cents: why I'm not enthusiastic about this feature is that it would add even more C code in stubs. For ifdefs and a few constant values it was unavoidable, but these includes are different: one should decide if they need a particular include or not, or which includes they want to use.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one in test.stub.php is just to test that the functionality works with both include syntaxes and that the preprocessor checks also work. My use case is including the necessary headers for @cvalue, such that the files including the _arginfo don't need to know which constants are required by the various register_*() functions, particularly when the same _arginfo is required in multiple files.

zend_attributes.h should just automatically included by the stubs when attributes are used to make them self-contained. It's incredibly annoying to manually include it when using deprecations.

);
#endif

namespace {
require "Zend/zend_attributes.stub.php";

Expand Down
9 changes: 8 additions & 1 deletion ext/zend_test/test_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.