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