Cython has moved to github.
cython-devel
view Cython/Compiler/Main.py @ 1938:6900df959135
Fix ticket #4, from package cimport module
| author | Robert Bradshaw <robertwb@math.washington.edu> |
|---|---|
| date | Thu Apr 02 16:45:33 2009 -0700 (3 years ago) |
| parents | 569ed4c256db |
| children | 26a61c2131fd 1ac0104af371 |
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(object):
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(object):
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 ComprehensionTransform, AlignFunctionDefinitions
84 from AutoDocTransforms import EmbedSignature
85 from Optimize import FlattenInListTransform, SwitchTransform, IterationTransform
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 FlattenBuiltinTypeCreation(),
127 ConstantFolding(),
128 # ComprehensionTransform(),
129 IterationTransform(),
130 SwitchTransform(),
131 FinalOptimizePhase(self),
132 # ClearResultCodes(self),
133 # SpecialFunctions(self),
134 # CreateClosureClasses(context),
135 ]
137 def create_pyx_pipeline(self, options, result, py=False):
138 def generate_pyx_code(module_node):
139 module_node.process_implementation(options, result)
140 result.compilation_source = module_node.compilation_source
141 return result
143 def inject_pxd_code(module_node):
144 from textwrap import dedent
145 stats = module_node.body.stats
146 for name, (statlistnode, scope) in self.pxds.iteritems():
147 # Copy over function nodes to the module
148 # (this seems strange -- I believe the right concept is to split
149 # ModuleNode into a ModuleNode and a CodeGenerator, and tell that
150 # CodeGenerator to generate code both from the pyx and pxd ModuleNodes.
151 stats.append(statlistnode)
152 # Until utility code is moved to code generation phase everywhere,
153 # we need to copy it over to the main scope
154 module_node.scope.utility_code_list.extend(scope.utility_code_list)
155 return module_node
157 return ([
158 create_parse(self),
159 ] + self.create_pipeline(pxd=False, py=py) + [
160 inject_pxd_code,
161 generate_pyx_code,
162 ])
164 def create_pxd_pipeline(self, scope, module_name):
165 def parse_pxd(source_desc):
166 tree = self.parse(source_desc, scope, pxd=True,
167 full_module_name=module_name)
168 tree.scope = scope
169 tree.is_pxd = True
170 return tree
172 from CodeGeneration import ExtractPxdCode
174 # The pxd pipeline ends up with a CCodeWriter containing the
175 # code of the pxd, as well as a pxd scope.
176 return [parse_pxd] + self.create_pipeline(pxd=True) + [
177 ExtractPxdCode(self),
178 ]
180 def create_py_pipeline(self, options, result):
181 return self.create_pyx_pipeline(options, result, py=True)
184 def process_pxd(self, source_desc, scope, module_name):
185 pipeline = self.create_pxd_pipeline(scope, module_name)
186 result = self.run_pipeline(pipeline, source_desc)
187 return result
189 def nonfatal_error(self, exc):
190 return Errors.report_error(exc)
192 def run_pipeline(self, pipeline, source):
193 err = None
194 data = source
195 try:
196 for phase in pipeline:
197 if phase is not None:
198 data = phase(data)
199 except CompileError, err:
200 # err is set
201 Errors.report_error(err)
202 except InternalError, err:
203 # Only raise if there was not an earlier error
204 if Errors.num_errors == 0:
205 raise
206 return (err, data)
208 def find_module(self, module_name,
209 relative_to = None, pos = None, need_pxd = 1):
210 # Finds and returns the module scope corresponding to
211 # the given relative or absolute module name. If this
212 # is the first time the module has been requested, finds
213 # the corresponding .pxd file and process it.
214 # If relative_to is not None, it must be a module scope,
215 # and the module will first be searched for relative to
216 # that module, provided its name is not a dotted name.
217 debug_find_module = 0
218 if debug_find_module:
219 print("Context.find_module: module_name = %s, relative_to = %s, pos = %s, need_pxd = %s" % (
220 module_name, relative_to, pos, need_pxd))
222 scope = None
223 pxd_pathname = None
224 if not module_name_pattern.match(module_name):
225 if pos is None:
226 pos = (module_name, 0, 0)
227 raise CompileError(pos,
228 "'%s' is not a valid module name" % module_name)
229 if "." not in module_name and relative_to:
230 if debug_find_module:
231 print("...trying relative import")
232 scope = relative_to.lookup_submodule(module_name)
233 if not scope:
234 qualified_name = relative_to.qualify_name(module_name)
235 pxd_pathname = self.find_pxd_file(qualified_name, pos)
236 if pxd_pathname:
237 scope = relative_to.find_submodule(module_name)
238 if not scope:
239 if debug_find_module:
240 print("...trying absolute import")
241 scope = self
242 for name in module_name.split("."):
243 scope = scope.find_submodule(name)
244 if debug_find_module:
245 print("...scope =", scope)
246 if not scope.pxd_file_loaded:
247 if debug_find_module:
248 print("...pxd not loaded")
249 scope.pxd_file_loaded = 1
250 if not pxd_pathname:
251 if debug_find_module:
252 print("...looking for pxd file")
253 pxd_pathname = self.find_pxd_file(module_name, pos)
254 if debug_find_module:
255 print("......found ", pxd_pathname)
256 if not pxd_pathname and need_pxd:
257 package_pathname = self.search_include_directories(module_name, ".py", pos)
258 if package_pathname and package_pathname.endswith('__init__.py'):
259 pass
260 else:
261 error(pos, "'%s.pxd' not found" % module_name)
262 if pxd_pathname:
263 try:
264 if debug_find_module:
265 print("Context.find_module: Parsing %s" % pxd_pathname)
266 source_desc = FileSourceDescriptor(pxd_pathname)
267 err, result = self.process_pxd(source_desc, scope, module_name)
268 if err:
269 raise err
270 (pxd_codenodes, pxd_scope) = result
271 self.pxds[module_name] = (pxd_codenodes, pxd_scope)
272 except CompileError:
273 pass
274 return scope
276 def find_pxd_file(self, qualified_name, pos):
277 # Search include path for the .pxd file corresponding to the
278 # given fully-qualified module name.
279 # Will find either a dotted filename or a file in a
280 # package directory. If a source file position is given,
281 # the directory containing the source file is searched first
282 # for a dotted filename, and its containing package root
283 # directory is searched first for a non-dotted filename.
284 return self.search_include_directories(qualified_name, ".pxd", pos)
286 def find_pyx_file(self, qualified_name, pos):
287 # Search include path for the .pyx file corresponding to the
288 # given fully-qualified module name, as for find_pxd_file().
289 return self.search_include_directories(qualified_name, ".pyx", pos)
291 def find_include_file(self, filename, pos):
292 # Search list of include directories for filename.
293 # Reports an error and returns None if not found.
294 path = self.search_include_directories(filename, "", pos,
295 include=True)
296 if not path:
297 error(pos, "'%s' not found" % filename)
298 return path
300 def search_include_directories(self, qualified_name, suffix, pos,
301 include=False):
302 # Search the list of include directories for the given
303 # file name. If a source file position is given, first
304 # searches the directory containing that file. Returns
305 # None if not found, but does not report an error.
306 # The 'include' option will disable package dereferencing.
307 dirs = self.include_directories
308 if pos:
309 file_desc = pos[0]
310 if not isinstance(file_desc, FileSourceDescriptor):
311 raise RuntimeError("Only file sources for code supported")
312 if include:
313 dirs = [os.path.dirname(file_desc.filename)] + dirs
314 else:
315 dirs = [self.find_root_package_dir(file_desc.filename)] + dirs
317 dotted_filename = qualified_name + suffix
318 if not include:
319 names = qualified_name.split('.')
320 package_names = names[:-1]
321 module_name = names[-1]
322 module_filename = module_name + suffix
323 package_filename = "__init__" + suffix
325 for dir in dirs:
326 path = os.path.join(dir, dotted_filename)
327 if os.path.exists(path):
328 return path
329 if not include:
330 package_dir = self.check_package_dir(dir, package_names)
331 if package_dir is not None:
332 path = os.path.join(package_dir, module_filename)
333 if os.path.exists(path):
334 return path
335 path = os.path.join(dir, package_dir, module_name,
336 package_filename)
337 if os.path.exists(path):
338 return path
339 return None
341 def find_root_package_dir(self, file_path):
342 dir = os.path.dirname(file_path)
343 while self.is_package_dir(dir):
344 parent = os.path.dirname(dir)
345 if parent == dir:
346 break
347 dir = parent
348 return dir
350 def is_package_dir(self, dir):
351 package_init = os.path.join(dir, "__init__.py")
352 return os.path.exists(package_init) or \
353 os.path.exists(package_init + "x") # same with .pyx
355 def check_package_dir(self, dir, package_names):
356 package_dir = os.path.join(dir, *package_names)
357 if not os.path.exists(package_dir):
358 return None
359 for dirname in package_names:
360 dir = os.path.join(dir, dirname)
361 if not self.is_package_dir(dir):
362 return None
363 return package_dir
365 def c_file_out_of_date(self, source_path):
366 c_path = Utils.replace_suffix(source_path, ".c")
367 if not os.path.exists(c_path):
368 return 1
369 c_time = Utils.modification_time(c_path)
370 if Utils.file_newer_than(source_path, c_time):
371 return 1
372 pos = [source_path]
373 pxd_path = Utils.replace_suffix(source_path, ".pxd")
374 if os.path.exists(pxd_path) and Utils.file_newer_than(pxd_path, c_time):
375 return 1
376 for kind, name in self.read_dependency_file(source_path):
377 if kind == "cimport":
378 dep_path = self.find_pxd_file(name, pos)
379 elif kind == "include":
380 dep_path = self.search_include_directories(name, pos)
381 else:
382 continue
383 if dep_path and Utils.file_newer_than(dep_path, c_time):
384 return 1
385 return 0
387 def find_cimported_module_names(self, source_path):
388 return [ name for kind, name in self.read_dependency_file(source_path)
389 if kind == "cimport" ]
391 def is_package_dir(self, dir_path):
392 # Return true if the given directory is a package directory.
393 for filename in ("__init__.py", "__init__.pyx"):
394 path = os.path.join(dir_path, filename)
395 if os.path.exists(path):
396 return 1
398 def read_dependency_file(self, source_path):
399 dep_path = Utils.replace_suffix(source_path, ".dep")
400 if os.path.exists(dep_path):
401 f = open(dep_path, "rU")
402 chunks = [ line.strip().split(" ", 1)
403 for line in f.readlines()
404 if " " in line.strip() ]
405 f.close()
406 return chunks
407 else:
408 return ()
410 def lookup_submodule(self, name):
411 # Look up a top-level module. Returns None if not found.
412 return self.modules.get(name, None)
414 def find_submodule(self, name):
415 # Find a top-level module, creating a new one if needed.
416 scope = self.lookup_submodule(name)
417 if not scope:
418 scope = ModuleScope(name,
419 parent_module = None, context = self)
420 self.modules[name] = scope
421 return scope
423 def parse(self, source_desc, scope, pxd, full_module_name):
424 if not isinstance(source_desc, FileSourceDescriptor):
425 raise RuntimeError("Only file sources for code supported")
426 source_filename = Utils.encode_filename(source_desc.filename)
427 # Parse the given source file and return a parse tree.
428 try:
429 f = Utils.open_source_file(source_filename, "rU")
430 try:
431 s = PyrexScanner(f, source_desc, source_encoding = f.encoding,
432 scope = scope, context = self)
433 tree = Parsing.p_module(s, pxd, full_module_name)
434 finally:
435 f.close()
436 except UnicodeDecodeError, msg:
437 #import traceback
438 #traceback.print_exc()
439 error((source_desc, 0, 0), "Decoding error, missing or incorrect coding=<encoding-name> at top of source (%s)" % msg)
440 if Errors.num_errors > 0:
441 raise CompileError
442 return tree
444 def extract_module_name(self, path, options):
445 # Find fully_qualified module name from the full pathname
446 # of a source file.
447 dir, filename = os.path.split(path)
448 module_name, _ = os.path.splitext(filename)
449 if "." in module_name:
450 return module_name
451 if module_name == "__init__":
452 dir, module_name = os.path.split(dir)
453 names = [module_name]
454 while self.is_package_dir(dir):
455 parent, package_name = os.path.split(dir)
456 if parent == dir:
457 break
458 names.append(package_name)
459 dir = parent
460 names.reverse()
461 return ".".join(names)
463 def setup_errors(self, options):
464 if options.use_listing_file:
465 result.listing_file = Utils.replace_suffix(source, ".lis")
466 Errors.open_listing_file(result.listing_file,
467 echo_to_stderr = options.errors_to_stderr)
468 else:
469 Errors.open_listing_file(None)
471 def teardown_errors(self, err, options, result):
472 source_desc = result.compilation_source.source_desc
473 if not isinstance(source_desc, FileSourceDescriptor):
474 raise RuntimeError("Only file sources for code supported")
475 Errors.close_listing_file()
476 result.num_errors = Errors.num_errors
477 if result.num_errors > 0:
478 err = True
479 if err and result.c_file:
480 try:
481 Utils.castrate_file(result.c_file, os.stat(source_desc.filename))
482 except EnvironmentError:
483 pass
484 result.c_file = None
485 if result.c_file and not options.c_only and c_compile:
486 result.object_file = c_compile(result.c_file,
487 verbose_flag = options.show_version,
488 cplus = options.cplus)
489 if not options.obj_only and c_link:
490 result.extension_file = c_link(result.object_file,
491 extra_objects = options.objects,
492 verbose_flag = options.show_version,
493 cplus = options.cplus)
495 def create_parse(context):
496 def parse(compsrc):
497 source_desc = compsrc.source_desc
498 full_module_name = compsrc.full_module_name
499 initial_pos = (source_desc, 1, 0)
500 scope = context.find_module(full_module_name, pos = initial_pos, need_pxd = 0)
501 tree = context.parse(source_desc, scope, pxd = 0, full_module_name = full_module_name)
502 tree.compilation_source = compsrc
503 tree.scope = scope
504 tree.is_pxd = False
505 return tree
506 return parse
508 def create_default_resultobj(compilation_source, options):
509 result = CompilationResult()
510 result.main_source_file = compilation_source.source_desc.filename
511 result.compilation_source = compilation_source
512 source_desc = compilation_source.source_desc
513 if options.output_file:
514 result.c_file = os.path.join(compilation_source.cwd, options.output_file)
515 else:
516 if options.cplus:
517 c_suffix = ".cpp"
518 else:
519 c_suffix = ".c"
520 result.c_file = Utils.replace_suffix(source_desc.filename, c_suffix)
521 return result
523 def run_pipeline(source, options, full_module_name = None):
524 # Set up context
525 context = Context(options.include_path, options.pragma_overrides)
527 # Set up source object
528 cwd = os.getcwd()
529 source_desc = FileSourceDescriptor(os.path.join(cwd, source))
530 full_module_name = full_module_name or context.extract_module_name(source, options)
531 source = CompilationSource(source_desc, full_module_name, cwd)
533 # Set up result object
534 result = create_default_resultobj(source, options)
536 # Get pipeline
537 if source_desc.filename.endswith(".py"):
538 pipeline = context.create_py_pipeline(options, result)
539 else:
540 pipeline = context.create_pyx_pipeline(options, result)
542 context.setup_errors(options)
543 err, enddata = context.run_pipeline(pipeline, source)
544 context.teardown_errors(err, options, result)
545 return result
547 #------------------------------------------------------------------------
548 #
549 # Main Python entry points
550 #
551 #------------------------------------------------------------------------
553 class CompilationSource(object):
554 """
555 Contains the data necesarry to start up a compilation pipeline for
556 a single compilation unit.
557 """
558 def __init__(self, source_desc, full_module_name, cwd):
559 self.source_desc = source_desc
560 self.full_module_name = full_module_name
561 self.cwd = cwd
563 class CompilationOptions(object):
564 """
565 Options to the Cython compiler:
567 show_version boolean Display version number
568 use_listing_file boolean Generate a .lis file
569 errors_to_stderr boolean Echo errors to stderr when using .lis
570 include_path [string] Directories to search for include files
571 output_file string Name of generated .c file
572 generate_pxi boolean Generate .pxi file for public declarations
573 recursive boolean Recursively find and compile dependencies
574 timestamps boolean Only compile changed source files. If None,
575 defaults to true when recursive is true.
576 verbose boolean Always print source names being compiled
577 quiet boolean Don't print source names in recursive mode
578 pragma_overrides dict Overrides for pragma options (see Options.py)
580 Following options are experimental and only used on MacOSX:
582 c_only boolean Stop after generating C file (default)
583 obj_only boolean Stop after compiling to .o file
584 objects [string] Extra .o files to link with
585 cplus boolean Compile as c++ code
586 """
588 def __init__(self, defaults = None, c_compile = 0, c_link = 0, **kw):
589 self.include_path = []
590 self.objects = []
591 if defaults:
592 if isinstance(defaults, CompilationOptions):
593 defaults = defaults.__dict__
594 else:
595 defaults = default_options
596 self.__dict__.update(defaults)
597 self.__dict__.update(kw)
598 if c_compile:
599 self.c_only = 0
600 if c_link:
601 self.obj_only = 0
604 class CompilationResult(object):
605 """
606 Results from the Cython compiler:
608 c_file string or None The generated C source file
609 h_file string or None The generated C header file
610 i_file string or None The generated .pxi file
611 api_file string or None The generated C API .h file
612 listing_file string or None File of error messages
613 object_file string or None Result of compiling the C file
614 extension_file string or None Result of linking the object file
615 num_errors integer Number of compilation errors
616 compilation_source CompilationSource
617 """
619 def __init__(self):
620 self.c_file = None
621 self.h_file = None
622 self.i_file = None
623 self.api_file = None
624 self.listing_file = None
625 self.object_file = None
626 self.extension_file = None
627 self.main_source_file = None
630 class CompilationResultSet(dict):
631 """
632 Results from compiling multiple Pyrex source files. A mapping
633 from source file paths to CompilationResult instances. Also
634 has the following attributes:
636 num_errors integer Total number of compilation errors
637 """
639 num_errors = 0
641 def add(self, source, result):
642 self[source] = result
643 self.num_errors += result.num_errors
646 def compile_single(source, options, full_module_name = None):
647 """
648 compile_single(source, options, full_module_name)
650 Compile the given Pyrex implementation file and return a CompilationResult.
651 Always compiles a single file; does not perform timestamp checking or
652 recursion.
653 """
654 return run_pipeline(source, options, full_module_name)
657 def compile_multiple(sources, options):
658 """
659 compile_multiple(sources, options)
661 Compiles the given sequence of Pyrex implementation files and returns
662 a CompilationResultSet. Performs timestamp checking and/or recursion
663 if these are specified in the options.
664 """
665 sources = [os.path.abspath(source) for source in sources]
666 processed = set()
667 results = CompilationResultSet()
668 recursive = options.recursive
669 timestamps = options.timestamps
670 if timestamps is None:
671 timestamps = recursive
672 verbose = options.verbose or ((recursive or timestamps) and not options.quiet)
673 for source in sources:
674 if source not in processed:
675 # Compiling multiple sources in one context doesn't quite
676 # work properly yet.
677 if not timestamps or context.c_file_out_of_date(source):
678 if verbose:
679 sys.stderr.write("Compiling %s\n" % source)
681 result = run_pipeline(source, options)
682 results.add(source, result)
683 processed.add(source)
684 if recursive:
685 for module_name in context.find_cimported_module_names(source):
686 path = context.find_pyx_file(module_name, [source])
687 if path:
688 sources.append(path)
689 else:
690 sys.stderr.write(
691 "Cannot find .pyx file for cimported module '%s'\n" % module_name)
692 return results
694 def compile(source, options = None, c_compile = 0, c_link = 0,
695 full_module_name = None, **kwds):
696 """
697 compile(source [, options], [, <option> = <value>]...)
699 Compile one or more Pyrex implementation files, with optional timestamp
700 checking and recursing on dependecies. The source argument may be a string
701 or a sequence of strings If it is a string and no recursion or timestamp
702 checking is requested, a CompilationResult is returned, otherwise a
703 CompilationResultSet is returned.
704 """
705 options = CompilationOptions(defaults = options, c_compile = c_compile,
706 c_link = c_link, **kwds)
707 if isinstance(source, basestring) and not options.timestamps \
708 and not options.recursive:
709 return compile_single(source, options, full_module_name)
710 else:
711 return compile_multiple(source, options)
713 #------------------------------------------------------------------------
714 #
715 # Main command-line entry point
716 #
717 #------------------------------------------------------------------------
719 def main(command_line = 0):
720 args = sys.argv[1:]
721 any_failures = 0
722 if command_line:
723 from CmdLine import parse_command_line
724 options, sources = parse_command_line(args)
725 else:
726 options = CompilationOptions(default_options)
727 sources = args
729 if options.show_version:
730 sys.stderr.write("Cython version %s\n" % Version.version)
731 if options.working_path!="":
732 os.chdir(options.working_path)
733 try:
734 result = compile(sources, options)
735 if result.num_errors > 0:
736 any_failures = 1
737 except (EnvironmentError, PyrexError), e:
738 sys.stderr.write(str(e) + '\n')
739 any_failures = 1
740 if any_failures:
741 sys.exit(1)
745 #------------------------------------------------------------------------
746 #
747 # Set the default options depending on the platform
748 #
749 #------------------------------------------------------------------------
751 default_options = dict(
752 show_version = 0,
753 use_listing_file = 0,
754 errors_to_stderr = 1,
755 c_only = 1,
756 obj_only = 1,
757 cplus = 0,
758 output_file = None,
759 annotate = False,
760 generate_pxi = 0,
761 working_path = "",
762 recursive = 0,
763 timestamps = None,
764 verbose = 0,
765 quiet = 0,
766 pragma_overrides = {},
767 emit_linenums = False,
768 )
769 if sys.platform == "mac":
770 from Cython.Mac.MacSystem import c_compile, c_link, CCompilerError
771 default_options['use_listing_file'] = 1
772 elif sys.platform == "darwin":
773 from Cython.Mac.DarwinSystem import c_compile, c_link, CCompilerError
774 else:
775 c_compile = None
776 c_link = None
