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

BUG: Fix generated sources not being included as dependencies in cython transpilation #11000

Merged
merged 1 commit into from
Jan 15, 2023
Merged
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
14 changes: 14 additions & 0 deletions mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1698,6 +1698,8 @@ def generate_cython_transpile(self, target: build.BuildTarget) -> \

ext = target.get_option(OptionKey('language', machine=target.for_machine, lang='cython'))

pyx_sources = [] # Keep track of sources we're adding to build

for src in target.get_sources():
if src.endswith('.pyx'):
output = os.path.join(self.get_target_private_dir(target), f'{src}.{ext}')
Expand All @@ -1711,9 +1713,11 @@ def generate_cython_transpile(self, target: build.BuildTarget) -> \
self.add_build(element)
# TODO: introspection?
cython_sources.append(output)
pyx_sources.append(element)
else:
static_sources[src.rel_to_builddir(self.build_to_src)] = src

header_deps = [] # Keep track of generated headers for those sources
for gen in target.get_generated_sources():
for ssrc in gen.get_outputs():
if isinstance(gen, GeneratedList):
Expand All @@ -1730,10 +1734,20 @@ def generate_cython_transpile(self, target: build.BuildTarget) -> \
[ssrc])
element.add_item('ARGS', args)
self.add_build(element)
pyx_sources.append(element)
# TODO: introspection?
cython_sources.append(output)
else:
generated_sources[ssrc] = mesonlib.File.from_built_file(gen.get_subdir(), ssrc)
# Following logic in L883-900 where we determine whether to add generated source
# as a header(order-only) dep to the .so compilation rule
if not self.environment.is_source(ssrc) and \
not self.environment.is_object(ssrc) and \
not self.environment.is_library(ssrc) and \
not modules.is_module_library(ssrc):
header_deps.append(ssrc)
for source in pyx_sources:
source.add_orderdep(header_deps)

return static_sources, generated_sources, cython_sources

Expand Down
1 change: 1 addition & 0 deletions test cases/cython/2 generated sources/includestuff.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include "stuff.pxi"
20 changes: 20 additions & 0 deletions test cases/cython/2 generated sources/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ project(
py_mod = import('python')
py3 = py_mod.find_installation('python3')
py3_dep = py3.dependency(required : false)
fs = import('fs')
if not py3_dep.found()
error('MESON_SKIP_TEST: Python library not found.')
endif
Expand Down Expand Up @@ -70,6 +71,25 @@ test(
env : ['PYTHONPATH=' + meson.current_build_dir()]
)

stuff_pxi = fs.copyfile(
'stuff.pxi.in',
'stuff.pxi'
)

# Need to copy the cython source to the build directory
# since meson can only generate the .pxi there
includestuff_pyx = fs.copyfile(
'includestuff.pyx'
)

stuff_pxi_dep = declare_dependency(sources: stuff_pxi)

includestuff_ext = py3.extension_module(
'includestuff',
includestuff_pyx,
dependencies: stuff_pxi_dep
)

subdir('libdir')

test(
Expand Down
2 changes: 2 additions & 0 deletions test cases/cython/2 generated sources/stuff.pxi.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def func():
print("Hello world")
26 changes: 26 additions & 0 deletions unittests/allplatformstests.py
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,32 @@ def test_build_by_default(self):
self.build(target=('barprog' + exe_suffix))
self.assertPathExists(exe2)

def test_build_generated_pyx_directly(self):
# Check that the transpile stage also includes
# dependencies for the compilation stage as dependencies
testdir = os.path.join("test cases/cython", '2 generated sources')
env = get_fake_env(testdir, self.builddir, self.prefix)
try:
detect_compiler_for(env, "cython", MachineChoice.HOST)
except EnvironmentException:
raise SkipTest("Cython is not installed")
self.init(testdir)
# Need to get the full target name of the pyx.c target
# (which is unfortunately not provided by introspection :( )
# We'll need to dig into the generated sources
targets = self.introspect('--targets')
name = None
for target in targets:
for target_sources in target["target_sources"]:
for generated_source in target_sources["generated_sources"]:
if "includestuff.pyx.c" in generated_source:
name = generated_source
break
# Split the path (we only want the includestuff.cpython-blahblahblah)
name = os.path.normpath(name).split("/")[-2:]
name = "/".join(name) # Glue list into a string
self.build(target=name)

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