Commit 4298c9f9 authored by Robert Bradshaw's avatar Robert Bradshaw

Add a mechanism to store metadata in the generated output file.

This will be useful for, e.g., implementing a fake cythonize that
can leverage the deductions made by the real cythonize, but could
have other uses as well.
parent 760da3f8
......@@ -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:
......
......@@ -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,
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment