aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Cython.md29
-rw-r--r--docs/markdown/snippets/cython-c++-intermediate.md22
-rw-r--r--mesonbuild/backend/ninjabackend.py6
-rw-r--r--mesonbuild/build.py36
-rw-r--r--mesonbuild/compilers/cython.py8
-rw-r--r--mesonbuild/interpreter/interpreter.py11
-rw-r--r--test cases/cython/1 basic/libdir/storer.h8
-rw-r--r--test cases/cython/1 basic/test.json10
8 files changed, 123 insertions, 7 deletions
diff --git a/docs/markdown/Cython.md b/docs/markdown/Cython.md
index 1d30c1f..3042750 100644
--- a/docs/markdown/Cython.md
+++ b/docs/markdown/Cython.md
@@ -31,3 +31,32 @@ py.extension_module(
dependencies : dep_py,
)
```
+
+## C++ intermediate support
+
+*(New in 0.60.0)*
+
+An option has been added to control this, called `cython_language`. This can be
+either `'c'` or `'cpp'`.
+
+For those coming from setuptools/distutils, they will find two things. First,
+meson ignores `# distutils: language = c++` inline directives. Second that Meson
+allows options only on a per-target granularity. This means that if you need to mix
+cython files being transpiled to C and to C++ you need two targets:
+
+```meson
+project('my project', 'cython')
+
+cython_cpp_lib = static_library(
+ 'helper_lib',
+ 'foo_cpp.pyx', # will be transpiled to C++
+ override_options : ['cython_language=cpp'],
+)
+
+py.extension_module(
+ 'foo',
+ 'foo.pyx', # will be transpiled to C
+ link_with : [cython_cpp_lib],
+ dependencies : dep_py,
+)
+```
diff --git a/docs/markdown/snippets/cython-c++-intermediate.md b/docs/markdown/snippets/cython-c++-intermediate.md
new file mode 100644
index 0000000..0a1c35f
--- /dev/null
+++ b/docs/markdown/snippets/cython-c++-intermediate.md
@@ -0,0 +1,22 @@
+## Cython can now transpile to C++ as an intermediate language
+
+Built-in cython support currently only allows C as an intermediate language, now
+C++ is also allowed. This can be set via the `cython_language` option, either on
+the command line, or in the meson.build files.
+
+```meson
+project(
+ 'myproject',
+ 'cython',
+ default_options : ['cython_language=cpp'],
+)
+```
+
+or on a per target basis with:
+```meson
+python.extension_module(
+ 'mod',
+ 'mod.pyx',
+ override_options : ['cython_language=cpp'],
+)
+```
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 844c612..7c97ca3 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -1598,9 +1598,11 @@ class NinjaBackend(backends.Backend):
args += self.build.get_global_args(cython, target.for_machine)
args += self.build.get_project_args(cython, target.subproject, target.for_machine)
+ ext = opt_proxy[OptionKey('language', machine=target.for_machine, lang='cython')].value
+
for src in target.get_sources():
if src.endswith('.pyx'):
- output = os.path.join(self.get_target_private_dir(target), f'{src}.c')
+ output = os.path.join(self.get_target_private_dir(target), f'{src}.{ext}')
args = args.copy()
args += cython.get_output_args(output)
element = NinjaBuildElement(
@@ -1622,7 +1624,7 @@ class NinjaBackend(backends.Backend):
ssrc = os.path.join(gen.get_subdir(), ssrc)
if ssrc.endswith('.pyx'):
args = args.copy()
- output = os.path.join(self.get_target_private_dir(target), f'{ssrc}.c')
+ output = os.path.join(self.get_target_private_dir(target), f'{ssrc}.{ext}')
args += cython.get_output_args(output)
element = NinjaBuildElement(
self.all_outputs, [output],
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index b5fa8ea..1498415 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -37,7 +37,7 @@ from .mesonlib import (
)
from .compilers import (
Compiler, is_object, clink_langs, sort_clink, lang_suffixes,
- is_known_suffix, detect_static_linker
+ is_known_suffix, detect_static_linker, detect_compiler_for
)
from .linkers import StaticLinker
from .interpreterbase import FeatureNew
@@ -833,8 +833,40 @@ class BuildTarget(Target):
# If all our sources are Vala, our target also needs the C compiler but
# it won't get added above.
- if ('vala' in self.compilers or 'cython' in self.compilers) and 'c' not in self.compilers:
+ if 'vala' in self.compilers and 'c' not in self.compilers:
self.compilers['c'] = compilers['c']
+ if 'cython' in self.compilers:
+ key = OptionKey('language', machine=self.for_machine, lang='cython')
+ if key in self.option_overrides_compiler:
+ value = self.option_overrides_compiler[key]
+ else:
+ value = self.environment.coredata.options[key].value
+
+ try:
+ self.compilers[value] = compilers[value]
+ except KeyError:
+ # TODO: it would be nice to not have to do this here, but we
+ # have two problems to work around:
+ # 1. If this is set via an override we have no way to know
+ # before now that we need a compiler for the non-default language
+ # 2. Because Cython itself initializes the `cython_language`
+ # option, we have no good place to insert that you need it
+ # before now, so we just have to do it here.
+ comp = detect_compiler_for(self.environment, value, self.for_machine)
+
+ # This is copied verbatim from the interpreter
+ if self.for_machine == MachineChoice.HOST or self.environment.is_cross_build():
+ logger_fun = mlog.log
+ else:
+ logger_fun = mlog.debug
+ logger_fun(comp.get_display_language(), 'compiler for the', self.for_machine.get_lower_case_name(), 'machine:',
+ mlog.bold(' '.join(comp.get_exelist())), comp.get_version_string())
+ if comp.linker is not None:
+ logger_fun(comp.get_display_language(), 'linker for the', self.for_machine.get_lower_case_name(), 'machine:',
+ mlog.bold(' '.join(comp.linker.get_exelist())), comp.linker.id, comp.linker.version)
+ if comp is None:
+ raise MesonException(f'Cannot find required compiler {value}')
+ self.compilers[value] = comp
def validate_sources(self):
if not self.sources:
diff --git a/mesonbuild/compilers/cython.py b/mesonbuild/compilers/cython.py
index 513f079..34ddff1 100644
--- a/mesonbuild/compilers/cython.py
+++ b/mesonbuild/compilers/cython.py
@@ -68,6 +68,11 @@ class CythonCompiler(Compiler):
'Python version to target',
['2', '3'],
'3',
+ ),
+ OptionKey('language', machine=self.for_machine, lang=self.language): coredata.UserComboOption(
+ 'Output C or C++ files',
+ ['c', 'cpp'],
+ 'c',
)
})
return opts
@@ -76,4 +81,7 @@ class CythonCompiler(Compiler):
args: T.List[str] = []
key = options[OptionKey('version', machine=self.for_machine, lang=self.language)]
args.append(f'-{key.value}')
+ lang = options[OptionKey('language', machine=self.for_machine, lang=self.language)]
+ if lang.value == 'cpp':
+ args.append('--cplus')
return args
diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py
index 4d4e5da..2d04d2d 100644
--- a/mesonbuild/interpreter/interpreter.py
+++ b/mesonbuild/interpreter/interpreter.py
@@ -1241,9 +1241,14 @@ external dependencies (including libraries) must go to "dependencies".''')
args = [a.lower() for a in args]
langs = set(self.coredata.compilers[for_machine].keys())
langs.update(args)
- if ('vala' in langs or 'cython' in langs) and 'c' not in langs:
- if 'vala' in langs:
- FeatureNew.single_use('Adding Vala language without C', '0.59.0', self.subproject)
+ # We'd really like to add cython's default language here, but it can't
+ # actually be done because the cython compiler hasn't been initialized,
+ # so we can't actually get the option yet. Because we can't know what
+ # compiler to add by default, and we don't want to add unnecessary
+ # compilers we don't add anything for cython here, and instead do it
+ # When the first cython target using a particular language is used.
+ if 'vala' in langs and 'c' not in langs:
+ FeatureNew.single_use('Adding Vala language without C', '0.59.0', self.subproject)
args.append('c')
success = True
diff --git a/test cases/cython/1 basic/libdir/storer.h b/test cases/cython/1 basic/libdir/storer.h
index 4f71917..6f5bc6f 100644
--- a/test cases/cython/1 basic/libdir/storer.h
+++ b/test cases/cython/1 basic/libdir/storer.h
@@ -1,8 +1,16 @@
#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct _Storer Storer;
Storer* storer_new();
void storer_destroy(Storer *s);
int storer_get_value(Storer *s);
void storer_set_value(Storer *s, int v);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/test cases/cython/1 basic/test.json b/test cases/cython/1 basic/test.json
new file mode 100644
index 0000000..ed7ac2b
--- /dev/null
+++ b/test cases/cython/1 basic/test.json
@@ -0,0 +1,10 @@
+{
+ "matrix": {
+ "options": {
+ "cython_language": [
+ { "val": "c" },
+ { "val": "cpp" }
+ ]
+ }
+ }
+}