diff --git a/Cython/Build/Dependencies.py b/Cython/Build/Dependencies.py index 9c015d1c3c2d5900ed4f717f7eb2e1c76760dd7c..e22f8caac6122c1e5a2ac9a3f58a90d8b20bb90d 100644 --- a/Cython/Build/Dependencies.py +++ b/Cython/Build/Dependencies.py @@ -621,6 +621,7 @@ def create_extension_list(patterns, exclude=[], ctx=None, aliases=None, quiet=Fa to_exclude.update(map(os.path.abspath, extended_iglob(pattern))) module_list = [] + module_metadata = {} for pattern in patterns: if isinstance(pattern, str): filepattern = pattern @@ -677,7 +678,10 @@ def create_extension_list(patterns, exclude=[], ctx=None, aliases=None, quiet=Fa source = encode_filename_in_py2(source) if source not in sources: sources.append(source) + extra_sources = kwds['sources'] del kwds['sources'] + else: + extra_sources = None if 'depends' in kwds: depends = resolve_depends(kwds['depends'], (kwds.get('include_dirs') or []) + [find_root_package_dir(file)]) if template is not None: @@ -692,9 +696,12 @@ def create_extension_list(patterns, exclude=[], ctx=None, aliases=None, quiet=Fa name=module_name, sources=sources, **kwds)) + if extra_sources: + kwds['sources'] = extra_sources + module_metadata[module_name] = {'distutils': kwds} m = module_list[-1] seen.add(name) - return module_list + return module_list, module_metadata # This is the user-exposed entry point. @@ -737,7 +744,7 @@ def cythonize(module_list, exclude=[], nthreads=0, aliases=None, quiet=False, fo cpp_options = CompilationOptions(**options); cpp_options.cplus = True ctx = c_options.create_context() options = c_options - module_list = create_extension_list( + module_list, module_metadata = create_extension_list( module_list, exclude=exclude, ctx=ctx, @@ -809,7 +816,7 @@ def cythonize(module_list, exclude=[], nthreads=0, aliases=None, quiet=False, fo else: fingerprint = None to_compile.append((priority, source, c_file, fingerprint, quiet, - options, not exclude_failures)) + options, not exclude_failures, module_metadata.get(m.name))) new_sources.append(c_file) if c_file not in modules_by_cfile: modules_by_cfile[c_file] = [m] @@ -920,7 +927,7 @@ else: # TODO: Share context? Issue: pyx processing leaks into pxd module @record_results -def cythonize_one(pyx_file, c_file, fingerprint, quiet, options=None, raise_on_failure=True): +def cythonize_one(pyx_file, c_file, fingerprint, quiet, options=None, raise_on_failure=True, embedded_metadata=None): from ..Compiler.Main import compile, default_options from ..Compiler.Errors import CompileError, PyrexError @@ -954,6 +961,7 @@ def cythonize_one(pyx_file, c_file, fingerprint, quiet, options=None, raise_on_f if options is None: options = CompilationOptions(default_options) options.output_file = c_file + options.embedded_metadata = embedded_metadata any_failures = 0 try: diff --git a/Cython/Compiler/Main.py b/Cython/Compiler/Main.py index 4ee84cd9bb4efb439317a691931095382a402d5d..29756bc80bf57ee013ff37a82cdc2a89f5d1441c 100644 --- a/Cython/Compiler/Main.py +++ b/Cython/Compiler/Main.py @@ -400,6 +400,7 @@ def create_default_resultobj(compilation_source, options): else: c_suffix = ".c" result.c_file = Utils.replace_suffix(source_desc.filename, c_suffix) + result.embedded_metadata = options.embedded_metadata return result def run_pipeline(source, options, full_module_name=None, context=None): @@ -479,7 +480,8 @@ class CompilationOptions(object): header files. timestamps boolean Only compile changed source files. verbose boolean Always print source names being compiled - compiler_directives dict Overrides for pragma options (see Options.py) + compiler_directives dict Overrides for pragma options (see Options.py) + embedded_metadata dict Metadata to embed in the C file as json. evaluate_tree_assertions boolean Test support: evaluate parse tree assertions language_level integer The Python language level: 2 or 3 formal_grammar boolean Parse the file with the formal grammar @@ -690,6 +692,7 @@ default_options = dict( verbose = 0, quiet = 0, compiler_directives = {}, + embedded_metadata = {}, evaluate_tree_assertions = False, emit_linenums = False, relative_path_in_code_position_comments = True, diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 3cbdbd9931c2cac5f78afe6a7b63a6eaf6efe487..94d60724c1f7d735955a8de5bfb94cb69a80d308 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -9,6 +9,7 @@ cython.declare(Naming=object, Options=object, PyrexTypes=object, TypeSlots=objec error=object, warning=object, py_object_type=object, UtilityCode=object, EncodedString=object) +import json import os import operator from .PyrexTypes import CPtrType @@ -308,7 +309,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): globalstate.initialize_main_c_code() h_code = globalstate['h_code'] - self.generate_module_preamble(env, modules, h_code) + self.generate_module_preamble(env, modules, result.embedded_metadata, h_code) globalstate.module_pos = self.pos globalstate.directives = self.directives @@ -547,9 +548,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): self.generate_cvariable_declarations(module, modulecode, defined_here) self.generate_cfunction_declarations(module, modulecode, defined_here) - def generate_module_preamble(self, env, cimported_modules, code): + def generate_module_preamble(self, env, cimported_modules, metadata, code): code.putln("/* Generated by Cython %s */" % Version.watermark) code.putln("") + if metadata: + code.putln("/* Cython Metadata */") + code.putln("/*") + code.putln(json.dumps(metadata, indent=4)) + code.putln("*/") + code.putln("") code.putln("#define PY_SSIZE_T_CLEAN") # sizeof(PyLongObject.ob_digit[0]) may have been determined dynamically