Builder.py
4.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# DExTer : Debugging Experience Tester
# ~~~~~~ ~ ~~ ~ ~~
#
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
"""Deals with the processing execution of shell or batch build scripts."""
import os
import subprocess
import unittest
from dex.dextIR import BuilderIR
from dex.utils import Timer
from dex.utils.Exceptions import BuildScriptException
def _quotify(text):
if '"' in text or ' ' not in text:
return text
return '"{}"'.format(text)
def _get_script_environment(source_files, compiler_options,
linker_options, executable_file):
source_files = [_quotify(f) for f in source_files]
object_files = [
_quotify('{}.o'.format(os.path.basename(f))) for f in source_files
]
source_indexes = ['{:02d}'.format(i + 1) for i in range(len(source_files))]
env_variables = {}
env_variables['SOURCE_INDEXES'] = ' '.join(source_indexes)
env_variables['SOURCE_FILES'] = ' '.join(source_files)
env_variables['OBJECT_FILES'] = ' '.join(object_files)
env_variables['LINKER_OPTIONS'] = linker_options
for i, _ in enumerate(source_files):
index = source_indexes[i]
env_variables['SOURCE_FILE_{}'.format(index)] = source_files[i]
env_variables['OBJECT_FILE_{}'.format(index)] = object_files[i]
env_variables['COMPILER_OPTIONS_{}'.format(index)] = compiler_options[i]
env_variables['EXECUTABLE_FILE'] = executable_file
return env_variables
def run_external_build_script(context, script_path, source_files,
compiler_options, linker_options,
executable_file):
"""Build an executable using a builder script.
The executable is saved to `context.working_directory.path`.
Returns:
( stdout (str), stderr (str), builder (BuilderIR) )
"""
builderIR = BuilderIR(
name=context.options.builder,
cflags=compiler_options,
ldflags=linker_options,
)
assert len(source_files) == len(compiler_options), (source_files,
compiler_options)
script_environ = _get_script_environment(source_files, compiler_options,
linker_options, executable_file)
env = dict(os.environ)
env.update(script_environ)
try:
with Timer('running build script'):
process = subprocess.Popen(
[script_path],
cwd=context.working_directory.path,
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out, err = process.communicate()
returncode = process.returncode
out = out.decode('utf-8')
err = err.decode('utf-8')
if returncode != 0:
raise BuildScriptException(
'{}: failed with returncode {}.\nstdout:\n{}\n\nstderr:\n{}\n'.
format(script_path, returncode, out, err),
script_error=err)
return out, err, builderIR
except OSError as e:
raise BuildScriptException('{}: {}'.format(e.strerror, script_path))
class TestBuilder(unittest.TestCase):
def test_get_script_environment(self):
source_files = ['a.a', 'b.b']
compiler_options = ['-option1 value1', '-option2 value2']
linker_options = '-optionX valueX'
executable_file = 'exe.exe'
env = _get_script_environment(source_files, compiler_options,
linker_options, executable_file)
assert env['SOURCE_FILES'] == 'a.a b.b'
assert env['OBJECT_FILES'] == 'a.a.o b.b.o'
assert env['SOURCE_INDEXES'] == '01 02'
assert env['LINKER_OPTIONS'] == '-optionX valueX'
assert env['SOURCE_FILE_01'] == 'a.a'
assert env['SOURCE_FILE_02'] == 'b.b'
assert env['OBJECT_FILE_01'] == 'a.a.o'
assert env['OBJECT_FILE_02'] == 'b.b.o'
assert env['EXECUTABLE_FILE'] == 'exe.exe'
assert env['COMPILER_OPTIONS_01'] == '-option1 value1'
assert env['COMPILER_OPTIONS_02'] == '-option2 value2'