From e1a88a201076bb1999f4ec74b505335225aaa561 Mon Sep 17 00:00:00 2001 From: zy69guqi <richard.angersbach@fau.de> Date: Mon, 10 Mar 2025 16:02:33 +0100 Subject: [PATCH] Remove extern C from kernelhandles, add EXTERNC macro, introduce c_interfacing config option --- src/pystencilssfg/composer/basic_composer.py | 17 ++++++++++------- src/pystencilssfg/config.py | 6 ++++++ src/pystencilssfg/context.py | 7 +++++++ src/pystencilssfg/emission/file_printer.py | 8 ++++---- src/pystencilssfg/generator.py | 12 ++++++++++++ src/pystencilssfg/ir/entities.py | 9 +++------ 6 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/pystencilssfg/composer/basic_composer.py b/src/pystencilssfg/composer/basic_composer.py index 9e58d78..9a870d9 100644 --- a/src/pystencilssfg/composer/basic_composer.py +++ b/src/pystencilssfg/composer/basic_composer.py @@ -91,7 +91,6 @@ class KernelsAdder: self._cursor = cursor self._kernel_namespace = knamespace self._inline: bool = False - self._externC: bool = False self._loc: SfgNamespaceBlock | None = None def inline(self) -> KernelsAdder: @@ -99,11 +98,6 @@ class KernelsAdder: self._inline = True return self - def externC(self) -> KernelsAdder: - """Generate kernel definitions ``extern "C"`` in the header file.""" - self._externC = True - return self - def add(self, kernel: Kernel, name: str | None = None): """Adds an existing pystencils AST to this namespace. If a name is specified, the AST's function name is changed.""" @@ -122,7 +116,7 @@ class KernelsAdder: kernel.name = kernel_name khandle = SfgKernelHandle( - kernel_name, self._kernel_namespace, kernel, inline=self._inline, externC=self._externC + kernel_name, self._kernel_namespace, kernel, inline=self._inline ) self._kernel_namespace.add_kernel(khandle) @@ -389,6 +383,8 @@ class SfgBasicComposer(SfgIComposer): if self._ctx.impl_file is None: seq.inline() + if self._ctx.c_interfacing: + seq.externC() return seq @@ -678,6 +674,7 @@ class SfgFunctionSequencerBase: # Qualifiers self._inline: bool = False + self._externC: bool = False self._constexpr: bool = False # Attributes @@ -704,6 +701,11 @@ class SfgFunctionSequencerBase: self._inline = True return self + def externC(self): + """Mark this function as ``extern "C"``.""" + self._externC = True + return self + def constexpr(self): """Mark this function as ``constexpr``.""" self._constexpr = True @@ -727,6 +729,7 @@ class SfgFunctionSequencer(SfgFunctionSequencerBase): tree, return_type=self._return_type, inline=self._inline, + externC=self._externC, constexpr=self._constexpr, attributes=self._attributes, required_params=self._params, diff --git a/src/pystencilssfg/config.py b/src/pystencilssfg/config.py index 34d2f27..44aaf51 100644 --- a/src/pystencilssfg/config.py +++ b/src/pystencilssfg/config.py @@ -123,6 +123,12 @@ class SfgConfig(ConfigBase): This will cause all definitions to be generated ``inline``. """ + c_interfacing: BasicOption[bool] = BasicOption(False) + """If set to `True`, generates header files compatible for interfacing with C. + + This will cause all definitions to be generated ``extern "C"``. + """ + outer_namespace: BasicOption[str | _GlobalNamespace] = BasicOption(GLOBAL_NAMESPACE) """The outermost namespace in the generated file. May be a valid C++ nested namespace qualifier (like ``a::b::c``) or `GLOBAL_NAMESPACE` if no outer namespace should be generated. diff --git a/src/pystencilssfg/context.py b/src/pystencilssfg/context.py index 1622a1e..6d76b7e 100644 --- a/src/pystencilssfg/context.py +++ b/src/pystencilssfg/context.py @@ -21,6 +21,7 @@ class SfgContext: self, header_file: SfgSourceFile, impl_file: SfgSourceFile | None, + c_interfacing: bool, namespace: str | None = None, codestyle: CodeStyle | None = None, argv: Sequence[str] | None = None, @@ -29,6 +30,8 @@ class SfgContext: self._argv = argv self._project_info = project_info + self._c_interfacing = c_interfacing + self._outer_namespace = namespace self._inner_namespace: str | None = None @@ -77,6 +80,10 @@ class SfgContext: def header_file(self) -> SfgSourceFile: return self._header_file + @property + def c_interfacing(self) -> bool: + return self._c_interfacing + @property def impl_file(self) -> SfgSourceFile | None: return self._impl_file diff --git a/src/pystencilssfg/emission/file_printer.py b/src/pystencilssfg/emission/file_printer.py index d6b9296..74ec3a2 100644 --- a/src/pystencilssfg/emission/file_printer.py +++ b/src/pystencilssfg/emission/file_printer.py @@ -84,12 +84,9 @@ class SfgFilePrinter: ) -> str: match declared_entity: case SfgKernelHandle(kernel): - func_prefix = "extern C" if declared_entity.externC else "" - func_prefix += " inline" if declared_entity.inline else "" - kernel_printer = CAstPrinter( indent_width=self._indent_width, - func_prefix=func_prefix, + func_prefix="inline" if declared_entity.inline else "", ) return kernel_printer.print_signature(kernel) + ";" @@ -195,6 +192,9 @@ class SfgFilePrinter: if func.inline and not inclass: code += "inline " + if isinstance(func, SfgFunction) and func.externC and not inclass: + code += "EXTERNC " + if isinstance(func, SfgMethod) and inclass: if func.static: code += "static " diff --git a/src/pystencilssfg/generator.py b/src/pystencilssfg/generator.py index c314d67..5110fcf 100644 --- a/src/pystencilssfg/generator.py +++ b/src/pystencilssfg/generator.py @@ -78,6 +78,7 @@ class SourceFileGenerator: config.override(sfg_config) self._header_only: bool = config.get_option("header_only") + self._c_interfacing: bool = config.get_option("c_interfacing") self._output_dir: Path = config.get_option("output_directory") output_files = config._get_output_files(basename) @@ -102,6 +103,16 @@ class SourceFileGenerator: # TODO: Find a way to not hard-code the restrict qualifier in pystencils self._header_file.elements.append("#define RESTRICT __restrict__") + # TODO: Find a way to not hard-code the 'extern" C"' qualifier in pystencils + self._header_file.elements.append( + """#ifdef __cplusplus\n + #define EXTERNC extern \"C\"\n + #else\n + #define EXTERNC \n + #endif\n + """ + ) + outer_namespace: str | _GlobalNamespace = config.get_option("outer_namespace") namespace: str | None @@ -113,6 +124,7 @@ class SourceFileGenerator: self._context = SfgContext( self._header_file, self._impl_file, + self._c_interfacing, namespace, config.codestyle, argv=script_args, diff --git a/src/pystencilssfg/ir/entities.py b/src/pystencilssfg/ir/entities.py index 850bbde..e20b2b7 100644 --- a/src/pystencilssfg/ir/entities.py +++ b/src/pystencilssfg/ir/entities.py @@ -147,7 +147,6 @@ class SfgKernelHandle(SfgCodeEntity): namespace: SfgKernelNamespace, kernel: Kernel, inline: bool = False, - externC: bool = False, ): super().__init__(name, namespace) @@ -155,7 +154,6 @@ class SfgKernelHandle(SfgCodeEntity): self._parameters = [SfgKernelParamVar(p) for p in kernel.parameters] self._inline: bool = inline - self._externC: bool = externC self._scalar_params: set[SfgVar] = set() self._fields: set[Field] = set() @@ -190,10 +188,6 @@ class SfgKernelHandle(SfgCodeEntity): def inline(self) -> bool: return self._inline - @property - def externC(self) -> bool: - return self._externC - class SfgKernelNamespace(SfgNamespace): """A namespace grouping together a number of kernels.""" @@ -228,6 +222,7 @@ class CommonFunctionProperties: parameters: tuple[SfgVar, ...] return_type: PsType inline: bool + externC: bool constexpr: bool attributes: Sequence[str] @@ -264,6 +259,7 @@ class SfgFunction(SfgCodeEntity, CommonFunctionProperties): tree: SfgCallTreeNode, return_type: PsType = void, inline: bool = False, + externC: bool = False, constexpr: bool = False, attributes: Sequence[str] = (), required_params: Sequence[SfgVar] | None = None, @@ -278,6 +274,7 @@ class SfgFunction(SfgCodeEntity, CommonFunctionProperties): parameters, return_type, inline, + externC, constexpr, attributes, ) -- GitLab