summaryrefslogtreecommitdiff
path: root/scripts/test_build_extern.py
diff options
context:
space:
mode:
authorGlenn Smith <glenn@vector35.com>2022-02-01 16:34:18 -0500
committerGlenn Smith <glenn@vector35.com>2022-02-02 19:22:08 -0500
commitb8af211f9a3647687c7e45c0fd04b0768df87ffe (patch)
tree64f13fe262399189d70aadf33e1c6e33f0a74c3e /scripts/test_build_extern.py
parent5f5785fd2b1cee6bc9a082e1209de00b1497d410 (diff)
Fancier CMake: find scripts, out-of-tree example builds
Diffstat (limited to 'scripts/test_build_extern.py')
-rw-r--r--scripts/test_build_extern.py106
1 files changed, 106 insertions, 0 deletions
diff --git a/scripts/test_build_extern.py b/scripts/test_build_extern.py
new file mode 100644
index 00000000..876b1581
--- /dev/null
+++ b/scripts/test_build_extern.py
@@ -0,0 +1,106 @@
+import argparse
+import glob
+import os
+from pathlib import Path
+import platform
+import shutil
+import subprocess
+import sys
+import tempfile
+
+import argparse
+
+parser = argparse.ArgumentParser(
+ description='Test building the API repo and plugins out-of-tree (for CI checking of end-user workflow)'
+)
+parser.add_argument('--headless', default=False, action='store_true', help='Only include headless plugins')
+parser.add_argument('-j', '--parallel', default=4, help='Number of parallel jobs to tell cmake to run.')
+args = parser.parse_args()
+
+try:
+ # Make sure we have clang!
+ subprocess.check_call(['clang', '-v'])
+except subprocess.SubprocessError as e:
+ print("Clang not found! Please install clang and add it to PATH")
+ sys.exit(1)
+
+if not args.headless:
+ try:
+ # Also Qt
+ subprocess.check_call(['qmake', '--version'])
+ except subprocess.SubprocessError as e:
+ print("qmake not found! Please install Qt and add it to PATH")
+ sys.exit(1)
+
+api_base = Path(__file__).parent.parent.absolute()
+
+configure_args = []
+build_args = []
+configure_env = os.environ.copy()
+
+if platform.system() == "Windows":
+ configure_env['CXXFLAGS'] = f'/MP{args.parallel}'
+ configure_env['CFLAGS'] = f'/MP{args.parallel}'
+else:
+ build_args.extend(['-j', str(args.parallel)])
+
+if args.headless:
+ configure_args.extend(['-DHEADLESS=1'])
+else:
+ configure_args.extend(['-DQT6=1', ])
+
+# Copy api out of the source tree and build it externally
+with tempfile.TemporaryDirectory() as tempdir:
+ temp_api_base = Path(tempdir) / 'binaryninjaapi'
+ print(f'Copy {api_base} => {temp_api_base}')
+ shutil.copytree(api_base, temp_api_base)
+
+ # Clean up dirty repo
+ if (temp_api_base / 'build').exists():
+ shutil.rmtree(temp_api_base / 'build')
+
+ # Now try to build
+ try:
+ subprocess.check_call(['cmake', '-B', 'build'] + configure_args, cwd=temp_api_base, env=configure_env)
+ subprocess.check_call(['cmake', '--build', 'build'] + build_args, cwd=temp_api_base)
+ finally:
+ if (temp_api_base / 'build').exists():
+ shutil.rmtree(temp_api_base / 'build')
+
+ # Now try to build examples (in-tree)
+ try:
+ subprocess.check_call(['cmake', '-B', 'build', '-DBN_API_BUILD_EXAMPLES=1'] + configure_args, cwd=temp_api_base,
+ env=configure_env)
+ subprocess.check_call(['cmake', '--build', 'build'] + build_args, cwd=temp_api_base)
+ finally:
+ if (temp_api_base / 'build').exists():
+ shutil.rmtree(temp_api_base / 'build')
+
+ # Now try to build examples (out-of-tree)
+ for f in glob.glob(str(api_base / 'examples' / '**' / 'CMakeLists.txt'), recursive=True):
+ example_base = Path(f).parent
+ if example_base == api_base / 'examples':
+ continue
+
+ # Check for headless
+ if args.headless:
+ with open(f, 'r') as cmake_file:
+ # Assume any ui plugin has 'binaryninjaui' in its contents
+ if 'binaryninjaui' in cmake_file.read():
+ continue
+
+ with tempfile.TemporaryDirectory() as tempexdir:
+ temp_example_base = Path(tempexdir) / example_base.name
+ print(f'Copy {example_base} => {temp_example_base}')
+ shutil.copytree(example_base, temp_example_base)
+
+ if (temp_example_base / 'build').exists():
+ shutil.rmtree(temp_example_base / 'build')
+
+ try:
+ subprocess.check_call(['cmake', '-B', 'build', f'-DBN_API_DIR={temp_api_base}'] + configure_args,
+ cwd=temp_example_base, env=configure_env)
+ subprocess.check_call(['cmake', '--build', 'build'] + build_args, cwd=temp_example_base)
+ finally:
+ if (temp_example_base / 'build').exists():
+ shutil.rmtree(temp_example_base / 'build')