comparison mx.truffle/mx_truffle.py @ 21961:e61e89bd867a

rename mx to mx.truffle
author Mick Jordan <mick.jordan@oracle.com>
date Fri, 19 Jun 2015 12:22:49 -0700
parents mx/mx_truffle.py@ef8c90391f1e
children 1ecffe20e460
comparison
equal deleted inserted replaced
21960:a88981c5ce8b 21961:e61e89bd867a
1 #
2 # commands.py - the GraalVM specific commands
3 #
4 # ----------------------------------------------------------------------------------------------------
5 #
6 # Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
7 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 #
9 # This code is free software; you can redistribute it and/or modify it
10 # under the terms of the GNU General Public License version 2 only, as
11 # published by the Free Software Foundation.
12 #
13 # This code is distributed in the hope that it will be useful, but WITHOUT
14 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 # version 2 for more details (a copy is included in the LICENSE file that
17 # accompanied this code).
18 #
19 # You should have received a copy of the GNU General Public License version
20 # 2 along with this work; if not, write to the Free Software Foundation,
21 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22 #
23 # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
24 # or visit www.oracle.com if you need additional information or have any
25 # questions.
26 #
27 # ----------------------------------------------------------------------------------------------------
28
29 import os, stat, errno, sys, shutil, zipfile, tarfile, tempfile, re, time, datetime, platform, subprocess, StringIO, socket
30 from os.path import join, exists, dirname, basename
31 from argparse import ArgumentParser, RawDescriptionHelpFormatter, REMAINDER
32 from outputparser import OutputParser, ValuesMatcher
33 import mx
34 import xml.dom.minidom
35 import itertools
36 import json, textwrap
37 import fnmatch
38
39 # This works because when mx loads this file, it makes sure __file__ gets an absolute path
40 _graal_home = dirname(dirname(__file__))
41
42 """ The VM that will be run by the 'vm' command and built by default by the 'build' command.
43 This can be set via the global '--vm' option or the DEFAULT_VM environment variable.
44 It can also be temporarily set by using of a VM context manager object in a 'with' statement. """
45 _vm = None
46
47 _make_eclipse_launch = False
48
49 _minVersion = mx.VersionSpec('1.7')
50
51 # max version (first _unsupported_ version)
52 _untilVersion = None
53
54 class JDKDeployedDist:
55 def __init__(self, name, isExtension=False, usesJVMCIClassLoader=False, partOfHotSpot=False):
56 self.name = name
57 self.isExtension = isExtension
58 self.usesJVMCIClassLoader = usesJVMCIClassLoader
59 self.partOfHotSpot = partOfHotSpot # true when this distribution is delivered with HotSpot
60
61 _jdkDeployedDists = [
62 JDKDeployedDist('TRUFFLE'),
63 ]
64
65 JDK_UNIX_PERMISSIONS_DIR = 0755
66 JDK_UNIX_PERMISSIONS_FILE = 0644
67 JDK_UNIX_PERMISSIONS_EXEC = 0755
68
69 def isVMSupported(vm):
70 if 'client' == vm and len(platform.mac_ver()[0]) != 0:
71 # Client VM not supported: java launcher on Mac OS X translates '-client' to '-server'
72 return False
73 return True
74
75 def _get_vm():
76 """
77 Gets the configured VM, presenting a dialogue if there is no currently configured VM.
78 """
79 global _vm
80 if _vm:
81 return _vm
82 vm = mx.get_env('DEFAULT_VM')
83 if vm is None:
84 extras = mx.get_env('EXTRA_JAVA_HOMES')
85 if not extras is None:
86 for e in extras.split(':'):
87 vm = e
88 break
89 envPath = join(_graal_home, 'mx', 'env')
90 if vm and 'graal' in vm:
91 if exists(envPath):
92 with open(envPath) as fp:
93 if 'DEFAULT_VM=' + vm in fp.read():
94 mx.log('Please update the DEFAULT_VM value in ' + envPath + ' to replace "graal" with "jvmci"')
95 vm = vm.replace('graal', 'jvmci')
96 if vm is None:
97 mx.abort('Need to specify VM with --vm option or DEFAULT_VM environment variable')
98 _vm = vm
99 return vm
100
101 def chmodRecursive(dirname, chmodFlagsDir):
102 if mx.get_os() == 'windows':
103 return
104
105 def _chmodDir(chmodFlags, dirname, fnames):
106 os.chmod(dirname, chmodFlagsDir)
107
108 os.path.walk(dirname, _chmodDir, chmodFlagsDir)
109
110 def clean(args):
111 """clean the source tree"""
112 opts = mx.clean(args, parser=ArgumentParser(prog='mx clean'))
113
114 if opts.native:
115 def handleRemoveReadonly(func, path, exc):
116 excvalue = exc[1]
117 if mx.get_os() == 'windows' and func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
118 os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) # 0777
119 func(path)
120 else:
121 raise
122
123 def rmIfExists(name):
124 if os.path.isdir(name):
125 shutil.rmtree(name, ignore_errors=False, onerror=handleRemoveReadonly)
126 elif os.path.isfile(name):
127 os.unlink(name)
128
129 rmIfExists(join(_graal_home, 'build'))
130 rmIfExists(join(_graal_home, 'build-nojvmci'))
131
132 def export(args):
133 """create archives of builds split by vmbuild and vm"""
134
135 parser = ArgumentParser(prog='mx export')
136 args = parser.parse_args(args)
137
138 # collect data about export
139 infos = dict()
140 infos['timestamp'] = time.time()
141
142 hgcfg = mx.HgConfig()
143 hgcfg.check()
144 infos['revision'] = hgcfg.tip('.') + ('+' if hgcfg.isDirty('.') else '')
145 # TODO: infos['repository']
146
147 infos['jdkversion'] = str(mx.java().version)
148
149 infos['architecture'] = mx.get_arch()
150 infos['platform'] = mx.get_os()
151
152 if mx.get_os != 'windows':
153 pass
154 # infos['ccompiler']
155 # infos['linker']
156
157 infos['hostname'] = socket.gethostname()
158
159 def _writeJson(suffix, properties):
160 d = infos.copy()
161 for k, v in properties.iteritems():
162 assert not d.has_key(k)
163 d[k] = v
164
165 jsonFileName = 'export-' + suffix + '.json'
166 with open(jsonFileName, 'w') as f:
167 print >> f, json.dumps(d)
168 return jsonFileName
169
170
171 def _genFileName(archivtype, middle):
172 idPrefix = infos['revision'] + '_'
173 idSuffix = '.tar.gz'
174 return join(_graal_home, "graalvm_" + archivtype + "_" + idPrefix + middle + idSuffix)
175
176 # graal directory
177 graalDirTarName = _genFileName('classfiles', 'javac')
178 mx.logv("creating graal " + graalDirTarName)
179 with tarfile.open(graalDirTarName, 'w:gz') as tar:
180 for root, _, files in os.walk("graal"):
181 for f in [f for f in files if not f.endswith('.java')]:
182 name = join(root, f)
183 # print name
184 tar.add(name, name)
185
186 n = _writeJson("graal", {'javacompiler' : 'javac'})
187 tar.add(n, n)
188
189
190 def _run_benchmark(args, availableBenchmarks, runBenchmark):
191
192 vmOpts, benchmarksAndOptions = _extract_VM_args(args, useDoubleDash=availableBenchmarks is None)
193
194 if availableBenchmarks is None:
195 harnessArgs = benchmarksAndOptions
196 return runBenchmark(None, harnessArgs, vmOpts)
197
198 if len(benchmarksAndOptions) == 0:
199 mx.abort('at least one benchmark name or "all" must be specified')
200 benchmarks = list(itertools.takewhile(lambda x: not x.startswith('-'), benchmarksAndOptions))
201 harnessArgs = benchmarksAndOptions[len(benchmarks):]
202
203 if 'all' in benchmarks:
204 benchmarks = availableBenchmarks
205 else:
206 for bm in benchmarks:
207 if bm not in availableBenchmarks:
208 mx.abort('unknown benchmark: ' + bm + '\nselect one of: ' + str(availableBenchmarks))
209
210 failed = []
211 for bm in benchmarks:
212 if not runBenchmark(bm, harnessArgs, vmOpts):
213 failed.append(bm)
214
215 if len(failed) != 0:
216 mx.abort('Benchmark failures: ' + str(failed))
217
218 def _vmLibDirInJdk(jdk):
219 """
220 Get the directory within a JDK where the server and client
221 subdirectories are located.
222 """
223 mxos = mx.get_os()
224 if mxos == 'darwin':
225 return join(jdk, 'jre', 'lib')
226 if mxos == 'windows' or mxos == 'cygwin':
227 return join(jdk, 'jre', 'bin')
228 return join(jdk, 'jre', 'lib', mx.get_arch())
229
230 def _vmJliLibDirs(jdk):
231 """
232 Get the directories within a JDK where the jli library designates to.
233 """
234 mxos = mx.get_os()
235 if mxos == 'darwin':
236 return [join(jdk, 'jre', 'lib', 'jli')]
237 if mxos == 'windows' or mxos == 'cygwin':
238 return [join(jdk, 'jre', 'bin'), join(jdk, 'bin')]
239 return [join(jdk, 'jre', 'lib', mx.get_arch(), 'jli'), join(jdk, 'lib', mx.get_arch(), 'jli')]
240
241 def _vmCfgInJdk(jdk, jvmCfgFile='jvm.cfg'):
242 """
243 Get the jvm.cfg file.
244 """
245 mxos = mx.get_os()
246 if mxos == "windows" or mxos == "cygwin":
247 return join(jdk, 'jre', 'lib', mx.get_arch(), jvmCfgFile)
248 return join(_vmLibDirInJdk(jdk), jvmCfgFile)
249
250 def _jdksDir():
251 return os.path.abspath(join(_graal_home, 'jdk' + str(mx.java().version)))
252
253 def _handle_missing_VM(bld, vm=None):
254 if not vm:
255 vm = _get_vm()
256 mx.log('The ' + bld + ' ' + vm + ' VM has not been created')
257 mx.abort('You need to run "mx --javahome ' + vm + ' use the selected VM')
258
259 def _jdk(build=None, vmToCheck=None, create=False, installJars=True):
260 """
261 Get the JDK into which Graal is installed, creating it first if necessary.
262 """
263 jdk = join(_jdksDir(), build)
264 if create:
265 srcJdk = mx.java().jdk
266 if not exists(jdk):
267 mx.log('Creating ' + jdk + ' from ' + srcJdk)
268 shutil.copytree(srcJdk, jdk)
269
270 # Make a copy of the default VM so that this JDK can be
271 # reliably used as the bootstrap for a HotSpot build.
272 jvmCfg = _vmCfgInJdk(jdk)
273 if not exists(jvmCfg):
274 mx.abort(jvmCfg + ' does not exist')
275
276 defaultVM = None
277 jvmCfgLines = []
278 with open(jvmCfg) as f:
279 for line in f:
280 if line.startswith('-') and defaultVM is None:
281 parts = line.split()
282 if len(parts) == 2:
283 assert parts[1] == 'KNOWN', parts[1]
284 defaultVM = parts[0][1:]
285 jvmCfgLines += ['# default VM is a copy of the unmodified ' + defaultVM + ' VM\n']
286 jvmCfgLines += ['-original KNOWN\n']
287 else:
288 # skip lines which we cannot parse (e.g. '-hotspot ALIASED_TO -client')
289 mx.log("WARNING: skipping not parsable line \"" + line + "\"")
290 else:
291 jvmCfgLines += [line]
292
293 assert defaultVM is not None, 'Could not find default VM in ' + jvmCfg
294 chmodRecursive(jdk, JDK_UNIX_PERMISSIONS_DIR)
295 shutil.move(join(_vmLibDirInJdk(jdk), defaultVM), join(_vmLibDirInJdk(jdk), 'original'))
296
297 if mx.get_os() != 'windows':
298 os.chmod(jvmCfg, JDK_UNIX_PERMISSIONS_FILE)
299 with open(jvmCfg, 'w') as fp:
300 for line in jvmCfgLines:
301 fp.write(line)
302
303 # patch 'release' file (append graalvm revision)
304 releaseFile = join(jdk, 'release')
305 if exists(releaseFile):
306 releaseFileLines = []
307 with open(releaseFile) as f:
308 for line in f:
309 releaseFileLines.append(line)
310
311 if mx.get_os() != 'windows':
312 os.chmod(releaseFile, JDK_UNIX_PERMISSIONS_FILE)
313 with open(releaseFile, 'w') as fp:
314 for line in releaseFileLines:
315 if line.startswith("SOURCE="):
316 try:
317 sourceLine = line[0:-2] # remove last char
318 hgcfg = mx.HgConfig()
319 hgcfg.check()
320 revision = hgcfg.tip('.')[:12] # take first 12 chars
321 fp.write(sourceLine + ' graal:' + revision + '\"\n')
322 except:
323 fp.write(line)
324 else:
325 fp.write(line)
326
327 # Install a copy of the disassembler library
328 try:
329 hsdis([], copyToDir=_vmLibDirInJdk(jdk))
330 except SystemExit:
331 pass
332 else:
333 if not exists(jdk):
334 _handle_missing_VM(build, vmToCheck)
335
336 if installJars:
337 for jdkDist in _jdkDeployedDists:
338 dist = mx.distribution(jdkDist.name)
339 if exists(dist.path) and jdkDist.partOfHotSpot:
340 _installDistInJdks(jdkDist)
341
342 return jdk
343
344 def _updateInstalledJVMCIOptionsFile(jdk):
345 jvmciOptions = join(_graal_home, 'jvmci.options')
346 jreLibDir = join(jdk, 'jre', 'lib')
347 if exists(jvmciOptions):
348 shutil.copy(jvmciOptions, join(jreLibDir, 'jvmci.options'))
349 else:
350 toDelete = join(jreLibDir, 'jvmci.options')
351 if exists(toDelete):
352 os.unlink(toDelete)
353
354 def _makeHotspotGeneratedSourcesDir():
355 """
356 Gets the directory containing all the HotSpot sources generated from
357 JVMCI Java sources. This directory will be created if it doesn't yet exist.
358 """
359 hsSrcGenDir = join(mx.project('com.oracle.jvmci.hotspot').source_gen_dir(), 'hotspot')
360 if not exists(hsSrcGenDir):
361 os.makedirs(hsSrcGenDir)
362 return hsSrcGenDir
363
364 def _copyToJdk(src, dst, permissions=JDK_UNIX_PERMISSIONS_FILE):
365 name = os.path.basename(src)
366 dstLib = join(dst, name)
367 if mx.get_env('SYMLINK_GRAAL_JAR', None) == 'true':
368 # Using symlinks is much faster than copying but may
369 # cause issues if the lib is being updated while
370 # the VM is running.
371 if not os.path.islink(dstLib) or not os.path.realpath(dstLib) == src:
372 if exists(dstLib):
373 os.remove(dstLib)
374 os.symlink(src, dstLib)
375 else:
376 # do a copy and then a move to get atomic updating (on Unix)
377 fd, tmp = tempfile.mkstemp(suffix='', prefix=name, dir=dst)
378 shutil.copyfile(src, tmp)
379 os.close(fd)
380 shutil.move(tmp, dstLib)
381 os.chmod(dstLib, permissions)
382
383 def _filterJVMCIServices(servicesMap, classpath):
384 """
385 Filters and returns the names in 'serviceImplNames' that denote
386 types available in 'classpath' implementing or extending
387 com.oracle.jvmci.service.Service.
388 """
389 _, binDir = mx._compile_mx_class('FilterTypes', os.pathsep.join(classpath), myDir=dirname(__file__))
390 serialized = [k + '=' + ','.join(v) for k, v in servicesMap.iteritems()]
391 cmd = [mx.java().java, '-cp', mx._cygpathU2W(os.pathsep.join([binDir] + classpath)), 'FilterTypes', 'com.oracle.jvmci.service.Service'] + serialized
392 serialized = subprocess.check_output(cmd)
393 if len(serialized) == 0:
394 return {}
395 servicesMap = {}
396 for e in serialized.split(' '):
397 k, v = e.split('=')
398 impls = v.split(',')
399 servicesMap[k] = impls
400 return servicesMap
401
402 def _extractJVMCIFiles(jdkJars, jvmciJars, servicesDir, optionsDir, cleanDestination=True):
403 if cleanDestination:
404 if exists(servicesDir):
405 shutil.rmtree(servicesDir)
406 if exists(optionsDir):
407 shutil.rmtree(optionsDir)
408 if not exists(servicesDir):
409 os.makedirs(servicesDir)
410 if not exists(optionsDir):
411 os.makedirs(optionsDir)
412 servicesMap = {}
413 optionsFiles = []
414 for jar in jvmciJars:
415 if os.path.isfile(jar):
416 with zipfile.ZipFile(jar) as zf:
417 for member in zf.namelist():
418 if member.startswith('META-INF/services') and member:
419 serviceName = basename(member)
420 if serviceName == "":
421 continue # Zip files may contain empty entries for directories (jar -cf ... creates such)
422 # we don't handle directories
423 assert serviceName and member == 'META-INF/services/' + serviceName
424 with zf.open(member) as serviceFile:
425 serviceImpls = servicesMap.setdefault(serviceName, [])
426 for line in serviceFile.readlines():
427 line = line.strip()
428 if line:
429 serviceImpls.append(line)
430 elif member.startswith('META-INF/options'):
431 filename = basename(member)
432 if filename == "":
433 continue # Zip files may contain empty entries for directories (jar -cf ... creates such)
434 # we don't handle directories
435 assert filename and member == 'META-INF/options/' + filename
436 targetpath = join(optionsDir, filename)
437 optionsFiles.append(filename)
438 with zf.open(member) as optionsFile, \
439 file(targetpath, "wb") as target:
440 shutil.copyfileobj(optionsFile, target)
441 servicesMap = _filterJVMCIServices(servicesMap, jdkJars)
442 for serviceName, serviceImpls in servicesMap.iteritems():
443 fd, tmp = tempfile.mkstemp(prefix=serviceName)
444 f = os.fdopen(fd, 'w+')
445 for serviceImpl in serviceImpls:
446 f.write(serviceImpl + os.linesep)
447 target = join(servicesDir, serviceName)
448 f.close()
449 shutil.move(tmp, target)
450 if mx.get_os() != 'windows':
451 os.chmod(target, JDK_UNIX_PERMISSIONS_FILE)
452
453 def _updateJVMCIFiles(jdkDir):
454 jreJVMCIDir = join(jdkDir, 'jre', 'lib', 'jvmci')
455 jvmciJars = [join(jreJVMCIDir, e) for e in os.listdir(jreJVMCIDir) if e.endswith('.jar')]
456 jreJVMCIServicesDir = join(jreJVMCIDir, 'services')
457 jreJVMCIOptionsDir = join(jreJVMCIDir, 'options')
458 _extractJVMCIFiles(_getJdkDeployedJars(jdkDir), jvmciJars, jreJVMCIServicesDir, jreJVMCIOptionsDir)
459
460 def _patchGraalVersionConstant(dist):
461 """
462 Patches the constant "@@@@@@@@@@@@@@@@graal.version@@@@@@@@@@@@@@@@" in the constant pool of Graal.class
463 with the computed Graal version string.
464 """
465 zf = zipfile.ZipFile(dist.path, 'r')
466 graalClassfilePath = 'com/oracle/graal/api/runtime/Graal.class'
467 try:
468 graalClassfile = zf.read(graalClassfilePath)
469 except KeyError:
470 mx.log(graalClassfilePath + ' is not present in ' + dist.path)
471 return
472 placeholder = '@@@@@@@@@@@@@@@@graal.version@@@@@@@@@@@@@@@@'
473 placeholderLen = len(placeholder)
474 versionSpec = '{:' + str(placeholderLen) + '}'
475 versionStr = versionSpec.format(graal_version())
476
477 if len(versionStr) > placeholderLen:
478 # Truncate the version string if necessary
479 assert versionStr.startswith('unknown'), versionStr
480 versionStr = versionStr[:placeholderLen]
481 if placeholder not in graalClassfile:
482 assert versionStr in graalClassfile, 'could not find "' + placeholder + '" or "' + versionStr + '" constant in ' + dist.path + '!' + graalClassfilePath
483 zf.close()
484 return False
485
486 zfOutFd, zfOutPath = tempfile.mkstemp(suffix='', prefix=basename(dist.path) + '.', dir=dirname(dist.path))
487 zfOut = zipfile.ZipFile(zfOutPath, 'w')
488 for zi in zf.infolist():
489 if zi.filename == graalClassfilePath:
490 data = graalClassfile.replace(placeholder, versionStr)
491 else:
492 data = zf.read(zi)
493 zfOut.writestr(zi, data)
494 zfOut.close()
495 os.close(zfOutFd)
496 zf.close()
497 shutil.move(zfOutPath, dist.path)
498
499 def _installDistInJdks(deployableDist):
500 """
501 Installs the jar(s) for a given Distribution into all existing JVMCI JDKs
502 """
503 if True:
504 return
505 dist = mx.distribution(deployableDist.name)
506 if dist.name == 'GRAAL':
507 _patchGraalVersionConstant(dist)
508
509 jdks = _jdksDir()
510 if exists(jdks):
511 for e in os.listdir(jdks):
512 jdkDir = join(jdks, e)
513 jreLibDir = join(jdkDir, 'jre', 'lib')
514 if exists(jreLibDir):
515 if deployableDist.isExtension:
516 targetDir = join(jreLibDir, 'ext')
517 elif deployableDist.usesJVMCIClassLoader:
518 targetDir = join(jreLibDir, 'jvmci')
519 else:
520 targetDir = jreLibDir
521 if not exists(targetDir):
522 os.makedirs(targetDir)
523 _copyToJdk(dist.path, targetDir)
524 if dist.sourcesPath:
525 _copyToJdk(dist.sourcesPath, jdkDir)
526 if deployableDist.usesJVMCIClassLoader:
527 # deploy service files
528 _updateJVMCIFiles(jdkDir)
529
530 def _getJdkDeployedJars(jdkDir):
531 """
532 Gets jar paths for all deployed distributions in the context of
533 a given JDK directory.
534 """
535 jreLibDir = join(jdkDir, 'jre', 'lib')
536 jars = []
537 for dist in _jdkDeployedDists:
538 jar = basename(mx.distribution(dist.name).path)
539 if dist.isExtension:
540 jars.append(join(jreLibDir, 'ext', jar))
541 elif dist.usesJVMCIClassLoader:
542 jars.append(join(jreLibDir, 'jvmci', jar))
543 else:
544 jars.append(join(jreLibDir, jar))
545 return jars
546
547
548 # run a command in the windows SDK Debug Shell
549 def _runInDebugShell(cmd, workingDir, logFile=None, findInOutput=None, respondTo=None):
550 if respondTo is None:
551 respondTo = {}
552 newLine = os.linesep
553 startToken = 'RUNINDEBUGSHELL_STARTSEQUENCE'
554 endToken = 'RUNINDEBUGSHELL_ENDSEQUENCE'
555
556 winSDK = mx.get_env('WIN_SDK', 'C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1\\')
557
558 if not exists(mx._cygpathW2U(winSDK)):
559 mx.abort("Could not find Windows SDK : '" + winSDK + "' does not exist")
560
561 winSDKSetEnv = mx._cygpathW2U(join(winSDK, 'Bin', 'SetEnv.cmd'))
562 if not exists(winSDKSetEnv):
563 mx.abort("Invalid Windows SDK path (" + winSDK + ") : could not find Bin/SetEnv.cmd (you can use the WIN_SDK environment variable to specify an other path)")
564
565 wincmd = 'cmd.exe /E:ON /V:ON /K "' + mx._cygpathU2W(winSDKSetEnv) + '"'
566 p = subprocess.Popen(wincmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
567 stdout = p.stdout
568 stdin = p.stdin
569 if logFile:
570 log = open(logFile, 'w')
571 ret = False
572
573 def _writeProcess(s):
574 stdin.write(s + newLine)
575
576 _writeProcess("echo " + startToken)
577 while True:
578 # encoding may be None on windows plattforms
579 if sys.stdout.encoding is None:
580 encoding = 'utf-8'
581 else:
582 encoding = sys.stdout.encoding
583
584 line = stdout.readline().decode(encoding)
585 if logFile:
586 log.write(line.encode('utf-8'))
587 line = line.strip()
588 mx.log(line)
589 if line == startToken:
590 _writeProcess('cd /D ' + workingDir + ' & ' + cmd + ' & echo ' + endToken)
591 for regex in respondTo.keys():
592 match = regex.search(line)
593 if match:
594 _writeProcess(respondTo[regex])
595 if findInOutput:
596 match = findInOutput.search(line)
597 if match:
598 ret = True
599 if line == endToken:
600 if not findInOutput:
601 _writeProcess('echo ERRXXX%errorlevel%')
602 else:
603 break
604 if line.startswith('ERRXXX'):
605 if line == 'ERRXXX0':
606 ret = True
607 break
608 _writeProcess("exit")
609 if logFile:
610 log.close()
611 return ret
612
613 def jdkhome(vm=None):
614 """return the JDK directory selected for the 'vm' command"""
615 return _jdk(installJars=False)
616
617 def print_jdkhome(args, vm=None):
618 """print the JDK directory selected for the 'vm' command"""
619 print jdkhome(vm)
620
621 def buildvars(args):
622 """describe the variables that can be set by the -D option to the 'mx build' commmand"""
623
624 buildVars = {
625 'ALT_BOOTDIR' : 'The location of the bootstrap JDK installation (default: ' + mx.java().jdk + ')',
626 'ALT_OUTPUTDIR' : 'Build directory',
627 'HOTSPOT_BUILD_JOBS' : 'Number of CPUs used by make (default: ' + str(mx.cpu_count()) + ')',
628 'INSTALL' : 'Install the built VM into the JDK? (default: y)',
629 'ZIP_DEBUGINFO_FILES' : 'Install zipped debug symbols file? (default: 0)',
630 }
631
632 mx.log('HotSpot build variables that can be set by the -D option to "mx build":')
633 mx.log('')
634 for n in sorted(buildVars.iterkeys()):
635 mx.log(n)
636 mx.log(textwrap.fill(buildVars[n], initial_indent=' ', subsequent_indent=' ', width=200))
637
638 mx.log('')
639 mx.log('Note that these variables can be given persistent values in the file ' + join(_graal_home, 'mx', 'env') + ' (see \'mx about\').')
640
641 cached_graal_version = None
642
643 def graal_version(dev_suffix='dev'):
644 global cached_graal_version
645
646 if not cached_graal_version:
647 # extract latest release tag for graal
648 try:
649 tags = [x.split() for x in subprocess.check_output(['hg', '-R', _graal_home, 'tags']).split('\n') if x.startswith("graal-")]
650 current_id = subprocess.check_output(['hg', '-R', _graal_home, 'log', '--template', '{rev}\n', '--rev', 'tip']).strip()
651 except:
652 # not a mercurial repository or hg commands are not available.
653 tags = None
654
655 if tags and current_id:
656 sorted_tags = sorted(tags, key=lambda e: [int(x) for x in e[0][len("graal-"):].split('.')], reverse=True)
657 most_recent_tag_name, most_recent_tag_revision = sorted_tags[0]
658 most_recent_tag_id = most_recent_tag_revision[:most_recent_tag_revision.index(":")]
659 most_recent_tag_version = most_recent_tag_name[len("graal-"):]
660
661 # tagged commit is one-off with commit that tags it
662 if int(current_id) - int(most_recent_tag_id) <= 1:
663 cached_graal_version = most_recent_tag_version
664 else:
665 major, minor = map(int, most_recent_tag_version.split('.'))
666 cached_graal_version = str(major) + '.' + str(minor + 1) + '-' + dev_suffix
667 else:
668 cached_graal_version = 'unknown-{0}'.format(platform.node())
669
670 return cached_graal_version
671
672 def build(args, vm=None):
673 """build the VM binary
674
675 The global '--vm' and '--vmbuild' options select which VM type and build target to build."""
676
677 # Override to fail quickly if extra arguments are given
678 # at the end of the command line. This allows for a more
679 # helpful error message.
680 class AP(ArgumentParser):
681 def __init__(self):
682 ArgumentParser.__init__(self, prog='mx build')
683 def parse_args(self, args):
684 result = ArgumentParser.parse_args(self, args)
685 if len(result.remainder) != 0:
686 firstBuildTarget = result.remainder[0]
687 mx.abort('To specify the ' + firstBuildTarget + ' VM build target, you need to use the global "--vmbuild" option. For example:\n' +
688 ' mx --vmbuild ' + firstBuildTarget + ' build')
689 return result
690
691 # Call mx.build to compile the Java sources
692 parser = AP()
693 parser.add_argument('-D', action='append', help='set a HotSpot build variable (run \'mx buildvars\' to list variables)', metavar='name=value')
694
695 opts2 = mx.build(['--source', '1.7'] + args, parser=parser)
696 assert len(opts2.remainder) == 0
697
698 def vmg(args):
699 """run the debug build of VM selected by the '--vm' option"""
700 return vm(args, vmbuild='debug')
701
702 def vmfg(args):
703 """run the fastdebug build of VM selected by the '--vm' option"""
704 return vm(args, vmbuild='fastdebug')
705
706 def _parseVmArgs(args, vm=None, cwd=None, vmbuild=None):
707 """run the VM selected by the '--vm' option"""
708
709 jdk = mx.java().jdk
710 mx.expand_project_in_args(args)
711 exe = join(jdk, 'bin', mx.exe_suffix('java'))
712 pfx = []
713
714 if '-version' in args:
715 ignoredArgs = args[args.index('-version') + 1:]
716 if len(ignoredArgs) > 0:
717 mx.log("Warning: The following options will be ignored by the vm because they come after the '-version' argument: " + ' '.join(ignoredArgs))
718
719 # Unconditionally prepend Truffle to the boot class path.
720 # This used to be done by the VM itself but was removed to
721 # separate the VM from Truffle.
722 truffle_jar = mx.archive(['@TRUFFLE'])[0]
723 args = ['-Xbootclasspath/p:' + truffle_jar] + args
724
725 args = mx.java().processArgs(args)
726 return (pfx, exe, vm, args, cwd)
727
728 def vm(args, vm=None, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, vmbuild=None):
729 (pfx_, exe_, _, args_, cwd) = _parseVmArgs(args, vm, cwd, vmbuild)
730 return mx.run(pfx_ + [exe_] + args_, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd)
731
732 def _find_classes_with_annotations(p, pkgRoot, annotations, includeInnerClasses=False):
733 """
734 Scan the sources of project 'p' for Java source files containing a line starting with 'annotation'
735 (ignoring preceding whitespace) and return the fully qualified class name for each Java
736 source file matched in a list.
737 """
738
739 matches = lambda line: len([a for a in annotations if line == a or line.startswith(a + '(')]) != 0
740 return p.find_classes_with_matching_source_line(pkgRoot, matches, includeInnerClasses)
741
742 def _extract_VM_args(args, allowClasspath=False, useDoubleDash=False, defaultAllVMArgs=True):
743 """
744 Partitions a command line into a leading sequence of HotSpot VM options and the rest.
745 """
746 for i in range(0, len(args)):
747 if useDoubleDash:
748 if args[i] == '--':
749 vmArgs = args[:i]
750 remainder = args[i + 1:]
751 return vmArgs, remainder
752 else:
753 if not args[i].startswith('-'):
754 if i != 0 and (args[i - 1] == '-cp' or args[i - 1] == '-classpath'):
755 if not allowClasspath:
756 mx.abort('Cannot supply explicit class path option')
757 else:
758 continue
759 vmArgs = args[:i]
760 remainder = args[i:]
761 return vmArgs, remainder
762
763 if defaultAllVMArgs:
764 return args, []
765 else:
766 return [], args
767
768 def _run_tests(args, harness, annotations, testfile, blacklist, whitelist, regex):
769
770
771 vmArgs, tests = _extract_VM_args(args)
772 for t in tests:
773 if t.startswith('-'):
774 mx.abort('VM option ' + t + ' must precede ' + tests[0])
775
776 candidates = {}
777 for p in mx.projects_opt_limit_to_suites():
778 if mx.java().javaCompliance < p.javaCompliance:
779 continue
780 for c in _find_classes_with_annotations(p, None, annotations).keys():
781 candidates[c] = p
782
783 classes = []
784 if len(tests) == 0:
785 classes = candidates.keys()
786 projectsCp = mx.classpath([pcp.name for pcp in mx.projects_opt_limit_to_suites() if pcp.javaCompliance <= mx.java().javaCompliance])
787 else:
788 projs = set()
789 found = False
790 if len(tests) == 1 and '#' in tests[0]:
791 words = tests[0].split('#')
792 if len(words) != 2:
793 mx.abort("Method specification is class#method: " + tests[0])
794 t, method = words
795
796 for c, p in candidates.iteritems():
797 # prefer exact matches first
798 if t == c:
799 found = True
800 classes.append(c)
801 projs.add(p.name)
802 if not found:
803 for c, p in candidates.iteritems():
804 if t in c:
805 found = True
806 classes.append(c)
807 projs.add(p.name)
808 if not found:
809 mx.log('warning: no tests matched by substring "' + t)
810 elif len(classes) != 1:
811 mx.abort('More than one test matches substring {0} {1}'.format(t, classes))
812
813 classes = [c + "#" + method for c in classes]
814 else:
815 for t in tests:
816 if '#' in t:
817 mx.abort('Method specifications can only be used in a single test: ' + t)
818 for c, p in candidates.iteritems():
819 if t in c:
820 found = True
821 classes.append(c)
822 projs.add(p.name)
823 if not found:
824 mx.log('warning: no tests matched by substring "' + t)
825 projectsCp = mx.classpath(projs)
826
827 if blacklist:
828 classes = [c for c in classes if not any((glob.match(c) for glob in blacklist))]
829
830 if whitelist:
831 classes = [c for c in classes if any((glob.match(c) for glob in whitelist))]
832
833 if regex:
834 classes = [c for c in classes if re.search(regex, c)]
835
836 if len(classes) != 0:
837 f_testfile = open(testfile, 'w')
838 for c in classes:
839 f_testfile.write(c + '\n')
840 f_testfile.close()
841 harness(projectsCp, vmArgs)
842
843 def _unittest(args, annotations, prefixCp="", blacklist=None, whitelist=None, verbose=False, fail_fast=False, enable_timing=False, regex=None, color=False, eager_stacktrace=False, gc_after_test=False):
844 testfile = os.environ.get('MX_TESTFILE', None)
845 if testfile is None:
846 (_, testfile) = tempfile.mkstemp(".testclasses", "graal")
847 os.close(_)
848
849 coreCp = mx.classpath(['com.oracle.truffle.tck', 'HCFDIS'])
850
851 coreArgs = []
852 if verbose:
853 coreArgs.append('-JUnitVerbose')
854 if fail_fast:
855 coreArgs.append('-JUnitFailFast')
856 if enable_timing:
857 coreArgs.append('-JUnitEnableTiming')
858 if color:
859 coreArgs.append('-JUnitColor')
860 if eager_stacktrace:
861 coreArgs.append('-JUnitEagerStackTrace')
862 if gc_after_test:
863 coreArgs.append('-JUnitGCAfterTest')
864
865
866 def harness(projectsCp, vmArgs):
867 if _get_vm() != 'jvmci':
868 prefixArgs = ['-esa', '-ea']
869 else:
870 prefixArgs = ['-XX:-BootstrapJVMCI', '-esa', '-ea']
871 if gc_after_test:
872 prefixArgs.append('-XX:-DisableExplicitGC')
873 with open(testfile) as fp:
874 testclasses = [l.rstrip() for l in fp.readlines()]
875
876 # Remove entries from class path that are in graal.jar and
877 # run the VM in a mode where application/test classes can
878 # access core Graal classes.
879 cp = prefixCp + coreCp + os.pathsep + projectsCp
880 if isJVMCIEnabled(_get_vm()):
881 excluded = set()
882 for jdkDist in _jdkDeployedDists:
883 dist = mx.distribution(jdkDist.name)
884 excluded.update([d.output_dir() for d in dist.sorted_deps()])
885 cp = os.pathsep.join([e for e in cp.split(os.pathsep) if e not in excluded])
886
887 # suppress menubar and dock when running on Mac
888 vmArgs = ['-Djava.awt.headless=true'] + vmArgs
889
890 if len(testclasses) == 1:
891 # Execute Junit directly when one test is being run. This simplifies
892 # replaying the VM execution in a native debugger (e.g., gdb).
893 vm(prefixArgs + vmArgs + ['-cp', mx._separatedCygpathU2W(cp), 'com.oracle.truffle.tck.TruffleJUnitCore'] + coreArgs + testclasses)
894 else:
895 vm(prefixArgs + vmArgs + ['-cp', mx._separatedCygpathU2W(cp), 'com.oracle.truffle.tck.TruffleJUnitCore'] + coreArgs + ['@' + mx._cygpathU2W(testfile)])
896
897 try:
898 _run_tests(args, harness, annotations, testfile, blacklist, whitelist, regex)
899 finally:
900 if os.environ.get('MX_TESTFILE') is None:
901 os.remove(testfile)
902
903 _unittestHelpSuffix = """
904 Unittest options:
905
906 --blacklist <file> run all testcases not specified in the blacklist
907 --whitelist <file> run only testcases which are included
908 in the given whitelist
909 --verbose enable verbose JUnit output
910 --fail-fast stop after first JUnit test class that has a failure
911 --enable-timing enable JUnit test timing
912 --regex <regex> run only testcases matching a regular expression
913 --color enable colors output
914 --eager-stacktrace print stacktrace eagerly
915 --gc-after-test force a GC after each test
916
917 To avoid conflicts with VM options '--' can be used as delimiter.
918
919 If filters are supplied, only tests whose fully qualified name
920 includes a filter as a substring are run.
921
922 For example, this command line:
923
924 mx unittest -G:Dump= -G:MethodFilter=BC_aload.* -G:+PrintCFG BC_aload
925
926 will run all JUnit test classes that contain 'BC_aload' in their
927 fully qualified name and will pass these options to the VM:
928
929 -G:Dump= -G:MethodFilter=BC_aload.* -G:+PrintCFG
930
931 To get around command line length limitations on some OSes, the
932 JUnit class names to be executed are written to a file that a
933 custom JUnit wrapper reads and passes onto JUnit proper. The
934 MX_TESTFILE environment variable can be set to specify a
935 file which will not be deleted once the unittests are done
936 (unlike the temporary file otherwise used).
937
938 As with all other commands, using the global '-v' before 'unittest'
939 command will cause mx to show the complete command line
940 it uses to run the VM.
941 """
942
943 def unittest(args):
944 """run the JUnit tests (all testcases){0}"""
945
946 parser = ArgumentParser(prog='mx unittest',
947 description='run the JUnit tests',
948 add_help=False,
949 formatter_class=RawDescriptionHelpFormatter,
950 epilog=_unittestHelpSuffix,
951 )
952 parser.add_argument('--blacklist', help='run all testcases not specified in the blacklist', metavar='<path>')
953 parser.add_argument('--whitelist', help='run testcases specified in whitelist only', metavar='<path>')
954 parser.add_argument('--verbose', help='enable verbose JUnit output', action='store_true')
955 parser.add_argument('--fail-fast', help='stop after first JUnit test class that has a failure', action='store_true')
956 parser.add_argument('--enable-timing', help='enable JUnit test timing', action='store_true')
957 parser.add_argument('--regex', help='run only testcases matching a regular expression', metavar='<regex>')
958 parser.add_argument('--color', help='enable color output', action='store_true')
959 parser.add_argument('--eager-stacktrace', help='print stacktrace eagerly', action='store_true')
960 parser.add_argument('--gc-after-test', help='force a GC after each test', action='store_true')
961
962 ut_args = []
963 delimiter = False
964 # check for delimiter
965 while len(args) > 0:
966 arg = args.pop(0)
967 if arg == '--':
968 delimiter = True
969 break
970 ut_args.append(arg)
971
972 if delimiter:
973 # all arguments before '--' must be recognized
974 parsed_args = parser.parse_args(ut_args)
975 else:
976 # parse all know arguments
977 parsed_args, args = parser.parse_known_args(ut_args)
978
979 if parsed_args.whitelist:
980 try:
981 with open(join(_graal_home, parsed_args.whitelist)) as fp:
982 parsed_args.whitelist = [re.compile(fnmatch.translate(l.rstrip())) for l in fp.readlines() if not l.startswith('#')]
983 except IOError:
984 mx.log('warning: could not read whitelist: ' + parsed_args.whitelist)
985 if parsed_args.blacklist:
986 try:
987 with open(join(_graal_home, parsed_args.blacklist)) as fp:
988 parsed_args.blacklist = [re.compile(fnmatch.translate(l.rstrip())) for l in fp.readlines() if not l.startswith('#')]
989 except IOError:
990 mx.log('warning: could not read blacklist: ' + parsed_args.blacklist)
991
992 _unittest(args, ['@Test', '@Parameters'], **parsed_args.__dict__)
993
994 def shortunittest(args):
995 """alias for 'unittest --whitelist test/whitelist_shortunittest.txt'{0}"""
996
997 args = ['--whitelist', 'test/whitelist_shortunittest.txt'] + args
998 unittest(args)
999
1000 class Task:
1001 # None or a list of strings. If not None, only tasks whose title
1002 # matches at least one of the substrings in this list will return
1003 # a non-None value from __enter__. The body of a 'with Task(...) as t'
1004 # statement should check 't' and exit immediately if it is None.
1005 filters = None
1006 filtersExclude = False
1007
1008 def __init__(self, title, tasks=None):
1009 self.tasks = tasks
1010 self.title = title
1011 if tasks is not None and Task.filters is not None:
1012 if Task.filtersExclude:
1013 self.skipped = any([f in title for f in Task.filters])
1014 else:
1015 self.skipped = not any([f in title for f in Task.filters])
1016 else:
1017 self.skipped = False
1018 if not self.skipped:
1019 self.start = time.time()
1020 self.end = None
1021 self.duration = None
1022 mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: BEGIN: ') + title)
1023 def __enter__(self):
1024 assert self.tasks is not None, "using Task with 'with' statement requires to pass the tasks list in the constructor"
1025 if self.skipped:
1026 return None
1027 return self
1028 def __exit__(self, exc_type, exc_value, traceback):
1029 if not self.skipped:
1030 self.tasks.append(self.stop())
1031 def stop(self):
1032 self.end = time.time()
1033 self.duration = datetime.timedelta(seconds=self.end - self.start)
1034 mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: END: ') + self.title + ' [' + str(self.duration) + ']')
1035 return self
1036 def abort(self, codeOrMessage):
1037 self.end = time.time()
1038 self.duration = datetime.timedelta(seconds=self.end - self.start)
1039 mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: ABORT: ') + self.title + ' [' + str(self.duration) + ']')
1040 mx.abort(codeOrMessage)
1041 return self
1042
1043 def _basic_gate_body(args, tasks):
1044 # Run unit tests on server-hosted-jvmci
1045 with Task('UnitTests:hosted-product', tasks) as t:
1046 if t: unittest(['--enable-timing', '--verbose', '--fail-fast'])
1047
1048
1049 def gate(args, gate_body=_basic_gate_body):
1050 """run the tests used to validate a push
1051
1052 If this command exits with a 0 exit code, then the source code is in
1053 a state that would be accepted for integration into the main repository."""
1054
1055 parser = ArgumentParser(prog='mx gate')
1056 parser.add_argument('-j', '--omit-java-clean', action='store_false', dest='cleanJava', help='omit cleaning Java native code')
1057 parser.add_argument('-n', '--omit-native-clean', action='store_false', dest='cleanNative', help='omit cleaning and building native code')
1058 parser.add_argument('-i', '--omit-ide-clean', action='store_false', dest='cleanIde', help='omit cleaning the ide project files')
1059 parser.add_argument('-g', '--only-build-jvmci', action='store_false', dest='buildNonJVMCI', help='only build the JVMCI VM')
1060 parser.add_argument('-t', '--task-filter', help='comma separated list of substrings to select subset of tasks to be run')
1061 parser.add_argument('-x', action='store_true', help='makes --task-filter an exclusion instead of inclusion filter')
1062
1063 args = parser.parse_args(args)
1064
1065 if args.task_filter:
1066 Task.filters = args.task_filter.split(',')
1067 Task.filtersExclude = args.x
1068 elif args.x:
1069 mx.abort('-x option cannot be used without --task-filter option')
1070
1071 # Force
1072 if not mx._opts.strict_compliance:
1073 mx.log("[gate] forcing strict compliance")
1074 mx._opts.strict_compliance = True
1075
1076 tasks = []
1077 total = Task('Gate')
1078 try:
1079 with Task('Pylint', tasks) as t:
1080 if t: mx.pylint([])
1081
1082 def _clean(name='Clean'):
1083 with Task(name, tasks) as t:
1084 if t:
1085 cleanArgs = []
1086 if not args.cleanNative:
1087 cleanArgs.append('--no-native')
1088 if not args.cleanJava:
1089 cleanArgs.append('--no-java')
1090 clean(cleanArgs)
1091 _clean()
1092
1093 with Task('IDEConfigCheck', tasks) as t:
1094 if t:
1095 if args.cleanIde:
1096 mx.ideclean([])
1097 mx.ideinit([])
1098
1099 eclipse_exe = mx.get_env('ECLIPSE_EXE')
1100 if eclipse_exe is not None:
1101 with Task('CodeFormatCheck', tasks) as t:
1102 if t and mx.eclipseformat(['-e', eclipse_exe]) != 0:
1103 t.abort('Formatter modified files - run "mx eclipseformat", check in changes and repush')
1104
1105 with Task('Canonicalization Check', tasks) as t:
1106 if t:
1107 mx.log(time.strftime('%d %b %Y %H:%M:%S - Ensuring mx/projects files are canonicalized...'))
1108 if mx.canonicalizeprojects([]) != 0:
1109 t.abort('Rerun "mx canonicalizeprojects" and check-in the modified mx/projects files.')
1110
1111 if mx.get_env('JDT'):
1112 with Task('BuildJavaWithEcj', tasks):
1113 if t: build(['-p', '--no-native', '--jdt-warning-as-error'])
1114 _clean('CleanAfterEcjBuild')
1115
1116 with Task('BuildJavaWithJavac', tasks):
1117 if t: build(['-p', '--no-native', '--force-javac'])
1118
1119 with Task('Checkstyle', tasks) as t:
1120 if t and mx.checkstyle([]) != 0:
1121 t.abort('Checkstyle warnings were found')
1122
1123 with Task('Checkheaders', tasks) as t:
1124 if t and checkheaders([]) != 0:
1125 t.abort('Checkheaders warnings were found')
1126
1127 with Task('FindBugs', tasks) as t:
1128 if t and findbugs([]) != 0:
1129 t.abort('FindBugs warnings were found')
1130
1131 gate_body(args, tasks)
1132
1133 except KeyboardInterrupt:
1134 total.abort(1)
1135
1136 except BaseException as e:
1137 import traceback
1138 traceback.print_exc()
1139 total.abort(str(e))
1140
1141 total.stop()
1142
1143 mx.log('Gate task times:')
1144 for t in tasks:
1145 mx.log(' ' + str(t.duration) + '\t' + t.title)
1146 mx.log(' =======')
1147 mx.log(' ' + str(total.duration))
1148
1149 if args.task_filter:
1150 Task.filters = None
1151
1152 def _igvJdk():
1153 v8u20 = mx.VersionSpec("1.8.0_20")
1154 v8u40 = mx.VersionSpec("1.8.0_40")
1155 v8 = mx.VersionSpec("1.8")
1156 def _igvJdkVersionCheck(version):
1157 return version >= v8 and (version < v8u20 or version >= v8u40)
1158 return mx.java_version(_igvJdkVersionCheck, versionDescription='>= 1.8 and < 1.8.0u20 or >= 1.8.0u40').jdk
1159
1160 def _igvBuildEnv():
1161 # When the http_proxy environment variable is set, convert it to the proxy settings that ant needs
1162 env = dict(os.environ)
1163 proxy = os.environ.get('http_proxy')
1164 if not (proxy is None) and len(proxy) > 0:
1165 if '://' in proxy:
1166 # Remove the http:// prefix (or any other protocol prefix)
1167 proxy = proxy.split('://', 1)[1]
1168 # Separate proxy server name and port number
1169 proxyName, proxyPort = proxy.split(':', 1)
1170 proxyEnv = '-DproxyHost="' + proxyName + '" -DproxyPort=' + proxyPort
1171 env['ANT_OPTS'] = proxyEnv
1172
1173 env['JAVA_HOME'] = _igvJdk()
1174 return env
1175
1176 def igv(args):
1177 """run the Ideal Graph Visualizer"""
1178 logFile = '.ideal_graph_visualizer.log'
1179 with open(join(_graal_home, logFile), 'w') as fp:
1180 mx.logv('[Ideal Graph Visualizer log is in ' + fp.name + ']')
1181 nbplatform = join(_graal_home, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'nbplatform')
1182
1183 # Remove NetBeans platform if it is earlier than the current supported version
1184 if exists(nbplatform):
1185 updateTrackingFile = join(nbplatform, 'platform', 'update_tracking', 'org-netbeans-core.xml')
1186 if not exists(updateTrackingFile):
1187 mx.log('Could not find \'' + updateTrackingFile + '\', removing NetBeans platform')
1188 shutil.rmtree(nbplatform)
1189 else:
1190 dom = xml.dom.minidom.parse(updateTrackingFile)
1191 currentVersion = mx.VersionSpec(dom.getElementsByTagName('module_version')[0].getAttribute('specification_version'))
1192 supportedVersion = mx.VersionSpec('3.43.1')
1193 if currentVersion < supportedVersion:
1194 mx.log('Replacing NetBeans platform version ' + str(currentVersion) + ' with version ' + str(supportedVersion))
1195 shutil.rmtree(nbplatform)
1196 elif supportedVersion < currentVersion:
1197 mx.log('Supported NetBeans version in igv command should be updated to ' + str(currentVersion))
1198
1199 if not exists(nbplatform):
1200 mx.logv('[This execution may take a while as the NetBeans platform needs to be downloaded]')
1201
1202 env = _igvBuildEnv()
1203 # make the jar for Batik 1.7 available.
1204 env['IGV_BATIK_JAR'] = mx.library('BATIK').get_path(True)
1205 if mx.run(['ant', '-f', mx._cygpathU2W(join(_graal_home, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml')), '-l', mx._cygpathU2W(fp.name), 'run'], env=env, nonZeroIsFatal=False):
1206 mx.abort("IGV ant build & launch failed. Check '" + logFile + "'. You can also try to delete 'src/share/tools/IdealGraphVisualizer/nbplatform'.")
1207
1208 def maven_install_truffle(args):
1209 """install Truffle into your local Maven repository"""
1210 for name in ['TRUFFLE', 'TRUFFLE_TCK', 'TRUFFLE_DSL_PROCESSOR', 'TRUFFLE_SL']:
1211 mx.archive(["@" + name])
1212 path = mx._dists[name].path
1213 mx.run(['mvn', 'install:install-file', '-DgroupId=com.oracle', '-DartifactId=' + name.lower(), '-Dversion=' + graal_version('SNAPSHOT'), '-Dpackaging=jar', '-Dfile=' + path])
1214
1215 def c1visualizer(args):
1216 """run the Cl Compiler Visualizer"""
1217 libpath = join(_graal_home, 'lib')
1218 if mx.get_os() == 'windows':
1219 executable = join(libpath, 'c1visualizer', 'bin', 'c1visualizer.exe')
1220 else:
1221 executable = join(libpath, 'c1visualizer', 'bin', 'c1visualizer')
1222
1223 # Check whether the current C1Visualizer installation is the up-to-date
1224 if exists(executable) and not exists(mx.library('C1VISUALIZER_DIST').get_path(resolve=False)):
1225 mx.log('Updating C1Visualizer')
1226 shutil.rmtree(join(libpath, 'c1visualizer'))
1227
1228 archive = mx.library('C1VISUALIZER_DIST').get_path(resolve=True)
1229
1230 if not exists(executable):
1231 zf = zipfile.ZipFile(archive, 'r')
1232 zf.extractall(libpath)
1233
1234 if not exists(executable):
1235 mx.abort('C1Visualizer binary does not exist: ' + executable)
1236
1237 if mx.get_os() != 'windows':
1238 # Make sure that execution is allowed. The zip file does not always specfiy that correctly
1239 os.chmod(executable, 0777)
1240
1241 mx.run([executable])
1242
1243 def hsdis(args, copyToDir=None):
1244 """download the hsdis library
1245
1246 This is needed to support HotSpot's assembly dumping features.
1247 By default it downloads the Intel syntax version, use the 'att' argument to install AT&T syntax."""
1248 flavor = 'intel'
1249 if 'att' in args:
1250 flavor = 'att'
1251 if mx.get_arch() == "sparcv9":
1252 flavor = "sparcv9"
1253 lib = mx.add_lib_suffix('hsdis-' + mx.get_arch())
1254 path = join(_graal_home, 'lib', lib)
1255
1256 sha1s = {
1257 'att/hsdis-amd64.dll' : 'bcbd535a9568b5075ab41e96205e26a2bac64f72',
1258 'att/hsdis-amd64.so' : '58919ba085d4ef7a513f25bae75e7e54ee73c049',
1259 'intel/hsdis-amd64.dll' : '6a388372cdd5fe905c1a26ced614334e405d1f30',
1260 'intel/hsdis-amd64.so' : '844ed9ffed64fe9599638f29a8450c50140e3192',
1261 'intel/hsdis-amd64.dylib' : 'fdb13ef0d7d23d93dacaae9c98837bea0d4fc5a2',
1262 'sparcv9/hsdis-sparcv9.so': '970640a9af0bd63641f9063c11275b371a59ee60',
1263 }
1264
1265 flavoredLib = flavor + "/" + lib
1266 if flavoredLib not in sha1s:
1267 mx.logv("hsdis not supported on this plattform or architecture")
1268 return
1269
1270 if not exists(path):
1271 sha1 = sha1s[flavoredLib]
1272 sha1path = path + '.sha1'
1273 mx.download_file_with_sha1('hsdis', path, ['http://lafo.ssw.uni-linz.ac.at/hsdis/' + flavoredLib], sha1, sha1path, True, True, sources=False)
1274 if copyToDir is not None and exists(copyToDir):
1275 shutil.copy(path, copyToDir)
1276
1277 def hcfdis(args):
1278 """disassemble HexCodeFiles embedded in text files
1279
1280 Run a tool over the input files to convert all embedded HexCodeFiles
1281 to a disassembled format."""
1282
1283 parser = ArgumentParser(prog='mx hcfdis')
1284 parser.add_argument('-m', '--map', help='address to symbol map applied to disassembler output')
1285 parser.add_argument('files', nargs=REMAINDER, metavar='files...')
1286
1287 args = parser.parse_args(args)
1288
1289 path = mx.library('HCFDIS').get_path(resolve=True)
1290 mx.run_java(['-cp', path, 'com.oracle.max.hcfdis.HexCodeFileDis'] + args.files)
1291
1292 if args.map is not None:
1293 addressRE = re.compile(r'0[xX]([A-Fa-f0-9]+)')
1294 with open(args.map) as fp:
1295 lines = fp.read().splitlines()
1296 symbols = dict()
1297 for l in lines:
1298 addressAndSymbol = l.split(' ', 1)
1299 if len(addressAndSymbol) == 2:
1300 address, symbol = addressAndSymbol
1301 if address.startswith('0x'):
1302 address = long(address, 16)
1303 symbols[address] = symbol
1304 for f in args.files:
1305 with open(f) as fp:
1306 lines = fp.read().splitlines()
1307 updated = False
1308 for i in range(0, len(lines)):
1309 l = lines[i]
1310 for m in addressRE.finditer(l):
1311 sval = m.group(0)
1312 val = long(sval, 16)
1313 sym = symbols.get(val)
1314 if sym:
1315 l = l.replace(sval, sym)
1316 updated = True
1317 lines[i] = l
1318 if updated:
1319 mx.log('updating ' + f)
1320 with open('new_' + f, "w") as fp:
1321 for l in lines:
1322 print >> fp, l
1323
1324 def sl(args):
1325 """run an SL program"""
1326 vmArgs, slArgs = _extract_VM_args(args)
1327 vm(vmArgs + ['-cp', mx.classpath(["TRUFFLE", "com.oracle.truffle.sl"]), "com.oracle.truffle.sl.SLLanguage"] + slArgs)
1328
1329 def sldebug(args):
1330 """run a simple command line debugger for the Simple Language"""
1331 vmArgs, slArgs = _extract_VM_args(args, useDoubleDash=True)
1332 vm(vmArgs + ['-cp', mx.classpath("com.oracle.truffle.sl.tools"), "com.oracle.truffle.sl.tools.debug.SLREPLServer"] + slArgs)
1333
1334 def isJVMCIEnabled(vm):
1335 return vm != 'original' and not vm.endswith('nojvmci')
1336
1337 def jol(args):
1338 """Java Object Layout"""
1339 joljar = mx.library('JOL_INTERNALS').get_path(resolve=True)
1340 candidates = mx.findclass(args, logToConsole=False, matcher=lambda s, classname: s == classname or classname.endswith('.' + s) or classname.endswith('$' + s))
1341
1342 if len(candidates) > 0:
1343 candidates = mx.select_items(sorted(candidates))
1344 else:
1345 # mx.findclass can be mistaken, don't give up yet
1346 candidates = args
1347
1348 vm(['-javaagent:' + joljar, '-cp', os.pathsep.join([mx.classpath(), joljar]), "org.openjdk.jol.MainObjectInternals"] + candidates)
1349
1350 def site(args):
1351 """create a website containing javadoc and the project dependency graph"""
1352
1353 return mx.site(['--name', 'Graal',
1354 '--jd', '@-tag', '--jd', '@test:X',
1355 '--jd', '@-tag', '--jd', '@run:X',
1356 '--jd', '@-tag', '--jd', '@bug:X',
1357 '--jd', '@-tag', '--jd', '@summary:X',
1358 '--jd', '@-tag', '--jd', '@vmoption:X',
1359 '--overview', join(_graal_home, 'graal', 'overview.html'),
1360 '--title', 'Graal OpenJDK Project Documentation',
1361 '--dot-output-base', 'projects'] + args)
1362
1363 def generateZshCompletion(args):
1364 """generate zsh completion for mx"""
1365 try:
1366 from genzshcomp import CompletionGenerator
1367 except ImportError:
1368 mx.abort("install genzshcomp (pip install genzshcomp)")
1369
1370 # need to fake module for the custom mx arg parser, otherwise a check in genzshcomp fails
1371 originalModule = mx._argParser.__module__
1372 mx._argParser.__module__ = "argparse"
1373 generator = CompletionGenerator("mx", mx._argParser)
1374 mx._argParser.__module__ = originalModule
1375
1376 # strip last line and define local variable "ret"
1377 complt = "\n".join(generator.get().split('\n')[0:-1]).replace('context state line', 'context state line ret=1')
1378
1379 # add array of possible subcommands (as they are not part of the argument parser)
1380 complt += '\n ": :->command" \\\n'
1381 complt += ' "*::args:->args" && ret=0\n'
1382 complt += '\n'
1383 complt += 'case $state in\n'
1384 complt += '\t(command)\n'
1385 complt += '\t\tlocal -a main_commands\n'
1386 complt += '\t\tmain_commands=(\n'
1387 for cmd in sorted(mx._commands.iterkeys()):
1388 c, _ = mx._commands[cmd][:2]
1389 doc = c.__doc__
1390 complt += '\t\t\t"{0}'.format(cmd)
1391 if doc:
1392 complt += ':{0}'.format(_fixQuotes(doc.split('\n', 1)[0]))
1393 complt += '"\n'
1394 complt += '\t\t)\n'
1395 complt += '\t\t_describe -t main_commands command main_commands && ret=0\n'
1396 complt += '\t\t;;\n'
1397
1398 complt += '\t(args)\n'
1399 # TODO: improve matcher: if mx args are given, this doesn't work
1400 complt += '\t\tcase $line[1] in\n'
1401 complt += '\t\t\t\tnoglob \\\n'
1402 complt += '\t\t\t\t\t_arguments -s -S \\\n'
1403 complt += _appendOptions("jvmci", r"G\:")
1404 # TODO: fix -XX:{-,+}Use* flags
1405 complt += _appendOptions("hotspot", r"XX\:")
1406 complt += '\t\t\t\t\t"-version" && ret=0 \n'
1407 complt += '\t\t\t\t;;\n'
1408 complt += '\t\tesac\n'
1409 complt += '\t\t;;\n'
1410 complt += 'esac\n'
1411 complt += '\n'
1412 complt += 'return $ret'
1413 print complt
1414
1415 def _fixQuotes(arg):
1416 return arg.replace('\"', '').replace('\'', '').replace('`', '').replace('{', '\\{').replace('}', '\\}').replace('[', '\\[').replace(']', '\\]')
1417
1418 def _appendOptions(optionType, optionPrefix):
1419 def isBoolean(vmap, field):
1420 return vmap[field] == "Boolean" or vmap[field] == "bool"
1421
1422 def hasDescription(vmap):
1423 return vmap['optDefault'] or vmap['optDoc']
1424
1425 complt = ""
1426 for vmap in _parseVMOptions(optionType):
1427 complt += '\t\t\t\t\t-"'
1428 complt += optionPrefix
1429 if isBoolean(vmap, 'optType'):
1430 complt += '"{-,+}"'
1431 complt += vmap['optName']
1432 if not isBoolean(vmap, 'optType'):
1433 complt += '='
1434 if hasDescription(vmap):
1435 complt += "["
1436 if vmap['optDefault']:
1437 complt += r"(default\: " + vmap['optDefault'] + ")"
1438 if vmap['optDoc']:
1439 complt += _fixQuotes(vmap['optDoc'])
1440 if hasDescription(vmap):
1441 complt += "]"
1442 complt += '" \\\n'
1443 return complt
1444
1445 def _parseVMOptions(optionType):
1446 parser = OutputParser()
1447 # TODO: the optDoc part can wrapped accross multiple lines, currently only the first line will be captured
1448 # TODO: fix matching for float literals
1449 jvmOptions = re.compile(
1450 r"^[ \t]*"
1451 r"(?P<optType>(Boolean|Integer|Float|Double|String|bool|intx|uintx|ccstr|double)) "
1452 r"(?P<optName>[a-zA-Z0-9]+)"
1453 r"[ \t]+=[ \t]*"
1454 r"(?P<optDefault>([\-0-9]+(\.[0-9]+(\.[0-9]+\.[0-9]+))?|false|true|null|Name|sun\.boot\.class\.path))?"
1455 r"[ \t]*"
1456 r"(?P<optDoc>.+)?",
1457 re.MULTILINE)
1458 parser.addMatcher(ValuesMatcher(jvmOptions, {
1459 'optType' : '<optType>',
1460 'optName' : '<optName>',
1461 'optDefault' : '<optDefault>',
1462 'optDoc' : '<optDoc>',
1463 }))
1464
1465 # gather JVMCI options
1466 output = StringIO.StringIO()
1467 vm(['-XX:-BootstrapJVMCI', '-XX:+UnlockDiagnosticVMOptions', '-G:+PrintFlags' if optionType == "jvmci" else '-XX:+PrintFlagsWithComments'],
1468 vm="jvmci",
1469 vmbuild="optimized",
1470 nonZeroIsFatal=False,
1471 out=output.write,
1472 err=subprocess.STDOUT)
1473
1474 valueMap = parser.parse(output.getvalue())
1475 return valueMap
1476
1477 def findbugs(args):
1478 '''run FindBugs against non-test Java projects'''
1479 findBugsHome = mx.get_env('FINDBUGS_HOME', None)
1480 if findBugsHome:
1481 findbugsJar = join(findBugsHome, 'lib', 'findbugs.jar')
1482 else:
1483 findbugsLib = join(_graal_home, 'lib', 'findbugs-3.0.0')
1484 if not exists(findbugsLib):
1485 tmp = tempfile.mkdtemp(prefix='findbugs-download-tmp', dir=_graal_home)
1486 try:
1487 findbugsDist = mx.library('FINDBUGS_DIST').get_path(resolve=True)
1488 with zipfile.ZipFile(findbugsDist) as zf:
1489 candidates = [e for e in zf.namelist() if e.endswith('/lib/findbugs.jar')]
1490 assert len(candidates) == 1, candidates
1491 libDirInZip = os.path.dirname(candidates[0])
1492 zf.extractall(tmp)
1493 shutil.copytree(join(tmp, libDirInZip), findbugsLib)
1494 finally:
1495 shutil.rmtree(tmp)
1496 findbugsJar = join(findbugsLib, 'findbugs.jar')
1497 assert exists(findbugsJar)
1498 nonTestProjects = [p for p in mx.projects() if not p.name.endswith('.test') and not p.name.endswith('.jtt')]
1499 outputDirs = map(mx._cygpathU2W, [p.output_dir() for p in nonTestProjects])
1500 javaCompliance = max([p.javaCompliance for p in nonTestProjects])
1501 findbugsResults = join(_graal_home, 'findbugs.results')
1502
1503 cmd = ['-jar', mx._cygpathU2W(findbugsJar), '-textui', '-low', '-maxRank', '15']
1504 if mx.is_interactive():
1505 cmd.append('-progress')
1506 cmd = cmd + ['-auxclasspath', mx._separatedCygpathU2W(mx.classpath([d.name for d in _jdkDeployedDists] + [p.name for p in nonTestProjects])), '-output', mx._cygpathU2W(findbugsResults), '-exitcode'] + args + outputDirs
1507 exitcode = mx.run_java(cmd, nonZeroIsFatal=False, javaConfig=mx.java(javaCompliance))
1508 if exitcode != 0:
1509 with open(findbugsResults) as fp:
1510 mx.log(fp.read())
1511 os.unlink(findbugsResults)
1512 return exitcode
1513
1514 def checkheaders(args):
1515 """check Java source headers against any required pattern"""
1516 failures = {}
1517 for p in mx.projects():
1518 if p.native:
1519 continue
1520
1521 csConfig = join(mx.project(p.checkstyleProj).dir, '.checkstyle_checks.xml')
1522 dom = xml.dom.minidom.parse(csConfig)
1523 for module in dom.getElementsByTagName('module'):
1524 if module.getAttribute('name') == 'RegexpHeader':
1525 for prop in module.getElementsByTagName('property'):
1526 if prop.getAttribute('name') == 'header':
1527 value = prop.getAttribute('value')
1528 matcher = re.compile(value, re.MULTILINE)
1529 for sourceDir in p.source_dirs():
1530 for root, _, files in os.walk(sourceDir):
1531 for name in files:
1532 if name.endswith('.java') and name != 'package-info.java':
1533 f = join(root, name)
1534 with open(f) as fp:
1535 content = fp.read()
1536 if not matcher.match(content):
1537 failures[f] = csConfig
1538 for n, v in failures.iteritems():
1539 mx.log('{0}: header does not match RegexpHeader defined in {1}'.format(n, v))
1540 return len(failures)
1541
1542 def mx_init(suite):
1543 commands = {
1544 'checkheaders': [checkheaders, ''],
1545 'clean': [clean, ''],
1546 'findbugs': [findbugs, ''],
1547 'generateZshCompletion' : [generateZshCompletion, ''],
1548 'maven-install-truffle' : [maven_install_truffle, ''],
1549 'jdkhome': [print_jdkhome, ''],
1550 'gate' : [gate, '[-options]'],
1551 'unittest' : [unittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix],
1552 'shortunittest' : [shortunittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix],
1553 'site' : [site, '[-options]'],
1554 'sl' : [sl, '[SL args|@VM options]'],
1555 'sldebug' : [sldebug, '[SL args|@VM options]'],
1556 'jol' : [jol, ''],
1557 }
1558
1559 mx.update_commands(suite, commands)
1560
1561 def mx_post_parse_cmd_line(opts): #
1562 # TODO _minVersion check could probably be part of a Suite in mx?
1563 if mx.java().version < _minVersion:
1564 mx.abort('Requires Java version ' + str(_minVersion) + ' or greater for JAVA_HOME, got version ' + str(mx.java().version))
1565 if _untilVersion and mx.java().version >= _untilVersion:
1566 mx.abort('Requires Java version strictly before ' + str(_untilVersion) + ' for JAVA_HOME, got version ' + str(mx.java().version))
1567
1568 for jdkDist in _jdkDeployedDists:
1569 def _close(jdkDeployable):
1570 def _install(dist):
1571 assert dist.name == jdkDeployable.name, dist.name + "!=" + jdkDeployable.name
1572 if not jdkDist.partOfHotSpot:
1573 _installDistInJdks(jdkDeployable)
1574 return _install
1575 mx.distribution(jdkDist.name).add_update_listener(_close(jdkDist))