Cython has moved to github.
cython-devel
view Cython/Compiler/Main.py @ 1486:8a2e7b51e770
initial constant folding transform: calculate constant values in node.constant_result
| author | Stefan Behnel <scoder@users.berlios.de> |
|---|---|
| date | Sat Dec 13 22:23:00 2008 +0100 (3 years ago) |
| parents | 49a8357fc01e |
| children | 223c184845ea |
line source
1 #
2 # Cython Top Level
3 #
5 import os, sys, re, codecs
6 if sys.version_info[:2] < (2, 3):
7 sys.stderr.write("Sorry, Cython requires Python 2.3 or later\n")
8 sys.exit(1)
10 try:
11 set
12 except NameError:
13 # Python 2.3
14 from sets import Set as set
16 from time import time
17 import Code
18 import Errors
19 import Parsing
20 import Version
21 from Scanning import PyrexScanner, FileSourceDescriptor
22 from Errors import PyrexError, CompileError, InternalError, error
23 from Symtab import BuiltinScope, ModuleScope
24 from Cython import Utils
25 from Cython.Utils import open_new_file, replace_suffix
26 import CythonScope
28 module_name_pattern = re.compile(r"[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$")
30 verbose = 0
32 def dumptree(t):
33 # For quick debugging in pipelines
34 print t.dump()
35 return t
37 class CompilationData:
38 # Bundles the information that is passed from transform to transform.
39 # (For now, this is only)
41 # While Context contains every pxd ever loaded, path information etc.,
42 # this only contains the data related to a single compilation pass
43 #
44 # pyx ModuleNode Main code tree of this compilation.
45 # pxds {string : ModuleNode} Trees for the pxds used in the pyx.
46 # codewriter CCodeWriter Where to output final code.
47 # options CompilationOptions
48 # result CompilationResult
49 pass
51 class Context:
52 # This class encapsulates the context needed for compiling
53 # one or more Cython implementation files along with their
54 # associated and imported declaration files. It includes
55 # the root of the module import namespace and the list
56 # of directories to search for include files.
57 #
58 # modules {string : ModuleScope}
59 # include_directories [string]
60 # future_directives [object]
62 def __init__(self, include_directories, pragma_overrides):
63 #self.modules = {"__builtin__" : BuiltinScope()}
64 import Builtin, CythonScope
65 self.modules = {"__builtin__" : Builtin.builtin_scope}
66 self.modules["cython"] = CythonScope.create_cython_scope(self)
67 self.include_directories = include_directories
68 self.future_directives = set()
69 self.pragma_overrides = pragma_overrides
71 self.pxds = {} # full name -> node tree
73 standard_include_path = os.path.abspath(
74 os.path.join(os.path.dirname(__file__), '..', 'Includes'))
75 self.include_directories = include_directories + [standard_include_path]
77 def create_pipeline(self, pxd, py=False):
78 from Visitor import PrintTree
79 from ParseTreeTransforms import WithTransform, NormalizeTree, PostParse, PxdPostParse
80 from ParseTreeTransforms import AnalyseDeclarationsTransform, AnalyseExpressionsTransform
81 from ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform
82 from ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods
83 from ParseTreeTransforms import AlignFunctionDefinitions
84 from AutoDocTransforms import EmbedSignature
85 from Optimize import FlattenInListTransform, SwitchTransform, DictIterTransform
86 from Optimize import FlattenBuiltinTypeCreation, ConstantFolding, FinalOptimizePhase
87 from Buffer import IntroduceBufferAuxiliaryVars
88 from ModuleNode import check_c_declarations
90 # Temporary hack that can be used to ensure that all result_code's
91 # are generated at code generation time.
92 import Visitor
93 class ClearResultCodes(Visitor.CythonTransform):
94 def visit_ExprNode(self, node):
95 self.visitchildren(node)
96 node.result_code = "<cleared>"
97 return node
99 if pxd:
100 _check_c_declarations = None
101 _specific_post_parse = PxdPostParse(self)
102 else:
103 _check_c_declarations = check_c_declarations
104 _specific_post_parse = None
106 if py and not pxd:
107 _align_function_definitions = AlignFunctionDefinitions(self)
108 else:
109 _align_function_definitions = None
111 return [
112 NormalizeTree(self),
113 PostParse(self),
114 _specific_post_parse,
115 InterpretCompilerDirectives(self, self.pragma_overrides),
116 _align_function_definitions,
117 FlattenInListTransform(),
118 WithTransform(self),
119 DecoratorTransform(self),
120 AnalyseDeclarationsTransform(self),
121 EmbedSignature(self),
122 TransformBuiltinMethods(self),
123 IntroduceBufferAuxiliaryVars(self),
124 _check_c_declarations,
125 AnalyseExpressionsTransform(self),
126 ConstantFolding(),
127 FlattenBuiltinTypeCreation(),
128 DictIterTransform(),
129 SwitchTransform(),
130 FinalOptimizePhase(self),
131 # ClearResultCodes(self),
132 # SpecialFunctions(self),
133 # CreateClosureClasses(context),
134 ]
136 def create_pyx_pipeline(self, options, result, py=False):
137 def generate_pyx_code(module_node):
138 module_node.process_implementation(options, result)
139 result.compilation_source = module_node.compilation_source
140 return result
142 def inject_pxd_code(module_node):
143 from textwrap import dedent
144 stats = module_node.body.stats
145 for name, (statlistnode, scope) in self.pxds.iteritems():
146 # Copy over function nodes to the module
147 # (this seems strange -- I believe the right concept is to split
148 # ModuleNode into a ModuleNode and a CodeGenerator, and tell that
149 # CodeGenerator to generate code both from the pyx and pxd ModuleNodes.
150 stats.append(statlistnode)
151 # Until utility code is moved to code generation phase everywhere,
152 # we need to copy it over to the main scope
153 module_node.scope.utility_code_list.extend(scope.utility_code_list)
154 return module_node
156 return ([
157 create_parse(self),
158 ] + self.create_pipeline(pxd=False, py=py) + [
159 inject_pxd_code,
160 generate_pyx_code,
161 ])
163 def create_pxd_pipeline(self, scope, module_name):
164 def parse_pxd(source_desc):
165 tree = self.parse(source_desc, scope, pxd=True,
166 full_module_name=module_name)
167 tree.scope = scope
168 tree.is_pxd = True
169 return tree
171 from CodeGeneration import ExtractPxdCode
173 # The pxd pipeline ends up with a CCodeWriter containing the
174 # code of the pxd, as well as a pxd scope.
175 return [parse_pxd] + self.create_pipeline(pxd=True) + [
176 ExtractPxdCode(self),
177 ]
179 def create_py_pipeline(self, options, result):
180 return self.create_pyx_pipeline(options, result, py=True)
183 def process_pxd(self, source_desc, scope, module_name):
184 pipeline = self.create_pxd_pipeline(scope, module_name)
185 result = self.run_pipeline(pipeline, source_desc)
186 return result
188 def nonfatal_error(self, exc):
189 return Errors.report_error(exc)
191 def run_pipeline(self, pipeline, source):
192 err = None
193 data = source
194 try:
195 for phase in pipeline:
196 if phase is not None:
197 data = phase(data)
198 except CompileError, err:
199 # err is set
200 Errors.report_error(err)
201 except InternalError, err:
202 # Only raise if there was not an earlier error
203 if Errors.num_errors == 0:
204 raise
205 return (err, data)
207 def find_module(self, module_name,
208 relative_to = None, pos = None, need_pxd = 1):
209 # Finds and returns the module scope corresponding to
210 # the given relative or absolute module name. If this
211 # is the first time the module has been requested, finds
212 # the corresponding .pxd file and process it.
213 # If relative_to is not None, it must be a module scope,
214 # and the module will first be searched for relative to
215 # that module, provided its name is not a dotted name.
216 debug_find_module = 0
217 if debug_find_module:
218 print("Context.find_module: module_name = %s, relative_to = %s, pos = %s, need_pxd = %s" % (
219 module_name, relative_to, pos, need_pxd))
221 scope = None
222 pxd_pathname = None
223 if not module_name_pattern.match(module_name):
224 if pos is None:
225 pos = (module_name, 0, 0)
226 raise CompileError(pos,
227 "'%s' is not a valid module name" % module_name)
228 if "." not in module_name and relative_to:
229 if debug_find_module:
230 print("...trying relative import")
231 scope = relative_to.lookup_submodule(module_name)
232 if not scope:
233 qualified_name = relative_to.qualify_name(module_name)
234 pxd_pathname = self.find_pxd_file(qualified_name, pos)
235 if pxd_pathname:
236 scope = relative_to.find_submodule(module_name)
237 if not scope:
238 if debug_find_module:
239 print("...trying absolute import")
240 scope = self
241 for name in module_name.split("."):
242 scope = scope.find_submodule(name)
243 if debug_find_module:
244 print("...scope =", scope)
245 if not scope.pxd_file_loaded:
246 if debug_find_module:
247 print("...pxd not loaded")
248 scope.pxd_file_loaded = 1
249 if not pxd_pathname:
250 if debug_find_module:
251 print("...looking for pxd file")
252 pxd_pathname = self.find_pxd_file(module_name, pos)
253 if debug_find_module:
254 print("......found ", pxd_pathname)
255 if not pxd_pathname and need_pxd:
256 error(pos, "'%s.pxd' not found" % module_name)
257 if pxd_pathname:
258 try:
259 if debug_find_module:
260 print("Context.find_module: Parsing %s" % pxd_pathname)
261 source_desc = FileSourceDescriptor(pxd_pathname)
262 err, result = self.process_pxd(source_desc, scope, module_name)
263 if err:
264 raise err
265 (pxd_codenodes, pxd_scope) = result
266 self.pxds[module_name] = (pxd_codenodes, pxd_scope)
267 except CompileError:
268 pass
269 return scope
271 def find_pxd_file(self, qualified_name, pos):
272 # Search include path for the .pxd file corresponding to the
273 # given fully-qualified module name.
274 # Will find either a dotted filename or a file in a
275 # package directory. If a source file position is given,
276 # the directory containing the source file is searched first
277 # for a dotted filename, and its containing package root
278 # directory is searched first for a non-dotted filename.
279 return self.search_include_directories(qualified_name, ".pxd", pos)
281 def find_pyx_file(self, qualified_name, pos):
282 # Search include path for the .pyx file corresponding to the
283 # given fully-qualified module name, as for find_pxd_file().
284 return self.search_include_directories(qualified_name, ".pyx", pos)
286 def find_include_file(self, filename, pos):
287 # Search list of include directories for filename.
288 # Reports an error and returns None if not found.
289 path = self.search_include_directories(filename, "", pos,
290 include=True)
291 if not path:
292 error(pos, "'%s' not found" % filename)
293 return path
295 def search_include_directories(self, qualified_name, suffix, pos,
296 include=False):
297 # Search the list of include directories for the given
298 # file name. If a source file position is given, first
299 # searches the directory containing that file. Returns
300 # None if not found, but does not report an error.
301 # The 'include' option will disable package dereferencing.
302 dirs = self.include_directories
303 if pos:
304 file_desc = pos[0]
305 if not isinstance(file_desc, FileSourceDescriptor):
306 raise RuntimeError("Only file sources for code supported")
307 if include:
308 dirs = [os.path.dirname(file_desc.filename)] + dirs
309 else:
310 dirs = [self.find_root_package_dir(file_desc.filename)] + dirs
312 dotted_filename = qualified_name + suffix
313 if not include:
314 names = qualified_name.split('.')
315 package_names = names[:-1]
316 module_name = names[-1]
317 module_filename = module_name + suffix
318 package_filename = "__init__" + suffix
320 for dir in dirs:
321 path = os.path.join(dir, dotted_filename)
322 if os.path.exists(path):
323 return path
324 if not include:
325 package_dir = self.check_package_dir(dir, package_names)
326 if package_dir is not None:
327 path = os.path.join(package_dir, module_filename)
328 if os.path.exists(path):
329 return path
330 path = os.path.join(dir, package_dir, module_name,
331 package_filename)
332 if os.path.exists(path):
333 return path
334 return None
336 def find_root_package_dir(self, file_path):
337 dir = os.path.dirname(file_path)
338 while self.is_package_dir(dir):
339 parent = os.path.dirname(dir)
340 if parent == dir:
341 break
342 dir = parent
343 return dir
345 def is_package_dir(self, dir):
346 package_init = os.path.join(dir, "__init__.py")
347 return os.path.exists(package_init) or \
348 os.path.exists(package_init + "x") # same with .pyx
350 def check_package_dir(self, dir, package_names):
351 package_dir = os.path.join(dir, *package_names)
352 if not os.path.exists(package_dir):
353 return None
354 for dirname in package_names:
355 dir = os.path.join(dir, dirname)
356 if not self.is_package_dir(dir):
357 return None
358 return package_dir
360 def c_file_out_of_date(self, source_path):
361 c_path = Utils.replace_suffix(source_path, ".c")
362 if not os.path.exists(c_path):
363 return 1
364 c_time = Utils.modification_time(c_path)
365 if Utils.file_newer_than(source_path, c_time):
366 return 1
367 pos = [source_path]
368 pxd_path = Utils.replace_suffix(source_path, ".pxd")
369 if os.path.exists(pxd_path) and Utils.file_newer_than(pxd_path, c_time):
370 return 1
371 for kind, name in self.read_dependency_file(source_path):
372 if kind == "cimport":
373 dep_path = self.find_pxd_file(name, pos)
374 elif kind == "include":
375 dep_path = self.search_include_directories(name, pos)
376 else:
377 continue
378 if dep_path and Utils.file_newer_than(dep_path, c_time):
379 return 1
380 return 0
382 def find_cimported_module_names(self, source_path):
383 return [ name for kind, name in self.read_dependency_file(source_path)
384 if kind == "cimport" ]
386 def is_package_dir(self, dir_path):
387 # Return true if the given directory is a package directory.
388 for filename in ("__init__.py", "__init__.pyx"):
389 path = os.path.join(dir_path, filename)
390 if os.path.exists(path):
391 return 1
393 def read_dependency_file(self, source_path):
394 dep_path = Utils.replace_suffix(source_path, ".dep")
395 if os.path.exists(dep_path):
396 f = open(dep_path, "rU")
397 chunks = [ line.strip().split(" ", 1)
398 for line in f.readlines()
399 if " " in line.strip() ]
400 f.close()
401 return chunks
402 else:
403 return ()
405 def lookup_submodule(self, name):
406 # Look up a top-level module. Returns None if not found.
407 return self.modules.get(name, None)
409 def find_submodule(self, name):
410 # Find a top-level module, creating a new one if needed.
411 scope = self.lookup_submodule(name)
412 if not scope:
413 scope = ModuleScope(name,
414 parent_module = None, context = self)
415 self.modules[name] = scope
416 return scope
418 def parse(self, source_desc, scope, pxd, full_module_name):
419 if not isinstance(source_desc, FileSourceDescriptor):
420 raise RuntimeError("Only file sources for code supported")
421 source_filename = Utils.encode_filename(source_desc.filename)
422 # Parse the given source file and return a parse tree.
423 try:
424 f = Utils.open_source_file(source_filename, "rU")
425 try:
426 s = PyrexScanner(f, source_desc, source_encoding = f.encoding,
427 scope = scope, context = self)
428 tree = Parsing.p_module(s, pxd, full_module_name)
429 finally:
430 f.close()
431 except UnicodeDecodeError, msg:
432 #import traceback
433 #traceback.print_exc()
434 error((source_desc, 0, 0), "Decoding error, missing or incorrect coding=<encoding-name> at top of source (%s)" % msg)
435 if Errors.num_errors > 0:
436 raise CompileError
437 return tree
439 def extract_module_name(self, path, options):
440 # Find fully_qualified module name from the full pathname
441 # of a source file.
442 dir, filename = os.path.split(path)
443 module_name, _ = os.path.splitext(filename)
444 if "." in module_name:
445 return module_name
446 if module_name == "__init__":
447 dir, module_name = os.path.split(dir)
448 names = [module_name]
449 while self.is_package_dir(dir):
450 parent, package_name = os.path.split(dir)
451 if parent == dir:
452 break
453 names.append(package_name)
454 dir = parent
455 names.reverse()
456 return ".".join(names)
458 def setup_errors(self, options):
459 if options.use_listing_file:
460 result.listing_file = Utils.replace_suffix(source, ".lis")
461 Errors.open_listing_file(result.listing_file,
462 echo_to_stderr = options.errors_to_stderr)
463 else:
464 Errors.open_listing_file(None)
466 def teardown_errors(self, err, options, result):
467 source_desc = result.compilation_source.source_desc
468 if not isinstance(source_desc, FileSourceDescriptor):
469 raise RuntimeError("Only file sources for code supported")
470 Errors.close_listing_file()
471 result.num_errors = Errors.num_errors
472 if result.num_errors > 0:
473 err = True
474 if err and result.c_file:
475 try:
476 Utils.castrate_file(result.c_file, os.stat(source_desc.filename))
477 except EnvironmentError:
478 pass
479 result.c_file = None
480 if result.c_file and not options.c_only and c_compile:
481 result.object_file = c_compile(result.c_file,
482 verbose_flag = options.show_version,
483 cplus = options.cplus)
484 if not options.obj_only and c_link:
485 result.extension_file = c_link(result.object_file,
486 extra_objects = options.objects,
487 verbose_flag = options.show_version,
488 cplus = options.cplus)
490 def create_parse(context):
491 def parse(compsrc):
492 source_desc = compsrc.source_desc
493 full_module_name = compsrc.full_module_name
494 initial_pos = (source_desc, 1, 0)
495 scope = context.find_module(full_module_name, pos = initial_pos, need_pxd = 0)
496 tree = context.parse(source_desc, scope, pxd = 0, full_module_name = full_module_name)
497 tree.compilation_source = compsrc
498 tree.scope = scope
499 tree.is_pxd = False
500 return tree
501 return parse
503 def create_default_resultobj(compilation_source, options):
504 result = CompilationResult()
505 result.main_source_file = compilation_source.source_desc.filename
506 result.compilation_source = compilation_source
507 source_desc = compilation_source.source_desc
508 if options.output_file:
509 result.c_file = os.path.join(compilation_source.cwd, options.output_file)
510 else:
511 if options.cplus:
512 c_suffix = ".cpp"
513 else:
514 c_suffix = ".c"
515 result.c_file = Utils.replace_suffix(source_desc.filename, c_suffix)
516 return result
518 def run_pipeline(source, options, full_module_name = None):
519 # Set up context
520 context = Context(options.include_path, options.pragma_overrides)
522 # Set up source object
523 cwd = os.getcwd()
524 source_desc = FileSourceDescriptor(os.path.join(cwd, source))
525 full_module_name = full_module_name or context.extract_module_name(source, options)
526 source = CompilationSource(source_desc, full_module_name, cwd)
528 # Set up result object
529 result = create_default_resultobj(source, options)
531 # Get pipeline
532 if source_desc.filename.endswith(".py"):
533 pipeline = context.create_py_pipeline(options, result)
534 else:
535 pipeline = context.create_pyx_pipeline(options, result)
537 context.setup_errors(options)
538 err, enddata = context.run_pipeline(pipeline, source)
539 context.teardown_errors(err, options, result)
540 return result
542 #------------------------------------------------------------------------
543 #
544 # Main Python entry points
545 #
546 #------------------------------------------------------------------------
548 class CompilationSource(object):
549 """
550 Contains the data necesarry to start up a compilation pipeline for
551 a single compilation unit.
552 """
553 def __init__(self, source_desc, full_module_name, cwd):
554 self.source_desc = source_desc
555 self.full_module_name = full_module_name
556 self.cwd = cwd
558 class CompilationOptions:
559 """
560 Options to the Cython compiler:
562 show_version boolean Display version number
563 use_listing_file boolean Generate a .lis file
564 errors_to_stderr boolean Echo errors to stderr when using .lis
565 include_path [string] Directories to search for include files
566 output_file string Name of generated .c file
567 generate_pxi boolean Generate .pxi file for public declarations
568 recursive boolean Recursively find and compile dependencies
569 timestamps boolean Only compile changed source files. If None,
570 defaults to true when recursive is true.
571 verbose boolean Always print source names being compiled
572 quiet boolean Don't print source names in recursive mode
573 pragma_overrides dict Overrides for pragma options (see Options.py)
575 Following options are experimental and only used on MacOSX:
577 c_only boolean Stop after generating C file (default)
578 obj_only boolean Stop after compiling to .o file
579 objects [string] Extra .o files to link with
580 cplus boolean Compile as c++ code
581 """
583 def __init__(self, defaults = None, c_compile = 0, c_link = 0, **kw):
584 self.include_path = []
585 self.objects = []
586 if defaults:
587 if isinstance(defaults, CompilationOptions):
588 defaults = defaults.__dict__
589 else:
590 defaults = default_options
591 self.__dict__.update(defaults)
592 self.__dict__.update(kw)
593 if c_compile:
594 self.c_only = 0
595 if c_link:
596 self.obj_only = 0
599 class CompilationResult:
600 """
601 Results from the Cython compiler:
603 c_file string or None The generated C source file
604 h_file string or None The generated C header file
605 i_file string or None The generated .pxi file
606 api_file string or None The generated C API .h file
607 listing_file string or None File of error messages
608 object_file string or None Result of compiling the C file
609 extension_file string or None Result of linking the object file
610 num_errors integer Number of compilation errors
611 compilation_source CompilationSource
612 """
614 def __init__(self):
615 self.c_file = None
616 self.h_file = None
617 self.i_file = None
618 self.api_file = None
619 self.listing_file = None
620 self.object_file = None
621 self.extension_file = None
622 self.main_source_file = None
625 class CompilationResultSet(dict):
626 """
627 Results from compiling multiple Pyrex source files. A mapping
628 from source file paths to CompilationResult instances. Also
629 has the following attributes:
631 num_errors integer Total number of compilation errors
632 """
634 num_errors = 0
636 def add(self, source, result):
637 self[source] = result
638 self.num_errors += result.num_errors
641 def compile_single(source, options, full_module_name = None):
642 """
643 compile_single(source, options, full_module_name)
645 Compile the given Pyrex implementation file and return a CompilationResult.
646 Always compiles a single file; does not perform timestamp checking or
647 recursion.
648 """
649 return run_pipeline(source, options, full_module_name)
652 def compile_multiple(sources, options):
653 """
654 compile_multiple(sources, options)
656 Compiles the given sequence of Pyrex implementation files and returns
657 a CompilationResultSet. Performs timestamp checking and/or recursion
658 if these are specified in the options.
659 """
660 sources = [os.path.abspath(source) for source in sources]
661 processed = set()
662 results = CompilationResultSet()
663 recursive = options.recursive
664 timestamps = options.timestamps
665 if timestamps is None:
666 timestamps = recursive
667 verbose = options.verbose or ((recursive or timestamps) and not options.quiet)
668 for source in sources:
669 if source not in processed:
670 # Compiling multiple sources in one context doesn't quite
671 # work properly yet.
672 if not timestamps or context.c_file_out_of_date(source):
673 if verbose:
674 sys.stderr.write("Compiling %s\n" % source)
676 result = run_pipeline(source, options)
677 results.add(source, result)
678 processed.add(source)
679 if recursive:
680 for module_name in context.find_cimported_module_names(source):
681 path = context.find_pyx_file(module_name, [source])
682 if path:
683 sources.append(path)
684 else:
685 sys.stderr.write(
686 "Cannot find .pyx file for cimported module '%s'\n" % module_name)
687 return results
689 def compile(source, options = None, c_compile = 0, c_link = 0,
690 full_module_name = None, **kwds):
691 """
692 compile(source [, options], [, <option> = <value>]...)
694 Compile one or more Pyrex implementation files, with optional timestamp
695 checking and recursing on dependecies. The source argument may be a string
696 or a sequence of strings If it is a string and no recursion or timestamp
697 checking is requested, a CompilationResult is returned, otherwise a
698 CompilationResultSet is returned.
699 """
700 options = CompilationOptions(defaults = options, c_compile = c_compile,
701 c_link = c_link, **kwds)
702 if isinstance(source, basestring) and not options.timestamps \
703 and not options.recursive:
704 return compile_single(source, options, full_module_name)
705 else:
706 return compile_multiple(source, options)
708 #------------------------------------------------------------------------
709 #
710 # Main command-line entry point
711 #
712 #------------------------------------------------------------------------
714 def main(command_line = 0):
715 args = sys.argv[1:]
716 any_failures = 0
717 if command_line:
718 from CmdLine import parse_command_line
719 options, sources = parse_command_line(args)
720 else:
721 options = CompilationOptions(default_options)
722 sources = args
724 if options.show_version:
725 sys.stderr.write("Cython version %s\n" % Version.version)
726 if options.working_path!="":
727 os.chdir(options.working_path)
728 try:
729 result = compile(sources, options)
730 if result.num_errors > 0:
731 any_failures = 1
732 except (EnvironmentError, PyrexError), e:
733 sys.stderr.write(str(e) + '\n')
734 any_failures = 1
735 if any_failures:
736 sys.exit(1)
740 #------------------------------------------------------------------------
741 #
742 # Set the default options depending on the platform
743 #
744 #------------------------------------------------------------------------
746 default_options = dict(
747 show_version = 0,
748 use_listing_file = 0,
749 errors_to_stderr = 1,
750 c_only = 1,
751 obj_only = 1,
752 cplus = 0,
753 output_file = None,
754 annotate = False,
755 generate_pxi = 0,
756 working_path = "",
757 recursive = 0,
758 timestamps = None,
759 verbose = 0,
760 quiet = 0,
761 pragma_overrides = {},
762 emit_linenums = False,
763 )
764 if sys.platform == "mac":
765 from Cython.Mac.MacSystem import c_compile, c_link, CCompilerError
766 default_options['use_listing_file'] = 1
767 elif sys.platform == "darwin":
768 from Cython.Mac.DarwinSystem import c_compile, c_link, CCompilerError
769 else:
770 c_compile = None
771 c_link = None
