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
10 changes: 8 additions & 2 deletions mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1838,7 +1838,10 @@ def generate_cython_transpile(self, target: build.BuildTarget) -> \

for src in target.get_sources():
if src.endswith('.pyx'):
output = os.path.join(self.get_target_private_dir(target), f'{src}.{ext}')
# Use basename to avoid too nested targets which can cause a
# problem with MAX_PATH on Windows
basename = os.path.basename(src.fname)
output = os.path.join(self.get_target_private_dir(target), f'{basename}.{ext}')
element = NinjaBuildElement(
self.all_outputs, [output],
self.compiler_to_rule_name(cython),
Expand All @@ -1859,7 +1862,10 @@ def generate_cython_transpile(self, target: build.BuildTarget) -> \
else:
ssrc = os.path.join(gen.get_subdir(), ssrc)
if ssrc.endswith('.pyx'):
output = os.path.join(self.get_target_private_dir(target), f'{ssrc}.{ext}')
# Use basename to avoid too nested targets which can cause
# a problem with MAX_PATH on Windows
basename = os.path.basename(ssrc)
output = os.path.join(self.get_target_private_dir(target), f'{basename}.{ext}')
element = NinjaBuildElement(
self.all_outputs, [output],
self.compiler_to_rule_name(cython),
Expand Down
16 changes: 16 additions & 0 deletions test cases/cython/5 nested folders/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
project(
'nested folders',
['c', 'cpp', 'cython'],
default_options : ['buildtype=release'],
)

py = import('python').find_installation(pure: false, required: true)

metric = py.extension_module(
'metric',
'package/metrics/metric.pyx',
subdir: 'package/metrics',
install: true
)

subdir('package')
1 change: 1 addition & 0 deletions test cases/cython/5 nested folders/package/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
subdir('metrics')
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def test():
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
_radius_neighbors_classmode = py.extension_module(
'_radius_neighbors_classmode',
'_radius_neighbors_classmode.pyx',
subdir: 'package/metrics/_pairwise_distances_reduction',
override_options: ['cython_language=cpp'],
install: true
)
14 changes: 14 additions & 0 deletions test cases/cython/5 nested folders/package/metrics/gen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# SPDX-License-Identifier: Apache-2.0

import argparse
import textwrap

parser = argparse.ArgumentParser()
parser.add_argument('output')
args = parser.parse_args()

with open(args.output, 'w') as f:
f.write(textwrap.dedent('''\
cpdef func():
return "Hello, World!"
'''))
13 changes: 13 additions & 0 deletions test cases/cython/5 nested folders/package/metrics/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
generated_pyx = custom_target(
'generated_pyx',
input : 'gen.py',
output : 'generated.pyx',
command : [py, '@INPUT@', '@OUTPUT@'],
)

includestuff_ext = py.extension_module(
'generated_pyx',
generated_pyx
)

subdir('_pairwise_distances_reduction')
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def test():
pass
12 changes: 12 additions & 0 deletions test cases/cython/5 nested folders/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"installed": [
{
"type": "python_lib",
"file": "usr/@PYTHON_PLATLIB@/package/metrics/metric"
},
{
"type": "python_lib",
"file": "usr/@PYTHON_PLATLIB@/package/metrics/_pairwise_distances_reduction/_radius_neighbors_classmode"
}
]
}
32 changes: 32 additions & 0 deletions unittests/allplatformstests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,38 @@ def test_build_pyx_depfiles(self):
self.assertBuildRelinkedOnlyTarget(name)


def test_cython_avoid_nested_generated_paths(self):
# Ensure that cython transpiled outputs are not in a too deeply nested folder
testdir = os.path.join("test cases/cython", "5 nested folders")
env = get_fake_env(testdir, self.builddir, self.prefix)
try:
detect_compiler_for(env, "cython", MachineChoice.HOST, True, "")
except EnvironmentException:
raise SkipTest("Cython is not installed")
self.init(testdir)

targets = self.introspect("--targets")

found = False
for target in targets:
for target_sources in target["target_sources"]:
for generated_source in target_sources.get("generated_sources", []):
if generated_source.endswith(".pyx.c") or generated_source.endswith("pyx.cpp"):
found = True
parts = os.path.normpath(generated_source).split(os.sep)
parent = parts[-2]
# We want the pyx.c files to be directly under the .p folder,
# for example:
# libdir/foo.cpython-313-x86_64-linux-gnu.so.p/foo.pyx.c
# rather than (additional libdir folder):
# libdir/foo.cpython-313-x86_64-linux-gnu.so.p/libdir/foo.pyx.c
self.assertTrue(
parent.endswith(".p"),
"pyx.c file should be directly under the .p folder,"
f" got {generated_source!r}"
)
self.assertTrue(found, "No cython transpiled outputs found")

def test_internal_include_order(self):
if mesonbuild.envconfig.detect_msys2_arch() and ('MESON_RSP_THRESHOLD' in os.environ):
raise SkipTest('Test does not yet support gcc rsp files on msys2')
Expand Down
Loading