gollvm: tools cleanup
Delete wrapper script (no longer needed). Relocate helper program
capture-fcn-attributes.go from driver subdir to tools subdir (makes
more sense to have it there).
Change-Id: I383e4e90ff6f419d7d710abc3c9808bf9b500c65
Reviewed-on: https://go-review.googlesource.com/c/159100
Reviewed-by: Cherry Zhang <cherryyz@google.com>
diff --git a/driver/capture-fcn-attributes.go b/tools/capture-fcn-attributes.go
similarity index 100%
rename from driver/capture-fcn-attributes.go
rename to tools/capture-fcn-attributes.go
diff --git a/tools/gollvm-wrap.py b/tools/gollvm-wrap.py
deleted file mode 100755
index 2a5844f..0000000
--- a/tools/gollvm-wrap.py
+++ /dev/null
@@ -1,384 +0,0 @@
-#!/usr/bin/python
-"""Wrapper to selectively run gollvm instead of gccgo.
-
-This is a shim script that intercepts invocations of 'gccgo' and then
-in turn invokes either the real gccgo driver or a copy of gollvm
-instead, depending on the arguments and on environment variables.
-
-When performing a Go build with gccgo, the Go command will typically
-invoke gccgo once for each compilation step, which might look like
-
- gccgo -I ... -o objfile.o -g <options> file.go file2.go ... fileN.go
-
-and then a final invocation will be made at the link step, e.g.
-
- gccgo -L ... somearchive.a ... -o binary
-
-The goal of this shim is to convert invocations of the first form to
-llvm-goc invocations, and to ignore invocations of the second form
-and just pass them on to gccgo.
-
-We also tack on a set of additional "-L" options to the llvm-goc
-invocation so that it can find the go runtime libraries, and intercept
-the "-o" option so that we can run the asembler afterwards.
-
-To use this script, you will need a copy of GCCGO, e.g. the directory
-produced by running "make all && make install" in a GCCGO build tree.
-From within the gccgo install dir, run
-
- gollvm-wrap.py --install
-
-This will modify the install directory to insert the wrapper into the
-compilation path.
-
-"""
-
-import getopt
-import os
-import re
-import subprocess
-import sys
-import tempfile
-
-import script_utils as u
-
-# Echo command before executing
-flag_echo = True
-
-# Dry run mode
-flag_dryrun = False
-
-# gccgo only mode
-flag_nollvm = False
-
-# never invoke the real gccgo
-flag_alwaysllvm = False
-
-# trace llvm-goc invocations
-flag_trace_llinvoc = False
-
-
-def docmd(cmd):
- """Execute a command."""
- if flag_echo:
- sys.stderr.write("executing: " + cmd + "\n")
- if flag_dryrun:
- return
- u.docmd(cmd)
-
-
-def form_golibargs(driver):
- """Form correct go library args."""
- ddir = os.path.dirname(driver)
- bdir = os.path.dirname(ddir)
- cmd = "find %s/lib64 -name runtime.gox -print" % bdir
- lines = u.docmdlines(cmd)
- if not lines:
- u.error("no output from %s -- bad gccgo install dir?" % cmd)
- line = lines[0]
- rdir = os.path.dirname(line)
- u.verbose(1, "libdir is %s" % rdir)
- return rdir
-
-
-def perform():
- """Main driver routine."""
- global flag_trace_llinvoc
-
- u.verbose(1, "argv: %s" % " ".join(sys.argv))
-
- # llvm-goc should be available somewhere in PATH, error if not
- lines = u.docmdlines("which llvm-goc", True)
- if not lines:
- u.error("no 'llvm-goc' in PATH -- can't proceed")
-
- # Bypass the whole mess if -A
- if flag_alwaysllvm:
- a = sys.argv
- a[0] = "llvm-goc"
- driver = "llvm-goc"
- rc = subprocess.call(a)
- if rc != 0:
- u.verbose(1, "return code %d from %s" % (rc, " ".join(a)))
- return 1
- return 0
-
- # Perform a walk of the command line arguments looking for Go files.
- reg = re.compile(r"^(\S+)\.go$")
- gofile = None
- basename = None
- for clarg in sys.argv[1:]:
- m = reg.match(clarg)
- if m:
- gofile = clarg
- basename = m.group(1)
- break
-
- if not gofile or flag_nollvm:
- # No go files. Invoke real gccgo.
- bd = os.path.dirname(sys.argv[0])
- driver = "%s/gccgo.real" % bd
- u.verbose(1, "driver path is %s" % driver)
- args = [sys.argv[0]] + sys.argv[1:]
- u.verbose(1, "args: '%s'" % " ".join(args))
- if not os.path.exists(driver):
- usage("internal error: %s does not exist [most likely this "
- "script was not installed correctly]" % driver)
- os.execv(driver, args)
- u.error("exec failed: %s" % driver)
-
- # Create a set of massaged args.
- nargs = []
- skipc = 0
- outfile = None
- linkoutfile = None
- minus_s = False
- minus_v = False
- minus_c = False
- ofiles = []
- ldflags = []
- largsSeen = False
- for ii in range(1, len(sys.argv)):
- clarg = sys.argv[ii]
- if skipc != 0:
- skipc -= 1
- continue
- if clarg == "-S":
- minus_s = True
- if clarg == "-c":
- minus_c = True
- if clarg == "-o":
- outfile = sys.argv[ii+1]
- skipc = 1
- continue
- if clarg.startswith("-L"):
- largsSeen = True
- if clarg == "-v":
- flag_trace_llinvoc = True
- minus_v = True
-
- # redirect some gcc flags to the ones gollvm uses
- if clarg == "-w":
- clarg = "-no-warn"
-
- # dummy flags that are not supported by gollvm
- if clarg == "-lm":
- continue # TODO: if the linker is invoked, pass this to the linker?
- if clarg == "-fbounds-check":
- continue
- if clarg == "-finline-functions":
- continue
- if clarg == "-fno-diagnostics-show-caret":
- continue
- if clarg == "-fno-toplevel-reorder":
- continue
- if clarg == "-fno-var-tracking-assignments":
- continue
- if clarg == "-fomit-frame-pointer":
- continue
- if clarg == "-funroll-loops":
- continue
- if clarg == "-funsafe-math-optimizations":
- continue
- if clarg == "-gno-record-gcc-switches":
- continue
- if clarg == "-mfancy-math-387":
- continue
- if clarg == "-minline-all-stringops":
- continue
- if clarg == "-pedantic-errors":
- continue
- if clarg.startswith("-fdiagnostics-color"):
- continue
- if clarg.startswith("-fdebug-prefix-map"):
- continue
-
- # skip .o and .a files in compilation, but record
- # them for linker invocation.
- if clarg.endswith(".o"):
- ofiles.append(clarg)
- continue
- if clarg.endswith(".a"):
- ofiles.append(clarg)
- continue
-
- if clarg == "-static":
- ldflags.append(clarg)
- continue
- if clarg == "-static-libgo":
- ldflags.append(clarg)
- continue
- if clarg == "-static-libstdc++":
- ldflags.append(clarg)
- continue
- if clarg == "-static-libgcc":
- ldflags.append(clarg)
- continue
-
- nargs.append(clarg)
- u.verbose(2, "append arg %s" % clarg)
-
- tf = None
- if not minus_c and not minus_s:
- if not outfile:
- outfile = "a.out"
- linkoutfile = outfile
- tf = tempfile.NamedTemporaryFile(mode="w", prefix="%s" % basename,
- delete=True)
- outfile = tf.name
-
- if outfile:
- nargs.append("-o")
- nargs.append(outfile)
-
- if not largsSeen:
- nargs.append("-L")
- nargs.append(form_golibargs(sys.argv[0]))
- u.verbose(1, "revised args: %s" % " ".join(nargs))
-
- # Invoke gollvm.
- driver = "llvm-goc"
- u.verbose(1, "driver path is %s" % driver)
- nargs = ["llvm-goc"] + nargs
- if flag_trace_llinvoc or minus_v:
- u.verbose(0, "%s" % " ".join(nargs))
- rc = subprocess.call(nargs)
- if rc != 0:
- u.verbose(1, "return code %d from %s" % (rc, " ".join(nargs)))
- return 1
-
- # Invoke the linker
- # Right now we use the real gccgo as the linker
- if not minus_c and not minus_s:
- bd = os.path.dirname(sys.argv[0])
- driver = "%s/gccgo.real" % bd
- ldflags += ["-o", linkoutfile]
- ldcmd = "%s %s %s " % (driver, " ".join(ldflags), outfile)
- ldcmd += " ".join(ofiles) # pass extra .o files to the linker
- u.verbose(1, "link command is: %s" % ldcmd)
- if minus_v:
- u.verbose(0, "%s" % ldcmd)
- rc = u.docmdnf(ldcmd)
- if rc != 0:
- u.verbose(1, "return code %d from %s" % (rc, ldcmd))
- return 1
- if tf:
- tf.close()
-
- return 0
-
-
-def install_shim(scriptpath):
- """Install shim into gccgo install dir."""
-
- # Make sure we're in the right place (gccgo install dir)
- if not os.path.exists("bin"):
- usage("expected to find bin subdir")
- if not os.path.exists("lib64/libgo.so"):
- usage("expected to find lib64/libgo.so")
- if not os.path.exists("bin/gccgo"):
- usage("expected to find bin/gccgo")
-
- # Copy script, or update if already in place.
- docmd("cp %s bin" % scriptpath)
- sdir = os.path.dirname(scriptpath)
- docmd("cp %s/script_utils.py bin" % sdir)
-
- # Test to see if script installed already
- cmd = "file bin/gccgo"
- lines = u.docmdlines(cmd)
- if not lines:
- u.error("no output from %s -- bad gccgo install dir?" % cmd)
- else:
- reg = re.compile(r"^.+ ELF .+$")
- m = reg.match(lines[0])
- if not m:
- u.warning("wrapper appears to be installed already in this dir")
- return
-
- # Move aside the real gccgo binary
- docmd("mv bin/gccgo bin/gccgo.real")
-
- # Emit a script into gccgo
- sys.stderr.write("emitting wrapper script into bin/gccgo\n")
- if not flag_dryrun:
- try:
- with open("./bin/gccgo", "w") as wf:
- here = os.getcwd()
- wf.write("#!/bin/sh\n")
- wf.write("P=%s/bin/gollvm-wrap.py\n" % here)
- wf.write("exec python ${P} \"$@\"\n")
- except IOError:
- u.error("open/write failed for bin/gccgo wrapper")
- docmd("chmod 0755 bin/gccgo")
-
- # Success
- u.verbose(0, "wrapper installed successfully")
-
- # Done
- return 0
-
-
-def usage(msgarg):
- """Print usage and exit."""
- if msgarg:
- sys.stderr.write("error: %s\n" % msgarg)
- print """\
- usage: %s <gccgo args>
-
- Options (via command line)
- --install installs wrapper into gccgo directory
-
- Options (via GOLLVM_WRAP_OPTIONS):
- -t trace llvm-goc executions
- -d increase debug msg verbosity level
- -e show commands being invoked
- -D dry run (echo cmds but do not execute)
- -G pure gccgo compile (no llvm-goc invocations)
-
- """ % os.path.basename(sys.argv[0])
- sys.exit(1)
-
-
-def parse_env_options():
- """Option parsing from env var."""
- global flag_echo, flag_dryrun, flag_nollvm, flag_trace_llinvoc
- global flag_alwaysllvm
-
- optstr = os.getenv("GOLLVM_WRAP_OPTIONS")
- if not optstr:
- return
- args = optstr.split()
-
- try:
- optlist, _ = getopt.getopt(args, "detDAG")
- except getopt.GetoptError as err:
- # unrecognized option
- usage(str(err))
-
- for opt, _ in optlist:
- if opt == "-d":
- u.increment_verbosity()
- elif opt == "-e":
- flag_echo = True
- elif opt == "-t":
- flag_trace_llinvoc = True
- elif opt == "-D":
- flag_dryrun = True
- elif opt == "-G":
- flag_nollvm = True
- elif opt == "-A":
- flag_alwaysllvm = True
- u.verbose(1, "env var options parsing complete")
-
-
-# Setup
-u.setdeflanglocale()
-parse_env_options()
-
-# Either --install mode or regular mode
-if len(sys.argv) == 2 and sys.argv[1] == "--install":
- prc = install_shim(sys.argv[0])
-else:
- prc = perform()
-sys.exit(prc)
diff --git a/tools/script_utils.py b/tools/script_utils.py
deleted file mode 100644
index d681a7f..0000000
--- a/tools/script_utils.py
+++ /dev/null
@@ -1,304 +0,0 @@
-#!/usr/bin/python
-"""Utility functions for scripts in my bin diretory.
-
-This module contains common utilities such as wrappers for
-error/warning reporting, executing shell commands in a controlled way,
-etc. These functions are shared by a number of helper scripts.
-
-"""
-
-import locale
-import os
-import re
-import shlex
-import signal
-import subprocess
-import sys
-import tempfile
-
-# Debugging verbosity level (0 -> no output)
-flag_debug = 0
-
-# Unit testing mode. If set to 1, throw exception instead of calling exit()
-flag_unittest = 0
-
-hrszre = re.compile(r"^([\d\.]+)(\S)$")
-factors = {"K": 1024.0, "M": 1048576.0, "G": 1073741824.0}
-
-
-def verbose(level, msg):
- """Print debug trace output of verbosity level is >= value in 'level'."""
- if level <= flag_debug:
- sys.stderr.write(msg + "\n")
-
-
-def verbosity_level():
- """Return debug trace level."""
- return flag_debug
-
-
-def increment_verbosity():
- """Increment debug trace level by 1."""
- global flag_debug
- flag_debug += 1
-
-
-def decrement_verbosity():
- """Lower debug trace level by 1."""
- global flag_debug
- flag_debug -= 1
-
-
-def unit_test_enable():
- """Set unit testing mode."""
- global flag_unittest
- sys.stderr.write("+++ unit testing mode enabled +++\n")
- flag_unittest = 1
-
-
-def warning(msg):
- """Issue a warning to stderr."""
- sys.stderr.write("warning: " + msg + "\n")
-
-
-def error(msg):
- """Issue an error to stderr, then exit."""
- errm = "error: " + msg + "\n"
- sys.stderr.write(errm)
- if flag_unittest:
- raise Exception(errm)
- else:
- exit(1)
-
-
-def docmd(cmd):
- """Run a command via subprocess, issuing fatal error if cmd fails."""
- args = shlex.split(cmd)
- verbose(2, "+ docmd executing: %s" % cmd)
- rc = subprocess.call(args)
- if rc != 0:
- error("command failed: %s" % cmd)
-
-
-# Similar to docmd, but return status after issuing failure message
-def docmdnf(cmd):
- """Run a command via subprocess, returning exit status."""
- args = shlex.split(cmd)
- verbose(2, "+ docmd executing: %s" % cmd)
- rc = subprocess.call(args)
- return rc
-
-
-# Similar to docmd, but suppress output
-def doscmd(cmd, nf=None):
- """Run a command via subprocess, suppressing output unless error."""
- verbose(2, "+ doscmd executing: %s" % cmd)
- args = shlex.split(cmd)
- cmdtf = tempfile.NamedTemporaryFile(mode="w", delete=True)
- rc = subprocess.call(args, stdout=cmdtf, stderr=cmdtf)
- if rc != 0:
- warning("error: command failed (rc=%d) cmd: %s" % (rc, cmd))
- warning("output from failing command:")
- subprocess.call(["cat", cmdtf.name])
- if nf:
- return None
- error("")
- cmdtf.close()
- return True
-
-
-# invoke command, writing output to file
-def docmdout(cmd, outfile, nf=None):
- """Run a command via subprocess, writing output to a file."""
- verbose(2, "+ docmdout executing: %s > %s" % (cmd, outfile))
- args = shlex.split(cmd)
- with open(outfile, "w") as outfile:
- rc = subprocess.call(args, stdout=outfile)
- if rc != 0:
- warning("error: command failed (rc=%d) cmd: %s" % (rc, cmd))
- if nf:
- return None
- error("")
- return True
-
-# invoke command, writing output to file
-def docmderrout(cmd, outfile, nf=None):
- """Run a command via subprocess, writing output to a file."""
- verbose(2, "+ docmdout executing: %s > %s" % (cmd, outfile))
- args = shlex.split(cmd)
- try:
- with open(outfile, "w") as outfile:
- rc = subprocess.call(args, stdout=outfile, stderr=outfile)
- if rc != 0:
- if nf:
- sys.stderr.write("error: command failed (rc=%d) cmd: %s\n" % (rc, cmd))
- return rc
- else:
- error("command failed (rc=%d) cmd: %s\n" % (rc, cmd))
- return rc
- except IOError:
- error("unable to open %s for writing" % outfile)
-
-
-# invoke command, reading from one file and writing to another
-def docmdinout(cmd, infile, outfile):
- """Run a command via subprocess with input and output file."""
- verbose(2, "+ docmdinout executing: %s < %s > %s" % (cmd, infile, outfile))
- args = shlex.split(cmd)
- cmdtf = tempfile.NamedTemporaryFile(mode="w", delete=True)
- with open(infile, "r") as inf:
- with open(outfile, "w") as outf:
- rc = subprocess.call(args, stdout=outf, stdin=inf, stderr=cmdtf)
- if rc != 0:
- warning("error: command failed (rc=%d) cmd: %s" % (rc, cmd))
- warning("output from failing command:")
- subprocess.call(["cat", cmdtf.name])
- return 1
- verbose(2, "+ finished: %s < %s > %s" % (cmd, infile, outfile))
- return 0
-
-
-# invoke command, returning array of lines read from it
-def docmdlines(cmd, nf=None):
- """Run a command via subprocess, returning output as an array of lines."""
- verbose(2, "+ docmdlines executing: %s" % cmd)
- args = shlex.split(cmd)
- mypipe = subprocess.Popen(args, stdout=subprocess.PIPE)
- encoding = locale.getdefaultlocale()[1]
- if encoding is None:
- encoding = 'UTF-8'
- pout, perr = mypipe.communicate()
- if mypipe.returncode != 0:
- if perr:
- decoded_err = perr.decode(encoding)
- warning(decoded_err)
- if nf:
- return None
- error("command failed (rc=%d): cmd was %s" % (mypipe.returncode, args))
- decoded = pout.decode(encoding)
- lines = decoded.strip().split("\n")
- return lines
-
-
-# invoke command, returning raw bytes from read
-def docmdbytes(cmd, nf=None):
- """Run a command via subprocess, returning output as raw bytestring."""
- args = shlex.split(cmd)
- mypipe = subprocess.Popen(args, stdout=subprocess.PIPE)
- pout, perr = mypipe.communicate()
- if mypipe.returncode != 0:
- encoding = locale.getdefaultlocale()[1]
- if perr:
- decoded_err = perr.decode(encoding)
- warning(decoded_err)
- if nf:
- return None
- error("command failed (rc=%d): cmd was %s" % (mypipe.returncode, args))
- return pout
-
-
-# invoke a command with input coming from an echo'd string, e.g.
-# Ex: "echo 1+2 | perl"
-def docmdinstring(cmd, instring):
- """Invoke a command with stdin coming from a specific string."""
- verbose(2, "+ docmdinstring executing: echo %s | %s " % (cmd, instring))
- args = shlex.split(cmd)
- mypipe = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
- encoding = locale.getdefaultlocale()[1]
- pout, perr = mypipe.communicate(instring)
- if mypipe.returncode != 0:
- if perr:
- decoded_err = perr.decode(encoding)
- warning(decoded_err)
- error("command failed (rc=%d): cmd was %s" % (mypipe.returncode, args))
- decoded = pout.decode(encoding)
- lines = decoded.strip().split("\n")
- return lines
-
-
-# Execute a command with an alarm timeout.
-def docmdwithtimeout(cmd, timeout_duration):
- """Run a command via subprocess, returning exit status or -1 if timeout."""
-
- class TimeoutError(Exception):
- pass
-
- def handler(signum, frame):
- raise TimeoutError()
-
- # set the timeout handler
- prevhandler = signal.signal(signal.SIGALRM, handler)
- signal.alarm(timeout_duration)
- try:
- result = docmdnf(cmd)
- except TimeoutError as exc:
- verbose(1, "timeout triggered after %d seconds" % timeout_duration)
- result = -1
- finally:
- signal.alarm(0)
- signal.signal(signal.SIGALRM, prevhandler)
- return result
-
-
-# perform default locale setup if needed
-def setdeflanglocale():
- if "LANG" not in os.environ:
- warning("no env setting for LANG -- using default values")
- os.environ["LANG"] = "en_US.UTF-8"
- os.environ["LANGUAGE"] = "en_US:"
-
-
-def determine_btrfs_ssdroot(here):
- """Determine ssd root."""
-
- path_components = here.split("/")
- root = "/%s" % path_components[1]
- verbose(2, "cwd=%s root=%s" % (here, root))
-
- # Is this a BTRFS ssd to begin with?
- outlines = docmdlines("stat -f --printf=%%T %s" % root)
- if not outlines:
- error("internal error-- could not determine FS type "
- "for root dir %s" % root)
- if outlines[0] != "btrfs":
- error("current FS type is %s, not btrfs (can't proceed)" % outlines[0])
- return root
-
-
-def hr_size_to_bytes(sz):
- """Convert human readable size back to bytes."""
- m = hrszre.match(sz)
- if not m:
- warning("unmatchable size expr %s" % sz)
- return None
- val = float(m.group(1))
- facs = m.group(2)
- if facs not in factors:
- warning("unknown factor '%s' in size expr %s" % (facs, sz))
- return None
- fac = factors[facs]
- nb = int(val * fac)
- return nb
-
-
-def trim_perf_report_file(infile):
- """Trim trailing spaces from lines in perf report."""
- verbose(1, "trim: reading " + infile)
- try:
- f = open(infile, "r")
- except IOError:
- warning("unable to open file %s for reading" % infile)
- return 1
- lines = f.readlines()
- f.close()
- verbose(1, "trim: rewriting " + infile)
- try:
- ft = open(infile, "w")
- except IOError:
- warning("unable to open file %s for rewriting" % infile)
- return 1
- for line in lines:
- sline = line.rstrip()
- ft.write(sline + "\n")
- ft.close()
- return 0