forked from OSchip/llvm-project
[lit] Add a generic build script with a lit substitution.
This adds a script called build.py as well as a lit substitution called %build that we can use to invoke it. The idea is that this allows a lit test to build test inferiors without having to worry about architecture / platform specific differences, command line syntax, finding / configurationg a proper toolchain, and other issues. They can simply write something like: %build --arch=32 -o %t.exe %p/Inputs/foo.cpp and it will just work. This paves the way for being able to run lit tests with multiple configurations, platforms, and compilers with a single test. Differential Revision: https://reviews.llvm.org/D54914 llvm-svn: 348058
This commit is contained in:
parent
e5664b1559
commit
ba968c0d1d
|
@ -2,8 +2,7 @@
|
|||
// REQUIRES: lld
|
||||
|
||||
// Test various interesting cases for AST reconstruction.
|
||||
// RUN: %clang_cl /Z7 /GS- /GR- /c /Fo%t.obj -- %s
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
|
||||
// RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/ast-reconstruction.lldbinit 2>&1 | FileCheck %s
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
// REQUIRES: lld
|
||||
|
||||
// Test various interesting cases for AST reconstruction.
|
||||
// RUN: %clang_cl /Z7 /GS- /GR- /std:c++latest -Xclang -fkeep-static-consts /c /Fo%t.obj -- %s
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
|
||||
// RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/bitfields.lldbinit 2>&1 | FileCheck %s
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
// REQUIRES: lld
|
||||
|
||||
// Test that we can show disassembly and source.
|
||||
// RUN: %clang_cl -m64 /Z7 /GS- /GR- /c /Fo%t.obj -- %s
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
|
||||
// RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/disassembly.lldbinit | FileCheck %s
|
||||
|
||||
|
@ -19,21 +18,21 @@ int main(int argc, char **argv) {
|
|||
|
||||
|
||||
// CHECK: (lldb) disassemble --flavor=intel -m -n main
|
||||
// CHECK: 13 int foo() { return 42; }
|
||||
// CHECK-NEXT: 14
|
||||
// CHECK-NEXT: ** 15 int main(int argc, char **argv) {
|
||||
// CHECK: 12 int foo() { return 42; }
|
||||
// CHECK-NEXT: 13
|
||||
// CHECK-NEXT: ** 14 int main(int argc, char **argv) {
|
||||
// CHECK: disassembly.cpp.tmp.exe`main:
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+0>: sub rsp, 0x38
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+4>: mov dword ptr [rsp + 0x34], 0x0
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+12>: mov qword ptr [rsp + 0x28], rdx
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+17>: mov dword ptr [rsp + 0x24], ecx
|
||||
// CHECK: ** 16 foo();
|
||||
// CHECK: disassembly.cpp.tmp.exe[{{.*}}] <+21>: call {{.*}} ; foo at disassembly.cpp:13
|
||||
// CHECK: ** 15 foo();
|
||||
// CHECK: disassembly.cpp.tmp.exe[{{.*}}] <+21>: call {{.*}} ; foo at disassembly.cpp:12
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+26>: xor ecx, ecx
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+28>: mov dword ptr [rsp + 0x20], eax
|
||||
// CHECK: ** 17 return 0;
|
||||
// CHECK-NEXT: 18 }
|
||||
// CHECK-NEXT: 19
|
||||
// CHECK: ** 16 return 0;
|
||||
// CHECK-NEXT: 17 }
|
||||
// CHECK-NEXT: 18
|
||||
// CHECK: disassembly.cpp.tmp.exe[{{.*}}] <+32>: mov eax, ecx
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+34>: add rsp, 0x38
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+38>: ret
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
// clang-format off
|
||||
// REQUIRES: lld
|
||||
|
||||
// RUN: %clang_cl /Z7 /GS- /GR- /c -Xclang -fkeep-static-consts /Fo%t.obj -- %s
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
|
||||
// RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/function-types-builtins.lldbinit | FileCheck %s
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
// clang-format off
|
||||
// REQUIRES: lld
|
||||
|
||||
// RUN: %clang_cl -m32 /Z7 /GS- /GR- /c -Xclang -fkeep-static-consts /Fo%t.obj -- %s
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
|
||||
// RUN: %build --compiler=clang-cl --arch=32 --nodefaultlib -o %t.exe -- %s
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/function-types-calling-conv.lldbinit | FileCheck %s
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
// REQUIRES: lld
|
||||
|
||||
// Test that we can display function signatures with class types.
|
||||
// RUN: %clang_cl /Z7 /GS- /GR- /c -fstandalone-debug -Xclang -fkeep-static-consts /Fo%t.obj -- %s
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
|
||||
// RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/function-types-classes.lldbinit | FileCheck %s
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
// REQUIRES: lld
|
||||
|
||||
// Test that we can display tag types.
|
||||
// RUN: %clang_cl /Z7 /GS- /GR- /c -Xclang -fkeep-static-consts /Fo%t.obj -- %s
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
|
||||
// RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/globals-classes.lldbinit | FileCheck %s
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
// REQUIRES: lld
|
||||
|
||||
// Make sure we can read variables from BSS
|
||||
// RUN: %clang_cl /Z7 /GS- /GR- /c /Fo%t.obj -- %s
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
|
||||
// RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
|
||||
// RUN: llvm-readobj -s %t.exe | FileCheck --check-prefix=BSS %s
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/globals-bss.lldbinit 2>&1 | FileCheck %s
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
// REQUIRES: lld
|
||||
|
||||
// Test that we can display tag types.
|
||||
// RUN: %clang_cl /Z7 /GS- /GR- /c -Xclang -fkeep-static-consts /Fo%t.obj -- %s
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
|
||||
// RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/globals-fundamental.lldbinit | FileCheck %s
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
// REQUIRES: lld
|
||||
|
||||
// Test various interesting cases for AST reconstruction.
|
||||
// RUN: %clang_cl /Z7 /GS- /GR- -Xclang -fkeep-static-consts /c /Fo%t.obj -- %s
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
|
||||
// RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/nested-types.lldbinit 2>&1 | FileCheck %s
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// Test that we can display S_CONSTANT records.
|
||||
|
||||
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-win32 %p/Inputs/s_constant.s > %t.obj
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
|
||||
// RUN: %build --compiler=clang-cl --nodefaultlib --mode=link -o %t.exe -- %t.obj
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/s_constant.lldbinit | FileCheck %s
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
// REQUIRES: lld
|
||||
|
||||
// Test that we can set simple breakpoints using PDB on any platform.
|
||||
// RUN: %clang_cl /Z7 /GS- /GR- /c /Fo%t.obj -- %s
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
|
||||
// RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/breakpoints.lldbinit | FileCheck %s
|
||||
|
||||
|
@ -38,27 +37,27 @@ int main(int argc, char **argv) {
|
|||
// CHECK: Current executable set to '{{.*}}simple-breakpoints.cpp.tmp.exe'
|
||||
// CHECK: (lldb) break set -n main
|
||||
// CHECK: Breakpoint 1: where = simple-breakpoints.cpp.tmp.exe`main + {{[0-9]+}}
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:31
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:30
|
||||
// CHECK: (lldb) break set -n OvlGlobalFn
|
||||
// CHECK: Breakpoint 2: 3 locations.
|
||||
// CHECK: (lldb) break set -n StaticFn
|
||||
// CHECK: Breakpoint 3: where = simple-breakpoints.cpp.tmp.exe`StaticFn + {{[0-9]+}}
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:24
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:23
|
||||
// CHECK: (lldb) break set -n DoesntExist
|
||||
// CHECK: Breakpoint 4: no locations (pending).
|
||||
// CHECK: (lldb) break list
|
||||
// CHECK: Current breakpoints:
|
||||
// CHECK: 1: name = 'main', locations = 1
|
||||
// CHECK: 1.1: where = simple-breakpoints.cpp.tmp.exe`main + {{[0-9]+}}
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:31
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:30
|
||||
// CHECK: 2: name = 'OvlGlobalFn', locations = 3
|
||||
// CHECK: 2.1: where = simple-breakpoints.cpp.tmp.exe`OvlGlobalFn + {{[0-9]+}}
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:13
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:12
|
||||
// CHECK: 2.2: where = simple-breakpoints.cpp.tmp.exe`OvlGlobalFn
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:16
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:15
|
||||
// CHECK: 2.3: where = simple-breakpoints.cpp.tmp.exe`OvlGlobalFn + {{[0-9]+}}
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:20
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:19
|
||||
// CHECK: 3: name = 'StaticFn', locations = 1
|
||||
// CHECK: 3.1: where = simple-breakpoints.cpp.tmp.exe`StaticFn + {{[0-9]+}}
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:24
|
||||
// CHECK-SAME: at simple-breakpoints.cpp:23
|
||||
// CHECK: 4: name = 'DoesntExist', locations = 0 (pending)
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
// REQUIRES: lld
|
||||
|
||||
// Test that we can set display source of functions.
|
||||
// RUN: %clang_cl /Z7 /GS- /GR- /c /Fo%t.obj -- %s
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
|
||||
// RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/source-list.lldbinit | FileCheck %s
|
||||
|
||||
|
@ -27,17 +26,17 @@ int main(int argc, char **argv) {
|
|||
|
||||
// CHECK: (lldb) source list -n main
|
||||
// CHECK: File: {{.*}}source-list.cpp
|
||||
// CHECK: 11
|
||||
// CHECK: 12 // Some context lines before
|
||||
// CHECK: 13 // the function.
|
||||
// CHECK: 10
|
||||
// CHECK: 11 // Some context lines before
|
||||
// CHECK: 12 // the function.
|
||||
// CHECK: 13
|
||||
// CHECK: 14
|
||||
// CHECK: 15
|
||||
// CHECK: 16 int main(int argc, char **argv) {
|
||||
// CHECK: 17 // Here are some comments.
|
||||
// CHECK: 18 // That we should print when listing source.
|
||||
// CHECK: 19 return 0;
|
||||
// CHECK: 20 }
|
||||
// CHECK: 21
|
||||
// CHECK: 22 // Some context lines after
|
||||
// CHECK: 23 // the function.
|
||||
// CHECK: 24
|
||||
// CHECK: 15 int main(int argc, char **argv) {
|
||||
// CHECK: 16 // Here are some comments.
|
||||
// CHECK: 17 // That we should print when listing source.
|
||||
// CHECK: 18 return 0;
|
||||
// CHECK: 19 }
|
||||
// CHECK: 20
|
||||
// CHECK: 21 // Some context lines after
|
||||
// CHECK: 22 // the function.
|
||||
// CHECK: 23
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
// REQUIRES: lld
|
||||
|
||||
// Test that we can display tag types.
|
||||
// RUN: %clang_cl /Z7 /GS- /GR- /c /Fo%t.obj -- %s
|
||||
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
|
||||
// RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
|
||||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
|
||||
// RUN: %p/Inputs/tag-types.lldbinit | FileCheck %s
|
||||
|
||||
|
|
|
@ -0,0 +1,644 @@
|
|||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
if sys.platform == 'win32':
|
||||
# This module was renamed in Python 3. Make sure to import it using a
|
||||
# consistent name regardless of python version.
|
||||
try:
|
||||
import winreg
|
||||
except:
|
||||
import _winreg as winreg
|
||||
|
||||
if __name__ != "__main__":
|
||||
raise RuntimeError("Do not import this script, run it instead")
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(description='LLDB compilation wrapper')
|
||||
parser.add_argument('--arch',
|
||||
metavar='arch',
|
||||
dest='arch',
|
||||
required=True,
|
||||
help='Specify the architecture to target. Valid values=[32,64]')
|
||||
|
||||
parser.add_argument('--compiler',
|
||||
metavar='compiler',
|
||||
dest='compiler',
|
||||
required=True,
|
||||
help='Path to a compiler executable, or one of the values [any, msvc, clang-cl, gcc, clang]')
|
||||
|
||||
parser.add_argument('--tools-dir',
|
||||
metavar='directory',
|
||||
dest='tools_dir',
|
||||
required=False,
|
||||
action='append',
|
||||
help='If specified, a path to search in addition to PATH when --compiler is not an exact path')
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
parser.add_argument('--apple-sdk',
|
||||
metavar='apple_sdk',
|
||||
dest='apple_sdk',
|
||||
default="macosx",
|
||||
help='Specify the name of the Apple SDK (macosx, macosx.internal, iphoneos, iphoneos.internal, or path to SDK) and use the appropriate tools from that SDK\'s toolchain.')
|
||||
|
||||
parser.add_argument('--output', '-o',
|
||||
dest='output',
|
||||
metavar='file',
|
||||
required=True,
|
||||
help='Path to output file')
|
||||
|
||||
parser.add_argument('--nodefaultlib',
|
||||
dest='nodefaultlib',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='When specified, the resulting image should not link against system libraries or include system headers. Useful when writing cross-targeting tests.')
|
||||
|
||||
parser.add_argument('--opt',
|
||||
dest='opt',
|
||||
default='none',
|
||||
choices=['none', 'basic', 'lto'],
|
||||
help='Optimization level')
|
||||
|
||||
parser.add_argument('--mode',
|
||||
dest='mode',
|
||||
default='compile-and-link',
|
||||
choices=['compile', 'link', 'compile-and-link'],
|
||||
help='Specifies whether to compile, link, or both')
|
||||
|
||||
parser.add_argument('--noclean',
|
||||
dest='clean',
|
||||
action='store_false',
|
||||
default=True,
|
||||
help='Dont clean output file before building')
|
||||
|
||||
parser.add_argument('--verbose',
|
||||
dest='verbose',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Print verbose output')
|
||||
|
||||
parser.add_argument('input',
|
||||
metavar='file',
|
||||
help='Source file to compile / object file to link')
|
||||
|
||||
|
||||
args = parser.parse_args(args=sys.argv[1:])
|
||||
|
||||
|
||||
def to_string(b):
|
||||
"""Return the parameter as type 'str', possibly encoding it.
|
||||
|
||||
In Python2, the 'str' type is the same as 'bytes'. In Python3, the
|
||||
'str' type is (essentially) Python2's 'unicode' type, and 'bytes' is
|
||||
distinct.
|
||||
|
||||
This function is copied from llvm/utils/lit/lit/util.py
|
||||
"""
|
||||
if isinstance(b, str):
|
||||
# In Python2, this branch is taken for types 'str' and 'bytes'.
|
||||
# In Python3, this branch is taken only for 'str'.
|
||||
return b
|
||||
if isinstance(b, bytes):
|
||||
# In Python2, this branch is never taken ('bytes' is handled as 'str').
|
||||
# In Python3, this is true only for 'bytes'.
|
||||
try:
|
||||
return b.decode('utf-8')
|
||||
except UnicodeDecodeError:
|
||||
# If the value is not valid Unicode, return the default
|
||||
# repr-line encoding.
|
||||
return str(b)
|
||||
|
||||
# By this point, here's what we *don't* have:
|
||||
#
|
||||
# - In Python2:
|
||||
# - 'str' or 'bytes' (1st branch above)
|
||||
# - In Python3:
|
||||
# - 'str' (1st branch above)
|
||||
# - 'bytes' (2nd branch above)
|
||||
#
|
||||
# The last type we might expect is the Python2 'unicode' type. There is no
|
||||
# 'unicode' type in Python3 (all the Python3 cases were already handled). In
|
||||
# order to get a 'str' object, we need to encode the 'unicode' object.
|
||||
try:
|
||||
return b.encode('utf-8')
|
||||
except AttributeError:
|
||||
raise TypeError('not sure how to convert %s to %s' % (type(b), str))
|
||||
|
||||
def print_environment(env):
|
||||
for e in env:
|
||||
value = env[e]
|
||||
split = value.split(os.pathsep)
|
||||
print(' {0} = {1}'.format(e, split[0]))
|
||||
prefix_width = 3 + len(e)
|
||||
for next in split[1:]:
|
||||
print(' {0}{1}'.format(' ' * prefix_width, next))
|
||||
|
||||
def find_executable(binary_name, search_paths):
|
||||
if sys.platform == 'win32':
|
||||
binary_name = binary_name + '.exe'
|
||||
|
||||
search_paths = os.pathsep.join(search_paths)
|
||||
paths = search_paths + os.pathsep + os.environ.get('PATH', '')
|
||||
for path in paths.split(os.pathsep):
|
||||
p = os.path.join(path, binary_name)
|
||||
if os.path.exists(p) and not os.path.isdir(p):
|
||||
return os.path.normpath(p)
|
||||
return None
|
||||
|
||||
def find_toolchain(compiler, tools_dir):
|
||||
if compiler == 'msvc':
|
||||
return ('msvc', find_executable('cl', tools_dir))
|
||||
if compiler == 'clang-cl':
|
||||
return ('clang-cl', find_executable('clang-cl', tools_dir))
|
||||
if compiler == 'gcc':
|
||||
return ('gcc', find_executable('g++', tools_dir))
|
||||
if compiler == 'clang':
|
||||
return ('clang', find_executable('clang++', tools_dir))
|
||||
if compiler == 'any':
|
||||
priorities = []
|
||||
if sys.platform == 'win32':
|
||||
priorities = ['clang-cl', 'msvc', 'clang', 'gcc']
|
||||
else:
|
||||
priorities = ['clang', 'gcc', 'clang-cl']
|
||||
for toolchain in priorities:
|
||||
(type, dir) = find_toolchain(toolchain, tools_dir)
|
||||
if type and dir:
|
||||
return (type, dir)
|
||||
# Could not find any toolchain.
|
||||
return (None, None)
|
||||
|
||||
# From here on, assume that |compiler| is a path to a file.
|
||||
file = os.path.basename(compiler)
|
||||
name, ext = os.path.splitext(file)
|
||||
if file.lower() == 'cl.exe':
|
||||
return 'msvc'
|
||||
if name == 'clang-cl':
|
||||
return 'clang-cl'
|
||||
if name.startswith('clang'):
|
||||
return 'clang'
|
||||
if name.startswith('gcc') or name.startswith('g++'):
|
||||
return 'gcc'
|
||||
if name == 'cc' or name == 'c++':
|
||||
return 'generic'
|
||||
return 'unknown'
|
||||
|
||||
class Builder(object):
|
||||
def __init__(self, toolchain_type, args):
|
||||
self.toolchain_type = toolchain_type
|
||||
self.input = args.input
|
||||
self.arch = args.arch
|
||||
self.opt = args.opt
|
||||
self.compiler = args.compiler
|
||||
self.clean = args.clean
|
||||
self.output = args.output
|
||||
self.mode = args.mode
|
||||
self.nodefaultlib = args.nodefaultlib
|
||||
self.verbose = args.verbose
|
||||
|
||||
class MsvcBuilder(Builder):
|
||||
def __init__(self, toolchain_type, args):
|
||||
Builder.__init__(self, toolchain_type, args)
|
||||
|
||||
self.msvc_arch_str = 'x86' if self.arch == '32' else 'x64'
|
||||
|
||||
if toolchain_type == 'msvc':
|
||||
# Make sure we're using the appropriate toolchain for the desired
|
||||
# target type.
|
||||
compiler_parent_dir = os.path.dirname(self.compiler)
|
||||
selected_target_version = os.path.basename(compiler_parent_dir)
|
||||
if selected_target_version != self.msvc_arch_str:
|
||||
host_dir = os.path.dirname(compiler_parent_dir)
|
||||
self.compiler = os.path.join(host_dir, self.msvc_arch_str, 'cl.exe')
|
||||
if self.verbose:
|
||||
print('Using alternate compiler "{0}" to match selected target.'.format(self.compiler))
|
||||
|
||||
if self.mode == 'link' or self.mode == 'compile-and-link':
|
||||
self.linker = self._find_linker('link') if toolchain_type == 'msvc' else self._find_linker('lld-link')
|
||||
if not self.linker:
|
||||
raise ValueError('Unable to find an appropriate linker.')
|
||||
|
||||
self.compile_env, self.link_env = self._get_visual_studio_environment()
|
||||
|
||||
def _find_linker(self, name):
|
||||
if sys.platform == 'win32':
|
||||
name = name + '.exe'
|
||||
compiler_dir = os.path.dirname(self.compiler)
|
||||
linker_path = os.path.join(compiler_dir, name)
|
||||
if not os.path.exists(linker_path):
|
||||
raise ValueError('Could not find \'{}\''.format(linker_path))
|
||||
return linker_path
|
||||
|
||||
def _get_vc_install_dir(self):
|
||||
dir = os.getenv('VCINSTALLDIR', None)
|
||||
if dir:
|
||||
if self.verbose:
|
||||
print('Using %VCINSTALLDIR% {}'.format(dir))
|
||||
return dir
|
||||
|
||||
dir = os.getenv('VSINSTALLDIR', None)
|
||||
if dir:
|
||||
if self.verbose:
|
||||
print('Using %VSINSTALLDIR% {}'.format(dir))
|
||||
return os.path.join(dir, 'VC')
|
||||
|
||||
dir = os.getenv('VS2019INSTALLDIR', None)
|
||||
if dir:
|
||||
if self.verbose:
|
||||
print('Using %VS2019INSTALLDIR% {}'.format(dir))
|
||||
return os.path.join(dir, 'VC')
|
||||
|
||||
dir = os.getenv('VS2017INSTALLDIR', None)
|
||||
if dir:
|
||||
if self.verbose:
|
||||
print('Using %VS2017INSTALLDIR% {}'.format(dir))
|
||||
return os.path.join(dir, 'VC')
|
||||
|
||||
dir = os.getenv('VS2015INSTALLDIR', None)
|
||||
if dir:
|
||||
if self.verbose:
|
||||
print('Using %VS2015INSTALLDIR% {}'.format(dir))
|
||||
return os.path.join(dir, 'VC')
|
||||
return None
|
||||
|
||||
def _get_vctools_version(self):
|
||||
ver = os.getenv('VCToolsVersion', None)
|
||||
if ver:
|
||||
if self.verbose:
|
||||
print('Using %VCToolsVersion% {}'.format(ver))
|
||||
return ver
|
||||
|
||||
vcinstalldir = self._get_vc_install_dir()
|
||||
vcinstalldir = os.path.join(vcinstalldir, 'Tools', 'MSVC')
|
||||
subdirs = next(os.walk(vcinstalldir))[1]
|
||||
if not subdirs:
|
||||
return None
|
||||
|
||||
from distutils.version import StrictVersion
|
||||
subdirs.sort(key=lambda x : StrictVersion(x))
|
||||
|
||||
if self.verbose:
|
||||
full_path = os.path.join(vcinstalldir, subdirs[-1])
|
||||
print('Using VC tools version directory {0} found by directory walk.'.format(full_path))
|
||||
return subdirs[-1]
|
||||
|
||||
def _get_vctools_install_dir(self):
|
||||
dir = os.getenv('VCToolsInstallDir', None)
|
||||
if dir:
|
||||
if self.verbose:
|
||||
print('Using %VCToolsInstallDir% {}'.format(dir))
|
||||
return dir
|
||||
|
||||
vcinstalldir = self._get_vc_install_dir()
|
||||
if not vcinstalldir:
|
||||
return None
|
||||
vctoolsver = self._get_vctools_version()
|
||||
if not vctoolsver:
|
||||
return None
|
||||
result = os.path.join(vcinstalldir, 'Tools', 'MSVC', vctoolsver)
|
||||
if not os.path.exists(result):
|
||||
return None
|
||||
if self.verbose:
|
||||
print('Using VC tools install dir {} found by directory walk'.format(result))
|
||||
return result
|
||||
|
||||
def _find_windows_sdk_in_registry_view(self, view):
|
||||
products_key = None
|
||||
roots_key = None
|
||||
installed_options_keys = []
|
||||
try:
|
||||
sam = view | winreg.KEY_READ
|
||||
products_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,
|
||||
r'Software\Microsoft\Windows Kits\Installed Products',
|
||||
0,
|
||||
sam)
|
||||
|
||||
# This is the GUID for the desktop component. If this is present
|
||||
# then the components required for the Desktop SDK are installed.
|
||||
# If not it will throw an exception.
|
||||
winreg.QueryValueEx(products_key, '{5A3D81EC-D870-9ECF-D997-24BDA6644752}')
|
||||
|
||||
roots_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,
|
||||
r'Software\Microsoft\Windows Kits\Installed Roots',
|
||||
0,
|
||||
sam)
|
||||
root_dir = winreg.QueryValueEx(roots_key, 'KitsRoot10')
|
||||
root_dir = to_string(root_dir[0])
|
||||
sdk_versions = []
|
||||
index = 0
|
||||
while True:
|
||||
# Installed SDK versions are stored as sub-keys of the
|
||||
# 'Installed Roots' key. Find all of their names, then sort
|
||||
# them by version
|
||||
try:
|
||||
ver_key = winreg.EnumKey(roots_key, index)
|
||||
sdk_versions.append(ver_key)
|
||||
index = index + 1
|
||||
except WindowsError:
|
||||
break
|
||||
if not sdk_versions:
|
||||
return (None, None)
|
||||
|
||||
# Windows SDK version numbers consist of 4 dotted components, so we
|
||||
# have to use LooseVersion, as StrictVersion supports 3 or fewer.
|
||||
from distutils.version import LooseVersion
|
||||
sdk_versions.sort(key=lambda x : LooseVersion(x), reverse=True)
|
||||
option_value_name = 'OptionId.DesktopCPP' + self.msvc_arch_str
|
||||
for v in sdk_versions:
|
||||
try:
|
||||
version_subkey = v + r'\Installed Options'
|
||||
key = winreg.OpenKey(roots_key, version_subkey)
|
||||
installed_options_keys.append(key)
|
||||
(value, value_type) = winreg.QueryValueEx(key, option_value_name)
|
||||
if value == 1:
|
||||
# The proper architecture is installed. Return the
|
||||
# associated paths.
|
||||
if self.verbose:
|
||||
print('Found Installed Windows SDK v{0} at {1}'.format(v, root_dir))
|
||||
return (root_dir, v)
|
||||
except:
|
||||
continue
|
||||
except:
|
||||
return (None, None)
|
||||
finally:
|
||||
del products_key
|
||||
del roots_key
|
||||
for k in installed_options_keys:
|
||||
del k
|
||||
return (None, None)
|
||||
|
||||
def _find_windows_sdk_in_registry(self):
|
||||
# This could be a clang-cl cross-compile. If so, there's no registry
|
||||
# so just exit.
|
||||
if sys.platform != 'win32':
|
||||
return (None, None)
|
||||
if self.verbose:
|
||||
print('Looking for Windows SDK in 64-bit registry.')
|
||||
dir, ver = self._find_windows_sdk_in_registry_view(winreg.KEY_WOW64_64KEY)
|
||||
if not dir or not ver:
|
||||
if self.verbose:
|
||||
print('Looking for Windows SDK in 32-bit registry.')
|
||||
dir, ver = self._find_windows_sdk_in_registry_view(winreg.KEY_WOW64_32KEY)
|
||||
|
||||
return (dir, ver)
|
||||
|
||||
def _get_winsdk_dir(self):
|
||||
# If a Windows SDK is specified in the environment, use that. Otherwise
|
||||
# try to find one in the Windows registry.
|
||||
dir = os.getenv('WindowsSdkDir', None)
|
||||
if not dir or not os.path.exists(dir):
|
||||
return self._find_windows_sdk_in_registry()
|
||||
ver = os.getenv('WindowsSDKLibVersion', None)
|
||||
if not ver:
|
||||
return self._find_windows_sdk_in_registry()
|
||||
|
||||
ver = ver.rstrip('\\')
|
||||
if self.verbose:
|
||||
print('Using %WindowsSdkDir% {}'.format(dir))
|
||||
print('Using %WindowsSDKLibVersion% {}'.format(ver))
|
||||
return (dir, ver)
|
||||
|
||||
def _get_msvc_native_toolchain_dir(self):
|
||||
assert self.toolchain_type == 'msvc'
|
||||
compiler_dir = os.path.dirname(self.compiler)
|
||||
target_dir = os.path.dirname(compiler_dir)
|
||||
host_name = os.path.basename(target_dir)
|
||||
host_name = host_name[4:].lower()
|
||||
return os.path.join(target_dir, host_name)
|
||||
|
||||
def _get_visual_studio_environment(self):
|
||||
vctools = self._get_vctools_install_dir()
|
||||
winsdk, winsdkver = self._get_winsdk_dir()
|
||||
|
||||
if not vctools and self.verbose:
|
||||
print('Unable to find VC tools installation directory.')
|
||||
if (not winsdk or not winsdkver) and self.verbose:
|
||||
print('Unable to find Windows SDK directory.')
|
||||
|
||||
vcincludes = []
|
||||
vclibs = []
|
||||
sdkincludes = []
|
||||
sdklibs = []
|
||||
if vctools is not None:
|
||||
includes = [['ATLMFC', 'include'], ['include']]
|
||||
libs = [['ATLMFC', 'lib'], ['lib']]
|
||||
vcincludes = [os.path.join(vctools, *y) for y in includes]
|
||||
vclibs = [os.path.join(vctools, *y) for y in libs]
|
||||
if winsdk is not None:
|
||||
includes = [['include', winsdkver, 'ucrt'],
|
||||
['include', winsdkver, 'shared'],
|
||||
['include', winsdkver, 'um'],
|
||||
['include', winsdkver, 'winrt'],
|
||||
['include', winsdkver, 'cppwinrt']]
|
||||
libs = [['lib', winsdkver, 'ucrt'],
|
||||
['lib', winsdkver, 'um']]
|
||||
sdkincludes = [os.path.join(winsdk, *y) for y in includes]
|
||||
sdklibs = [os.path.join(winsdk, *y) for y in libs]
|
||||
|
||||
includes = vcincludes + sdkincludes
|
||||
libs = vclibs + sdklibs
|
||||
libs = [os.path.join(x, self.msvc_arch_str) for x in libs]
|
||||
compileenv = None
|
||||
linkenv = None
|
||||
defaultenv = {}
|
||||
if sys.platform == 'win32':
|
||||
defaultenv = { x : os.environ[x] for x in
|
||||
['SystemDrive', 'SystemRoot', 'TMP', 'TEMP'] }
|
||||
# The directory to mspdbcore.dll needs to be in PATH, but this is
|
||||
# always in the native toolchain path, not the cross-toolchain
|
||||
# path. So, for example, if we're using HostX64\x86 then we need
|
||||
# to add HostX64\x64 to the path, and if we're using HostX86\x64
|
||||
# then we need to add HostX86\x86 to the path.
|
||||
if self.toolchain_type == 'msvc':
|
||||
defaultenv['PATH'] = self._get_msvc_native_toolchain_dir()
|
||||
|
||||
if includes:
|
||||
compileenv = {}
|
||||
compileenv['INCLUDE'] = os.pathsep.join(includes)
|
||||
compileenv.update(defaultenv)
|
||||
if libs:
|
||||
linkenv = {}
|
||||
linkenv['LIB'] = os.pathsep.join(libs)
|
||||
linkenv.update(defaultenv)
|
||||
return (compileenv, linkenv)
|
||||
|
||||
def _ilk_file_name(self):
|
||||
if self.mode == 'link':
|
||||
return None
|
||||
return os.path.splitext(self.output)[0] + '.ilk'
|
||||
|
||||
def _obj_file_name(self):
|
||||
if self.mode == 'compile':
|
||||
return self.output
|
||||
return os.path.splitext(self.output)[0] + '.obj'
|
||||
|
||||
def _pdb_file_name(self):
|
||||
if self.mode == 'compile':
|
||||
return None
|
||||
return os.path.splitext(self.output)[0] + '.pdb'
|
||||
|
||||
def _exe_file_name(self):
|
||||
if self.mode == 'compile':
|
||||
return None
|
||||
return self.output
|
||||
|
||||
def _get_compilation_command(self):
|
||||
args = []
|
||||
|
||||
args.append(self.compiler)
|
||||
if self.toolchain_type == 'clang-cl':
|
||||
args.append('-m' + self.arch)
|
||||
|
||||
if self.opt == 'none':
|
||||
args.append('/Od')
|
||||
elif self.opt == 'basic':
|
||||
args.append('/O2')
|
||||
elif self.opt == 'lto':
|
||||
if self.toolchain_type == 'msvc':
|
||||
args.append('/GL')
|
||||
args.append('/Gw')
|
||||
else:
|
||||
args.append('-flto=thin')
|
||||
if self.nodefaultlib:
|
||||
args.append('/GS-')
|
||||
args.append('/GR-')
|
||||
args.append('/Z7')
|
||||
if self.toolchain_type == 'clang-cl':
|
||||
args.append('-Xclang')
|
||||
args.append('-fkeep-static-consts')
|
||||
args.append('/c')
|
||||
|
||||
args.append('/Fo' + self._obj_file_name())
|
||||
args.append(self.input)
|
||||
input = os.path.basename(self.input)
|
||||
output = os.path.basename(self._obj_file_name())
|
||||
return ('compiling {0} -> {1}'.format(input, output),
|
||||
self.compile_env,
|
||||
args)
|
||||
|
||||
def _get_link_command(self):
|
||||
args = []
|
||||
args.append(self.linker)
|
||||
args.append('/DEBUG:FULL')
|
||||
args.append('/INCREMENTAL:NO')
|
||||
if self.nodefaultlib:
|
||||
args.append('/nodefaultlib')
|
||||
args.append('/entry:main')
|
||||
args.append('/PDB:' + self._pdb_file_name())
|
||||
args.append('/OUT:' + self._exe_file_name())
|
||||
args.append(self._obj_file_name())
|
||||
|
||||
input = os.path.basename(self._obj_file_name())
|
||||
output = os.path.basename(self._exe_file_name())
|
||||
return ('linking {0} -> {1}'.format(input, output),
|
||||
self.link_env,
|
||||
args)
|
||||
|
||||
def build_commands(self):
|
||||
commands = []
|
||||
if self.mode == 'compile' or self.mode == 'compile-and-link':
|
||||
commands.append(self._get_compilation_command())
|
||||
if self.mode == 'link' or self.mode == 'compile-and-link':
|
||||
commands.append(self._get_link_command())
|
||||
return commands
|
||||
|
||||
def output_files(self):
|
||||
outdir = os.path.dirname(self.output)
|
||||
file = os.path.basename(self.output)
|
||||
name, ext = os.path.splitext(file)
|
||||
|
||||
outputs = []
|
||||
if self.mode == 'compile' or self.mode == 'compile-and-link':
|
||||
outputs.append(self._ilk_file_name())
|
||||
outputs.append(self._obj_file_name())
|
||||
if self.mode == 'link' or self.mode == 'compile-and-link':
|
||||
outputs.append(self._pdb_file_name())
|
||||
outputs.append(self._exe_file_name())
|
||||
|
||||
return [x for x in outputs if x is not None]
|
||||
|
||||
class GccBuilder(Builder):
|
||||
def __init__(self, toolchain_type, args):
|
||||
Builder.__init__(self, toolchain_type, args)
|
||||
|
||||
def build_commands(self):
|
||||
pass
|
||||
|
||||
def output_files(self):
|
||||
pass
|
||||
|
||||
def indent(text, spaces):
|
||||
def prefixed_lines():
|
||||
prefix = ' ' * spaces
|
||||
for line in text.splitlines(True):
|
||||
yield prefix + line
|
||||
return ''.join(prefixed_lines())
|
||||
|
||||
def build(commands):
|
||||
global args
|
||||
for (status, env, child_args) in commands:
|
||||
print('\n\n')
|
||||
print(status)
|
||||
if args.verbose:
|
||||
print(' Command Line: ' + ' '.join(child_args))
|
||||
print(' Env:')
|
||||
print_environment(env)
|
||||
popen = subprocess.Popen(child_args,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
env=env,
|
||||
universal_newlines=True)
|
||||
stdout, stderr = popen.communicate()
|
||||
res = popen.wait()
|
||||
if res == -signal.SIGINT:
|
||||
raise KeyboardInterrupt
|
||||
print(' STDOUT:')
|
||||
print(indent(stdout, 4))
|
||||
if res != 0:
|
||||
print(' STDERR:')
|
||||
print(indent(stderr, 4))
|
||||
sys.exit(res)
|
||||
|
||||
def clean(files):
|
||||
global args
|
||||
for o in files:
|
||||
file = o if args.verbose else os.path.basename(o)
|
||||
print('Cleaning {0}'.format(file))
|
||||
try:
|
||||
if os.path.exists(o):
|
||||
os.remove(o)
|
||||
if args.verbose:
|
||||
print(' The file was successfully cleaned.')
|
||||
elif args.verbose:
|
||||
print(' The file does not exist.')
|
||||
except:
|
||||
if args.verbose:
|
||||
print(' The file could not be removed.')
|
||||
|
||||
(toolchain_type, toolchain_path) = find_toolchain(args.compiler, args.tools_dir)
|
||||
if not toolchain_path or not toolchain_type:
|
||||
print('Unable to find toolchain {0}'.format(args.compiler))
|
||||
sys.exit(1)
|
||||
|
||||
if args.verbose:
|
||||
print("Script Environment:")
|
||||
print_environment(os.environ)
|
||||
|
||||
args.compiler = toolchain_path
|
||||
if not os.path.exists(args.compiler):
|
||||
raise ValueError('The toolchain {} does not exist.'.format(args.compiler))
|
||||
|
||||
if toolchain_type == 'msvc' or toolchain_type=='clang-cl':
|
||||
builder = MsvcBuilder(toolchain_type, args)
|
||||
else:
|
||||
builder = GccBuilder(toolchain_type, args)
|
||||
|
||||
if args.clean:
|
||||
clean(builder.output_files())
|
||||
|
||||
cmds = builder.build_commands()
|
||||
|
||||
build(cmds)
|
|
@ -1,4 +1,5 @@
|
|||
import os
|
||||
import itertools
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
|
@ -19,6 +20,15 @@ def use_lldb_substitutions(config):
|
|||
command=FindTool('lldb-mi'),
|
||||
extra_args=['--synchronous'],
|
||||
unresolved='ignore')
|
||||
build_script = os.path.dirname(__file__)
|
||||
build_script = os.path.join(build_script, 'build.py')
|
||||
build_script_args = [build_script,
|
||||
'--compiler=any', # Default to best compiler
|
||||
'--arch=64'] # Default to 64-bit, user can override
|
||||
if config.lldb_lit_tools_dir:
|
||||
build_script_args.append('--tools-dir={0}'.format(config.lldb_lit_tools_dir))
|
||||
if config.lldb_tools_dir:
|
||||
build_script_args.append('--tools-dir={0}'.format(config.lldb_tools_dir))
|
||||
primary_tools = [
|
||||
ToolSubst('%lldb',
|
||||
command=FindTool('lldb'),
|
||||
|
@ -30,7 +40,10 @@ def use_lldb_substitutions(config):
|
|||
command=FindTool(dsname),
|
||||
extra_args=dsargs,
|
||||
unresolved='ignore'),
|
||||
'lldb-test'
|
||||
'lldb-test',
|
||||
ToolSubst('%build',
|
||||
command="'" + sys.executable + "'",
|
||||
extra_args=build_script_args)
|
||||
]
|
||||
|
||||
llvm_config.add_tool_substitutions(primary_tools,
|
||||
|
|
|
@ -33,6 +33,8 @@ class LLVMConfig(object):
|
|||
['cmp.exe', 'grep.exe', 'sed.exe'])
|
||||
if path is not None:
|
||||
self.with_environment('PATH', path, append_path=True)
|
||||
# Many tools behave strangely if these environment variables aren't set.
|
||||
self.with_system_environment(['SystemDrive', 'SystemRoot', 'TEMP', 'TMP'])
|
||||
self.use_lit_shell = True
|
||||
|
||||
# Choose between lit's internal shell pipeline runner and a real shell. If
|
||||
|
|
Loading…
Reference in New Issue