Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tools: update gyp-next to 0.18.0 #52835

Closed
wants to merge 2 commits into from
Closed
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
22 changes: 22 additions & 0 deletions tools/gyp/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Changelog

## [0.18.0](https://github.com/nodejs/gyp-next/compare/v0.17.0...v0.18.0) (2024-05-08)


### Features

* support language standard keys in msvs_settings ([#252](https://github.com/nodejs/gyp-next/issues/252)) ([322f6d5](https://github.com/nodejs/gyp-next/commit/322f6d5d5233967522f3e55c623a8e7d7281e024))

## [0.17.0](https://github.com/nodejs/gyp-next/compare/v0.16.2...v0.17.0) (2024-04-29)


### Features

* generate compile_commands.json with ninja ([#228](https://github.com/nodejs/gyp-next/issues/228)) ([7b20b46](https://github.com/nodejs/gyp-next/commit/7b20b4673d8cf46ff61898eb19569007d55c854a))


### Bug Fixes

* failed to detect flavor if compiler path include white spaces ([#240](https://github.com/nodejs/gyp-next/issues/240)) ([f3b9753](https://github.com/nodejs/gyp-next/commit/f3b9753e7526377020e7d40e66b624db771cf84a))
* support cross compiling for wasm with make generator ([#222](https://github.com/nodejs/gyp-next/issues/222)) ([de0e1c9](https://github.com/nodejs/gyp-next/commit/de0e1c9a5791d1bf4bc3103f878ab74814864ab4))
* support empty dictionary keys in input ([#245](https://github.com/nodejs/gyp-next/issues/245)) ([178459f](https://github.com/nodejs/gyp-next/commit/178459ff343a2771d5f30f04467d2f032d6b3565))
* update Ruff to 0.3.1 ([876ccaf](https://github.com/nodejs/gyp-next/commit/876ccaf5629e1b95e13aaa2b0eb6cbd08fa80593))

## [0.16.2](https://github.com/nodejs/gyp-next/compare/v0.16.1...v0.16.2) (2024-03-07)


Expand Down
4 changes: 4 additions & 0 deletions tools/gyp/data/ninja/build.ninja
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
rule cc
command = cc $in $out

build my.out: cc my.in
2 changes: 2 additions & 0 deletions tools/gyp/pylib/gyp/MSVSSettings.py
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,8 @@ def _ValidateSettings(validators, settings, stderr):
_compile, "CompileAsManaged", _Enumeration([], new=["false", "true"])
) # /clr
_MSBuildOnly(_compile, "CreateHotpatchableImage", _boolean) # /hotpatch
_MSBuildOnly(_compile, "LanguageStandard", _string)
_MSBuildOnly(_compile, "LanguageStandard_C", _string)
_MSBuildOnly(_compile, "MultiProcessorCompilation", _boolean) # /MP
_MSBuildOnly(_compile, "PreprocessOutputPath", _string) # /Fi
_MSBuildOnly(_compile, "ProcessorNumber", _integer) # the number of processors
Expand Down
63 changes: 60 additions & 3 deletions tools/gyp/pylib/gyp/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import tempfile
import sys
import subprocess
import shlex

from collections.abc import MutableSet

Expand Down Expand Up @@ -422,17 +423,61 @@ def EnsureDirExists(path):
except OSError:
pass

def GetCrossCompilerPredefines(): # -> dict
cmd = []

# shlex.split() will eat '\' in posix mode, but
# setting posix=False will preserve extra '"' cause CreateProcess fail on Windows
# this makes '\' in %CC_target% and %CFLAGS% work
def replace_sep(s):
return s.replace(os.sep, "/") if os.sep != "/" else s

if CC := os.environ.get("CC_target") or os.environ.get("CC"):
cmd += shlex.split(replace_sep(CC))
if CFLAGS := os.environ.get("CFLAGS"):
cmd += shlex.split(replace_sep(CFLAGS))
elif CXX := os.environ.get("CXX_target") or os.environ.get("CXX"):
cmd += shlex.split(replace_sep(CXX))
if CXXFLAGS := os.environ.get("CXXFLAGS"):
cmd += shlex.split(replace_sep(CXXFLAGS))
else:
return {}

def GetFlavor(params):
if sys.platform == "win32":
fd, input = tempfile.mkstemp(suffix=".c")
real_cmd = [*cmd, "-dM", "-E", "-x", "c", input]
try:
os.close(fd)
stdout = subprocess.run(
real_cmd, shell=True,
capture_output=True, check=True
).stdout
finally:
os.unlink(input)
else:
input = "/dev/null"
real_cmd = [*cmd, "-dM", "-E", "-x", "c", input]
stdout = subprocess.run(
real_cmd, shell=False,
capture_output=True, check=True
).stdout

defines = {}
lines = stdout.decode("utf-8").replace("\r\n", "\n").split("\n")
for line in lines:
if (line or "").startswith("#define "):
_, key, *value = line.split(" ")
defines[key] = " ".join(value)
return defines

def GetFlavorByPlatform():
"""Returns |params.flavor| if it's set, the system's default flavor else."""
flavors = {
"cygwin": "win",
"win32": "win",
"darwin": "mac",
}

if "flavor" in params:
return params["flavor"]
if sys.platform in flavors:
return flavors[sys.platform]
if sys.platform.startswith("sunos"):
Expand All @@ -452,6 +497,18 @@ def GetFlavor(params):

return "linux"

def GetFlavor(params):
if "flavor" in params:
return params["flavor"]

defines = GetCrossCompilerPredefines()
if "__EMSCRIPTEN__" in defines:
return "emscripten"
if "__wasm__" in defines:
return "wasi" if "__wasi__" in defines else "wasm"

return GetFlavorByPlatform()


def CopyTool(flavor, out_path, generator_flags={}):
"""Finds (flock|mac|win)_tool.gyp in the gyp directory and copies it
Expand Down
103 changes: 98 additions & 5 deletions tools/gyp/pylib/gyp/common_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
import gyp.common
import unittest
import sys

import os
from unittest.mock import patch, MagicMock

class TestTopologicallySorted(unittest.TestCase):
def test_Valid(self):
Expand All @@ -24,9 +25,8 @@ def test_Valid(self):
def GetEdge(node):
return tuple(graph[node])

self.assertEqual(
gyp.common.TopologicallySorted(graph.keys(), GetEdge), ["a", "c", "d", "b"]
)
assert gyp.common.TopologicallySorted(
graph.keys(), GetEdge) == ["a", "c", "d", "b"]

def test_Cycle(self):
"""Test that an exception is thrown on a cyclic graph."""
Expand Down Expand Up @@ -58,7 +58,7 @@ def tearDown(self):

def assertFlavor(self, expected, argument, param):
sys.platform = argument
self.assertEqual(expected, gyp.common.GetFlavor(param))
assert expected == gyp.common.GetFlavor(param)

def test_platform_default(self):
self.assertFlavor("freebsd", "freebsd9", {})
Expand All @@ -73,6 +73,99 @@ def test_platform_default(self):
def test_param(self):
self.assertFlavor("foobar", "linux2", {"flavor": "foobar"})

class MockCommunicate:
def __init__(self, stdout):
self.stdout = stdout

def decode(self, encoding):
return self.stdout

@patch("os.close")
@patch("os.unlink")
@patch("tempfile.mkstemp")
def test_GetCrossCompilerPredefines(self, mock_mkstemp, mock_unlink, mock_close):
mock_close.return_value = None
mock_unlink.return_value = None
mock_mkstemp.return_value = (0, "temp.c")

def mock_run(env, defines_stdout, expected_cmd):
with patch("subprocess.run") as mock_run:
mock_process = MagicMock()
mock_process.returncode = 0
mock_process.stdout = TestGetFlavor.MockCommunicate(defines_stdout)
mock_run.return_value = mock_process
expected_input = "temp.c" if sys.platform == "win32" else "/dev/null"
with patch.dict(os.environ, env):
defines = gyp.common.GetCrossCompilerPredefines()
flavor = gyp.common.GetFlavor({})
if env.get("CC_target"):
mock_run.assert_called_with(
[
*expected_cmd,
"-dM", "-E", "-x", "c", expected_input
],
shell=sys.platform == "win32",
capture_output=True, check=True)
return [defines, flavor]

[defines1, _] = mock_run({}, "", [])
assert {} == defines1

[defines2, flavor2] = mock_run(
{ "CC_target": "/opt/wasi-sdk/bin/clang" },
"#define __wasm__ 1\n#define __wasi__ 1\n",
["/opt/wasi-sdk/bin/clang"]
)
assert { "__wasm__": "1", "__wasi__": "1" } == defines2
assert flavor2 == "wasi"

[defines3, flavor3] = mock_run(
{ "CC_target": "/opt/wasi-sdk/bin/clang --target=wasm32" },
"#define __wasm__ 1\n",
["/opt/wasi-sdk/bin/clang", "--target=wasm32"]
)
assert { "__wasm__": "1" } == defines3
assert flavor3 == "wasm"

[defines4, flavor4] = mock_run(
{ "CC_target": "/emsdk/upstream/emscripten/emcc" },
"#define __EMSCRIPTEN__ 1\n",
["/emsdk/upstream/emscripten/emcc"]
)
assert { "__EMSCRIPTEN__": "1" } == defines4
assert flavor4 == "emscripten"

# Test path which include white space
[defines5, flavor5] = mock_run(
{
"CC_target": "\"/Users/Toyo Li/wasi-sdk/bin/clang\" -O3",
"CFLAGS": "--target=wasm32-wasi-threads -pthread"
},
"#define __wasm__ 1\n#define __wasi__ 1\n#define _REENTRANT 1\n",
[
"/Users/Toyo Li/wasi-sdk/bin/clang",
"-O3",
"--target=wasm32-wasi-threads",
"-pthread"
]
)
assert {
"__wasm__": "1",
"__wasi__": "1",
"_REENTRANT": "1"
} == defines5
assert flavor5 == "wasi"

original_sep = os.sep
os.sep = "\\"
[defines6, flavor6] = mock_run(
{ "CC_target": "\"C:\\Program Files\\wasi-sdk\\clang.exe\"" },
"#define __wasm__ 1\n#define __wasi__ 1\n",
["C:/Program Files/wasi-sdk/clang.exe"]
)
os.sep = original_sep
assert { "__wasm__": "1", "__wasi__": "1" } == defines6
assert flavor6 == "wasi"

if __name__ == "__main__":
unittest.main()
6 changes: 3 additions & 3 deletions tools/gyp/pylib/gyp/generator/android.py
Original file line number Diff line number Diff line change
Expand Up @@ -739,9 +739,9 @@ def ComputeOutput(self, spec):
% (self.android_class, self.android_module)
)
else:
path = "$(call intermediates-dir-for,{},{},,,$(GYP_VAR_PREFIX))".format(
self.android_class,
self.android_module,
path = (
f"$(call intermediates-dir-for,{self.android_class},"
f"{self.android_module},,,$(GYP_VAR_PREFIX))"
)

assert spec.get("product_dir") is None # TODO: not supported?
Expand Down
10 changes: 7 additions & 3 deletions tools/gyp/pylib/gyp/generator/compile_commands_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,14 @@ def GenerateOutput(target_list, target_dicts, data, params):
cwd = os.path.dirname(build_file)
AddCommandsForTarget(cwd, target, params, per_config_commands)

output_dir = None
try:
output_dir = params["options"].generator_output
except (AttributeError, KeyError):
output_dir = params["generator_flags"].get("output_dir", "out")
# generator_output can be `None` on Windows machines, or even not
# defined in other cases
output_dir = params.get("options").generator_output
except AttributeError:
pass
output_dir = output_dir or params["generator_flags"].get("output_dir", "out")
for configuration_name, commands in per_config_commands.items():
filename = os.path.join(output_dir, configuration_name, "compile_commands.json")
gyp.common.EnsureDirExists(filename)
Expand Down
7 changes: 3 additions & 4 deletions tools/gyp/pylib/gyp/generator/gypsh.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,9 @@ def GenerateOutput(target_list, target_dicts, data, params):
# Use a banner that looks like the stock Python one and like what
# code.interact uses by default, but tack on something to indicate what
# locals are available, and identify gypsh.
banner = "Python {} on {}\nlocals.keys() = {}\ngypsh".format(
sys.version,
sys.platform,
repr(sorted(locals.keys())),
banner = (
f"Python {sys.version} on {sys.platform}\nlocals.keys() = "
f"{sorted(locals.keys())!r}\ngypsh"
)

code.interact(banner, local=locals)
Loading