531 lines
17 KiB
Python
531 lines
17 KiB
Python
import argparse
|
|
import os
|
|
import platform
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from typing import Tuple
|
|
from colorama import Fore, Back, Style
|
|
|
|
from util import *
|
|
|
|
sys.stdout.reconfigure(encoding='utf-8') # for windows gh runner
|
|
|
|
expected_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../test/expected/")
|
|
|
|
def get_c_compiler_counterpart(compiler: str) -> str:
|
|
return compiler.replace("clang++", "clang").replace("g++", "gcc")
|
|
|
|
MAX_LINE_DIFF = 2
|
|
|
|
def similarity(name: str, target: List[str]) -> int:
|
|
parts = name.split(".txt")[0].split(".")
|
|
c = 0
|
|
for part in parts:
|
|
if part in target:
|
|
c += 1
|
|
else:
|
|
return -1
|
|
return c
|
|
|
|
def output_matches(raw_output: str, params: Tuple[str]):
|
|
target = []
|
|
|
|
if params[0].startswith("gcc") or params[0].startswith("g++"):
|
|
target.append("gcc")
|
|
elif params[0].startswith("clang"):
|
|
target.append("clang")
|
|
elif params[0].startswith("cl"):
|
|
target.append("msvc")
|
|
|
|
if platform.system() == "Windows":
|
|
target.append("windows")
|
|
elif platform.system() == "Darwin":
|
|
target.append("macos")
|
|
else:
|
|
target.append("linux")
|
|
|
|
other_configs = params[1:]
|
|
for config in other_configs:
|
|
assert "WITH_" in config
|
|
target.append(config.split("WITH_")[1].lower())
|
|
|
|
print(f"Searching for expected file best matching {target}")
|
|
|
|
files = [f for f in os.listdir(expected_dir) if os.path.isfile(os.path.join(expected_dir, f))]
|
|
if len(files) == 0:
|
|
print(f"Error: No expected files to use (searching {expected_dir})")
|
|
sys.exit(1)
|
|
files = list(map(lambda f: (f, similarity(f, target)), files))
|
|
m = max(files, key=lambda entry: entry[1])[1]
|
|
if m <= 0:
|
|
print(f"Error: Could not find match for {target} in {files}")
|
|
sys.exit(1)
|
|
files = [entry[0] for entry in files if entry[1] == m]
|
|
if len(files) > 1:
|
|
print(f"Error: Ambiguous expected file to use ({files})")
|
|
sys.exit(1)
|
|
|
|
file = files[0]
|
|
print(f"Reading from {file}")
|
|
|
|
with open(os.path.join(expected_dir, file), "r") as f:
|
|
raw_expected = f.read()
|
|
|
|
if raw_output.strip() == "":
|
|
print(f"Error: No output from test")
|
|
return False
|
|
|
|
expected = [line.strip().split("||") for line in raw_expected.split("\n")]
|
|
output = [line.strip().split("||") for line in raw_output.split("\n")]
|
|
|
|
max_line_diff = 0
|
|
|
|
errored = False
|
|
|
|
try:
|
|
for i, ((output_file, output_line, output_symbol), (expected_file, expected_line, expected_symbol)) in enumerate(zip(output, expected)):
|
|
if output_file != expected_file:
|
|
print(f"Error: File name mismatch on line {i + 1}, found \"{output_file}\" expected \"{expected_file}\"")
|
|
errored = True
|
|
if abs(int(output_line) - int(expected_line)) > max_line_diff:
|
|
print(f"Error: File line mismatch on line {i + 1}, found {output_line} expected {expected_line}")
|
|
errored = True
|
|
if output_symbol != expected_symbol:
|
|
print(f"Error: File symbol mismatch on line {i + 1}, found \"{output_symbol}\" expected \"{expected_symbol}\"")
|
|
errored = True
|
|
if expected_symbol == "main" or expected_symbol == "main()":
|
|
break
|
|
except ValueError:
|
|
print("ValueError during output checking")
|
|
errored = True
|
|
|
|
if errored:
|
|
print("Output:")
|
|
print(raw_output)
|
|
print("Expected:")
|
|
print(raw_expected)
|
|
|
|
return not errored
|
|
|
|
def run_test(runner: MatrixRunner, test_binary, params: Tuple[str]):
|
|
def output_matcher(output: str):
|
|
return output_matches(output, params)
|
|
return runner.run_command(test_binary, output_matcher=output_matcher)
|
|
|
|
def build(runner: MatrixRunner):
|
|
matrix = runner.current_config()
|
|
if platform.system() != "Windows":
|
|
args = [
|
|
"cmake",
|
|
"..",
|
|
f"-DCMAKE_BUILD_TYPE={matrix['target']}",
|
|
f"-DCMAKE_CXX_COMPILER={matrix['compiler']}",
|
|
f"-DCMAKE_C_COMPILER={get_c_compiler_counterpart(matrix['compiler'])}",
|
|
f"-DCMAKE_CXX_STANDARD={matrix['std']}",
|
|
f"-DCPPTRACE_USE_EXTERNAL_LIBDWARF=On",
|
|
f"-DCPPTRACE_USE_EXTERNAL_ZSTD=On",
|
|
f"-DCPPTRACE_WERROR_BUILD=On",
|
|
f"-D{matrix['unwind']}=On",
|
|
f"-D{matrix['symbols']}=On",
|
|
f"-D{matrix['demangle']}=On",
|
|
"-DCPPTRACE_BACKTRACE_PATH=/usr/lib/gcc/x86_64-linux-gnu/10/include/backtrace.h",
|
|
"-DCPPTRACE_BUILD_TESTING=On",
|
|
"-DCPPTRACE_SKIP_UNIT=On",
|
|
f"-DBUILD_SHARED_LIBS={matrix['shared']}"
|
|
]
|
|
if matrix['symbols'] == "CPPTRACE_GET_SYMBOLS_WITH_LIBDL":
|
|
args.append("-DCPPTRACE_BUILD_TEST_RDYNAMIC=On")
|
|
succeeded = runner.run_command(*args)
|
|
if succeeded:
|
|
return runner.run_command("make", "-j")
|
|
else:
|
|
args = [
|
|
"cmake",
|
|
"..",
|
|
f"-DCMAKE_BUILD_TYPE={matrix['target']}",
|
|
f"-DCMAKE_CXX_COMPILER={matrix['compiler']}",
|
|
f"-DCMAKE_C_COMPILER={get_c_compiler_counterpart(matrix['compiler'])}",
|
|
f"-DCMAKE_CXX_STANDARD={matrix['std']}",
|
|
f"-DCPPTRACE_USE_EXTERNAL_LIBDWARF=On",
|
|
f"-DCPPTRACE_USE_EXTERNAL_ZSTD=On",
|
|
f"-DCPPTRACE_WERROR_BUILD=On",
|
|
f"-D{matrix['unwind']}=On",
|
|
f"-D{matrix['symbols']}=On",
|
|
f"-D{matrix['demangle']}=On",
|
|
"-DCPPTRACE_BUILD_TESTING=On",
|
|
"-DCPPTRACE_SKIP_UNIT=On",
|
|
f"-DBUILD_SHARED_LIBS={matrix['shared']}"
|
|
]
|
|
if matrix["compiler"] == "g++":
|
|
args.append("-GUnix Makefiles")
|
|
succeeded = runner.run_command(*args)
|
|
if succeeded:
|
|
if matrix["compiler"] == "g++":
|
|
return runner.run_command("make", "-j")
|
|
else:
|
|
return runner.run_command("msbuild", "cpptrace.sln")
|
|
return False
|
|
|
|
def build_full_or_auto(runner: MatrixRunner):
|
|
matrix = runner.current_config()
|
|
if platform.system() != "Windows":
|
|
args = [
|
|
"cmake",
|
|
"..",
|
|
f"-DCMAKE_BUILD_TYPE={matrix['target']}",
|
|
f"-DCMAKE_CXX_COMPILER={matrix['compiler']}",
|
|
f"-DCMAKE_C_COMPILER={get_c_compiler_counterpart(matrix['compiler'])}",
|
|
f"-DCMAKE_CXX_STANDARD={matrix['std']}",
|
|
f"-DCPPTRACE_USE_EXTERNAL_LIBDWARF=On",
|
|
f"-DCPPTRACE_USE_EXTERNAL_ZSTD=On",
|
|
f"-DCPPTRACE_WERROR_BUILD=On",
|
|
f"-DCPPTRACE_BACKTRACE_PATH=/usr/lib/gcc/x86_64-linux-gnu/10/include/backtrace.h",
|
|
"-DCPPTRACE_BUILD_TESTING=On",
|
|
"-DCPPTRACE_SKIP_UNIT=On",
|
|
f"-DBUILD_SHARED_LIBS={matrix['shared']}"
|
|
]
|
|
if matrix["config"] != "":
|
|
args.append(f"{matrix['config']}")
|
|
succeeded = runner.run_command(*args)
|
|
if succeeded:
|
|
return runner.run_command("make", "-j")
|
|
else:
|
|
args = [
|
|
"cmake",
|
|
"..",
|
|
f"-DCMAKE_BUILD_TYPE={matrix['target']}",
|
|
f"-DCMAKE_CXX_COMPILER={matrix['compiler']}",
|
|
f"-DCMAKE_C_COMPILER={get_c_compiler_counterpart(matrix['compiler'])}",
|
|
f"-DCMAKE_CXX_STANDARD={matrix['std']}",
|
|
f"-DCPPTRACE_USE_EXTERNAL_LIBDWARF=On",
|
|
f"-DCPPTRACE_USE_EXTERNAL_ZSTD=On",
|
|
f"-DCPPTRACE_WERROR_BUILD=On",
|
|
"-DCPPTRACE_BUILD_TESTING=On",
|
|
"-DCPPTRACE_SKIP_UNIT=On",
|
|
f"-DBUILD_SHARED_LIBS={matrix['shared']}"
|
|
]
|
|
if matrix["config"] != "":
|
|
args.append(f"{matrix['config']}")
|
|
if matrix["compiler"] == "g++":
|
|
args.append("-GUnix Makefiles")
|
|
succeeded = runner.run_command(*args)
|
|
if succeeded:
|
|
if matrix["compiler"] == "g++":
|
|
return runner.run_command("make", "-j")
|
|
else:
|
|
return runner.run_command("msbuild", "cpptrace.sln")
|
|
return False
|
|
|
|
def test(runner: MatrixRunner):
|
|
matrix = runner.current_config()
|
|
if platform.system() != "Windows":
|
|
return run_test(
|
|
runner,
|
|
"./integration",
|
|
(matrix["compiler"], matrix["unwind"], matrix["symbols"], matrix["demangle"])
|
|
)
|
|
else:
|
|
if matrix["compiler"] == "g++":
|
|
return run_test(
|
|
runner,
|
|
f".\\integration.exe",
|
|
(matrix["compiler"], matrix["unwind"], matrix["symbols"], matrix["demangle"])
|
|
)
|
|
else:
|
|
return run_test(
|
|
runner,
|
|
f".\\{matrix['target']}\\integration.exe",
|
|
(matrix["compiler"], matrix["unwind"], matrix["symbols"], matrix["demangle"])
|
|
)
|
|
|
|
def test_full_or_auto(runner: MatrixRunner):
|
|
matrix = runner.current_config()
|
|
if platform.system() != "Windows":
|
|
return run_test(
|
|
runner,
|
|
"./integration",
|
|
(matrix["compiler"],)
|
|
)
|
|
else:
|
|
if matrix["compiler"] == "g++":
|
|
return run_test(
|
|
runner,
|
|
f".\\integration.exe",
|
|
(matrix["compiler"],)
|
|
)
|
|
else:
|
|
return run_test(
|
|
runner,
|
|
f".\\{matrix['target']}\\integration.exe",
|
|
(matrix["compiler"],)
|
|
)
|
|
|
|
def build_and_test(runner: MatrixRunner):
|
|
matrix = runner.current_config()
|
|
|
|
if os.path.exists("build"):
|
|
shutil.rmtree("build", ignore_errors=True)
|
|
|
|
if not os.path.exists("build"):
|
|
os.mkdir("build")
|
|
os.chdir("build")
|
|
|
|
good = False
|
|
if build(runner):
|
|
good = test(runner)
|
|
|
|
os.chdir("..")
|
|
print()
|
|
|
|
return good
|
|
|
|
def build_and_test_full_or_auto(runner: MatrixRunner):
|
|
matrix = runner.current_config()
|
|
|
|
if os.path.exists("build"):
|
|
shutil.rmtree("build", ignore_errors=True)
|
|
|
|
if not os.path.exists("build"):
|
|
os.mkdir("build")
|
|
os.chdir("build")
|
|
|
|
good = False
|
|
if build_full_or_auto(runner):
|
|
good = test_full_or_auto(runner)
|
|
|
|
os.chdir("..")
|
|
print()
|
|
|
|
return good
|
|
|
|
def run_linux_matrix(compilers: list, shared: bool):
|
|
MatrixRunner(
|
|
matrix = {
|
|
"compiler": compilers,
|
|
"target": ["Debug"],
|
|
"std": ["11", "20"],
|
|
"unwind": [
|
|
"CPPTRACE_UNWIND_WITH_EXECINFO",
|
|
"CPPTRACE_UNWIND_WITH_UNWIND",
|
|
"CPPTRACE_UNWIND_WITH_LIBUNWIND",
|
|
#"CPPTRACE_UNWIND_WITH_NOTHING",
|
|
],
|
|
"symbols": [
|
|
# Disabled due to libbacktrace bug
|
|
# "CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE",
|
|
"CPPTRACE_GET_SYMBOLS_WITH_LIBDL",
|
|
"CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
|
|
"CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF",
|
|
#"CPPTRACE_GET_SYMBOLS_WITH_NOTHING",
|
|
],
|
|
"demangle": [
|
|
"CPPTRACE_DEMANGLE_WITH_CXXABI",
|
|
#"CPPTRACE_DEMANGLE_WITH_NOTHING",
|
|
],
|
|
"shared": ["On" if shared else "Off"]
|
|
},
|
|
exclude = []
|
|
).run(build_and_test)
|
|
|
|
def run_linux_default(compilers: list, shared: bool):
|
|
MatrixRunner(
|
|
matrix = {
|
|
"compiler": compilers,
|
|
"target": ["Debug"],
|
|
"std": ["11", "20"],
|
|
"config": [""],
|
|
"shared": ["On" if shared else "Off"]
|
|
},
|
|
exclude = []
|
|
).run(build_and_test_full_or_auto)
|
|
|
|
def run_macos_matrix(compilers: list, shared: bool):
|
|
MatrixRunner(
|
|
matrix = {
|
|
"compiler": compilers,
|
|
"target": ["Debug"],
|
|
"std": ["11", "20"],
|
|
"unwind": [
|
|
"CPPTRACE_UNWIND_WITH_EXECINFO",
|
|
"CPPTRACE_UNWIND_WITH_UNWIND",
|
|
#"CPPTRACE_UNWIND_WITH_NOTHING",
|
|
],
|
|
"symbols": [
|
|
#"CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE",
|
|
"CPPTRACE_GET_SYMBOLS_WITH_LIBDL",
|
|
"CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
|
|
"CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF",
|
|
#"CPPTRACE_GET_SYMBOLS_WITH_NOTHING",
|
|
],
|
|
"demangle": [
|
|
"CPPTRACE_DEMANGLE_WITH_CXXABI",
|
|
#"CPPTRACE_DEMANGLE_WITH_NOTHING",
|
|
],
|
|
"shared": ["On" if shared else "Off"]
|
|
},
|
|
exclude = []
|
|
).run(build_and_test)
|
|
|
|
def run_macos_default(compilers: list, shared: bool):
|
|
MatrixRunner(
|
|
matrix = {
|
|
"compiler": compilers,
|
|
"target": ["Debug"],
|
|
"std": ["11", "20"],
|
|
"config": [""],
|
|
"shared": ["On" if shared else "Off"]
|
|
},
|
|
exclude = []
|
|
).run(build_and_test_full_or_auto)
|
|
|
|
def run_windows_matrix(compilers: list, shared: bool):
|
|
MatrixRunner(
|
|
matrix = {
|
|
"compiler": compilers,
|
|
"target": ["Debug"],
|
|
"std": ["11", "20"],
|
|
"unwind": [
|
|
"CPPTRACE_UNWIND_WITH_WINAPI",
|
|
"CPPTRACE_UNWIND_WITH_DBGHELP",
|
|
"CPPTRACE_UNWIND_WITH_UNWIND", # Broken on github actions for some reason
|
|
#"CPPTRACE_UNWIND_WITH_NOTHING",
|
|
],
|
|
"symbols": [
|
|
"CPPTRACE_GET_SYMBOLS_WITH_DBGHELP",
|
|
"CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
|
|
"CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF",
|
|
#"CPPTRACE_GET_SYMBOLS_WITH_NOTHING",
|
|
],
|
|
"demangle": [
|
|
"CPPTRACE_DEMANGLE_WITH_CXXABI",
|
|
"CPPTRACE_DEMANGLE_WITH_NOTHING",
|
|
],
|
|
"shared": ["On" if shared else "Off"]
|
|
},
|
|
exclude = [
|
|
{
|
|
"demangle": "CPPTRACE_DEMANGLE_WITH_CXXABI",
|
|
"compiler": "cl"
|
|
},
|
|
{
|
|
"unwind": "CPPTRACE_UNWIND_WITH_UNWIND",
|
|
"compiler": "cl"
|
|
},
|
|
{
|
|
"unwind": "CPPTRACE_UNWIND_WITH_UNWIND",
|
|
"compiler": "clang++"
|
|
},
|
|
{
|
|
"symbols": "CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
|
|
"compiler": "cl"
|
|
},
|
|
{
|
|
"symbols": "CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
|
|
"compiler": "clang++"
|
|
},
|
|
{
|
|
"symbols": "CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF",
|
|
"compiler": "cl"
|
|
},
|
|
{
|
|
"symbols": "CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF",
|
|
"compiler": "clang++"
|
|
},
|
|
{
|
|
"symbols": "CPPTRACE_GET_SYMBOLS_WITH_DBGHELP",
|
|
"compiler": "g++"
|
|
},
|
|
{
|
|
"symbols": "CPPTRACE_GET_SYMBOLS_WITH_DBGHELP",
|
|
"demangle": "CPPTRACE_DEMANGLE_WITH_CXXABI"
|
|
},
|
|
{
|
|
"symbols": "CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF",
|
|
"demangle": "CPPTRACE_DEMANGLE_WITH_NOTHING"
|
|
},
|
|
{
|
|
"symbols": "CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
|
|
"demangle": "CPPTRACE_DEMANGLE_WITH_NOTHING"
|
|
}
|
|
]
|
|
).run(build_and_test)
|
|
|
|
def run_windows_default(compilers: list, shared: bool):
|
|
MatrixRunner(
|
|
matrix = {
|
|
"compiler": compilers,
|
|
"target": ["Debug"],
|
|
"std": ["11", "20"],
|
|
"config": [""],
|
|
"shared": ["On" if shared else "Off"]
|
|
},
|
|
exclude = []
|
|
).run(build_and_test_full_or_auto)
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
prog="Build in all configs",
|
|
description="Try building the library in all possible configurations for the current host"
|
|
)
|
|
parser.add_argument(
|
|
"--clang",
|
|
action="store_true"
|
|
)
|
|
parser.add_argument(
|
|
"--gcc",
|
|
action="store_true"
|
|
)
|
|
parser.add_argument(
|
|
"--msvc",
|
|
action="store_true"
|
|
)
|
|
parser.add_argument(
|
|
"--all",
|
|
action="store_true"
|
|
)
|
|
parser.add_argument(
|
|
"--shared",
|
|
action="store_true"
|
|
)
|
|
parser.add_argument(
|
|
"--default-config",
|
|
action="store_true"
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
if platform.system() == "Linux":
|
|
compilers = []
|
|
if args.clang or args.all:
|
|
compilers.append("clang++-14")
|
|
if args.gcc or args.all:
|
|
compilers.append("g++-10")
|
|
if args.default_config:
|
|
run_linux_default(compilers, args.shared)
|
|
else:
|
|
run_linux_matrix(compilers, args.shared)
|
|
if platform.system() == "Darwin":
|
|
compilers = []
|
|
if args.clang or args.all:
|
|
compilers.append("clang++")
|
|
if args.gcc or args.all:
|
|
compilers.append("g++-12")
|
|
if args.default_config:
|
|
run_macos_default(compilers, args.shared)
|
|
else:
|
|
run_macos_matrix(compilers, args.shared)
|
|
if platform.system() == "Windows":
|
|
compilers = []
|
|
if args.clang or args.all:
|
|
compilers.append("clang++")
|
|
if args.msvc or args.all:
|
|
compilers.append("cl")
|
|
if args.gcc or args.all:
|
|
compilers.append("g++")
|
|
if args.default_config:
|
|
run_windows_default(compilers, args.shared)
|
|
else:
|
|
run_windows_matrix(compilers, args.shared)
|
|
|
|
main()
|