forked from radareorg/radare2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
meson.py
executable file
·308 lines (276 loc) · 10.7 KB
/
meson.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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
#!/usr/bin/env python
"""Meson build for radare2"""
import argparse
import glob
import logging
import os
import re
import shutil
import subprocess
import sys
BUILDDIR = 'build'
BACKENDS = ['ninja', 'vs2015', 'vs2017', 'vs2019']
PATH_FMT = {}
R2_PATH = {
'R2_LIBDIR': r'lib',
'R2_INCDIR': r'include',
'R2_DATDIR': r'share',
'R2_WWWROOT': r'{R2_DATDIR}\www',
'R2_SDB': r'{R2_DATDIR}',
'R2_ZIGNS': r'{R2_DATDIR}\zigns',
'R2_THEMES': r'{R2_DATDIR}\cons',
'R2_FORTUNES': r'{R2_DATDIR}\doc',
'R2_FLAGS': r'{R2_DATDIR}\flag',
'R2_HUD': r'{R2_DATDIR}\hud'
}
MESON = None
ROOT = None
log = None
def set_global_variables():
"""[R_API] Set global variables"""
global log
global ROOT
global MESON
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))
logging.basicConfig(format='[%(name)s][%(levelname)s]: %(message)s',
level=logging.DEBUG)
log = logging.getLogger('r2-meson')
with open(os.path.join(ROOT, 'configure.acr')) as f:
f.readline()
version = f.readline().split()[1].rstrip()
if os.name == 'nt':
meson = os.path.join(os.path.dirname(sys.executable), 'Scripts', 'meson.exe')
if os.path.exists(meson):
MESON = [meson]
else:
meson = os.path.join(os.path.dirname(sys.executable), 'Scripts', 'meson.py')
MESON = [sys.executable, meson]
else:
MESON = ['meson']
PATH_FMT['ROOT'] = ROOT
PATH_FMT['R2_VERSION'] = version
log.debug('Root: %s', ROOT)
log.debug('Meson: %s', MESON)
log.debug('Version: %s', version)
def meson(command, rootdir=None, builddir=None, prefix=None, backend=None,
release=False, shared=None, *, options=[]):
"""[R_API] Invoke meson"""
cmd = MESON + [command]
if rootdir:
cmd.append(rootdir)
if builddir:
cmd.append(builddir)
if prefix:
cmd.append('--prefix={}'.format(prefix))
if backend:
cmd.append('--backend={}'.format(backend))
if release:
cmd.append('--buildtype=release')
if shared != None:
cmd.append('--default-library={}'.format('shared' if shared else 'static'))
if options:
cmd.extend(options)
log.debug('Invoking meson: %s', cmd)
ret = subprocess.call(cmd)
if ret != 0:
log.error('Meson error. Exiting.')
sys.exit(1)
def ninja(folder, *targets):
"""[R_API] Invoke ninja"""
command = ['ninja', '-C', folder]
if targets:
command.extend(targets)
log.debug('Invoking ninja: %s', command)
ret = subprocess.call(command)
if ret != 0:
log.error('Ninja error. Exiting.')
sys.exit(1)
def msbuild(project, *params):
"""[R_API] Invoke MSbuild"""
command = ['msbuild', project]
if params:
command.extend(params)
log.info('Invoking MSbuild: %s', command)
ret = subprocess.call(command)
if ret != 0:
log.error('MSbuild error. Exiting.')
sys.exit(1)
def copytree(src, dst, exclude=()):
src = src.format(**PATH_FMT)
dst = dst.format(**PATH_FMT).format(**PATH_FMT)
log.debug('copytree "%s" -> "%s"', src, dst)
shutil.copytree(src, dst, ignore=shutil.ignore_patterns(*exclude) if exclude else None)
def move(src, dst):
src = src.format(**PATH_FMT)
dst = dst.format(**PATH_FMT).format(**PATH_FMT)
term = os.path.sep if os.path.isdir(dst) else ''
log.debug('move "%s" -> "%s%s"', src, dst, term)
for file in glob.iglob(src):
shutil.move(file, dst)
def copy(src, dst):
src = src.format(**PATH_FMT)
dst = dst.format(**PATH_FMT).format(**PATH_FMT)
term = os.path.sep if os.path.isdir(dst) else ''
log.debug('copy "%s" -> "%s%s"', src, dst, term)
for file in glob.iglob(src, recursive='**' in src):
shutil.copy2(file, dst)
def makedirs(path):
path = path.format(**PATH_FMT).format(**PATH_FMT)
log.debug('makedirs "%s"', path)
os.makedirs(path)
def xp_compat(builddir):
log.info('Running XP compat script')
with open(os.path.join(builddir, 'REGEN.vcxproj'), 'r') as f:
version = re.search('<PlatformToolset>(.*)</PlatformToolset>', f.read()).group(1)
if version.endswith('_xp'):
log.info('Skipping %s', builddir)
return
log.debug('Translating from %s to %s_xp', version, version)
newversion = version+'_xp'
for f in glob.iglob(os.path.join(builddir, '**', '*.vcxproj'), recursive=True):
with open(f, 'r') as proj:
c = proj.read()
c = c.replace(version, newversion)
with open(f, 'w') as proj:
proj.write(c)
log.debug("%s .. OK", f)
def build(args):
""" Build radare2 """
log.info('Building radare2')
r2_builddir = os.path.join(ROOT, args.dir)
options = ['-D%s' % x for x in args.options]
if args.webui:
options.append('-Duse_webui=true')
if args.local:
options.append('-Dlocal=true')
if args.fuzz:
options.append('-Denable_libfuzzer=true')
if not os.path.exists(r2_builddir):
meson('setup', builddir=r2_builddir, prefix=args.prefix, backend=args.backend,
release=args.release, shared=args.shared, options=options)
if args.backend != 'ninja':
# XP support was dropped in Visual Studio 2019 v142 platform
if args.backend == 'vs2017' and args.xp:
xp_compat(r2_builddir)
if not args.project:
project = os.path.join(r2_builddir, 'radare2.sln')
params = ['/m', '/clp:Summary;Verbosity=minimal']
if args.backend == 'vs2017' and args.xp:
params.append('/p:XPDeprecationWarning=false')
msbuild(project, *params)
else:
ninja(r2_builddir)
def install(args):
""" Install radare2 """
meson('install', options=['-C', '{}'.format(args.dir), '--no-rebuild'])
def main():
# Create logger and get applications paths
set_global_variables()
# Create parser
parser = argparse.ArgumentParser(description='Mesonbuild scripts for radare2')
# --sanitize=address,signed-integer-overflow for faster build
parser.add_argument('--sanitize', nargs='?',
const='address,undefined,signed-integer-overflow', metavar='sanitizers',
help='Build radare2 with sanitizer support (default: %(const)s)')
parser.add_argument('--fuzz', action='store_true',
help='Build radare2 with libFuzzer support')
parser.add_argument('--project', action='store_true',
help='Create a visual studio project and do not build.')
parser.add_argument('--release', action='store_true',
help='Set the build as Release (remove debug info)')
parser.add_argument('--backend', choices=BACKENDS, default='ninja',
help='Choose build backend (default: %(default)s)')
parser.add_argument('--shared', action='store_true',
help='Link dynamically (shared library) rather than statically')
parser.add_argument('--local', action='store_true',
help='Adds support for local/side-by-side installation (sets rpath if needed)')
parser.add_argument('--prefix', default=None,
help='Set project installation prefix')
parser.add_argument('--dir', default=BUILDDIR, required=False,
help='Destination build directory (default: %(default)s)')
parser.add_argument('--alias', action='store_true',
help='Show the "m" alias shell command')
parser.add_argument('--xp', action='store_true',
help='Adds support for Windows XP')
parser.add_argument('--pull', action='store_true',
help='git pull before building')
parser.add_argument('--nosudo', action='store_true',
help='Do not use sudo for install/symstall/uninstall')
parser.add_argument('--uninstall', action='store_true',
help='Uninstall')
parser.add_argument('--symstall', action='store_true',
help='Install using symlinks')
parser.add_argument('--webui', action='store_true',
help='Install WebUIs')
parser.add_argument('--install', action='store_true',
help='Install radare2 after building')
parser.add_argument('--options', nargs='*', default=[])
args = parser.parse_args()
if args.alias:
print("alias m=\"" + os.path.abspath(__file__) + "\"")
sys.exit(0);
if args.sanitize:
if os.uname().sysname == 'OpenBSD':
log.error("Sanitizers unsupported under OpenBSD")
sys.exit(1)
sanitizers = args.sanitize
if args.fuzz and 'fuzzer' not in sanitizers:
sanitizers = "fuzzer," + sanitizers
cflags = os.environ.get('CFLAGS')
if not cflags:
cflags = ''
os.environ['CFLAGS'] = cflags + ' -fsanitize=' + sanitizers
if os.uname().sysname != 'Darwin':
ldflags = os.environ.get('LDFLAGS')
if not ldflags:
ldflags = ''
os.environ['LDFLAGS'] = ldflags + ' -fsanitize=' + sanitizers
# Check arguments
if args.pull:
# Attempt to update from an existing remote
upstream_remote = subprocess.check_output(["git", "remote", "-v"]).decode()
try:
remote = re.search(r'(.*?)\t.*radareorg/radare2 \(fetch\)', upstream_remote).group(1)
except AttributeError: # If search misses, None.group() throws this
remote = 'https://github.com/radareorg/radare2'
os.system(f'git pull {remote} master')
if args.project and args.backend == 'ninja':
log.error('--project is not compatible with --backend ninja')
sys.exit(1)
if args.xp and args.backend in 'ninja':
log.error('--xp is not compatible with --backend ninja')
sys.exit(1)
if args.xp and args.backend in 'vs2019':
log.error('--xp is not compatible with --backend vs2019')
sys.exit(1)
if not args.prefix:
args.prefix = os.path.join(ROOT, args.dir, 'priv_install_dir')
else:
args.prefix = os.path.abspath(args.prefix)
for option in args.options:
if '=' not in option:
log.error('Invalid option: %s', option)
sys.exit(1)
key, value = option.split('=', 1)
key = key.upper()
if key not in R2_PATH:
continue
if os.path.isabs(value):
log.error('Relative path is required: %s', option)
sys.exit(1)
R2_PATH[key] = os.path.normpath(value)
PATH_FMT.update(R2_PATH)
sudo = 'sudo '
if args.nosudo:
sudo = ''
# Build it!
log.debug('Arguments: %s', args)
build(args)
if args.uninstall:
os.system(sudo + 'make uninstall PWD="$PWD/build" BTOP="$PWD/build/binr"')
if args.install:
install(args)
if args.symstall:
os.system(sudo + 'make symstall PWD="$PWD/build" BTOP="$PWD/build/binr"')
if __name__ == '__main__':
main()