Unit test more thoroughly and rework matrix ci system (#147)

This commit is contained in:
Jeremy Rifkin 2024-07-11 23:59:22 -06:00 committed by GitHub
parent e1fb3527a4
commit 7497bf2a6f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 635 additions and 518 deletions

View File

@ -4,8 +4,6 @@ on:
push:
pull_request:
# TODO: Test statically linked
jobs:
test-linux:
runs-on: ubuntu-22.04
@ -140,34 +138,15 @@ jobs:
unittest-linux:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
compiler: [g++-10, clang++-14]
shared: [OFF, ON]
build_type: [Debug, RelWithDebInfo]
has_dl_find_object: [OFF, ON]
steps:
- uses: actions/checkout@v4
- name: dependencies
run: |
sudo apt install gcc-10 g++-10 libgcc-10-dev ninja-build
cd ..
cpptrace/ci/setup-prerequisites-unittest.sh
- name: build and test
run: |
mkdir build
cd build
cmake .. \
-GNinja \
-DCMAKE_CXX_COMPILER=${{matrix.compiler}} \
-DCMAKE_C_COMPILER=${{matrix.compiler == 'g++-10' && 'gcc-10' || 'clang-14'}} \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DBUILD_SHARED_LIBS=${{matrix.shared}} \
-DHAS_DL_FIND_OBJECT=${{matrix.has_dl_find_object}} \
-DCPPTRACE_WERROR_BUILD=On \
-DCPPTRACE_BUILD_TESTING=On
ninja
./unittest
bash -c "exec -a u ./unittest"
python3 ci/unittest.py
unittest-windows:
runs-on: windows-2022
strategy:

View File

@ -385,9 +385,9 @@ if(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF)
cmake_policy(SET CMP0074 NEW)
FetchContent_Declare(
zstd
GIT_REPOSITORY https://github.com/facebook/zstd.git
GIT_TAG 63779c798237346c2b245c546c40b72a5a5913fe # v1.5.5
GIT_SHALLOW 1
GIT_REPOSITORY ${CPPTRACE_ZSTD_REPO}
GIT_TAG ${CPPTRACE_ZSTD_TAG}
GIT_SHALLOW ${CPPTRACE_ZSTD_SHALLOW}
SOURCE_SUBDIR build/cmake
)
# FetchContent_MakeAvailable(zstd)
@ -409,18 +409,9 @@ if(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF)
# set(BUILD_DWARFDUMP FALSE)
FetchContent_Declare(
libdwarf
# GIT_REPOSITORY https://github.com/davea42/libdwarf-code.git
# GIT_TAG 6216e185863f41d6f19ab850caabfff7326020d7 # v0.8.0
# GIT_TAG 8b0bd09d8c77d45a68cb1bb00a54186a92b683d9 # v0.9.0
# GIT_TAG 8cdcc531f310d1c5ae61da469d8056bdd36b77e7 # v0.9.1 + some cmake changes
# Using a lightweight mirror that's optimized for clone + configure speed
# GIT_TAG ee53f0b6c99fc8cdaa3ae77af0196fb20e16177a # main 5.10.24
GIT_REPOSITORY https://github.com/jeremy-rifkin/libdwarf-lite.git
# GIT_TAG c78e984f3abbd20f6e01d6f51819e826b1691f65 # v0.8.0
# GIT_TAG 71090c680b4c943448ba87a0f1f864f174e4edda # v0.9.0
# GIT_TAG 5c0cb251f94b27e90184e6b2d9a0c9c62593babc # v0.9.1 + some cmake changes
GIT_TAG 87401f22cd05628d23059cb29ee6448a55c3a88a # v0.9.2
GIT_SHALLOW 1
GIT_REPOSITORY ${CPPTRACE_LIBDWARF_REPO}
GIT_TAG ${CPPTRACE_LIBDWARF_TAG}
GIT_SHALLOW ${CPPTRACE_LIBDWARF_SHALLOW}
)
# FetchContent_MakeAvailable(libdwarf)
FetchContent_GetProperties(libdwarf)

View File

@ -746,7 +746,7 @@ make install
cd ~/scratch/cpptrace-test
git clone https://github.com/jeremy-rifkin/libdwarf-lite.git
cd libdwarf-lite
git checkout 5c0cb251f94b27e90184e6b2d9a0c9c62593babc
git checkout 6dbcc23dba6ffd230063bda4b9d7298bf88d9d41
mkdir build
cd build
cmake .. -DPIC_ALWAYS=On -DBUILD_DWARFDUMP=Off -DCMAKE_PREFIX_PATH=~/scratch/cpptrace-test/resources -DCMAKE_INSTALL_PREFIX=~/scratch/cpptrace-test/resources

View File

@ -11,28 +11,8 @@ from util import *
sys.stdout.reconfigure(encoding='utf-8') # for windows gh runner
failed = False
def run_command(*args: List[str]):
print(f"{Fore.CYAN}{Style.BRIGHT}Running Command \"{' '.join(args)}\"{Style.RESET_ALL}")
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
print(Style.RESET_ALL, end="") # makefile in parallel sometimes messes up colors
if p.returncode != 0:
print(f"{Fore.RED}{Style.BRIGHT}Command failed{Style.RESET_ALL}")
print("stdout:")
print(stdout.decode("utf-8"), end="")
print("stderr:")
print(stderr.decode("utf-8"), end="")
global failed
failed = True
return False
else:
print(f"{Fore.GREEN}{Style.BRIGHT}Command succeeded{Style.RESET_ALL}")
return True
def build(matrix):
print(f"{Fore.BLUE}{Style.BRIGHT}{'=' * 10} Running build with config {', '.join(matrix.values())} {'=' * 10}{Style.RESET_ALL}")
def build(runner: MatrixRunner):
matrix = runner.current_config()
if os.path.exists("build"):
shutil.rmtree("build", ignore_errors=True)
@ -41,7 +21,7 @@ def build(matrix):
os.chdir("build")
if platform.system() != "Windows":
succeeded = run_command(
succeeded = runner.run_command(
"cmake",
"..",
f"-DCMAKE_BUILD_TYPE={matrix['target']}",
@ -56,7 +36,7 @@ def build(matrix):
"-DCPPTRACE_BACKTRACE_PATH=/usr/lib/gcc/x86_64-linux-gnu/10/include/backtrace.h",
)
if succeeded:
succeeded = run_command("make", "-j", "VERBOSE=1")
succeeded = runner.run_command("make", "-j", "VERBOSE=1")
else:
args = [
"cmake",
@ -73,20 +53,20 @@ def build(matrix):
]
if matrix["compiler"] == "g++":
args.append("-GUnix Makefiles")
succeeded = run_command(*args)
succeeded = runner.run_command(*args)
if succeeded:
if matrix["compiler"] == "g++":
succeeded = run_command("make", "-j", "VERBOSE=1")
succeeded = runner.run_command("make", "-j", "VERBOSE=1")
else:
succeeded = run_command("msbuild", "cpptrace.sln")
succeeded = runner.run_command("msbuild", "cpptrace.sln")
os.chdir("..")
print()
return succeeded
def build_full_or_auto(matrix):
print(f"{Fore.BLUE}{Style.BRIGHT}{'=' * 10} Running build with config {'<auto>' if matrix['config'] == '' else ', '.join(matrix.values())} {'=' * 10}{Style.RESET_ALL}")
def build_full_or_auto(runner: MatrixRunner):
matrix = runner.current_config()
if os.path.exists("build"):
shutil.rmtree("build", ignore_errors=True)
@ -108,9 +88,9 @@ def build_full_or_auto(matrix):
]
if matrix["config"] != "":
args.append(f"{matrix['config']}")
succeeded = run_command(*args)
succeeded = runner.run_command(*args)
if succeeded:
succeeded = run_command("make", "-j")
succeeded = runner.run_command("make", "-j")
else:
args = [
"cmake",
@ -126,12 +106,12 @@ def build_full_or_auto(matrix):
args.append(f"{matrix['config']}")
if matrix["compiler"] == "g++":
args.append("-GUnix Makefiles")
succeeded = run_command(*args)
succeeded = runner.run_command(*args)
if succeeded:
if matrix["compiler"] == "g++":
succeeded = run_command("make", "-j")
succeeded = runner.run_command("make", "-j")
else:
succeeded = run_command("msbuild", "cpptrace.sln")
succeeded = runner.run_command("msbuild", "cpptrace.sln")
os.chdir("..")
print()
@ -139,143 +119,149 @@ def build_full_or_auto(matrix):
return succeeded
def run_linux_matrix(compilers: list):
matrix = {
"compiler": compilers,
"target": ["Debug"],
"std": ["11", "20"],
"unwind": [
"CPPTRACE_UNWIND_WITH_UNWIND",
"CPPTRACE_UNWIND_WITH_EXECINFO",
"CPPTRACE_UNWIND_WITH_LIBUNWIND",
"CPPTRACE_UNWIND_WITH_NOTHING",
],
"symbols": [
"CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE",
"CPPTRACE_GET_SYMBOLS_WITH_LIBDL",
"CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF",
"CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
"CPPTRACE_GET_SYMBOLS_WITH_NOTHING",
],
"demangle": [
"CPPTRACE_DEMANGLE_WITH_CXXABI",
"CPPTRACE_DEMANGLE_WITH_NOTHING",
],
}
exclude = []
run_matrix(matrix, exclude, build)
MatrixRunner(
matrix = {
"compiler": compilers,
"target": ["Debug"],
"std": ["11", "20"],
"unwind": [
"CPPTRACE_UNWIND_WITH_UNWIND",
"CPPTRACE_UNWIND_WITH_EXECINFO",
"CPPTRACE_UNWIND_WITH_LIBUNWIND",
"CPPTRACE_UNWIND_WITH_NOTHING",
],
"symbols": [
"CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE",
"CPPTRACE_GET_SYMBOLS_WITH_LIBDL",
"CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF",
"CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
"CPPTRACE_GET_SYMBOLS_WITH_NOTHING",
],
"demangle": [
"CPPTRACE_DEMANGLE_WITH_CXXABI",
"CPPTRACE_DEMANGLE_WITH_NOTHING",
],
},
exclude = []
).run(build)
def run_linux_default(compilers: list):
matrix = {
"compiler": compilers,
"target": ["Debug"],
"std": ["11", "20"],
"config": [""]
}
exclude = []
run_matrix(matrix, exclude, build_full_or_auto)
MatrixRunner(
matrix = {
"compiler": compilers,
"target": ["Debug"],
"std": ["11", "20"],
"config": [""]
},
exclude = []
).run(build_full_or_auto)
def run_macos_matrix(compilers: list):
matrix = {
"compiler": compilers,
"target": ["Debug"],
"std": ["11", "20"],
"unwind": [
"CPPTRACE_UNWIND_WITH_UNWIND",
"CPPTRACE_UNWIND_WITH_EXECINFO",
"CPPTRACE_UNWIND_WITH_NOTHING",
],
"symbols": [
#"CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE",
"CPPTRACE_GET_SYMBOLS_WITH_LIBDL",
"CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF",
"CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
"CPPTRACE_GET_SYMBOLS_WITH_NOTHING",
],
"demangle": [
"CPPTRACE_DEMANGLE_WITH_CXXABI",
"CPPTRACE_DEMANGLE_WITH_NOTHING",
]
}
exclude = []
run_matrix(matrix, exclude, build)
MatrixRunner(
matrix = {
"compiler": compilers,
"target": ["Debug"],
"std": ["11", "20"],
"unwind": [
"CPPTRACE_UNWIND_WITH_UNWIND",
"CPPTRACE_UNWIND_WITH_EXECINFO",
"CPPTRACE_UNWIND_WITH_NOTHING",
],
"symbols": [
#"CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE",
"CPPTRACE_GET_SYMBOLS_WITH_LIBDL",
"CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF",
"CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
"CPPTRACE_GET_SYMBOLS_WITH_NOTHING",
],
"demangle": [
"CPPTRACE_DEMANGLE_WITH_CXXABI",
"CPPTRACE_DEMANGLE_WITH_NOTHING",
]
},
exclude = []
).run(build)
def run_macos_default(compilers: list):
matrix = {
"compiler": compilers,
"target": ["Debug"],
"std": ["11", "20"],
"config": [""]
}
exclude = []
run_matrix(matrix, exclude, build_full_or_auto)
MatrixRunner(
matrix = {
"compiler": compilers,
"target": ["Debug"],
"std": ["11", "20"],
"config": [""]
},
exclude = []
).run(build_full_or_auto)
def run_windows_matrix(compilers: list):
matrix = {
"compiler": compilers,
"target": ["Debug"],
"std": ["11", "20"],
"unwind": [
"CPPTRACE_UNWIND_WITH_WINAPI",
"CPPTRACE_UNWIND_WITH_DBGHELP",
"CPPTRACE_UNWIND_WITH_UNWIND",
"CPPTRACE_UNWIND_WITH_NOTHING",
],
"symbols": [
"CPPTRACE_GET_SYMBOLS_WITH_DBGHELP",
"CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF",
"CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
"CPPTRACE_GET_SYMBOLS_WITH_NOTHING",
],
"demangle": [
#"CPPTRACE_DEMANGLE_WITH_CXXABI",
"CPPTRACE_DEMANGLE_WITH_NOTHING",
MatrixRunner(
matrix = {
"compiler": compilers,
"target": ["Debug"],
"std": ["11", "20"],
"unwind": [
"CPPTRACE_UNWIND_WITH_WINAPI",
"CPPTRACE_UNWIND_WITH_DBGHELP",
"CPPTRACE_UNWIND_WITH_UNWIND",
"CPPTRACE_UNWIND_WITH_NOTHING",
],
"symbols": [
"CPPTRACE_GET_SYMBOLS_WITH_DBGHELP",
"CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF",
"CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
"CPPTRACE_GET_SYMBOLS_WITH_NOTHING",
],
"demangle": [
#"CPPTRACE_DEMANGLE_WITH_CXXABI",
"CPPTRACE_DEMANGLE_WITH_NOTHING",
]
},
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++"
},
]
}
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++"
},
]
run_matrix(matrix, exclude, build)
).run(build)
def run_windows_default(compilers: list):
matrix = {
"compiler": compilers,
"target": ["Debug"],
"std": ["11", "20"],
"config": [""]
}
exclude = []
run_matrix(matrix, exclude, build_full_or_auto)
MatrixRunner(
matrix = {
"compiler": compilers,
"target": ["Debug"],
"std": ["11", "20"],
"config": [""]
},
exclude = []
).run(build_full_or_auto)
def main():
parser = argparse.ArgumentParser(
@ -337,9 +323,4 @@ def main():
else:
run_windows_matrix(compilers)
global failed
if failed:
print("🔴 Some checks failed")
sys.exit(1)
main()

View File

@ -17,7 +17,7 @@ mkdir libdwarf
cd libdwarf
git init
git remote add origin https://github.com/jeremy-rifkin/libdwarf-lite.git
git fetch --depth 1 origin 5c0cb251f94b27e90184e6b2d9a0c9c62593babc
git fetch --depth 1 origin 6dbcc23dba6ffd230063bda4b9d7298bf88d9d41
git checkout FETCH_HEAD
mkdir build
cd build

View File

@ -0,0 +1,37 @@
#!/bin/bash
sudo apt install gcc-10 g++-10 libgcc-10-dev ninja-build
mkdir zstd
cd zstd
git init
git remote add origin https://github.com/facebook/zstd.git
git fetch --depth 1 origin 63779c798237346c2b245c546c40b72a5a5913fe # 1.5.5
git checkout FETCH_HEAD
make -j
sudo make install
cd ..
mkdir libdwarf
cd libdwarf
git init
git remote add origin https://github.com/davea42/libdwarf-code.git
git fetch --depth 1 origin e2ab28a547ed8a53f2c96a825247a7cc8f7e40bb
git checkout FETCH_HEAD
mkdir build
cd build
cmake .. -GNinja -DPIC_ALWAYS=TRUE -DBUILD_DWARFDUMP=FALSE
sudo ninja install
cd ../..
mkdir googletest
cd googletest
git init
git remote add origin https://github.com/google/googletest.git
git fetch --depth 1 origin f8d7d77c06936315286eb55f8de22cd23c188571
git checkout FETCH_HEAD
mkdir build
cd build
cmake .. -GNinja
sudo ninja install

View File

@ -16,7 +16,7 @@ mkdir libdwarf
cd libdwarf
git init
git remote add origin https://github.com/jeremy-rifkin/libdwarf-lite.git
git fetch --depth 1 origin 5c0cb251f94b27e90184e6b2d9a0c9c62593babc
git fetch --depth 1 origin 6dbcc23dba6ffd230063bda4b9d7298bf88d9d41
git checkout FETCH_HEAD
mkdir build
cd build

View File

@ -11,8 +11,6 @@ from util import *
sys.stdout.reconfigure(encoding='utf-8') # for windows gh runner
failed = False
expected_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../test/expected/")
def get_c_compiler_counterpart(compiler: str) -> str:
@ -110,57 +108,13 @@ def output_matches(raw_output: str, params: Tuple[str]):
return not errored
def run_command(*args: List[str], always_output=False):
global failed
print(f"{Fore.CYAN}{Style.BRIGHT}Running Command \"{' '.join(args)}\"{Style.RESET_ALL}")
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
print(Style.RESET_ALL, end="") # makefile in parallel sometimes messes up colors
if p.returncode != 0:
print(f"{Fore.RED}{Style.BRIGHT}Command failed{Style.RESET_ALL}")
print("stdout:")
print(stdout.decode("utf-8"), end="")
print("stderr:")
print(stderr.decode("utf-8"), end="")
failed = True
return False
else:
print(f"{Fore.GREEN}{Style.BRIGHT}Command succeeded{Style.RESET_ALL}")
if always_output:
print("stdout:")
print(stdout.decode("utf-8"), end="")
print("stderr:")
print(stderr.decode("utf-8"), end="")
return True
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 run_test(test_binary, params: Tuple[str]):
global failed
print(f"{Fore.CYAN}{Style.BRIGHT}Running test{Style.RESET_ALL}")
test = subprocess.Popen([test_binary], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
test_stdout, test_stderr = test.communicate()
print(Style.RESET_ALL, end="") # makefile in parallel sometimes messes up colors
if test.returncode != 0:
print(f"[🔴 Test command failed with code {test.returncode}]")
print("stderr:")
print(test_stderr.decode("utf-8"), end="")
print("stdout:")
print(test_stdout.decode("utf-8"), end="")
failed = True
return False
else:
if len(test_stderr) != 0:
print("stderr:")
print(test_stderr.decode("utf-8"), end="")
if output_matches(test_stdout.decode("utf-8"), params):
print(f"{Fore.GREEN}{Style.BRIGHT}Test succeeded{Style.RESET_ALL}")
return True
else:
print(f"{Fore.RED}{Style.BRIGHT}Test failed{Style.RESET_ALL}")
failed = True
return False
def build(matrix):
def build(runner: MatrixRunner):
matrix = runner.current_config()
if platform.system() != "Windows":
args = [
"cmake",
@ -182,9 +136,9 @@ def build(matrix):
]
if matrix['symbols'] == "CPPTRACE_GET_SYMBOLS_WITH_LIBDL":
args.append("-DCPPTRACE_BUILD_TEST_RDYNAMIC=On")
succeeded = run_command(*args)
succeeded = runner.run_command(*args)
if succeeded:
return run_command("make", "-j")
return runner.run_command("make", "-j")
else:
args = [
"cmake",
@ -205,15 +159,16 @@ def build(matrix):
]
if matrix["compiler"] == "g++":
args.append("-GUnix Makefiles")
succeeded = run_command(*args)
succeeded = runner.run_command(*args)
if succeeded:
if matrix["compiler"] == "g++":
return run_command("make", "-j")
return runner.run_command("make", "-j")
else:
return run_command("msbuild", "cpptrace.sln")
return runner.run_command("msbuild", "cpptrace.sln")
return False
def build_full_or_auto(matrix):
def build_full_or_auto(runner: MatrixRunner):
matrix = runner.current_config()
if platform.system() != "Windows":
args = [
"cmake",
@ -232,9 +187,9 @@ def build_full_or_auto(matrix):
]
if matrix["config"] != "":
args.append(f"{matrix['config']}")
succeeded = run_command(*args)
succeeded = runner.run_command(*args)
if succeeded:
return run_command("make", "-j")
return runner.run_command("make", "-j")
else:
args = [
"cmake",
@ -254,52 +209,60 @@ def build_full_or_auto(matrix):
args.append(f"{matrix['config']}")
if matrix["compiler"] == "g++":
args.append("-GUnix Makefiles")
succeeded = run_command(*args)
succeeded = runner.run_command(*args)
if succeeded:
if matrix["compiler"] == "g++":
return run_command("make", "-j")
return runner.run_command("make", "-j")
else:
return run_command("msbuild", "cpptrace.sln")
return runner.run_command("msbuild", "cpptrace.sln")
return False
def test(matrix):
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(matrix):
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(matrix):
print(f"{Fore.BLUE}{Style.BRIGHT}{'=' * 10} Running build and test with config {', '.join(matrix.values())} {'=' * 10}{Style.RESET_ALL}")
def build_and_test(runner: MatrixRunner):
matrix = runner.current_config()
if os.path.exists("build"):
shutil.rmtree("build", ignore_errors=True)
@ -309,16 +272,16 @@ def build_and_test(matrix):
os.chdir("build")
good = False
if build(matrix):
good = test(matrix)
if build(runner):
good = test(runner)
os.chdir("..")
print()
return good
def build_and_test_full_or_auto(matrix):
print(f"{Fore.BLUE}{Style.BRIGHT}{'=' * 10} Running build and test with config {'<auto>' if matrix['config'] == '' else ', '.join(matrix.values())} {'=' * 10}{Style.RESET_ALL}")
def build_and_test_full_or_auto(runner: MatrixRunner):
matrix = runner.current_config()
if os.path.exists("build"):
shutil.rmtree("build", ignore_errors=True)
@ -328,8 +291,8 @@ def build_and_test_full_or_auto(matrix):
os.chdir("build")
good = False
if build_full_or_auto(matrix):
good = test_full_or_auto(matrix)
if build_full_or_auto(runner):
good = test_full_or_auto(runner)
os.chdir("..")
print()
@ -337,162 +300,168 @@ def build_and_test_full_or_auto(matrix):
return good
def run_linux_matrix(compilers: list, shared: bool):
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_matrix(matrix, exclude, build_and_test)
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):
matrix = {
"compiler": compilers,
"target": ["Debug"],
"std": ["11", "20"],
"config": [""],
"shared": ["On" if shared else "Off"]
}
exclude = []
run_matrix(matrix, exclude, build_and_test_full_or_auto)
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):
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_matrix(matrix, exclude, build_and_test)
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):
matrix = {
"compiler": compilers,
"target": ["Debug"],
"std": ["11", "20"],
"config": [""],
"shared": ["On" if shared else "Off"]
}
exclude = []
run_matrix(matrix, exclude, build_and_test_full_or_auto)
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):
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"
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"]
},
{
"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_matrix(matrix, exclude, build_and_test)
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):
matrix = {
"compiler": compilers,
"target": ["Debug"],
"std": ["11", "20"],
"config": [""],
"shared": ["On" if shared else "Off"]
}
exclude = []
run_matrix(matrix, exclude, build_and_test_full_or_auto)
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(
@ -558,9 +527,4 @@ def main():
else:
run_windows_matrix(compilers, args.shared)
global failed
if failed:
print("🔴 Some checks failed")
sys.exit(1)
main()

91
ci/unittest.py Normal file
View File

@ -0,0 +1,91 @@
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
def get_c_compiler_counterpart(compiler: str) -> str:
return compiler.replace("clang++", "clang").replace("g++", "gcc")
def build(runner: MatrixRunner):
if platform.system() != "Windows":
matrix = runner.current_config()
args = [
"cmake",
"..",
"-GNinja",
f"-DCMAKE_CXX_COMPILER={matrix['compiler']}",
f"-DCMAKE_C_COMPILER={get_c_compiler_counterpart(matrix['compiler'])}",
f"-DCMAKE_BUILD_TYPE={matrix['build_type']}",
f"-DBUILD_SHARED_LIBS={matrix['shared']}",
f"-DHAS_DL_FIND_OBJECT={matrix['has_dl_find_object']}",
"-DCPPTRACE_WERROR_BUILD=On",
"-DCPPTRACE_BUILD_TESTING=On",
f"-DCPPTRACE_SANITIZER_BUILD={matrix['sanitizers']}",
f"-DCPPTRACE_BUILD_TESTING_SPLIT_DWARF={matrix['split_dwarf']}",
f"-DCPPTRACE_BUILD_TESTING_SPLIT_DWARF={matrix['dwarf_version']}",
f"-DCPPTRACE_USE_EXTERNAL_LIBDWARF=On",
f"-DCPPTRACE_USE_EXTERNAL_ZSTD=On",
f"-DCPPTRACE_USE_EXTERNAL_GTEST=On",
]
return runner.run_command(*args) and runner.run_command("ninja")
else:
raise ValueError()
def test(runner: MatrixRunner):
if platform.system() != "Windows":
return runner.run_command("./unittest") and runner.run_command("bash", "-c", "exec -a u ./unittest")
else:
raise ValueError()
def build_and_test(runner: MatrixRunner):
# the build directory has to be purged on compiler or shared change
last = runner.last_config()
current = runner.current_config()
if last is None or last["compiler"] != current["compiler"] or last["shared"] != current["shared"]:
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(flush=True)
return good
def run_linux_matrix():
MatrixRunner(
matrix = {
"compiler": ["g++-10", "clang++-14"],
"shared": ["OFF", "ON"],
"build_type": ["Debug", "RelWithDebInfo"],
"sanitizers": ["OFF", "ON"],
"has_dl_find_object": ["OFF", "ON"],
"split_dwarf": ["OFF", "ON"],
"dwarf_version": ["4", "5"],
},
exclude = []
).run(build_and_test)
def main():
if platform.system() == "Linux":
run_linux_matrix()
if platform.system() == "Darwin":
raise ValueError() # run_macos_matrix()
if platform.system() == "Windows":
raise ValueError() # run_windows_matrix()
main()

View File

@ -4,6 +4,7 @@ import itertools
from typing import List
from colorama import Fore, Back, Style
import re
import time
# https://stackoverflow.com/a/14693789/15675011
ansi_escape = re.compile(r'''
@ -18,95 +19,121 @@ ansi_escape = re.compile(r'''
)
''', re.VERBOSE)
def adj_width(text):
return len(text) - len(ansi_escape.sub("", text))
class MatrixRunner:
def __init__(self, matrix, exclude):
self.matrix = matrix
self.exclude = exclude
self.keys = [*matrix.keys()]
self.values = [*matrix.values()]
self.results = {} # insertion-ordered
self.failed = False
self.work = self.get_work()
def do_exclude(matrix_config, exclude):
return all(map(lambda k: matrix_config[k] == exclude[k], exclude.keys()))
self.last_matrix_config = None
self.current_matrix_config = None
def print_table(table):
columns = len(table[0])
column_widths = [1 for _ in range(columns)]
for row in table:
for i, cell in enumerate(row):
column_widths[i] = max(column_widths[i], len(ansi_escape.sub("", cell)))
for j, cell in enumerate(table[0]):
print("| {cell:{width}} ".format(cell=cell, width=column_widths[j] + adj_width(cell)), end="")
print("|")
for i, row in enumerate(table[1:]):
for j, cell in enumerate(row):
print("| {cell:{width}} ".format(cell=cell, width=column_widths[j] + adj_width(cell)), end="")
print("|")
def run_matrix(matrix, exclude, fn):
keys = [*matrix.keys()]
values = [*matrix.values()]
#print("Values:", values)
results = {} # insertion-ordered
for config in itertools.product(*matrix.values()):
#print(config)
matrix_config = {}
for k, v in zip(matrix.keys(), config):
matrix_config[k] = v
#print(matrix_config)
if any(map(lambda ex: do_exclude(matrix_config, ex), exclude)):
continue
def run_command(self, *args: List[str], always_output=False, output_matcher=None) -> bool:
self.log(f"{Fore.CYAN}{Style.BRIGHT}Running Command \"{' '.join(args)}\"{Style.RESET_ALL}")
start_time = time.time()
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
runtime = time.time() - start_time
self.log(Style.RESET_ALL, end="") # makefile in parallel sometimes messes up colors
if p.returncode != 0:
self.log(f"{Fore.RED}{Style.BRIGHT}Command failed{Style.RESET_ALL} {Fore.MAGENTA}(time: {runtime:.2f}s){Style.RESET_ALL}")
self.log("stdout:")
self.log(stdout.decode("utf-8"), end="")
self.log("stderr:")
self.log(stderr.decode("utf-8"), end="")
self.failed = True
return False
else:
config_tuple = tuple(values[i].index(p) for i, p in enumerate(config))
results[config_tuple] = fn(matrix_config)
# Fudged data for testing
#print(config_tuple)
#if "symbols" not in matrix_config:
# results[config_tuple] = matrix_config["compiler"] != "g++-10"
#else:
# results[config_tuple] = not (matrix_config["compiler"] == "clang++-14" and matrix_config["symbols"] == "CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE")
# I had an idea for printing 2d slices of the n-dimensional matrix, but it didn't pan out as much as I'd hoped
dimensions = len(values)
# # Output diagnostic tables
# print("Results:", results)
# if dimensions >= 2:
# for iteraxes in itertools.combinations(range(dimensions), dimensions - 2):
# # iteraxes are the axes we iterate over to slice, these fixed axes are the axes of the table
# # just the complement of axes, these are the two fixed axes
# fixed = [x for x in range(dimensions) if x not in iteraxes]
# assert(len(fixed) == 2)
# if any([len(values[i]) == 1 for i in fixed]):
# continue
# print("Fixed:", fixed)
# for iteraxesvalues in itertools.product(
# *[range(len(values[i])) if i in iteraxes else [-1] for i in range(dimensions)]
# ):
# print(">>", iteraxesvalues)
# # Now that we have our iteraxes values we have a unique plane
# table = [
# ["", *[value for value in values[fixed[0]]]]
# ]
# #print(values[fixed[1]])
# for row_i, row_value in enumerate(values[fixed[1]]):
# row = [row_value]
# for col_i in range(len(values[fixed[0]])):
# iteraxesvaluescopy = [x for x in iteraxesvalues]
# iteraxesvaluescopy[fixed[1]] = row_i
# iteraxesvaluescopy[fixed[0]] = col_i
# #print("----->", iteraxesvaluescopy)
# row.append(
# f"{Fore.GREEN}{Style.BRIGHT}Good{Style.RESET_ALL}"
# if results[tuple(iteraxesvaluescopy)]
# else f"{Fore.RED}{Style.BRIGHT}Bad{Style.RESET_ALL}"
# if tuple(iteraxesvaluescopy) in results else ""
# )
# table.append(row)
# print_table(table)
self.log(f"{Fore.GREEN}{Style.BRIGHT}Command succeeded{Style.RESET_ALL} {Fore.MAGENTA}(time: {runtime:.2f}s){Style.RESET_ALL}")
if always_output:
self.log("stdout:")
self.log(stdout.decode("utf-8"), end="")
self.log("stderr:")
self.log(stderr.decode("utf-8"), end="")
elif len(stderr) != 0:
self.log("stderr:")
self.log(stderr.decode("utf-8"), end="")
if output_matcher is not None:
if not output_matcher(stdout.decode("utf-8")):
self.failed = True
return False
return True
# Better idea would be looking for m<n tuples that are consistently failing and reporting on those
#for fixed_axes in itertools.product(range(dimensions), 2):
# pass
def set_fail(self):
self.failed = True
print("Results:")
table = [keys]
for result in results:
table.append([
f"{Fore.GREEN if results[result] else Fore.RED}{Style.BRIGHT}{values[i][v]}{Style.RESET_ALL}"
for i, v in enumerate(result)
])
print_table(table)
def current_config(self):
return self.current_matrix_config
def last_config(self):
return self.last_matrix_config
def log(self, *args, **kwargs):
print(*args, **kwargs, flush=True)
def do_exclude(self, matrix_config, exclude):
return all(map(lambda k: matrix_config[k] == exclude[k], exclude.keys()))
def assignment_to_matrix_config(self, assignment):
matrix_config = {}
for k, v in zip(self.matrix.keys(), assignment):
matrix_config[k] = v
return matrix_config
def get_work(self):
work = []
for assignment in itertools.product(*self.matrix.values()):
if any(map(lambda ex: self.do_exclude(self.assignment_to_matrix_config(assignment), ex), self.exclude)):
continue
work.append(assignment)
return work
def run(self, fn):
for i, assignment in enumerate(self.work):
matrix_config = self.assignment_to_matrix_config(assignment)
config_tuple = tuple(self.values[i].index(p) for i, p in enumerate(assignment))
config_str = ', '.join(matrix_config.values())
if config_str == "":
self.log(f"{Fore.BLUE}{Style.BRIGHT}{'=' * 10} [{i + 1}/{len(self.work)}] Running with blank config {'=' * 10}{Style.RESET_ALL}")
else:
self.log(f"{Fore.BLUE}{Style.BRIGHT}{'=' * 10} [{i + 1}/{len(self.work)}] Running with config {', '.join(matrix_config.values())} {'=' * 10}{Style.RESET_ALL}")
self.last_matrix_config = self.current_matrix_config
self.current_matrix_config = matrix_config
self.results[config_tuple] = fn(self)
self.print_results()
if self.failed:
self.log("🔴 Some checks failed")
sys.exit(1)
else:
self.log("🟢 All checks passed")
def adj_width(self, text):
return len(text) - len(ansi_escape.sub("", text))
def print_table(self, table):
columns = len(table[0])
column_widths = [1 for _ in range(columns)]
for row in table:
for i, cell in enumerate(row):
column_widths[i] = max(column_widths[i], len(ansi_escape.sub("", cell)))
for j, cell in enumerate(table[0]):
self.log("| {cell:{width}} ".format(cell=cell, width=column_widths[j] + self.adj_width(cell)), end="")
self.log("|")
for i, row in enumerate(table[1:]):
for j, cell in enumerate(row):
self.log("| {cell:{width}} ".format(cell=cell, width=column_widths[j] + self.adj_width(cell)), end="")
self.log("|")
def print_results(self):
self.log("Results:")
table = [self.keys]
for result in self.results:
table.append([
f"{Fore.GREEN if self.results[result] else Fore.RED}{Style.BRIGHT}{self.values[i][v]}{Style.RESET_ALL}"
for i, v in enumerate(result)
])
self.print_table(table)

View File

@ -151,10 +151,26 @@ option(CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH "" OFF)
if(PROJECT_IS_TOP_LEVEL)
option(CPPTRACE_BUILD_TESTING "" OFF)
option(CPPTRACE_BUILD_TESTING_SPLIT_DWARF "" OFF)
set(CPPTRACE_BUILD_TESTING_DWARF_VERSION "0" CACHE STRING "")
option(CPPTRACE_BUILD_TEST_RDYNAMIC "" OFF)
set(CPPTRACE_ZSTD_REPO "https://github.com/facebook/zstd.git" CACHE STRING "")
set(CPPTRACE_ZSTD_TAG "63779c798237346c2b245c546c40b72a5a5913fe" CACHE STRING "") # v1.5.5
set(CPPTRACE_ZSTD_SHALLOW "1" CACHE STRING "")
set(CPPTRACE_LIBDWARF_REPO "https://github.com/jeremy-rifkin/libdwarf-lite.git" CACHE STRING "")
set(CPPTRACE_LIBDWARF_TAG "6dbcc23dba6ffd230063bda4b9d7298bf88d9d41" CACHE STRING "") # v0.10.1
set(CPPTRACE_LIBDWARF_SHALLOW "1" CACHE STRING "")
mark_as_advanced(
CPPTRACE_BUILD_TESTING
CPPTRACE_BUILD_TESTING_SPLIT_DWARF
CPPTRACE_BUILD_TESTING_DWARF_VERSION
CPPTRACE_BUILD_TEST_RDYNAMIC
CPPTRACE_ZSTD_REPO
CPPTRACE_ZSTD_TAG
CPPTRACE_ZSTD_SHALLOW
CPPTRACE_LIBDWARF_REPO
CPPTRACE_LIBDWARF_TAG
CPPTRACE_LIBDWARF_SHALLOW
)
endif()

View File

@ -2,11 +2,22 @@ include(CTest)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(
warning_options
${warning_options} $<$<CXX_COMPILER_ID:GNU>:-Wno-infinite-recursion>
)
macro(add_test_dependencies exec_name)
target_compile_features(${exec_name} PRIVATE cxx_std_11)
target_link_libraries(${exec_name} PRIVATE ${target_name})
target_compile_options(${exec_name} PRIVATE ${warning_options})
target_compile_options(${exec_name} PRIVATE -g)
if(CPPTRACE_BUILD_TESTING_SPLIT_DWARF)
target_compile_options(${exec_name} PRIVATE -gsplit-dwarf)
endif()
if(NOT (CPPTRACE_BUILD_TESTING_DWARF_VERSION STREQUAL "0"))
target_compile_options(${exec_name} PRIVATE -gdwarf-${CPPTRACE_BUILD_TESTING_DWARF_VERSION})
endif()
# Clang has been fast to adopt dwarf 5, other tools (e.g. addr2line from binutils) have not
check_cxx_compiler_flag("-gdwarf-4" HAS_DWARF4)
if(HAS_DWARF4)
@ -32,6 +43,12 @@ if(UNIX)
target_compile_features(signal_demo PRIVATE cxx_std_11)
target_link_libraries(signal_demo PRIVATE ${target_name})
target_compile_options(signal_demo PRIVATE -g)
if(CPPTRACE_BUILD_TESTING_SPLIT_DWARF)
target_compile_options(signal_demo PRIVATE -gsplit-dwarf)
endif()
if(NOT (CPPTRACE_BUILD_TESTING_DWARF_VERSION STREQUAL "0"))
target_compile_options(signal_demo PRIVATE -gdwarf-${CPPTRACE_BUILD_TESTING_DWARF_VERSION})
endif()
add_executable(signal_tracer signal_tracer.cpp)
target_compile_features(signal_tracer PRIVATE cxx_std_11)
@ -65,5 +82,14 @@ if(NOT CPPTRACE_SKIP_UNIT)
target_link_libraries(unittest PRIVATE ${target_name} GTest::gtest_main GTest::gmock_main)
target_compile_options(unittest PRIVATE ${warning_options} $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wno-pedantic -Wno-attributes>)
target_compile_options(unittest PRIVATE -g)
if(CPPTRACE_BUILD_TESTING_SPLIT_DWARF)
target_compile_options(unittest PRIVATE -gsplit-dwarf)
endif()
if(NOT (CPPTRACE_BUILD_TESTING_DWARF_VERSION STREQUAL "0"))
target_compile_options(unittest PRIVATE -gdwarf-${CPPTRACE_BUILD_TESTING_DWARF_VERSION})
endif()
if(CPPTRACE_SANITIZER_BUILD)
target_compile_definitions(unittest PRIVATE CPPTRACE_SANITIZER_BUILD)
endif()
add_test(NAME unittest COMMAND unittest)
endif()

View File

@ -14,7 +14,10 @@ using namespace std::literals;
// Raw trace tests
// This is fickle, however, it's the only way to do it really. It's reasonably reliable test in practice.
// This is fickle, however, it's the only way to do it really. I've gotten it reasonably reliable test in practice.
// Sanitizers do interfere.
#ifndef CPPTRACE_SANITIZER_BUILD
// NOTE: MSVC likes creating trampoline-like entries for non-static functions
CPPTRACE_FORCE_NO_INLINE static void raw_trace_basic() {
@ -165,3 +168,5 @@ TEST(RawTrace, MultipleCalls) {
raw_trace_multi_precise_1();
#endif
}
#endif