diff --git a/.gitignore b/.gitignore
index 4ed68fa53..a7e14dffc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,3 +46,11 @@ cppfront/x64/Debug/microsoft/STL/std.compat.ixx.ifc.dt.module.json.command
 cppfront/x64/Debug/microsoft/STL/std.ixx.ifc.dt.d.json
 cppfront/x64/Debug/microsoft/STL/std.ixx.ifc.dt.module.json
 cppfront/x64/Debug/microsoft/STL/std.ixx.ifc.dt.module.json.command
+
+# Crashes and hangs
+crashes/
+hangs/
+
+# Generated files
+cppfront.exe
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000..c2d89d382
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,45 @@
+#  Copyright 2022-2025 Herb Sutter
+#  SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#  
+#  Part of the Cppfront Project, under the Apache License v2.0 with LLVM Exceptions.
+#  See https://github.com/hsutter/cppfront/blob/main/LICENSE for license information.
+#
+#  This Makefile is strictly optional and is just a convenience for building cppfront.
+#  You can also build cppfront by running the cppfront.cpp source file through your 
+#  C++ compiler in the normal manner.
+
+all: cppfront.exe source/reflect.h include/cpp2regex.h
+
+CXX ?= g++
+CPPFRONT ?= ./cppfront.exe
+CFLAGS ?=
+
+CFLAGS += -Wall -Werror -Wextra -Wpedantic
+
+ifeq (${DEBUG},1)
+CFLAGS += -g
+endif
+ifeq (${RELEASE},1)
+CFLAGS += -O3
+endif
+ifeq (${PROFILE},1)
+CFLAGS += -pg
+endif
+ifeq (${SANITIZE},1)
+CFLAGS += -fsanitize=address -fsanitize=undefined
+endif
+ifeq (${COVERAGE},1)
+CFLAGS += --coverage
+endif
+
+cppfront.exe: source/cppfront.cpp source/common.h source/cpp2regex.h include/cpp2regex.h source/cpp2util.h include/cpp2util.h source/io.h source/lex.h source/parse.h source/reflect.h source/sema.h source/to_cpp1.h
+	${CXX} -std=c++20 -o cppfront.exe -Iinclude ${CFLAGS} source/cppfront.cpp
+
+include/cpp2regex.h: include/cpp2regex.h2
+	${CPPFRONT} include/cpp2regex.h2 -o include/cpp2regex.h
+
+source/reflect.h: source/reflect.h2
+	${CPPFRONT} source/reflect.h2 -o source/reflect.h
+
+clean:
+	rm -f cppfront.exe
diff --git a/regression-tests/run-tests.sh b/regression-tests/run-tests.sh
index 6e3ac81b7..83fc52eb4 100644
--- a/regression-tests/run-tests.sh
+++ b/regression-tests/run-tests.sh
@@ -2,13 +2,15 @@
 
 ################
 usage() {
-    echo "Usage: $0 -c <compiler> [-l <run label>] [-t <tests to run>]"
+    echo "Usage: $0 -c <compiler> [-l <run label>] [-t <tests to run>] [-e <executable>]"
     echo "    -c <compiler>     The compiler to use for the test"
     echo "    -s <cxx_std>      The C++ standard to compile with (e.g. 'c++20', 'c++2b', 'c++latest' depending on the compiler)"
     echo "    -d <stdlib>       Clang-only: the C++ Standard Library to link with ('libstdc++', 'libc++', or 'default' for platform default)"
     echo "    -l <run label>    The label to use in output patch file name"
     echo "    -t <tests to run> Runs only the provided, comma-separated tests (filenames including .cpp2)"
     echo "                      If the argument is not used all tests are run"
+    echo "    -e <executable>   Use the provided cppfront executable for the test"
+    echo "                      If the argument is not used run-tests will build cppfront"
     exit 1
 }
 
@@ -89,7 +91,7 @@ check_file () {
     fi
 }
 
-optstring="c:s:d:l:t:"
+optstring="c:s:d:l:t:e:"
 while getopts ${optstring} arg; do
   case "${arg}" in
     c)
@@ -104,6 +106,9 @@ while getopts ${optstring} arg; do
     l)
         label="${OPTARG}"
         ;;
+    e)
+        executable="${OPTARG}"
+        ;;
     t)
         # Replace commas with spaces
         chosen_tests=${OPTARG//,/ }
@@ -177,7 +182,9 @@ else
             "$compiler_version" == *"g++-13"*
          ]]; then
         exec_out_dir="$expected_results_dir/gcc-13"
-    elif [[ "$compiler_version" == *"g++-14"* ]]; then
+    elif [[ "$compiler_version" == *"g++-14"* ||
+            "$compiler_version" == *"g++ (Ubuntu 14"*
+         ]]; then
         exec_out_dir="$expected_results_dir/gcc-14"
     else
         printf "Unhandled compiler version:\n$compiler_version\n\n"
@@ -250,12 +257,16 @@ else
 fi
 
 ################
-cppfront_cmd="cppfront.exe"
-echo "Building cppfront"
-$compiler_cmd"$cppfront_cmd" ../source/cppfront.cpp
-if [[ $? -ne 0 ]]; then
-    echo "Compilation failed"
-    exit 2
+if [ -z "$executable" ]; then
+    cppfront_cmd="cppfront.exe"
+    echo "Building cppfront"
+    $compiler_cmd"$cppfront_cmd" ../source/cppfront.cpp
+    if [[ $? -ne 0 ]]; then
+        echo "Compilation failed"
+        exit 2
+    fi
+else
+    cppfront_cmd="$executable"
 fi
 
 ################