Commit c828e80a authored by Jerome Kieffer's avatar Jerome Kieffer

Exposes compile_time_env to the command line

close #2314
parent 6c6574c7
...@@ -139,6 +139,9 @@ def parse_args(args): ...@@ -139,6 +139,9 @@ def parse_args(args):
parser.add_option('-X', '--directive', metavar='NAME=VALUE,...', dest='directives', parser.add_option('-X', '--directive', metavar='NAME=VALUE,...', dest='directives',
type=str, action='callback', callback=parse_directives, default={}, type=str, action='callback', callback=parse_directives, default={},
help='set a compiler directive') help='set a compiler directive')
parser.add_option('-E', '--compile-time-env', metavar='NAME=VALUE,...', dest='compile_time_env',
type=str, action='callback', callback=Options.parse_compile_time_env, default={},
help='set a compile time environment variables')
parser.add_option('-s', '--option', metavar='NAME=VALUE', dest='options', parser.add_option('-s', '--option', metavar='NAME=VALUE', dest='options',
type=str, action='callback', callback=parse_options, default={}, type=str, action='callback', callback=parse_options, default={},
help='set a cythonize option') help='set a cythonize option')
......
...@@ -47,10 +47,11 @@ Options: ...@@ -47,10 +47,11 @@ Options:
--warning-errors, -Werror Make all warnings into errors --warning-errors, -Werror Make all warnings into errors
--warning-extra, -Wextra Enable extra warnings --warning-extra, -Wextra Enable extra warnings
-X, --directive <name>=<value>[,<name=value,...] Overrides a compiler directive -X, --directive <name>=<value>[,<name=value,...] Overrides a compiler directive
-E, --compile-time-env name=value[,<name=value,...] Provides compile time env like DEF would do.
""" """
#The following experimental options are supported only on MacOSX: # The following experimental options are supported only on MacOSX:
# -C, --compile Compile generated .c file to .o file # -C, --compile Compile generated .c file to .o file
# --link Link .o file to produce extension module (implies -C) # --link Link .o file to produce extension module (implies -C)
# -+, --cplus Use C++ compiler for compiling and linking # -+, --cplus Use C++ compiler for compiling and linking
...@@ -174,6 +175,17 @@ def parse_command_line(args): ...@@ -174,6 +175,17 @@ def parse_command_line(args):
except ValueError as e: except ValueError as e:
sys.stderr.write("Error in compiler directive: %s\n" % e.args[0]) sys.stderr.write("Error in compiler directive: %s\n" % e.args[0])
sys.exit(1) sys.exit(1)
elif option == "--compile-time-env" or option.startswith('-E'):
if option.startswith('-E') and option[2:].strip():
x_args = option[2:]
else:
x_args = pop_value()
try:
options.compile_time_env = Options.parse_compile_time_env(
x_args, current_settings=options.compile_time_env)
except ValueError as e:
sys.stderr.write("Error in compile-time-env: %s\n" % e.args[0])
sys.exit(1)
elif option.startswith('--debug'): elif option.startswith('--debug'):
option = option[2:].replace('-', '_') option = option[2:].replace('-', '_')
from . import DebugFlags from . import DebugFlags
......
...@@ -146,14 +146,14 @@ _directive_defaults = { ...@@ -146,14 +146,14 @@ _directive_defaults = {
'exceptval' : None, # (except value=None, check=True) 'exceptval' : None, # (except value=None, check=True)
'auto_cpdef': False, 'auto_cpdef': False,
'auto_pickle': None, 'auto_pickle': None,
'cdivision': False, # was True before 0.12 'cdivision': False, # was True before 0.12
'cdivision_warnings': False, 'cdivision_warnings': False,
'overflowcheck': False, 'overflowcheck': False,
'overflowcheck.fold': True, 'overflowcheck.fold': True,
'always_allow_keywords': False, 'always_allow_keywords': False,
'allow_none_for_extension_args': True, 'allow_none_for_extension_args': True,
'wraparound' : True, 'wraparound' : True,
'ccomplex' : False, # use C99/C++ for complex types and arith 'ccomplex' : False, # use C99/C++ for complex types and arith
'callspec' : "", 'callspec' : "",
'final' : False, 'final' : False,
'internal' : False, 'internal' : False,
...@@ -162,20 +162,20 @@ _directive_defaults = { ...@@ -162,20 +162,20 @@ _directive_defaults = {
'no_gc': False, 'no_gc': False,
'linetrace': False, 'linetrace': False,
'emit_code_comments': True, # copy original source code into C code comments 'emit_code_comments': True, # copy original source code into C code comments
'annotation_typing': True, # read type declarations from Python function annotations 'annotation_typing': True, # read type declarations from Python function annotations
'infer_types': None, 'infer_types': None,
'infer_types.verbose': False, 'infer_types.verbose': False,
'autotestdict': True, 'autotestdict': True,
'autotestdict.cdef': False, 'autotestdict.cdef': False,
'autotestdict.all': False, 'autotestdict.all': False,
'language_level': 2, 'language_level': 2,
'fast_getattr': False, # Undocumented until we come up with a better way to handle this everywhere. 'fast_getattr': False, # Undocumented until we come up with a better way to handle this everywhere.
'py2_import': False, # For backward compatibility of Cython's source code in Py3 source mode 'py2_import': False, # For backward compatibility of Cython's source code in Py3 source mode
'preliminary_late_includes_cy28': False, # Temporary directive in 0.28, to be removed in a later version (see GH#2079). 'preliminary_late_includes_cy28': False, # Temporary directive in 0.28, to be removed in a later version (see GH#2079).
'iterable_coroutine': False, # Make async coroutines backwards compatible with the old asyncio yield-from syntax. 'iterable_coroutine': False, # Make async coroutines backwards compatible with the old asyncio yield-from syntax.
'c_string_type': 'bytes', 'c_string_type': 'bytes',
'c_string_encoding': '', 'c_string_encoding': '',
'type_version_tag': True, # enables Py_TPFLAGS_HAVE_VERSION_TAG on extension types 'type_version_tag': True, # enables Py_TPFLAGS_HAVE_VERSION_TAG on extension types
'unraisable_tracebacks': True, 'unraisable_tracebacks': True,
'old_style_globals': False, 'old_style_globals': False,
'np_pythran': False, 'np_pythran': False,
...@@ -195,16 +195,16 @@ _directive_defaults = { ...@@ -195,16 +195,16 @@ _directive_defaults = {
# optimizations # optimizations
'optimize.inline_defnode_calls': True, 'optimize.inline_defnode_calls': True,
'optimize.unpack_method_calls': True, # increases code size when True 'optimize.unpack_method_calls': True, # increases code size when True
'optimize.unpack_method_calls_in_pyinit': False, # uselessly increases code size when True 'optimize.unpack_method_calls_in_pyinit': False, # uselessly increases code size when True
'optimize.use_switch': True, 'optimize.use_switch': True,
# remove unreachable code # remove unreachable code
'remove_unreachable': True, 'remove_unreachable': True,
# control flow debug directives # control flow debug directives
'control_flow.dot_output': "", # Graphviz output filename 'control_flow.dot_output': "", # Graphviz output filename
'control_flow.dot_annotate_defs': False, # Annotate definitions 'control_flow.dot_annotate_defs': False, # Annotate definitions
# test support # test support
'test_assert_path_exists' : [], 'test_assert_path_exists' : [],
...@@ -273,9 +273,9 @@ directive_types = { ...@@ -273,9 +273,9 @@ directive_types = {
'auto_pickle': bool, 'auto_pickle': bool,
'final' : bool, # final cdef classes and methods 'final' : bool, # final cdef classes and methods
'internal' : bool, # cdef class visibility in the module dict 'internal' : bool, # cdef class visibility in the module dict
'infer_types' : bool, # values can be True/None/False 'infer_types' : bool, # values can be True/None/False
'binding' : bool, 'binding' : bool,
'cfunc' : None, # decorators do not take directive value 'cfunc' : None, # decorators do not take directive value
'ccall' : None, 'ccall' : None,
'inline' : None, 'inline' : None,
'staticmethod' : None, 'staticmethod' : None,
...@@ -291,7 +291,7 @@ for key, val in _directive_defaults.items(): ...@@ -291,7 +291,7 @@ for key, val in _directive_defaults.items():
if key not in directive_types: if key not in directive_types:
directive_types[key] = type(val) directive_types[key] = type(val)
directive_scopes = { # defaults to available everywhere directive_scopes = { # defaults to available everywhere
# 'module', 'function', 'class', 'with statement' # 'module', 'function', 'class', 'with statement'
'auto_pickle': ('module', 'cclass'), 'auto_pickle': ('module', 'cclass'),
'final' : ('cclass', 'function'), 'final' : ('cclass', 'function'),
...@@ -423,7 +423,7 @@ def parse_directive_list(s, relaxed_bool=False, ignore_unknown=False, ...@@ -423,7 +423,7 @@ def parse_directive_list(s, relaxed_bool=False, ignore_unknown=False,
item = item.strip() item = item.strip()
if not item: if not item:
continue continue
if not '=' in item: if '=' not in item:
raise ValueError('Expected "=" in option "%s"' % item) raise ValueError('Expected "=" in option "%s"' % item)
name, value = [s.strip() for s in item.strip().split('=', 1)] name, value = [s.strip() for s in item.strip().split('=', 1)]
if name not in _directive_defaults: if name not in _directive_defaults:
...@@ -441,3 +441,73 @@ def parse_directive_list(s, relaxed_bool=False, ignore_unknown=False, ...@@ -441,3 +441,73 @@ def parse_directive_list(s, relaxed_bool=False, ignore_unknown=False,
parsed_value = parse_directive_value(name, value, relaxed_bool=relaxed_bool) parsed_value = parse_directive_value(name, value, relaxed_bool=relaxed_bool)
result[name] = parsed_value result[name] = parsed_value
return result return result
def parse_variable_value(value):
"""
Parses value as an option value for the given name and returns
the interpreted value.
>>> parse_variable_value('True')
True
>>> parse_variable_value('true')
'true'
>>> parse_variable_value('us-ascii')
'us-ascii'
>>> parse_variable_value('str')
'str'
>>> parse_variable_value('123')
123
>>> parse_variable_value('1.23')
1.23
"""
if value == "True":
return True
elif value == "False":
return False
elif value == "None":
return None
elif value.isdigit():
return int(value)
else:
try:
value = float(value)
except Exception:
# Not a float
pass
return value
def parse_compile_time_env(s, current_settings=None):
"""
Parses a comma-separated list of pragma options. Whitespace
is not considered.
>>> parse_compile_time_env(' ')
{}
>>> (parse_compile_time_env('boundscheck=True') ==
... {'boundscheck': True})
True
>>> parse_compile_time_env(' asdf')
Traceback (most recent call last):
...
ValueError: Expected "=" in option "asdf"
>>> parse_compile_time_env('boundscheck=hey') == {'boundscheck': 'hey'}
True
>>> parse_compile_time_env('unknown=True') == {'unknown': True}
True
"""
if current_settings is None:
result = {}
else:
result = current_settings
for item in s.split(','):
item = item.strip()
if not item:
continue
if '=' not in item:
raise ValueError('Expected "=" in option "%s"' % item)
name, value = [s.strip() for s in item.strip().split('=', 1)]
result[name] = parse_variable_value(value)
return result
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