def run(self, cfg, flags, args):
        output = target.flag(flags, "-o", "-")
        if ("--join", "") in flags:
            if len(args) < 1:
                raise target.ArgError()
            ifs = [parse(x) for x in args]
            result = ifs[0]
            for x in ifs[1:]:
                interface.joinInterfaces(result, x)
        else:
            # This is computing the interface
            if len(args) < 1:
                raise target.ArgError()
            if args[0] == "@*":
                iface = None
            else:
                iface = parse(args[0])
            libs = args[1:]

            if "--deep" in flags:
                result = deep(libs, iface)
            else:
                result = shallow(libs, iface)

        interface.writeInterface(result, output)
        return 0
def shallow(libs, iface):
    tf = tempfile.NamedTemporaryFile(suffix=".iface", delete=False)
    tf.close()
    if not (iface is None):
        interface.writeInterface(iface, tf.name)
    else:
        iface = interface.emptyInterface()

    for l in libs:
        passes.interface(l, tf.name, [tf.name], quiet=True)
        x = interface.parseInterface(tf.name)
        interface.joinInterfaces(iface, x)

    tf.unlink(tf.name)
    return iface
Пример #3
0
class PrevirtTool(target.Target):
    def opts(self, args):
        return getopt.getopt(args, ':o', ['work-dir=', 'force', 'no-strip'])

    def usage(self):
        return "%s [--work-dir=<dir>] [--force] [--no-strip] <manifest>" % self.name

    def desc(self):
        return """  Previrtualize a compilation unit based on its manifest."""

    def args(self):
        return [('--work-dir',
                 "Output intermediate files to the given location"),
                ('--no-strip', "Leave symbol information in the binary"),
                ('--force', "Proceed after dependency warnings")]

    def run(self, cfg, flags, args):
        if len(args) != 1:
            raise ArgError()

        manifest_file = args[0]
        manifest = json.load(open(manifest_file, 'r'))

        work_dir = get_work_dir(flags)
        if work_dir is None:
            work_dir = os.getcwd()
        force = get_flag(flags, 'force', False)

        if not os.path.exists(work_dir):
            sys.stderr.write("making working directory... '%s'\n" % work_dir)
            os.mkdir(work_dir)
        if not os.path.isdir(work_dir):
            sys.stderr.write("working directory '%s' is not a directory\n" %
                             work_dir)
            return 1

        modules = get_default(manifest, 'modules', [])
        if not (get_default(manifest, 'module', None) is None):
            modules += [get_default(manifest, 'module', None)]
        if len(modules) == 0:
            sys.stderr.write(
                "The manifest file '%s' does not have a main module!\n" %
                manifest_file)
            return 1

        libs = get_default(manifest, 'libs', [])
        ldflags = get_default(manifest, 'ldflags', [])
        native_libs = get_default(manifest, 'native-libs', [])
        shared = get_default(manifest, 'shared', [])
        search = get_default(manifest, 'search', [])
        arguments = get_default(manifest, 'args', None)
        name = get_default(manifest, 'name', None)
        watches = [
            os.path.abspath(x) for x in get_default(manifest, 'watch', [])
        ]
        binary = get_default(manifest, 'binary', modules[0] + '.exe')

        try:
            found_libs = [get_library(x, search) for x in libs]
        except NotFound, e:
            sys.stderr.write(
                "The library '%s' could not be found. Search path:" %
                e.__str__())
            sys.stderr.write('\n'.join(search))
            return 1

        print "\n\nldflags: ", ldflags, "\n\n"
        print "\n\nFound libraries: ", found_libs, "\n\n"

        non_llvm_libs = []

        if not all(map(lambda x: x[1], found_libs)):
            sys.stderr.write(
                "LLVM versions could not be found for all libraries\n")
            ok = True
            native = False
            for (x, tf) in found_libs:
                if tf and native:
                    ok = False
                if not tf:
                    native = True

                if tf:
                    sys.stderr.write("%s -- llvm\n" % x)
                else:
                    sys.stderr.write("%s -- native\n" % x)
                    non_llvm_libs.append(x)

            if not ok:
                sys.stderr.write(
                    "If native libraries refer to llvm libraries, this is NOT safe!\n"
                )
                if not force:
                    return 1

        llvm_libs = [x for (x, y) in found_libs if y]

        print "\n\nLLVM libs: ", llvm_libs, "\n\n"
        print "\n\nnon LLVM libs: ", non_llvm_libs, "\n\n"
        print "\n\nmodules: ", modules, "\n\n"

        temp_llvm_libs = []
        files = {}
        all_my_modules = [] + modules
        #+ Adding an archive_libs list to hold the native libraries that could not be converted to bitcode
        archive_libs = []
        for x in modules + llvm_libs:
            libCreated = False
            bn = prevent_collisions(x)
            target = os.path.join(work_dir, bn)
            if os.path.abspath(x) != target:
                shutil.copyfile(x, target)
            if target.endswith('.a'):
                if files.has_key(x):
                    # We've already seen this file, but we may need to pull in more symbols
                    print "don't handle linking the same file multiple times!"
                    return 1
                else:
                    sys.stderr.write(
                        "got archive %s, need to convert to .bc\n" % x)
                    #+ If the Bitcode equivalent of the library was found, the lib is added to the temp_llvm_libs instead to archive_libs(native)
                    libCreated = toolchain.archive_to_module(
                        target, target[:-2] + '.bc', minimal=all_my_modules)
                    if libCreated:
                        files[x] = FileStream(target[:-2], 'bc')
                        temp_llvm_libs.append(x)
                    else:
                        sys.stderr.write(
                            "Bitcode library not created; using native instead \n"
                        )
                        archive_libs.append(target)

            else:
                idx = target.rfind('.bc')
                if target[idx:] != '.bc':
                    shutil.copyfile(target, target[:idx] + '.bc')
                files[x] = FileStream(target[:idx], 'bc')
                if x not in modules:
                    temp_llvm_libs.append(x)
            if libCreated:
                all_my_modules += [files[x].get()]
            llvm_libs = temp_llvm_libs

    #print "\n\nLLVM libs after: ", llvm_libs, "\n\n"

    # Change directory
        os.chdir(work_dir)

        if not (arguments is None):
            # We need to specialize main for program arguments
            main = files[modules[0]]
            pre = main.get()
            post = main.new('a')

            passes.specialize_program_args(pre,
                                           post,
                                           arguments,
                                           'arguments',
                                           name=name)

        if watches != []:

            def _watch(m):
                "Applying watches"
                pre = m.get()
                post = m.new('watch')
                print pre
                toolchain.watch(pre, post, watches)

            InParallel(_watch, files.values())
        else:
            print "no watches to apply"

    # Internalize everything that we can
    # We can never internalize main
        interface.writeInterface(interface.mainInterface(), 'main.iface')

        # First compute the simple interfaces
        vals = files.items()
        refs = dict([(k,
                      VersionedFile(prevent_collisions(k[:k.rfind('.bc')]),
                                    'iface')) for (k, _) in vals])

        def _references((m, f)):
            "Computing references"
            name = refs[m].new()
            passes.interface(f.get(), name, [])

        InParallel(_references, vals)

        def _internalize((m, i)):
            "Internalizing from references"
            pre = i.get()
            post = i.new('i')
            # sys.stderr.write("%s interfaces\n%s" % (m,  '\n'.join([refs[f].get() for f in refs.keys() if f != m] +
            #              ['main.iface'])))

            passes.intern(pre, post,
                          [refs[f].get()
                           for f in refs.keys() if f != m] + ['main.iface'])

        InParallel(_internalize, vals)

        # Strip everything
        # This is safe because external names are not stripped
        def _strip(m):
            "Stripping symbols"
            pre = m.get()
            post = m.new('x')
            passes.strip(pre, post)

        if get_flag(flags, 'no-strip', None) is None:
            InParallel(_strip, files.values())

    # Begin main loop
        iface_before_file = VersionedFile('interface_before', 'iface')
        iface_after_file = VersionedFile('interface_after', 'iface')
        progress = True
        rewrite_files = {}
        for m in files.keys():
            base = prevent_collisions(m[:m.rfind('.bc')])
            rewrite_files[m] = VersionedFile(base, 'rw')
        iteration = 0
        while progress:
            iteration += 1
            progress = False

            # Intra-module previrt
            def intra(m):
                "Intra-module previrtualization"
                # for m in files.values():
                # intra-module previrt
                pre = m.get()
                pre_base = os.path.basename(pre)
                post = m.new('p')
                post_base = os.path.basename(post)
                fn = 'previrt_%s-%s' % (pre_base, post_base)
                print '%s === passes.peval ===> %s' % (pre_base, post_base)
                passes.peval(pre, post, log=open(fn, 'w'))

            InParallel(intra, files.values())

            # Inter-module previrt
            iface = passes.deep([x.get() for x in files.values()],
                                ['main.iface'])
            interface.writeInterface(iface, iface_before_file.new())

            # Specialize
            def _spec((nm, m)):
                "Inter-module module specialization"
                pre = m.get()
                post = m.new('s')
                rw = rewrite_files[nm].new()
                passes.specialize(pre, post, rw, [iface_before_file.get()])

            InParallel(_spec, files.items())

            # Rewrite
            def rewrite((nm, m)):
                "Inter-module module rewriting"
                pre = m.get()
                post = m.new('r')
                rws = [rewrite_files[x].get() for x in files.keys() if x != nm]
                out = [None]
                retcode = passes.rewrite(pre, post, rws, output=out)
                fn = 'rewrite_%s-%s' % (os.path.basename(pre),
                                        os.path.basename(post))
                dbg = open(fn, 'w')
                dbg.write(out[0])
                dbg.close()
                return retcode

            rws = InParallel(rewrite, files.items())
            progress = any(rws)

            # Aggressive internalization
            InParallel(_references, vals)
            InParallel(_internalize, vals)

            # Compute the interface again
            iface = passes.deep([x.get() for x in files.values()],
                                ['main.iface'])
            interface.writeInterface(iface, iface_after_file.new())

            # Prune
            def prune(m):
                "Pruning dead code/variables"
                pre = m.get()
                post = m.new('occam')
                passes.intern(pre, post, [iface_after_file.get()])

            InParallel(prune, files.values())

    # Make symlinks for the "final" versions
        for x in files.values():
            trg = x.base('-final')
            if os.path.exists(trg):
                os.unlink(trg)
            os.symlink(x.get(), trg)

    #+ final_libs contains the native and bitcode libraries in a list
        final_libs = [files[x].get()
                      for x in llvm_libs] + [x for x in archive_libs]

        print "\n\nFiles: ", files, "\n\n"
        print "\n\nArchive libs: ", archive_libs, "\n\n"
        print "\n\nLLVM libs: ", llvm_libs, "\n\n"
        print "\n\nFinal libs: ", final_libs, "\n\n"

        def toLflag(path):
            if os.path.exists(path):
                return "-L%s" % path
            else:
                return None

        searchflags = [x for x in map(toLflag, search) if x is not None]

        #removed these in the apache build. are they ever needed?
        xlinker_start = ['']
        xlinker_end = ['']
        #xlinker_start = ['-Wl,-static']
        #xlinker_end = ['-Wl,-call_shared']

        #iam: these two flags are not for Darwin.
        if platform.system() == 'Darwin':
            xlinker_start = ['']
            xlinker_end = ['']

        if '-lpthread' in native_libs:
            shared.append('-pthread')

    # Link everything together
        sys.stderr.write("linking...\n")
        if binary.endswith('.bc'):
            binary = binary[:-3]
        toolchain.llvmLDWrapper(binary, [files[m].get() for m in modules],
                                final_libs, searchflags, shared, xlinker_start,
                                native_libs, xlinker_end, [])
        sys.stderr.write("done\n")

        if not (POOL is None):
            POOL.shutdown()

        return 0