forked from Vector35/binaryninja-api
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_build_extern.py
105 lines (88 loc) · 3.45 KB
/
test_build_extern.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import argparse
import glob
import os
from pathlib import Path
import platform
import shutil
import subprocess
import sys
import tempfile
from datetime import datetime
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'])
# 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} at {datetime.now()}')
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_PATH={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')