Commit 79f73b939d3 for nodejs
commit 79f73b939d3b3e167014a0f2ba575bec3ae23e0e
Author: Node.js GitHub Bot <github-bot@iojs.org>
Date: Thu Oct 1 11:37:03 2026 -0400
tools: update gyp-next to 0.22.3
PR-URL: https://github.com/nodejs/node/pull/66397
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Xuguang Mei <meixuguang@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
diff --git a/tools/gyp/CHANGELOG.md b/tools/gyp/CHANGELOG.md
index c6686c4784a..e590b6fdb8c 100644
--- a/tools/gyp/CHANGELOG.md
+++ b/tools/gyp/CHANGELOG.md
@@ -1,5 +1,19 @@
# Changelog
+## [0.22.3](https://github.com/nodejs/gyp-next/compare/v0.22.2...v0.22.3) (2026-09-29)
+
+
+### Bug Fixes
+
+* add Python 3.15 beta to the testing ([#344](https://github.com/nodejs/gyp-next/issues/344)) ([bb6522f](https://github.com/nodejs/gyp-next/commit/bb6522fbacc620da2cc382484d75c75ee35d780c))
+* **ci:** add zizmor security linter for github actions ([#358](https://github.com/nodejs/gyp-next/issues/358)) ([3d4c42b](https://github.com/nodejs/gyp-next/commit/3d4c42b386582df54368c29fcd7c3121737451a2))
+* **ci:** enable Python 3.15 release candidate on Windows ([#357](https://github.com/nodejs/gyp-next/issues/357)) ([e2080d2](https://github.com/nodejs/gyp-next/commit/e2080d25c31a0c1f08178a52802be7fd56848376))
+* **ci:** test on npm@12 ([#359](https://github.com/nodejs/gyp-next/issues/359)) ([1729f6e](https://github.com/nodejs/gyp-next/commit/1729f6e3bf8071d95cda85129cdf4ebab0a877ef))
+* **ci:** update ruff github aactio to v4.0.0 ([#348](https://github.com/nodejs/gyp-next/issues/348)) ([8d213cd](https://github.com/nodejs/gyp-next/commit/8d213cd35cec96e91dc98359ccd247404f71f27b))
+* **cmake:** add a dummy source to libraries without sources ([#362](https://github.com/nodejs/gyp-next/issues/362)) ([391165e](https://github.com/nodejs/gyp-next/commit/391165e76f682a318216b8b5c6ca1de0ef5f8f24))
+* **cmake:** require CMake 3.10 and quote custom command comments ([#361](https://github.com/nodejs/gyp-next/issues/361)) ([b418211](https://github.com/nodejs/gyp-next/commit/b418211c49705c0fb42177b666c140cf96d0149f))
+* write pch cflags as a list instead of a map object ([#355](https://github.com/nodejs/gyp-next/issues/355)) ([fe8188c](https://github.com/nodejs/gyp-next/commit/fe8188c6af0cf53488960b0ec655b1dcc01a7c94))
+
## [0.22.2](https://github.com/nodejs/gyp-next/compare/v0.22.1...v0.22.2) (2026-04-22)
diff --git a/tools/gyp/README.md b/tools/gyp/README.md
index 6360a6c3342..9f8b1e6119f 100644
--- a/tools/gyp/README.md
+++ b/tools/gyp/README.md
@@ -11,7 +11,7 @@ When used as a command line utility, __gyp-next__ can also be installed with [pi
* `uv tool install gyp-next`
```
Installing to a new venv 'gyp-next'
- installed package gyp-next 0.13.0, installed using Python 3.10.6
+ installed package gyp-next 0.13.0, installed using Python 3.14.7
These apps are now globally available
- gyp
done! ✨ 🌟 ✨
diff --git a/tools/gyp/commitlint.config.mjs b/tools/gyp/commitlint.config.mjs
new file mode 100644
index 00000000000..c7a07938b92
--- /dev/null
+++ b/tools/gyp/commitlint.config.mjs
@@ -0,0 +1,6 @@
+export default {
+ extends: ['@commitlint/config-conventional'],
+ rules: {
+ 'body-max-line-length': [0, 'always'],
+ },
+};
diff --git a/tools/gyp/pylib/gyp/generator/cmake.py b/tools/gyp/pylib/gyp/generator/cmake.py
index dc9ea39acb7..1028272a41c 100644
--- a/tools/gyp/pylib/gyp/generator/cmake.py
+++ b/tools/gyp/pylib/gyp/generator/cmake.py
@@ -304,12 +304,9 @@ def WriteActions(target_name, actions, extra_sources, extra_deps, path_to_gyp, o
output.write(path_to_gyp)
output.write("\n")
- output.write(" COMMENT ")
- if "message" in action:
- output.write(action["message"])
- else:
- output.write(action_target_name)
- output.write("\n")
+ output.write(' COMMENT "')
+ output.write(CMakeStringEscape(action.get("message", action_target_name)))
+ output.write('"\n')
output.write(" VERBATIM\n")
output.write(")\n")
@@ -415,12 +412,9 @@ def WriteRules(target_name, rules, extra_sources, extra_deps, path_to_gyp, outpu
output.write(path_to_gyp)
output.write("\n")
- output.write(" COMMENT ")
- if "message" in rule:
- output.write(rule["message"])
- else:
- output.write(action_name)
- output.write("\n")
+ output.write(' COMMENT "')
+ output.write(CMakeStringEscape(rule.get("message", action_name)))
+ output.write('"\n')
output.write(" VERBATIM\n")
output.write(")\n")
@@ -537,9 +531,9 @@ def WriteCopies(target_name, copies, extra_deps, path_to_gyp, output):
output.write(path_to_gyp)
output.write("\n")
- output.write("COMMENT Copying for ")
- output.write(target_name)
- output.write("\n")
+ output.write('COMMENT "Copying for ')
+ output.write(CMakeStringEscape(target_name))
+ output.write('"\n')
output.write("VERBATIM\n")
output.write(")\n")
@@ -779,8 +773,10 @@ def WriteTarget(
other_sources_name = cmake_target_name + "__other_srcs"
SetVariableList(output, other_sources_name, other_sources)
- # CMake gets upset when executable targets provide no sources.
+ # CMake gets upset when executable or library targets provide no sources.
# http://www.cmake.org/pipermail/cmake/2010-July/038461.html
+ # Libraries without sources are used to aggregate dependencies; build an
+ # empty library for them, as the make generator does.
dummy_sources_name = None
has_sources = (
s_sources_name
@@ -789,7 +785,7 @@ def WriteTarget(
or linkable_sources_name
or other_sources_name
)
- if target_type == "executable" and not has_sources:
+ if target_type != "none" and not has_sources:
dummy_sources_name = cmake_target_name + "__dummy_srcs"
SetVariable(
output, dummy_sources_name, "${obj}.${TOOLSET}/${TARGET}/genc/dummy.c"
@@ -1160,8 +1156,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params, config_to_u
gyp.common.EnsureDirExists(output_file)
output = open(output_file, "w")
- output.write("cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)\n")
- output.write("cmake_policy(VERSION 2.8.8)\n")
+ output.write("cmake_minimum_required(VERSION 3.10)\n")
gyp_file, project_target, _ = gyp.common.ParseQualifiedTarget(target_list[-1])
output.write("project(")
diff --git a/tools/gyp/pylib/gyp/generator/cmake_test.py b/tools/gyp/pylib/gyp/generator/cmake_test.py
new file mode 100644
index 00000000000..fe45cd6d922
--- /dev/null
+++ b/tools/gyp/pylib/gyp/generator/cmake_test.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python3
+
+"""Unit tests for the cmake.py file."""
+
+import io
+import types
+import unittest
+
+from gyp.generator import cmake
+
+
+class TestCustomCommandComment(unittest.TestCase):
+ def test_ActionMessageIsQuotedAndEscaped(self):
+ output = io.StringIO()
+ action = {
+ "action_name": "gen",
+ "inputs": ["in.txt"],
+ "outputs": ["out.txt"],
+ "action": ["python", "gen.py"],
+ "message": 'Generating "out.txt"; (see #1)',
+ }
+ cmake.WriteActions("tgt", [action], [], [], ".", output)
+ self.assertIn(
+ ' COMMENT "Generating \\"out.txt\\"\\; (see #1)"\n', output.getvalue()
+ )
+
+ def test_ActionWithoutMessageUsesTargetName(self):
+ output = io.StringIO()
+ action = {
+ "action_name": "gen",
+ "inputs": [],
+ "outputs": ["out.txt"],
+ "action": ["python", "gen.py"],
+ }
+ cmake.WriteActions("tgt", [action], [], [], ".", output)
+ self.assertIn(' COMMENT "tgt__gen"\n', output.getvalue())
+
+ def test_RuleMessageKeepsVariableReferences(self):
+ output = io.StringIO()
+ rule = {
+ "rule_name": "compile",
+ "outputs": ["${RULE_INPUT_ROOT}.o"],
+ "action": ["cc", "${RULE_INPUT_PATH}"],
+ "rule_sources": ["foo.c"],
+ "message": "Compiling ${RULE_INPUT_NAME}",
+ }
+ cmake.WriteRules("tgt", [rule], [], [], ".", output)
+ self.assertIn(' COMMENT "Compiling ${RULE_INPUT_NAME}"\n', output.getvalue())
+
+ def test_CopiesMessageIsQuoted(self):
+ output = io.StringIO()
+ copies = [{"files": ["a.txt"], "destination": "out"}]
+ cmake.WriteCopies("tgt", copies, [], ".", output)
+ self.assertIn('COMMENT "Copying for tgt"\n', output.getvalue())
+
+
+class TestTargetWithoutSources(unittest.TestCase):
+ def _WriteTarget(self, target_type, sources=()):
+ qualified_target = "foo.gyp:foo#target"
+ spec = {
+ "target_name": "foo",
+ "type": target_type,
+ "toolset": "target",
+ "sources": list(sources),
+ }
+ output = io.StringIO()
+ cmake.WriteTarget(
+ cmake.CMakeNamer([qualified_target]),
+ qualified_target,
+ {qualified_target: spec},
+ "out/Default",
+ "Default",
+ types.SimpleNamespace(toplevel_dir="."),
+ {},
+ [qualified_target],
+ "linux",
+ output,
+ )
+ return output.getvalue()
+
+ def test_DummySourceForEmptyTargets(self):
+ for target_type, add_target in (
+ ("executable", "add_executable(foo"),
+ ("static_library", "add_library(foo STATIC"),
+ ("shared_library", "add_library(foo SHARED"),
+ ("loadable_module", "add_library(foo MODULE"),
+ ):
+ with self.subTest(target_type=target_type):
+ output = self._WriteTarget(target_type)
+ self.assertIn(' file(WRITE "${foo__dummy_srcs}" "")\n', output)
+ self.assertIn(add_target + " ${foo__dummy_srcs})\n", output)
+
+ def test_NoDummySourceForLibraryWithSources(self):
+ output = self._WriteTarget("static_library", ["foo.c"])
+ self.assertIn("add_library(foo STATIC ${foo__c_srcs})\n", output)
+ self.assertNotIn("dummy", output)
+
+ def test_NoDummySourceForNoneTarget(self):
+ output = self._WriteTarget("none")
+ self.assertIn("add_custom_target(foo SOURCES)\n", output)
+ self.assertNotIn("dummy", output)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tools/gyp/pylib/gyp/msvs_emulation.py b/tools/gyp/pylib/gyp/msvs_emulation.py
index f1c1581981e..84e0b4f327a 100644
--- a/tools/gyp/pylib/gyp/msvs_emulation.py
+++ b/tools/gyp/pylib/gyp/msvs_emulation.py
@@ -1057,13 +1057,18 @@ class PrecompiledHeader:
pch_output = ["/Yc" + self._PchHeader()]
if command == "cxx":
return (
- [("cflags_cc", map(expand_special, cflags_cc + pch_output))],
+ [
+ (
+ "cflags_cc",
+ [expand_special(x) for x in cflags_cc + pch_output],
+ )
+ ],
self.output_obj,
[],
)
elif command == "cc":
return (
- [("cflags_c", map(expand_special, cflags_c + pch_output))],
+ [("cflags_c", [expand_special(x) for x in cflags_c + pch_output])],
self.output_obj,
[],
)
diff --git a/tools/gyp/pyproject.toml b/tools/gyp/pyproject.toml
index 487cb75002d..9ce52a6785e 100644
--- a/tools/gyp/pyproject.toml
+++ b/tools/gyp/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "gyp-next"
-version = "0.22.2"
+version = "0.22.3"
authors = [
{ name="Node.js contributors", email="ryzokuken@disroot.org" },
]
diff --git a/tools/gyp/test/fixtures/expected-darwin/cmake/CMakeLists.txt b/tools/gyp/test/fixtures/expected-darwin/cmake/CMakeLists.txt
index 90b95e75eb5..6721481cc8b 100644
--- a/tools/gyp/test/fixtures/expected-darwin/cmake/CMakeLists.txt
+++ b/tools/gyp/test/fixtures/expected-darwin/cmake/CMakeLists.txt
@@ -1,5 +1,4 @@
-cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)
-cmake_policy(VERSION 2.8.8)
+cmake_minimum_required(VERSION 3.10)
project(test)
set(configuration "Default")
enable_language(ASM)
diff --git a/tools/gyp/test/fixtures/expected-linux/cmake/CMakeLists.txt b/tools/gyp/test/fixtures/expected-linux/cmake/CMakeLists.txt
index 968642201ac..43261eb1882 100644
--- a/tools/gyp/test/fixtures/expected-linux/cmake/CMakeLists.txt
+++ b/tools/gyp/test/fixtures/expected-linux/cmake/CMakeLists.txt
@@ -1,5 +1,4 @@
-cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)
-cmake_policy(VERSION 2.8.8)
+cmake_minimum_required(VERSION 3.10)
project(test)
set(configuration "Default")
enable_language(ASM)
diff --git a/tools/gyp/test/fixtures/pch.cc b/tools/gyp/test/fixtures/pch.cc
new file mode 100644
index 00000000000..1d9f38c57d6
--- /dev/null
+++ b/tools/gyp/test/fixtures/pch.cc
@@ -0,0 +1 @@
+#include "pch.h"
diff --git a/tools/gyp/test/fixtures/pch.gyp b/tools/gyp/test/fixtures/pch.gyp
new file mode 100644
index 00000000000..628c94101dc
--- /dev/null
+++ b/tools/gyp/test/fixtures/pch.gyp
@@ -0,0 +1,13 @@
+{
+ 'targets': [
+ {
+ 'target_name': 'pch',
+ 'type': 'executable',
+ 'sources': [
+ 'pch.cc',
+ ],
+ 'msvs_precompiled_header': 'pch.h',
+ 'msvs_precompiled_source': 'pch.cc',
+ },
+ ]
+}
diff --git a/tools/gyp/test/fixtures/pch.h b/tools/gyp/test/fixtures/pch.h
new file mode 100644
index 00000000000..6f70f09beec
--- /dev/null
+++ b/tools/gyp/test/fixtures/pch.h
@@ -0,0 +1 @@
+#pragma once
diff --git a/tools/gyp/test/integration_test.py b/tools/gyp/test/integration_test.py
index 26d78763078..8244708a9bd 100644
--- a/tools/gyp/test/integration_test.py
+++ b/tools/gyp/test/integration_test.py
@@ -11,7 +11,8 @@ import unittest
import gyp
fixture_dir = os.path.join(os.path.dirname(__file__), "fixtures")
-gyp_file = os.path.join(os.path.dirname(__file__), "fixtures/integration.gyp")
+gyp_file = os.path.join(fixture_dir, "integration.gyp")
+pch_gyp_file = os.path.join(fixture_dir, "pch.gyp")
if sys.platform == "win32":
sysname = sys.platform
@@ -91,3 +92,16 @@ class TestGypWindows(unittest.TestCase):
assert_file(self, "test.vcproj", "msvs/test.vcproj")
assert_file(self, "integration.sln", "msvs/integration.sln")
+
+ def test_ninja_precompiled_header(self) -> None:
+ try:
+ rc = gyp.main(["-f", "ninja", "--depth", fixture_dir, pch_gyp_file])
+ except ValueError as exc:
+ self.skipTest(str(exc))
+ assert rc == 0
+
+ with open(os.path.join(fixture_dir, "out/Default/obj/pch.ninja")) as in_file:
+ ninja_file = in_file.read()
+
+ assert "map object at" not in ninja_file
+ assert "/Ycpch.h" in ninja_file