Commit 465f158e authored by Stefan Behnel's avatar Stefan Behnel

preliminary merge of Pyrex 0.9.6.2 -> crashes

parent 26634fc5
...@@ -21,6 +21,7 @@ class CCodeWriter: ...@@ -21,6 +21,7 @@ class CCodeWriter:
# in_try_finally boolean inside try of try...finally # in_try_finally boolean inside try of try...finally
# filename_table {string : int} for finding filename table indexes # filename_table {string : int} for finding filename table indexes
# filename_list [string] filenames in filename table order # filename_list [string] filenames in filename table order
# exc_vars (string * 3) exception variables for reraise, or None
# input_file_contents dict contents (=list of lines) of any file that was used as input # input_file_contents dict contents (=list of lines) of any file that was used as input
# to create this output C code. This is # to create this output C code. This is
# used to annotate the comments. # used to annotate the comments.
...@@ -37,6 +38,7 @@ class CCodeWriter: ...@@ -37,6 +38,7 @@ class CCodeWriter:
self.error_label = None self.error_label = None
self.filename_table = {} self.filename_table = {}
self.filename_list = [] self.filename_list = []
self.exc_vars = None
self.input_file_contents = {} self.input_file_contents = {}
def putln(self, code = ""): def putln(self, code = ""):
...@@ -186,8 +188,10 @@ class CCodeWriter: ...@@ -186,8 +188,10 @@ class CCodeWriter:
#print "Code.put_var_declaration:", entry.name, "definition =", definition ### #print "Code.put_var_declaration:", entry.name, "definition =", definition ###
visibility = entry.visibility visibility = entry.visibility
if visibility == 'private' and not definition: if visibility == 'private' and not definition:
#print "...private and not definition, skipping" ###
return return
if not entry.used and visibility == "private": if not entry.used and visibility == "private":
#print "not used and private, skipping" ###
return return
storage_class = "" storage_class = ""
if visibility == 'extern': if visibility == 'extern':
...@@ -288,13 +292,6 @@ class CCodeWriter: ...@@ -288,13 +292,6 @@ class CCodeWriter:
# code = "((PyObject*)%s)" % code # code = "((PyObject*)%s)" % code
self.put_init_to_py_none(code, entry.type) self.put_init_to_py_none(code, entry.type)
def put_py_gil_state_ensure(self, cname):
self.putln("PyGILState_STATE %s;" % cname)
self.putln("%s = PyGILState_Ensure();" % cname)
def put_py_gil_state_release(self, cname):
self.putln("PyGILState_Release(%s);" % cname)
def put_pymethoddef(self, entry, term): def put_pymethoddef(self, entry, term):
if entry.doc: if entry.doc:
doc_code = entry.doc_cname doc_code = entry.doc_cname
...@@ -316,6 +313,10 @@ class CCodeWriter: ...@@ -316,6 +313,10 @@ class CCodeWriter:
# return self.putln("if (unlikely(%s < 0)) %s" % (value, self.error_goto(pos))) # TODO this path is almost _never_ taken, yet this macro makes is slower! # return self.putln("if (unlikely(%s < 0)) %s" % (value, self.error_goto(pos))) # TODO this path is almost _never_ taken, yet this macro makes is slower!
return self.putln("if (%s < 0) %s" % (value, self.error_goto(pos))) return self.putln("if (%s < 0) %s" % (value, self.error_goto(pos)))
def put_h_guard(self, guard):
self.putln("#ifndef %s" % guard)
self.putln("#define %s" % guard)
def error_goto(self, pos): def error_goto(self, pos):
lbl = self.error_label lbl = self.error_label
self.use_label(lbl) self.use_label(lbl)
......
This diff is collapsed.
...@@ -17,12 +17,14 @@ import Parsing ...@@ -17,12 +17,14 @@ import Parsing
from Symtab import BuiltinScope, ModuleScope from Symtab import BuiltinScope, ModuleScope
import Code import Code
from Cython.Utils import replace_suffix from Cython.Utils import replace_suffix
import Builtin
from Cython import Utils
verbose = 0 verbose = 0
class Context: class Context:
# This class encapsulates the context needed for compiling # This class encapsulates the context needed for compiling
# one or more Pyrex implementation files along with their # one or more Cython implementation files along with their
# associated and imported declaration files. It includes # associated and imported declaration files. It includes
# the root of the module import namespace and the list # the root of the module import namespace and the list
# of directories to search for include files. # of directories to search for include files.
...@@ -31,7 +33,8 @@ class Context: ...@@ -31,7 +33,8 @@ class Context:
# include_directories [string] # include_directories [string]
def __init__(self, include_directories): def __init__(self, include_directories):
self.modules = {"__builtin__" : BuiltinScope()} #self.modules = {"__builtin__" : BuiltinScope()}
self.modules = {"__builtin__" : Builtin.builtin_scope}
self.include_directories = include_directories self.include_directories = include_directories
def find_module(self, module_name, def find_module(self, module_name,
...@@ -180,22 +183,29 @@ class Context: ...@@ -180,22 +183,29 @@ class Context:
else: else:
c_suffix = ".c" c_suffix = ".c"
result.c_file = replace_suffix(source, c_suffix) result.c_file = replace_suffix(source, c_suffix)
c_stat = None
if result.c_file:
try:
c_stat = os.stat(result.c_file)
except EnvironmentError:
pass
module_name = self.extract_module_name(source, options) module_name = self.extract_module_name(source, options)
initial_pos = (source, 1, 0) initial_pos = (source, 1, 0)
scope = self.find_module(module_name, pos = initial_pos, need_pxd = 0) scope = self.find_module(module_name, pos = initial_pos, need_pxd = 0)
errors_occurred = False errors_occurred = False
try: try:
tree = self.parse(source, scope.type_names, pxd = 0, full_module_name = full_module_name) tree = self.parse(source, scope.type_names, pxd = 0, full_module_name = full_module_name)
tree.process_implementation(scope, result) tree.process_implementation(scope, options, result)
except CompileError: except CompileError:
errors_occurred = True errors_occurred = True
Errors.close_listing_file() Errors.close_listing_file()
result.num_errors = Errors.num_errors result.num_errors = Errors.num_errors
if result.num_errors > 0: if result.num_errors > 0:
errors_occurred = True errors_occurred = True
if errors_occurred: if errors_occurred and result.c_file:
try: try:
os.unlink(result.c_file) #os.unlink(result.c_file)
Utils.castrate_file(result.c_file, c_stat)
except EnvironmentError: except EnvironmentError:
pass pass
result.c_file = None result.c_file = None
...@@ -225,6 +235,7 @@ class CompilationOptions: ...@@ -225,6 +235,7 @@ class CompilationOptions:
errors_to_stderr boolean Echo errors to stderr when using .lis errors_to_stderr boolean Echo errors to stderr when using .lis
include_path [string] Directories to search for include files include_path [string] Directories to search for include files
output_file string Name of generated .c file output_file string Name of generated .c file
generate_pxi boolean Generate .pxi file for public declarations
Following options are experimental and only used on MacOSX: Following options are experimental and only used on MacOSX:
...@@ -238,7 +249,11 @@ class CompilationOptions: ...@@ -238,7 +249,11 @@ class CompilationOptions:
self.include_path = [] self.include_path = []
self.objects = [] self.objects = []
if defaults: if defaults:
self.__dict__.update(defaults.__dict__) if isinstance(defaults, CompilationOptions):
defaults = defaults.__dict__
else:
defaults = default_options
self.__dict__.update(defaults)
self.__dict__.update(kw) self.__dict__.update(kw)
...@@ -249,6 +264,7 @@ class CompilationResult: ...@@ -249,6 +264,7 @@ class CompilationResult:
c_file string or None The generated C source file c_file string or None The generated C source file
h_file string or None The generated C header file h_file string or None The generated C header file
i_file string or None The generated .pxi file i_file string or None The generated .pxi file
api_file string or None The generated C API .h file
listing_file string or None File of error messages listing_file string or None File of error messages
object_file string or None Result of compiling the C file object_file string or None Result of compiling the C file
extension_file string or None Result of linking the object file extension_file string or None Result of linking the object file
...@@ -259,6 +275,7 @@ class CompilationResult: ...@@ -259,6 +275,7 @@ class CompilationResult:
self.c_file = None self.c_file = None
self.h_file = None self.h_file = None
self.i_file = None self.i_file = None
self.api_file = None
self.listing_file = None self.listing_file = None
self.object_file = None self.object_file = None
self.extension_file = None self.extension_file = None
...@@ -317,18 +334,19 @@ def main(command_line = 0): ...@@ -317,18 +334,19 @@ def main(command_line = 0):
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
default_options = CompilationOptions( default_options = dict(
show_version = 0, show_version = 0,
use_listing_file = 0, use_listing_file = 0,
errors_to_stderr = 1, errors_to_stderr = 1,
c_only = 1, c_only = 1,
obj_only = 1, obj_only = 1,
cplus = 0, cplus = 0,
output_file = None) output_file = None,
generate_pxi = 0)
if sys.platform == "mac": if sys.platform == "mac":
from Cython.Mac.MacSystem import c_compile, c_link, CCompilerError from Cython.Mac.MacSystem import c_compile, c_link, CCompilerError
default_options.use_listing_file = 1 default_options['use_listing_file'] = 1
elif sys.platform == "darwin": elif sys.platform == "darwin":
from Cython.Mac.DarwinSystem import c_compile, c_link, CCompilerError from Cython.Mac.DarwinSystem import c_compile, c_link, CCompilerError
else: else:
......
This diff is collapsed.
...@@ -50,6 +50,7 @@ module_cname = pyrex_prefix + "m" ...@@ -50,6 +50,7 @@ module_cname = pyrex_prefix + "m"
moddoc_cname = pyrex_prefix + "mdoc" moddoc_cname = pyrex_prefix + "mdoc"
methtable_cname = pyrex_prefix + "methods" methtable_cname = pyrex_prefix + "methods"
retval_cname = pyrex_prefix + "r" retval_cname = pyrex_prefix + "r"
reqd_kwds_cname = pyrex_prefix + "reqd_kwds"
self_cname = pyrex_prefix + "self" self_cname = pyrex_prefix + "self"
stringtab_cname = pyrex_prefix + "string_tab" stringtab_cname = pyrex_prefix + "string_tab"
vtabslot_cname = pyrex_prefix + "vtab" vtabslot_cname = pyrex_prefix + "vtab"
...@@ -58,6 +59,16 @@ gilstate_cname = pyrex_prefix + "state" ...@@ -58,6 +59,16 @@ gilstate_cname = pyrex_prefix + "state"
extern_c_macro = pyrex_prefix.upper() + "EXTERN_C" extern_c_macro = pyrex_prefix.upper() + "EXTERN_C"
exc_type_name = pyrex_prefix + "exc_type"
exc_value_name = pyrex_prefix + "exc_value"
exc_tb_name = pyrex_prefix + "exc_tb"
exc_lineno_name = pyrex_prefix + "exc_lineno"
exc_vars = (exc_type_name, exc_value_name, exc_tb_name)
h_guard_prefix = "__PYX_HAVE__"
api_guard_prefix = "__PYX_HAVE_API__"
api_func_guard = "__PYX_HAVE_API_FUNC_"
def py_version_hex(major, minor=0, micro=0, release_level=0, release_serial=0): def py_version_hex(major, minor=0, micro=0, release_level=0, release_serial=0):
return (major << 24) | (minor << 16) | (micro << 8) | (release_level << 4) | (release_serial) return (major << 24) | (minor << 16) | (micro << 8) | (release_level << 4) | (release_serial)
This diff is collapsed.
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# #
intern_names = 1 # Intern global variable and attribute names intern_names = 1 # Intern global variable and attribute names
cache_builtins = 1 # Perform lookups on builtin names only once cache_builtins = 0 # Perform lookups on builtin names only once
embed_pos_in_docstring = 0 embed_pos_in_docstring = 0
gcc_branch_hints = 1 gcc_branch_hints = 1
......
This diff is collapsed.
This diff is collapsed.
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
import cPickle as pickle import cPickle as pickle
import os import os
import platform
import stat import stat
import sys import sys
from time import time from time import time
...@@ -138,11 +139,7 @@ reserved_words = [ ...@@ -138,11 +139,7 @@ reserved_words = [
"raise", "import", "exec", "try", "except", "finally", "raise", "import", "exec", "try", "except", "finally",
"while", "if", "elif", "else", "for", "in", "assert", "while", "if", "elif", "else", "for", "in", "assert",
"and", "or", "not", "is", "in", "lambda", "from", "and", "or", "not", "is", "in", "lambda", "from",
"NULL", "cimport", "by", "with", "rdef" "NULL", "cimport", "by", "with", "rdef", "DEF", "IF", "ELIF", "ELSE"
]
function_contexts = [ # allowed arguments to the "with" option
"GIL"
] ]
class Method: class Method:
...@@ -164,7 +161,53 @@ def build_resword_dict(): ...@@ -164,7 +161,53 @@ def build_resword_dict():
#------------------------------------------------------------------ #------------------------------------------------------------------
class CompileTimeScope(object):
def __init__(self, outer = None):
self.entries = {}
self.outer = outer
def declare(self, name, value):
self.entries[name] = value
def lookup_here(self, name):
return self.entries[name]
def lookup(self, name):
try:
return self.lookup_here(name)
except KeyError:
outer = self.outer
if outer:
return outer.lookup(name)
else:
raise
def initial_compile_time_env():
benv = CompileTimeScope()
names = ('UNAME_SYSNAME', 'UNAME_NODENAME', 'UNAME_RELEASE',
'UNAME_VERSION', 'UNAME_MACHINE')
for name, value in zip(names, platform.uname()):
benv.declare(name, value)
import __builtin__
names = ('False', 'True',
'abs', 'bool', 'chr', 'cmp', 'complex', 'dict', 'divmod', 'enumerate',
'float', 'hash', 'hex', 'int', 'len', 'list', 'long', 'map', 'max', 'min',
'oct', 'ord', 'pow', 'range', 'reduce', 'repr', 'round', 'slice', 'str',
'sum', 'tuple', 'xrange', 'zip')
for name in names:
benv.declare(name, getattr(__builtin__, name))
denv = CompileTimeScope(benv)
return denv
#------------------------------------------------------------------
class PyrexScanner(Scanner): class PyrexScanner(Scanner):
# context Context Compilation context
# type_names set Identifiers to be treated as type names
# compile_time_env dict Environment for conditional compilation
# compile_time_eval boolean In a true conditional compilation context
# compile_time_expr boolean In a compile-time expression context
resword_dict = build_resword_dict() resword_dict = build_resword_dict()
...@@ -174,9 +217,15 @@ class PyrexScanner(Scanner): ...@@ -174,9 +217,15 @@ class PyrexScanner(Scanner):
if parent_scanner: if parent_scanner:
self.context = parent_scanner.context self.context = parent_scanner.context
self.type_names = parent_scanner.type_names self.type_names = parent_scanner.type_names
self.compile_time_env = parent_scanner.compile_time_env
self.compile_time_eval = parent_scanner.compile_time_eval
self.compile_time_expr = parent_scanner.compile_time_expr
else: else:
self.context = context self.context = context
self.type_names = type_names self.type_names = type_names
self.compile_time_env = initial_compile_time_env()
self.compile_time_eval = 1
self.compile_time_expr = 0
self.trace = trace_scanner self.trace = trace_scanner
self.indentation_stack = [0] self.indentation_stack = [0]
self.indentation_char = None self.indentation_char = None
...@@ -307,6 +356,15 @@ class PyrexScanner(Scanner): ...@@ -307,6 +356,15 @@ class PyrexScanner(Scanner):
if self.sy == what: if self.sy == what:
self.next() self.next()
else: else:
self.expected(what, message)
def expect_keyword(self, what, message = None):
if self.sy == 'IDENT' and self.systring == what:
self.next()
else:
self.expected(what, message)
def expected(self, what, message):
if message: if message:
self.error(message) self.error(message)
else: else:
...@@ -320,7 +378,7 @@ class PyrexScanner(Scanner): ...@@ -320,7 +378,7 @@ class PyrexScanner(Scanner):
self.expect('DEDENT', self.expect('DEDENT',
"Expected a decrease in indentation level") "Expected a decrease in indentation level")
def expect_newline(self, message): def expect_newline(self, message = "Expected a newline"):
# Expect either a newline or end of file # Expect either a newline or end of file
if self.sy <> 'EOF': if self.sy <> 'EOF':
self.expect('NEWLINE', message) self.expect('NEWLINE', message)
This diff is collapsed.
...@@ -84,6 +84,19 @@ class Signature: ...@@ -84,6 +84,19 @@ class Signature:
def return_type(self): def return_type(self):
return self.format_map[self.ret_format] return self.format_map[self.ret_format]
def exception_value(self):
return self.error_value_map.get(self.ret_format)
def function_type(self):
# Construct a C function type descriptor for this signature
args = []
for i in xrange(self.num_fixed_args()):
arg_type = self.fixed_arg_type(i)
args.append(PyrexTypes.CFuncTypeArg("", arg_type, None))
ret_type = self.return_type()
exc_value = self.exception_value()
return PyrexTypes.CFuncType(ret_type, args, exception_value = exc_value)
def method_flags(self): def method_flags(self):
if self.ret_format == "O": if self.ret_format == "O":
full_args = self.fixed_arg_format full_args = self.fixed_arg_format
...@@ -104,22 +117,23 @@ class SlotDescriptor: ...@@ -104,22 +117,23 @@ class SlotDescriptor:
# #
# slot_name string Member name of the slot in the type object # slot_name string Member name of the slot in the type object
# is_initialised_dynamically Is initialised by code in the module init function # is_initialised_dynamically Is initialised by code in the module init function
# flag Py_TPFLAGS_XXX value indicating presence of slot
def __init__(self, slot_name, dynamic = 0, min_python_version = None): def __init__(self, slot_name, dynamic = 0, flag = None):
self.slot_name = slot_name self.slot_name = slot_name
self.is_initialised_dynamically = dynamic self.is_initialised_dynamically = dynamic
self.min_python_version = min_python_version self.flag = flag
def generate(self, scope, code): def generate(self, scope, code):
if self.is_initialised_dynamically: if self.is_initialised_dynamically:
value = 0 value = 0
else: else:
value = self.slot_code(scope) value = self.slot_code(scope)
if self.min_python_version is not None: flag = self.flag
code.putln("#if PY_VERSION_HEX >= " + if flag:
code.get_py_version_hex(self.min_python_version)) code.putln("#if Py_TPFLAGS_DEFAULT & %s" % flag)
code.putln("%s, /*%s*/" % (value, self.slot_name)) code.putln("%s, /*%s*/" % (value, self.slot_name))
if self.min_python_version is not None: if flag:
code.putln("#endif") code.putln("#endif")
# Some C implementations have trouble statically # Some C implementations have trouble statically
...@@ -182,10 +196,8 @@ class MethodSlot(SlotDescriptor): ...@@ -182,10 +196,8 @@ class MethodSlot(SlotDescriptor):
# method_name string The __xxx__ name of the method # method_name string The __xxx__ name of the method
# default string or None Default value of the slot # default string or None Default value of the slot
def __init__(self, signature, slot_name, method_name, def __init__(self, signature, slot_name, method_name, default = None, flag = None):
default = None, min_python_version = None): SlotDescriptor.__init__(self, slot_name, flag = flag)
SlotDescriptor.__init__(self, slot_name,
min_python_version = min_python_version)
self.signature = signature self.signature = signature
self.slot_name = slot_name self.slot_name = slot_name
self.method_name = method_name self.method_name = method_name
...@@ -411,7 +423,7 @@ getcharbufferproc = Signature("TiS", 'i') # typedef int (*getcharbufferproc)(Py ...@@ -411,7 +423,7 @@ getcharbufferproc = Signature("TiS", 'i') # typedef int (*getcharbufferproc)(Py
readbufferproc = Signature("TZP", "Z") # typedef Py_ssize_t (*readbufferproc)(PyObject *, Py_ssize_t, void **); readbufferproc = Signature("TZP", "Z") # typedef Py_ssize_t (*readbufferproc)(PyObject *, Py_ssize_t, void **);
writebufferproc = Signature("TZP", "Z") # typedef Py_ssize_t (*writebufferproc)(PyObject *, Py_ssize_t, void **); writebufferproc = Signature("TZP", "Z") # typedef Py_ssize_t (*writebufferproc)(PyObject *, Py_ssize_t, void **);
segcountproc = Signature("TZ", "Z") # typedef Py_ssize_t (*segcountproc)(PyObject *, Py_ssize_t *); segcountproc = Signature("TZ", "Z") # typedef Py_ssize_t (*segcountproc)(PyObject *, Py_ssize_t *);
writebufferproc = Signature("TZS", "Z") # typedef Py_ssize_t (*charbufferproc)(PyObject *, Py_ssize_t, char **); charbufferproc = Signature("TZS", "Z") # typedef Py_ssize_t (*charbufferproc)(PyObject *, Py_ssize_t, char **);
objargproc = Signature("TO", 'r') # typedef int (*objobjproc)(PyObject *, PyObject *); objargproc = Signature("TO", 'r') # typedef int (*objobjproc)(PyObject *, PyObject *);
# typedef int (*visitproc)(PyObject *, void *); # typedef int (*visitproc)(PyObject *, void *);
# typedef int (*traverseproc)(PyObject *, visitproc, void *); # typedef int (*traverseproc)(PyObject *, visitproc, void *);
...@@ -502,11 +514,11 @@ PyNumberMethods = ( ...@@ -502,11 +514,11 @@ PyNumberMethods = (
MethodSlot(ibinaryfunc, "nb_inplace_true_divide", "__itruediv__"), MethodSlot(ibinaryfunc, "nb_inplace_true_divide", "__itruediv__"),
# Added in release 2.5 # Added in release 2.5
MethodSlot(unaryfunc, "nb_index", "__index__", min_python_version=(2,5)), MethodSlot(unaryfunc, "nb_index", "__index__", flag = "Py_TPFLAGS_HAVE_INDEX")
) )
PySequenceMethods = ( PySequenceMethods = (
MethodSlot(lenfunc, "sq_length", "__len__"), # EmptySlot("sq_length"), # mp_length used instead MethodSlot(lenfunc, "sq_length", "__len__"),
EmptySlot("sq_concat"), # nb_add used instead EmptySlot("sq_concat"), # nb_add used instead
EmptySlot("sq_repeat"), # nb_multiply used instead EmptySlot("sq_repeat"), # nb_multiply used instead
SyntheticSlot("sq_item", ["__getitem__"], "0"), #EmptySlot("sq_item"), # mp_subscript used instead SyntheticSlot("sq_item", ["__getitem__"], "0"), #EmptySlot("sq_item"), # mp_subscript used instead
...@@ -610,7 +622,7 @@ slot_table = ( ...@@ -610,7 +622,7 @@ slot_table = (
# #
#------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------
MethodSlot(initproc, "", "__new__") MethodSlot(initproc, "", "__cinit__")
MethodSlot(destructor, "", "__dealloc__") MethodSlot(destructor, "", "__dealloc__")
MethodSlot(objobjargproc, "", "__setitem__") MethodSlot(objobjargproc, "", "__setitem__")
MethodSlot(objargproc, "", "__delitem__") MethodSlot(objargproc, "", "__delitem__")
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
def print_call_chain(*args): def print_call_chain(*args):
import sys import sys
print " ".join(map(str, args)) print " ".join(map(str, args))
f = sys._getframe(2) f = sys._getframe(1)
while f: while f:
name = f.f_code.co_name name = f.f_code.co_name
s = f.f_locals.get('self', None) s = f.f_locals.get('self', None)
......
# July 2002, Graham Fawcett # July 2002, Graham Fawcett
# #
# this hack was inspired by the way Thomas Heller got py2exe # this hack was inspired by the way Thomas Heller got py2exe
# to appear as a distutil command # to appear as a distutil command
# #
# we replace distutils.command.build_ext with our own version # we replace distutils.command.build_ext with our own version
# and keep the old one under the module name _build_ext, # and keep the old one under the module name _build_ext,
# so that *our* build_ext can make use of it. # so that *our* build_ext can make use of it.
from build_ext import build_ext from build_ext import build_ext
from extension import Extension
# Subclasses disutils.command.build_ext, """Cython.Distutils.build_ext
# replacing it with a Pyrex version that compiles pyx->c
# before calling the original build_ext command.
# July 2002, Graham Fawcett
# Modified by Darrell Gallion <dgallion1@yahoo.com>
# to allow inclusion of .c files along with .pyx files.
# Pyrex is (c) Greg Ewing.
import distutils.command.build_ext Implements a version of the Distutils 'build_ext' command, for
#import Cython.Compiler.Main building Cython extension modules."""
from Cython.Compiler.Main import CompilationOptions, default_options, compile
from Cython.Compiler.Errors import PyrexError
from distutils.dep_util import newer
import os
import sys
def replace_suffix(path, new_suffix): # This module should be kept compatible with Python 2.1.
return os.path.splitext(path)[0] + new_suffix
class build_ext (distutils.command.build_ext.build_ext): __revision__ = "$Id:$"
description = "compile Cython scripts, then build C/C++ extensions (compile/link to build directory)" import sys, os, string, re
from types import *
from distutils.core import Command
from distutils.errors import *
from distutils.sysconfig import customize_compiler, get_python_version
from distutils.dep_util import newer_group
from distutils import log
from distutils.dir_util import mkpath
try:
from Cython.Compiler.Main \
import CompilationOptions, \
default_options as pyrex_default_options, \
compile as cython_compile
from Cython.Compiler.Errors import PyrexError
except ImportError, e:
print e
PyrexError = None
from distutils.command import build_ext as _build_ext
extension_name_re = _build_ext.extension_name_re
show_compilers = _build_ext.show_compilers
class build_ext(_build_ext.build_ext):
description = "build C/C++ and Cython extensions (compile/link to build directory)"
sep_by = _build_ext.build_ext.sep_by
user_options = _build_ext.build_ext.user_options
boolean_options = _build_ext.build_ext.boolean_options
help_options = _build_ext.build_ext.help_options
# Add the pyrex specific data.
user_options.extend([
('pyrex-cplus', None,
"generate C++ source files"),
('pyrex-create-listing', None,
"write errors to a listing file"),
('pyrex-include-dirs=', None,
"path to the Cython include files" + sep_by),
('pyrex-c-in-temp', None,
"put generated C files in temp directory"),
('pyrex-gen-pxi', None,
"generate .pxi file for public declarations"),
])
boolean_options.extend([
'pyrex-cplus', 'pyrex-create-listing', 'pyrex-c-in-temp'
])
def initialize_options(self):
_build_ext.build_ext.initialize_options(self)
self.pyrex_cplus = 0
self.pyrex_create_listing = 0
self.pyrex_include_dirs = None
self.pyrex_c_in_temp = 0
self.pyrex_gen_pxi = 0
def finalize_options (self): def finalize_options (self):
distutils.command.build_ext.build_ext.finalize_options(self) _build_ext.build_ext.finalize_options(self)
if self.pyrex_include_dirs is None:
# The following hack should no longer be needed. self.pyrex_include_dirs = []
if 0: elif type(self.pyrex_include_dirs) is StringType:
# compiling with mingw32 gets an "initializer not a constant" error self.pyrex_include_dirs = \
# doesn't appear to happen with MSVC! string.split(self.pyrex_include_dirs, os.pathsep)
# so if we are compiling with mingw32, # finalize_options ()
# switch to C++ mode, to avoid the problem
if self.compiler == 'mingw32': def build_extensions(self):
self.swig_cpp = 1 # First, sanity-check the 'extensions' list
self.check_extensions_list(self.extensions)
def swig_sources (self, sources, extension = None): for ext in self.extensions:
if not self.extensions: ext.sources = self.cython_sources(ext.sources, ext)
return self.build_extension(ext)
#suffix = self.swig_cpp and '.cpp' or '.c' def cython_sources(self, sources, extension):
suffix = '.c'
cplus = 0 """
include_dirs = [] Walk the list of source files in 'sources', looking for Cython
if extension is not None: source (.pyx) files. Run Cython on all that are found, and return
module_name = extension.name a modified 'sources' list with Cython source files replaced by the
include_dirs = extension.include_dirs or [] generated C (or C++) files.
if extension.language == "c++": """
cplus = 1
suffix = ".cpp" if PyrexError == None:
raise DistutilsPlatformError, \
("Cython does not appear to be installed "
"on platform '%s'") % os.name
new_sources = []
pyrex_sources = []
pyrex_targets = {}
# Setup create_list and cplus from the extension options if
# Cython.Distutils.extension.Extension is used, otherwise just
# use what was parsed from the command-line or the configuration file.
# cplus will also be set to true is extension.language is equal to
# 'C++' or 'c++'.
#try:
# create_listing = self.pyrex_create_listing or \
# extension.pyrex_create_listing
# cplus = self.pyrex_cplus or \
# extension.pyrex_cplus or \
# (extension.language != None and \
# extension.language.lower() == 'c++')
#except AttributeError:
# create_listing = self.pyrex_create_listing
# cplus = self.pyrex_cplus or \
# (extension.language != None and \
# extension.language.lower() == 'c++')
create_listing = self.pyrex_create_listing or \
getattr(extension, 'pyrex_create_listing', 0)
cplus = self.pyrex_cplus or getattr(extension, 'pyrex_cplus', 0) or \
(extension.language and extension.language.lower() == 'c++')
pyrex_gen_pxi = self.pyrex_gen_pxi or getattr(extension, 'pyrex_gen_pxi', 0)
# Set up the include_path for the Cython compiler:
# 1. Start with the command line option.
# 2. Add in any (unique) paths from the extension
# pyrex_include_dirs (if Cython.Distutils.extension is used).
# 3. Add in any (unique) paths from the extension include_dirs
includes = self.pyrex_include_dirs
try:
for i in extension.pyrex_include_dirs:
if not i in includes:
includes.append(i)
except AttributeError:
pass
for i in extension.include_dirs:
if not i in includes:
includes.append(i)
# Set the target_ext to '.c'. Cython will change this to '.cpp' if
# needed.
if cplus:
target_ext = '.cpp'
else:
target_ext = '.c'
# Decide whether to drop the generated C files into the temp dir
# or the source tree.
if not self.inplace and (self.pyrex_c_in_temp
or getattr(extension, 'pyrex_c_in_temp', 0)):
target_dir = os.path.join(self.build_temp, "pyrex")
else:
target_dir = ""
for source in sources:
(base, ext) = os.path.splitext(source)
if ext == ".pyx": # Cython source file
new_sources.append(os.path.join(target_dir, base + target_ext))
pyrex_sources.append(source)
pyrex_targets[source] = new_sources[-1]
else: else:
module_name = None new_sources.append(source)
# collect the names of the source (.pyx) files if not pyrex_sources:
pyx_sources = [source for source in sources if source.endswith('.pyx')] return new_sources
other_sources = [source for source in sources if not source.endswith('.pyx')]
module_name = extension.name
for pyx in pyx_sources:
# should I raise an exception if it doesn't exist? for source in pyrex_sources:
if os.path.exists(pyx): target = pyrex_targets[source]
source = pyx source_time = os.stat(source).st_mtime
target = replace_suffix(source, suffix) try:
if newer(source, target) or self.force: target_time = os.stat(target).st_mtime
self.cython_compile(source, module_name, include_dirs, cplus) newer = source_time > target_time
except EnvironmentError:
return [replace_suffix(src, suffix) for src in pyx_sources] + other_sources newer = 1
if newer:
def cython_compile(self, source, module_name, include_dirs, cplus): log.info("cythoning %s to %s", source, target)
options = CompilationOptions( self.mkpath(os.path.dirname(target))
default_options, options = CompilationOptions(pyrex_default_options,
include_path = include_dirs + self.include_dirs, use_listing_file = create_listing,
cplus=cplus) include_path = includes,
result = compile(source, options, full_module_name=module_name) output_file = target,
if result.num_errors <> 0: cplus = cplus,
sys.exit(1) generate_pxi = pyrex_gen_pxi)
result = cython_compile(source, options=options,
full_module_name=module_name)
return new_sources
# cython_sources ()
# class build_ext
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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