From c65ec9e4df0fa8f39aeab41932a0b3b1c068793c Mon Sep 17 00:00:00 2001 From: "Node.js GitHub Bot" Date: Tue, 29 Sep 2026 15:06:53 +0000 Subject: [PATCH 1/2] tools: update gyp-next to 0.22.3 --- tools/gyp/CHANGELOG.md | 14 +++ tools/gyp/README.md | 2 +- tools/gyp/commitlint.config.js | 6 + tools/gyp/pylib/gyp/generator/cmake.py | 33 +++--- tools/gyp/pylib/gyp/generator/cmake_test.py | 105 ++++++++++++++++++ tools/gyp/pylib/gyp/msvs_emulation.py | 9 +- tools/gyp/pyproject.toml | 2 +- .../expected-darwin/cmake/CMakeLists.txt | 3 +- .../expected-linux/cmake/CMakeLists.txt | 3 +- tools/gyp/test/fixtures/pch.cc | 1 + tools/gyp/test/fixtures/pch.gyp | 13 +++ tools/gyp/test/fixtures/pch.h | 1 + tools/gyp/test/integration_test.py | 16 ++- 13 files changed, 180 insertions(+), 28 deletions(-) create mode 100644 tools/gyp/commitlint.config.js create mode 100644 tools/gyp/pylib/gyp/generator/cmake_test.py create mode 100644 tools/gyp/test/fixtures/pch.cc create mode 100644 tools/gyp/test/fixtures/pch.gyp create mode 100644 tools/gyp/test/fixtures/pch.h diff --git a/tools/gyp/CHANGELOG.md b/tools/gyp/CHANGELOG.md index c6686c4784a7..e590b6fdb8c8 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 6360a6c33429..9f8b1e6119f4 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.js b/tools/gyp/commitlint.config.js new file mode 100644 index 000000000000..c7a07938b92f --- /dev/null +++ b/tools/gyp/commitlint.config.js @@ -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 dc9ea39acb7f..1028272a41c2 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 __init__(self, ext, command): 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 000000000000..fe45cd6d9228 --- /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 f1c1581981e3..84e0b4f327a5 100644 --- a/tools/gyp/pylib/gyp/msvs_emulation.py +++ b/tools/gyp/pylib/gyp/msvs_emulation.py @@ -1057,13 +1057,18 @@ def GetFlagsModifications( 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 487cb75002d2..9ce52a6785e4 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 90b95e75eb51..6721481cc8b0 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 968642201ac6..43261eb1882e 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 000000000000..1d9f38c57d63 --- /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 000000000000..628c94101dc8 --- /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 000000000000..6f70f09beec2 --- /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 26d787630785..8244708a9bd5 100644 --- a/tools/gyp/test/integration_test.py +++ b/tools/gyp/test/integration_test.py @@ -11,7 +11,8 @@ 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 @@ def test_msvs(self) -> None: 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 From 5e8c8d4b5b22937771de3636df37769aa9315843 Mon Sep 17 00:00:00 2001 From: Renegade334 Date: Tue, 29 Sep 2026 18:48:11 +0200 Subject: [PATCH 2/2] fixup! tools: update gyp-next to 0.22.3 --- tools/gyp/{commitlint.config.js => commitlint.config.mjs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tools/gyp/{commitlint.config.js => commitlint.config.mjs} (100%) diff --git a/tools/gyp/commitlint.config.js b/tools/gyp/commitlint.config.mjs similarity index 100% rename from tools/gyp/commitlint.config.js rename to tools/gyp/commitlint.config.mjs