First, add LLD as a dependency on Windows. The windows batch scripts pass -fuse-ld=lld, so they need it. Second, decode builder stdout/stderr even if the command fails. Otherwise it gets printed as b'line 1\n\rline 2\n\r'. Last, make the batch script one line less noisy. We might want to try to do more here, though. It would be nice if we could get as close to possible as lit, where you can literally copy & paste the failing command to re-run it. With the two changes above, now the feature tests that use clang++.bat pass for me. The clang-cl_vs2015 ones still fail, and I'll fix them separately. Reviewers: jmorse Differential Revision: https://reviews.llvm.org/D69725
120 lines
4.2 KiB
Python
120 lines
4.2 KiB
Python
# 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'
|