cython

Форк
0
/
BuildExecutable.py 
169 строк · 4.6 Кб
1
"""
2
Compile a Python script into an executable that embeds CPython.
3
Requires CPython to be built as a shared library ('libpythonX.Y').
4

5
Basic usage:
6

7
    python -m Cython.Build.BuildExecutable [ARGS] somefile.py
8
"""
9

10

11
DEBUG = True
12

13
import sys
14
import os
15
if sys.version_info < (3, 9):
16
    from distutils import sysconfig as _sysconfig
17

18
    class sysconfig:
19

20
        @staticmethod
21
        def get_path(name):
22
            assert name == 'include'
23
            return _sysconfig.get_python_inc()
24

25
        get_config_var = staticmethod(_sysconfig.get_config_var)
26
else:
27
    # sysconfig can be trusted from cpython >= 3.8.7
28
    import sysconfig
29

30

31
def get_config_var(name, default=''):
32
    return sysconfig.get_config_var(name) or default
33

34
INCDIR = sysconfig.get_path('include')
35
LIBDIR1 = get_config_var('LIBDIR')
36
LIBDIR2 = get_config_var('LIBPL')
37
PYLIB = get_config_var('LIBRARY')
38
PYLIB_DYN = get_config_var('LDLIBRARY')
39
if PYLIB_DYN == PYLIB:
40
    # no shared library
41
    PYLIB_DYN = ''
42
else:
43
    PYLIB_DYN = os.path.splitext(PYLIB_DYN[3:])[0]  # 'lib(XYZ).so' -> XYZ
44

45
CC = get_config_var('CC', os.environ.get('CC', ''))
46
CFLAGS = get_config_var('CFLAGS') + ' ' + os.environ.get('CFLAGS', '')
47
LINKCC = get_config_var('LINKCC', os.environ.get('LINKCC', CC))
48
LINKFORSHARED = get_config_var('LINKFORSHARED')
49
LIBS = get_config_var('LIBS')
50
SYSLIBS = get_config_var('SYSLIBS')
51
EXE_EXT = sysconfig.get_config_var('EXE')
52

53

54
def _debug(msg, *args):
55
    if DEBUG:
56
        if args:
57
            msg = msg % args
58
        sys.stderr.write(msg + '\n')
59

60

61
def dump_config():
62
    _debug('INCDIR: %s', INCDIR)
63
    _debug('LIBDIR1: %s', LIBDIR1)
64
    _debug('LIBDIR2: %s', LIBDIR2)
65
    _debug('PYLIB: %s', PYLIB)
66
    _debug('PYLIB_DYN: %s', PYLIB_DYN)
67
    _debug('CC: %s', CC)
68
    _debug('CFLAGS: %s', CFLAGS)
69
    _debug('LINKCC: %s', LINKCC)
70
    _debug('LINKFORSHARED: %s', LINKFORSHARED)
71
    _debug('LIBS: %s', LIBS)
72
    _debug('SYSLIBS: %s', SYSLIBS)
73
    _debug('EXE_EXT: %s', EXE_EXT)
74

75

76
def _parse_args(args):
77
    cy_args = []
78
    last_arg = None
79
    for i, arg in enumerate(args):
80
        if arg.startswith('-'):
81
            cy_args.append(arg)
82
        elif last_arg in ('-X', '--directive'):
83
            cy_args.append(arg)
84
        else:
85
            input_file = arg
86
            args = args[i+1:]
87
            break
88
        last_arg = arg
89
    else:
90
        raise ValueError('no input file provided')
91

92
    return input_file, cy_args, args
93

94

95
def runcmd(cmd, shell=True):
96
    if shell:
97
        cmd = ' '.join(cmd)
98
        _debug(cmd)
99
    else:
100
        _debug(' '.join(cmd))
101

102
    import subprocess
103
    returncode = subprocess.call(cmd, shell=shell)
104

105
    if returncode:
106
        sys.exit(returncode)
107

108

109
def clink(basename):
110
    runcmd([LINKCC, '-o', basename + EXE_EXT, basename+'.o', '-L'+LIBDIR1, '-L'+LIBDIR2]
111
           + [PYLIB_DYN and ('-l'+PYLIB_DYN) or os.path.join(LIBDIR1, PYLIB)]
112
           + LIBS.split() + SYSLIBS.split() + LINKFORSHARED.split())
113

114

115
def ccompile(basename):
116
    runcmd([CC, '-c', '-o', basename+'.o', basename+'.c', '-I' + INCDIR] + CFLAGS.split())
117

118

119
def cycompile(input_file, options=()):
120
    from ..Compiler import Version, CmdLine, Main
121
    options, sources = CmdLine.parse_command_line(list(options or ()) + ['--embed', input_file])
122
    _debug('Using Cython %s to compile %s', Version.version, input_file)
123
    result = Main.compile(sources, options)
124
    if result.num_errors > 0:
125
        sys.exit(1)
126

127

128
def exec_file(program_name, args=()):
129
    runcmd([os.path.abspath(program_name)] + list(args), shell=False)
130

131

132
def build(input_file, compiler_args=(), force=False):
133
    """
134
    Build an executable program from a Cython module.
135

136
    Returns the name of the executable file.
137
    """
138
    basename = os.path.splitext(input_file)[0]
139
    exe_file = basename + EXE_EXT
140
    if not force and os.path.abspath(exe_file) == os.path.abspath(input_file):
141
        raise ValueError("Input and output file names are the same, refusing to overwrite")
142
    if (not force and os.path.exists(exe_file) and os.path.exists(input_file)
143
            and os.path.getmtime(input_file) <= os.path.getmtime(exe_file)):
144
        _debug("File is up to date, not regenerating %s", exe_file)
145
        return exe_file
146
    cycompile(input_file, compiler_args)
147
    ccompile(basename)
148
    clink(basename)
149
    return exe_file
150

151

152
def build_and_run(args):
153
    """
154
    Build an executable program from a Cython module and run it.
155

156
    Arguments after the module name will be passed verbatimly to the program.
157
    """
158
    program_name, args = _build(args)
159
    exec_file(program_name, args)
160

161

162
def _build(args):
163
    input_file, cy_args, args = _parse_args(args)
164
    program_name = build(input_file, cy_args)
165
    return program_name, args
166

167

168
if __name__ == '__main__':
169
    _build(sys.argv[1:])
170

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.