1#
2#   Cython - Command Line Parsing
3#
4
5from __future__ import absolute_import
6
7import os
8import sys
9from . import Options
10
11usage = """\
12Cython (http://cython.org) is a compiler for code written in the
13Cython language.  Cython is based on Pyrex by Greg Ewing.
14
15Usage: cython [options] sourcefile.{pyx,py} ...
16
17Options:
18  -V, --version                  Display version number of cython compiler
19  -l, --create-listing           Write error messages to a listing file
20  -I, --include-dir <directory>  Search for include files in named directory
21                                 (multiple include directories are allowed).
22  -o, --output-file <filename>   Specify name of generated C file
23  -t, --timestamps               Only compile newer source files
24  -f, --force                    Compile all source files (overrides implied -t)
25  -v, --verbose                  Be verbose, print file names on multiple compilation
26  -p, --embed-positions          If specified, the positions in Cython files of each
27                                 function definition is embedded in its docstring.
28  --cleanup <level>              Release interned objects on python exit, for memory debugging.
29                                 Level indicates aggressiveness, default 0 releases nothing.
30  -w, --working <directory>      Sets the working directory for Cython (the directory modules
31                                 are searched from)
32  --gdb                          Output debug information for cygdb
33  --gdb-outdir <directory>       Specify gdb debug information output directory. Implies --gdb.
34
35  -D, --no-docstrings            Strip docstrings from the compiled module.
36  -a, --annotate                 Produce a colorized HTML version of the source.
37  --annotate-coverage <cov.xml>  Annotate and include coverage information from cov.xml.
38  --line-directives              Produce #line directives pointing to the .pyx source
39  --cplus                        Output a C++ rather than C file.
40  --embed[=<method_name>]        Generate a main() function that embeds the Python interpreter.
41  -2                             Compile based on Python-2 syntax and code semantics.
42  -3                             Compile based on Python-3 syntax and code semantics.
43  --3str                         Compile based on Python-3 syntax and code semantics without
44                                 assuming unicode by default for string literals under Python 2.
45  --lenient                      Change some compile time errors to runtime errors to
46                                 improve Python compatibility
47  --capi-reexport-cincludes      Add cincluded headers to any auto-generated header files.
48  --fast-fail                    Abort the compilation on the first error
49  --warning-errors, -Werror      Make all warnings into errors
50  --warning-extra, -Wextra       Enable extra warnings
51  -X, --directive <name>=<value>[,<name=value,...] Overrides a compiler directive
52  -E, --compile-time-env name=value[,<name=value,...] Provides compile time env like DEF would do.
53"""
54
55
56# The following experimental options are supported only on MacOSX:
57#  -C, --compile    Compile generated .c file to .o file
58#  --link           Link .o file to produce extension module (implies -C)
59#  -+, --cplus      Use C++ compiler for compiling and linking
60#  Additional .o files to link may be supplied when using -X."""
61
62def bad_usage():
63    sys.stderr.write(usage)
64    sys.exit(1)
65
66
67def parse_command_line(args):
68    from .Main import CompilationOptions, default_options
69
70    pending_arg = []
71
72    def pop_arg():
73        if not args or pending_arg:
74            bad_usage()
75        if '=' in args[0] and args[0].startswith('--'):  # allow "--long-option=xyz"
76            name, value = args.pop(0).split('=', 1)
77            pending_arg.append(value)
78            return name
79        return args.pop(0)
80
81    def pop_value(default=None):
82        if pending_arg:
83            return pending_arg.pop()
84        elif default is not None:
85            return default
86        elif not args:
87            bad_usage()
88        return args.pop(0)
89
90    def get_param(option):
91        tail = option[2:]
92        if tail:
93            return tail
94        else:
95            return pop_arg()
96
97    options = CompilationOptions(default_options)
98    sources = []
99    while args:
100        if args[0].startswith("-"):
101            option = pop_arg()
102            if option in ("-V", "--version"):
103                options.show_version = 1
104            elif option in ("-l", "--create-listing"):
105                options.use_listing_file = 1
106            elif option in ("-+", "--cplus"):
107                options.cplus = 1
108            elif option == "--embed":
109                Options.embed = pop_value("main")
110            elif option.startswith("-I"):
111                options.include_path.append(get_param(option))
112            elif option == "--include-dir":
113                options.include_path.append(pop_value())
114            elif option in ("-w", "--working"):
115                options.working_path = pop_value()
116            elif option in ("-o", "--output-file"):
117                options.output_file = pop_value()
118            elif option in ("-t", "--timestamps"):
119                options.timestamps = 1
120            elif option in ("-f", "--force"):
121                options.timestamps = 0
122            elif option in ("-v", "--verbose"):
123                options.verbose += 1
124            elif option in ("-p", "--embed-positions"):
125                Options.embed_pos_in_docstring = 1
126            elif option in ("-z", "--pre-import"):
127                Options.pre_import = pop_value()
128            elif option == "--cleanup":
129                Options.generate_cleanup_code = int(pop_value())
130            elif option in ("-D", "--no-docstrings"):
131                Options.docstrings = False
132            elif option in ("-a", "--annotate"):
133                Options.annotate = True
134            elif option == "--annotate-coverage":
135                Options.annotate = True
136                Options.annotate_coverage_xml = pop_value()
137            elif option == "--convert-range":
138                Options.convert_range = True
139            elif option == "--line-directives":
140                options.emit_linenums = True
141            elif option == "--no-c-in-traceback":
142                options.c_line_in_traceback = False
143            elif option == "--gdb":
144                options.gdb_debug = True
145                options.output_dir = os.curdir
146            elif option == "--gdb-outdir":
147                options.gdb_debug = True
148                options.output_dir = pop_value()
149            elif option == "--lenient":
150                Options.error_on_unknown_names = False
151                Options.error_on_uninitialized = False
152            elif option == '-2':
153                options.language_level = 2
154            elif option == '-3':
155                options.language_level = 3
156            elif option == '--3str':
157                options.language_level = '3str'
158            elif option == "--capi-reexport-cincludes":
159                options.capi_reexport_cincludes = True
160            elif option == "--fast-fail":
161                Options.fast_fail = True
162            elif option == "--cimport-from-pyx":
163                Options.cimport_from_pyx = True
164            elif option in ('-Werror', '--warning-errors'):
165                Options.warning_errors = True
166            elif option in ('-Wextra', '--warning-extra'):
167                options.compiler_directives.update(Options.extra_warnings)
168            elif option == "--old-style-globals":
169                Options.old_style_globals = True
170            elif option == "--directive" or option.startswith('-X'):
171                if option.startswith('-X') and option[2:].strip():
172                    x_args = option[2:]
173                else:
174                    x_args = pop_value()
175                try:
176                    options.compiler_directives = Options.parse_directive_list(
177                        x_args, relaxed_bool=True,
178                        current_settings=options.compiler_directives)
179                except ValueError as e:
180                    sys.stderr.write("Error in compiler directive: %s\n" % e.args[0])
181                    sys.exit(1)
182            elif option == "--compile-time-env" or option.startswith('-E'):
183                if option.startswith('-E') and option[2:].strip():
184                    x_args = option[2:]
185                else:
186                    x_args = pop_value()
187                try:
188                    options.compile_time_env = Options.parse_compile_time_env(
189                        x_args, current_settings=options.compile_time_env)
190                except ValueError as e:
191                    sys.stderr.write("Error in compile-time-env: %s\n" % e.args[0])
192                    sys.exit(1)
193            elif option.startswith('--debug'):
194                option = option[2:].replace('-', '_')
195                from . import DebugFlags
196                if option in dir(DebugFlags):
197                    setattr(DebugFlags, option, True)
198                else:
199                    sys.stderr.write("Unknown debug flag: %s\n" % option)
200                    bad_usage()
201            elif option in ('-h', '--help'):
202                sys.stdout.write(usage)
203                sys.exit(0)
204            else:
205                sys.stderr.write("Unknown compiler flag: %s\n" % option)
206                sys.exit(1)
207        else:
208            sources.append(pop_arg())
209
210    if pending_arg:
211        bad_usage()
212
213    if options.use_listing_file and len(sources) > 1:
214        sys.stderr.write(
215            "cython: Only one source file allowed when using -o\n")
216        sys.exit(1)
217    if len(sources) == 0 and not options.show_version:
218        bad_usage()
219    if Options.embed and len(sources) > 1:
220        sys.stderr.write(
221            "cython: Only one source file allowed when using -embed\n")
222        sys.exit(1)
223    return options, sources
224
225