def generate_cython_transpile(self, target: build.BuildTarget) -> \
            T.Tuple[T.MutableMapping[str, File], T.MutableMapping[str, File], T.List[str]]:
        """Generate rules for transpiling Cython files to C or C++"""

        static_sources: T.MutableMapping[str, File] = OrderedDict()
        generated_sources: T.MutableMapping[str, File] = OrderedDict()
        cython_sources: T.List[str] = []

        cython = target.compilers['cython']

        args: T.List[str] = []
        args += cython.get_always_args()
        args += cython.get_debug_args(self.get_target_option(target, 'debug'))
        args += cython.get_optimization_args(self.get_target_option(target, 'optimization'))
        args += cython.get_option_compile_args(target, self.environment, target.subproject)
        args += cython.get_option_std_args(target, self.environment, target.subproject)
        args += self.build.get_global_args(cython, target.for_machine)
        args += self.build.get_project_args(cython, target.subproject, target.for_machine)
        args += target.get_extra_args('cython')

        ext = self.get_target_option(target, OptionKey('cython_language', machine=target.for_machine))

        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}')
                element = NinjaBuildElement(
                    self.all_outputs, [output],
                    self.compiler_to_rule_name(cython),
                    [src.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir())])
                element.add_item('ARGS', args)
                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):
                    ssrc = os.path.join(self.get_target_private_dir(target), ssrc)
                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}')
                    element = NinjaBuildElement(
                        self.all_outputs, [output],
                        self.compiler_to_rule_name(cython),
                        [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
Generate rules for transpiling Cython files to C or C++
mesonbuild/backend/ninjabackend.py