예제 #1
0
def install_tinycbor() -> Optional[str]:
    """
    download, unpack, build, and install tinycbor.
    """
    cc_cmd_db = os.path.join(c.CBOR_SRC, "compile_commands.json")

    def path_to_cc_db():
        if not os.path.isfile(cc_cmd_db) and not on_mac():
            die("not found: " + cc_cmd_db)
        return cc_cmd_db

    # skip recompilation iff:
    # 1. cbor appears to have been installed,
    # 2. we have the right archive downloaded (catches version changes), and
    # 3. we have a compile commands database for sanity testing or
    #    we're on mac where we can't use bear to generate the database.
    if os.path.isdir(c.CBOR_PREFIX) and \
       os.path.isfile(c.CBOR_ARCHIVE) and \
       (os.path.isfile(cc_cmd_db) or on_mac()):
        logging.debug("skipping tinycbor installation")
        return path_to_cc_db()

    # download
    if not os.path.isfile(c.CBOR_ARCHIVE):
        curl = get_cmd_or_die("curl")
        curl['-s', c.CBOR_URL, '-o', c.CBOR_ARCHIVE] & pb.TEE

    # remove any existing build dir since we don't know if
    # tinycbor was built for the current host environment.
    if os.path.isdir(c.CBOR_SRC):
        shutil.rmtree(c.CBOR_SRC, ignore_errors=True)

    # unpack
    tar = get_cmd_or_die("tar")
    with pb.local.cwd(c.DEPS_DIR):
        tar['xf', c.CBOR_ARCHIVE] & pb.TEE

    # update install prefix
    update_cbor_prefix(os.path.join(c.CBOR_SRC, "Makefile"))

    # make && install
    # NOTE: we use bear to wrap make invocations such that
    # we get a .json database of compiler commands that we
    # can use to test ast-exporter. On macOS, bear requires
    # system integrity protection to be turned off, so we
    # only use bear on Ubuntu Linux hosts.
    with pb.local.cwd(c.CBOR_SRC):
        make = get_cmd_or_die("make")
        if not on_mac():
            bear = get_cmd_or_die(c.BEAR_BIN)
            make = bear[make]
        make & pb.TEE  # nopep8
        make('install')  # & pb.TEE

    return path_to_cc_db()
예제 #2
0
def _parse_args():
    """
    define and parse command line arguments here.
    """
    desc = 'download dependencies for the AST exporter and built it.'
    parser = argparse.ArgumentParser(description=desc)
    parser.add_argument('-c', '--clean-all', default=False,
                        action='store_true', dest='clean_all',
                        help='clean everything before building')
    parser.add_argument('--with-clang', default=False,
                        action='store_true', dest='with_clang',
                        help='build clang with this tool')
    llvm_ver_help = 'fetch and build specified version of clang/LLVM (default: {})'.format(c.LLVM_VER)
    # FIXME: build this list by globbing for scripts/llvm-*.0.*-key.asc
    llvm_ver_choices = ["6.0.0", "6.0.1", "7.0.0", "7.0.1", "8.0.0"]
    parser.add_argument('--with-llvm-version', default=None,
                        action='store', dest='llvm_ver',
                        help=llvm_ver_help, choices=llvm_ver_choices)
    parser.add_argument('--without-assertions', default=True,
                        action='store_false', dest='assertions',
                        help='build the tool and clang without assertions')
    parser.add_argument('-x', '--xcode', default=False,
                        action='store_true', dest='xcode',
                        help='generate Xcode project files (macOS only)')
    parser.add_argument('-v', '--verbose', default=False,
                        action='store_true', dest='verbose',
                        help='emit verbose information during build')
    c.add_args(parser)
    args = parser.parse_args()

    if not on_mac() and args.xcode:
        die("-x/--xcode option requires macOS host.")

    c.update_args(args)
    return args
예제 #3
0
def build_transpiler(args):
    cargo = get_cmd_or_die("cargo")
    build_flags = ["build", "--features", "llvm-static"]

    if not args.debug:
        build_flags.append("--release")

    llvm_config = os.path.join(c.LLVM_BLD, "bin/llvm-config")
    assert os.path.isfile(llvm_config), "missing binary: " + llvm_config

    if on_mac():
        llvm_system_libs = "-lz -lcurses -lm -lxml2"
    else:  # linux
        llvm_system_libs = "-lz -lrt -ltinfo -ldl -lpthread -lm"

    llvm_libdir = os.path.join(c.LLVM_BLD, "lib")

    # log how we run `cargo build` to aid troubleshooting, IDE setup, etc.
    msg = "invoking cargo build as\ncd {} && \\\n".format(c.C2RUST_DIR)
    msg += "LLVM_CONFIG_PATH={} \\\n".format(llvm_config)
    msg += "LLVM_SYSTEM_LIBS='{}' \\\n".format(llvm_system_libs)
    msg += "C2RUST_AST_EXPORTER_LIB_DIR={} \\\n".format(llvm_libdir)
    msg += " cargo +{} ".format(c.CUSTOM_RUST_NAME)
    msg += " ".join(build_flags)
    logging.debug(msg)

    with pb.local.cwd(c.C2RUST_DIR):
        with pb.local.env(LLVM_CONFIG_PATH=llvm_config,
                          LLVM_SYSTEM_LIBS=llvm_system_libs,
                          C2RUST_AST_EXPORTER_LIB_DIR=llvm_libdir):
            # build with custom rust toolchain
            invoke(cargo, "+" + c.CUSTOM_RUST_NAME, *build_flags)
예제 #4
0
def _main():
    if on_mac():
        die("Cross-checking is only supported on Linux hosts.")

    setup_logging()
    logging.debug("args: %s", " ".join(sys.argv))

    # earlier plumbum versions are missing features such as TEE
    if pb.__version__ < c.MIN_PLUMBUM_VERSION:
        err = "locally installed version {} of plumbum is too old.\n" \
            .format(pb.__version__)
        err += "please upgrade plumbum to version {} or later." \
            .format(c.MIN_PLUMBUM_VERSION)
        die(err)

    args = _parse_args()
    if args.clean_all:
        logging.info("cleaning all dependencies and previous built files")
        shutil.rmtree(c.CLANG_XCHECK_PLUGIN_BLD, ignore_errors=True)
        make = get_cmd_or_die('make')
        with pb.local.cwd(c.LIBFAKECHECKS_DIR):
            make('clean')

    # clang 3.6.0 is known to work; 3.4.0 known to not work.
    ensure_clang_version([3, 6, 0])
    # NOTE: it seems safe to disable this check since we now
    # that we use a rust-toolchain file for rustc versioning.
    # ensure_rustc_version(c.CUSTOM_RUST_RUSTC_VERSION)

    ensure_dir(c.CLANG_XCHECK_PLUGIN_BLD)
    ensure_dir(c.BUILD_DIR)
    git_ignore_dir(c.BUILD_DIR)

    build_clang_plugin(args)
예제 #5
0
    def translate(self, cc_db, extra_args: List[str] = []) -> RustFile:
        extensionless_file, _ = os.path.splitext(self.path)

        # help plumbum find rust
        ld_lib_path = get_rust_toolchain_libpath()
        if 'LD_LIBRARY_PATH' in pb.local.env:
            ld_lib_path += ':' + pb.local.env['LD_LIBRARY_PATH']

        # run the transpiler
        transpiler = get_cmd_or_die(c.TRANSPILER)

        args = [
            cc_db,
            "--prefix-function-names",
            "rust_",
            "--overwrite-existing",
        ]

        if self.disable_incremental_relooper:
            args.append("--no-incremental-relooper")
        if self.disallow_current_block:
            args.append("--fail-on-multiple")
        if self.translate_const_macros:
            args.append("--translate-const-macros")
        if self.reorganize_definitions:
            args.append("--reorganize-definitions")
        if self.emit_build_files:
            args.append("--emit-build-files")

        if self.logLevel == 'DEBUG':
            args.append("--log-level=debug")

        args.append("--")
        args.extend(extra_args)

        # Add -isysroot on MacOS to get SDK directory
        if on_mac():
            try:
                xcrun = pb.local["xcrun"]
                args.append("-isysroot" + xcrun("--show-sdk-path").strip())
            except pb.CommandNotFound:
                pass

        with pb.local.env(RUST_BACKTRACE='1', LD_LIBRARY_PATH=ld_lib_path):
            # log the command in a format that's easy to re-run
            translation_cmd = "LD_LIBRARY_PATH=" + ld_lib_path + " \\\n"
            translation_cmd += str(transpiler[args])
            logging.debug("translation command:\n %s", translation_cmd)
            retcode, stdout, stderr = (transpiler[args]).run(
                retcode=None)

            logging.debug("stdout:\n%s", stdout)
            logging.debug("stderr:\n%s", stderr)

        if retcode != 0:
            raise NonZeroReturn(stderr)

        return RustFile(extensionless_file + ".rs")
예제 #6
0
def _main():
    setup_logging()
    logging.debug("args: %s", " ".join(sys.argv))

    # FIXME: allow env/cli override of LLVM_SRC, LLVM_VER, and LLVM_BLD
    # FIXME: check that cmake and ninja are installed
    # FIXME: option to build LLVM/Clang from master?

    # earlier plumbum versions are missing features such as TEE
    if pb.__version__ < c.MIN_PLUMBUM_VERSION:
        err = "locally installed version {} of plumbum is too old.\n" \
            .format(pb.__version__)
        err += "please upgrade plumbum to version {} or later." \
            .format(c.MIN_PLUMBUM_VERSION)
        die(err)

    args = _parse_args()
    if args.clean_all:
        logging.info("cleaning all dependencies and previous built files")
        shutil.rmtree(c.LLVM_SRC, ignore_errors=True)
        shutil.rmtree(c.LLVM_BLD, ignore_errors=True)
        shutil.rmtree(c.DEPS_DIR, ignore_errors=True)

    # prerequisites
    if not have_rust_toolchain(c.CUSTOM_RUST_NAME):
        die("missing rust toolchain: " + c.CUSTOM_RUST_NAME, errno.ENOENT)

    # clang 3.6.0 is known to work; 3.4.0 known to not work.
    ensure_clang_version([3, 6, 0])
    ensure_rustc_version(c.CUSTOM_RUST_RUSTC_VERSION)

    ensure_dir(c.LLVM_BLD)
    ensure_dir(c.DEPS_DIR)
    git_ignore_dir(c.DEPS_DIR)

    if on_linux():
        build_a_bear()
        if not os.path.isfile(c.BEAR_BIN):
            die("bear not found", errno.ENOENT)

    download_llvm_sources()

    integrate_ast_exporter()

    cc_db = install_tinycbor()

    configure_and_build_llvm(args)

    # NOTE: we're not doing this anymore since it is
    # faster and takes less space to simply pull the
    # prebuilt nightly binaries with rustup
    # download_and_build_custom_rustc(args)

    build_ast_importer(args.debug)

    if not on_mac() and args.sanity_test:
        test_ast_exporter(cc_db)
예제 #7
0
def build_transpiler(args):
    nice = get_cmd_or_die("nice")
    cargo = get_cmd_or_die("cargo")

    if need_cargo_clean(args):
        invoke(cargo, "clean")

    build_flags = [
        "-n", "19",
        str(cargo), "build", "--features", "llvm-static"
    ]

    if not args.debug:
        build_flags.append("--release")

    if args.verbose:
        build_flags.append("-vv")

    llvm_config = os.path.join(c.LLVM_BLD, "bin/llvm-config")
    assert os.path.isfile(llvm_config), "missing binary: " + llvm_config

    if on_mac():
        llvm_system_libs = "-lz -lcurses -lm -lxml2"
    else:  # linux
        llvm_system_libs = "-lz -lrt -ltinfo -ldl -lpthread -lm"

    llvm_libdir = os.path.join(c.LLVM_BLD, "lib")

    # log how we run `cargo build` to aid troubleshooting, IDE setup, etc.
    msg = "invoking cargo build as\ncd {} && \\\n".format(c.C2RUST_DIR)
    msg += "LIBCURL_NO_PKG_CONFIG=1\\\n"
    msg += "ZLIB_NO_PKG_CONFIG=1\\\n"
    msg += "LLVM_CONFIG_PATH={} \\\n".format(llvm_config)
    msg += "LLVM_SYSTEM_LIBS='{}' \\\n".format(llvm_system_libs)
    msg += "C2RUST_AST_EXPORTER_LIB_DIR={} \\\n".format(llvm_libdir)
    msg += " cargo"
    msg += " ".join(build_flags)
    logging.debug(msg)

    # NOTE: the `curl-rust` and `libz-sys` crates use the `pkg_config`
    # crate to locate the system libraries they wrap. This causes
    # `pkg_config` to add `/usr/lib` to `rustc`s library search path
    # which means that our `cargo` invocation picks up the system
    # libraries even when we're trying to link against libs we built.
    # https://docs.rs/pkg-config/0.3.14/pkg_config/
    with pb.local.cwd(c.C2RUST_DIR):
        with pb.local.env(LIBCURL_NO_PKG_CONFIG=1,
                          ZLIB_NO_PKG_CONFIG=1,
                          LLVM_CONFIG_PATH=llvm_config,
                          LLVM_SYSTEM_LIBS=llvm_system_libs,
                          C2RUST_AST_EXPORTER_LIB_DIR=llvm_libdir):
            invoke(nice, *build_flags)
예제 #8
0
def _is_excluded(name):
    """
    The examples that use x11 and the `f128` crate need to be excluded on macOS.
    This function can be extended to exclude examples
    on the linux platform as well.
    """
    mac_exclusion_set = {
        "grabc",
        "libxml2",
        "tinycc",
        "xzoom",
    }

    return name in mac_exclusion_set and on_mac()
예제 #9
0
def build_transpiler(args):
    nice = get_cmd_or_die("nice")
    cargo = get_cmd_or_die("cargo")

    if need_cargo_clean(args):
        invoke(cargo, "clean")

    build_flags = [
        "-n", "19",
        str(cargo), "build", "--features", "llvm-static"
    ]

    if not args.debug:
        build_flags.append("--release")

    if args.verbose:
        build_flags.append("-vv")

    llvm_config = os.path.join(c.LLVM_BLD, "bin/llvm-config")
    assert os.path.isfile(llvm_config), \
        "expected llvm_config at " + llvm_config

    if on_mac():
        llvm_system_libs = "-lz -lcurses -lm -lxml2"
    else:  # linux
        llvm_system_libs = "-lz -lrt -ltinfo -ldl -lpthread -lm"

    llvm_libdir = os.path.join(c.LLVM_BLD, "lib")

    # NOTE: the `curl-rust` and `libz-sys` crates use the `pkg_config`
    # crate to locate the system libraries they wrap. This causes
    # `pkg_config` to add `/usr/lib` to `rustc`s library search path
    # which means that our `cargo` invocation picks up the system
    # libraries even when we're trying to link against libs we built.
    # https://docs.rs/pkg-config/0.3.14/pkg_config/
    with pb.local.cwd(c.C2RUST_DIR):
        with pb.local.env(LIBCURL_NO_PKG_CONFIG=1,
                          ZLIB_NO_PKG_CONFIG=1,
                          LLVM_CONFIG_PATH=llvm_config,
                          LLVM_LIB_DIR=llvm_libdir,
                          LLVM_SYSTEM_LIBS=llvm_system_libs):
            invoke(nice, *build_flags)
예제 #10
0
def test_ast_exporter(cc_db_path: str):
    """
    run ast-exporter on tinycbor if on linux. testing is
    not supported on macOS since bear requires system integrity
    protection to be disabled.
    """
    assert not on_mac(), "sanity testing requires linux host"

    ast_extr = os.path.join(c.LLVM_BIN, "ast-exporter")
    if not os.path.isfile(ast_extr):
        die("ast-exporter not found in " + c.LLVM_BIN)
    ast_extr = get_cmd_or_die(ast_extr)

    include_dirs = get_system_include_dirs()

    with open(cc_db_path, "r") as handle:
        cc_db = json.load(handle)
    for cmd in cc_db:
        exporter_ast_from(ast_extr, cc_db_path, include_dirs, **cmd)

    logging.info("PASS sanity testing")
def test_ruby(args: argparse.Namespace) -> bool:
    if on_mac():
        die("transpiling ruby on mac is not supported.")

    if not os.path.isfile(os.path.join(c.DEPS_DIR, RUBY_ARCHIVE)):
        with pb.local.cwd(c.DEPS_DIR):
            download_archive(RUBY_URL, RUBY_ARCHIVE)
            invoke_quietly(TAR, "xf", RUBY_ARCHIVE)

    cc_db_file = os.path.join(RUBY_SRC, c.CC_DB_JSON)

    # unconditionally compile ruby since we don't know if
    # cc_db was generated from the environment we're in.
    with pb.local.cwd(RUBY_SRC), pb.local.env(CC="clang", cflags="-w"):
        configure = pb.local.get("./configure")
        invoke(configure)
        invoke(BEAR[MAKE[JOBS]])

    if not os.path.isfile(cc_db_file):
        die("missing " + cc_db_file, errno.ENOENT)

    with open(cc_db_file) as cc_db:
        return transpile_files(cc_db, args.jobs, None, False, args.verbose)
예제 #12
0
def _parse_args():
    """
    define and parse command line arguments here.
    """
    desc = 'download dependencies for the AST exporter and built it.'
    parser = argparse.ArgumentParser(description=desc)
    parser.add_argument('-c',
                        '--clean-all',
                        default=False,
                        action='store_true',
                        dest='clean_all',
                        help='clean everything before building')
    parser.add_argument('--with-clang',
                        default=False,
                        action='store_true',
                        dest='with_clang',
                        help='build clang with this tool')
    parser.add_argument('--without-assertions',
                        default=True,
                        action='store_false',
                        dest='assertions',
                        help='build the tool and clang without assertions')
    parser.add_argument('-x',
                        '--xcode',
                        default=False,
                        action='store_true',
                        dest='xcode',
                        help='generate Xcode project files (macOS only)')
    c.add_args(parser)
    args = parser.parse_args()

    if not on_mac() and args.xcode:
        die("-x/--xcode option requires macOS host.")

    c.update_args(args)
    return args
예제 #13
0
 def path_to_cc_db():
     if not os.path.isfile(cc_cmd_db) and not on_mac():
         die("not found: " + cc_cmd_db)
     return cc_cmd_db
예제 #14
0
def transpile_files(cc_db: TextIO,
                    filter: str = None,
                    extra_impo_args: List[str] = [],
                    import_only: bool = False,
                    verbose: bool = False,
                    emit_build_files: bool = True,
                    main_module_for_build_files: str = None,
                    cross_checks: bool = False,
                    use_fakechecks: bool = False,
                    cross_check_config: List[str] = [],
                    reloop_cfgs: bool = True) -> bool:
    """
    run the ast-exporter and ast-importer on all C files
    in a compile commands database.
    """
    rustfmt = os.path.join(get_rust_toolchain_binpath(), "rustfmt")
    rustfmt = get_cmd_or_die(rustfmt)
    ast_expo = get_cmd_or_die(c.AST_EXPO)
    ast_impo = get_cmd_or_die(c.AST_IMPO)
    cc_db_name = cc_db.name
    cc_db = json.load(cc_db)

    check_main_module(main_module_for_build_files, cc_db)

    if filter:  # skip commands not matching file filter
        cc_db = [cmd for cmd in cc_db if filter in c['file']]

    if not on_mac():
        ensure_code_compiled_with_clang(cc_db)
    include_dirs = get_system_include_dirs()

    impo_args = ['--translate-entry']
    if emit_build_files:
        impo_args.append('--emit-module')
    if cross_checks:
        impo_args.append('--cross-checks')
        for ccc in cross_check_config:
            impo_args.append('--cross-check-config')
            impo_args.append(ccc)
    if reloop_cfgs:
        impo_args.append('--reloop-cfgs')

    def transpile_single(cmd) -> Tuple[str, int, str, str, str]:

        if import_only:
            cbor_file = os.path.join(cmd['directory'], cmd['file'] + ".cbor")
        else:
            cbor_file = export_ast_from(ast_expo, cc_db_name, include_dirs,
                                        **cmd)
        assert os.path.isfile(cbor_file), "missing: " + cbor_file

        ld_lib_path = get_rust_toolchain_libpath()

        # don't overwrite existing ld lib path if any...
        if 'LD_LIBRARY_PATH' in pb.local.env:
            ld_lib_path += ':' + pb.local.env['LD_LIBRARY_PATH']

        # import ast
        with pb.local.env(RUST_BACKTRACE='1', LD_LIBRARY_PATH=ld_lib_path):
            file_basename = os.path.basename(cmd['file'])
            cbor_basename = os.path.basename(cbor_file)
            logging.info(" importing ast from %s", cbor_basename)
            translation_cmd = "RUST_BACKTRACE=1 \\\n"
            translation_cmd += "LD_LIBRARY_PATH=" + ld_lib_path + " \\\n"
            translation_cmd += str(ast_impo[cbor_file, impo_args,
                                            extra_impo_args])
            logging.debug("translation command:\n %s", translation_cmd)
            try:
                retcode, _stdout, _stderr = ast_impo[cbor_file, impo_args,
                                                     extra_impo_args].run()

                e = "Expected file suffix `.c.cbor`; actual: " + cbor_basename
                assert cbor_file.endswith(".c.cbor"), e
                rust_file = cbor_file[:-7] + ".rs"
                with open(rust_file, "w") as rust_fh:
                    rust_fh.writelines(_stdout)
                    logging.debug("wrote output rust to %s", rust_file)

                rustfmt(rust_file)

                return (file_basename, retcode, _stdout, _stderr,
                        os.path.abspath(rust_file))
            except pb.ProcessExecutionError as pee:
                return (file_basename, pee.retcode, pee.stdout, pee.stderr,
                        None)

    commands = sorted(cc_db, key=lambda cmd: os.path.basename(cmd['file']))
    results = (transpile_single(cmd) for cmd in commands)

    if emit_build_files:
        modules = [(rust_src, retcode == 0)
                   for (_, retcode, _, _, rust_src) in results
                   if rust_src is not None]
        cc_db_dir = os.path.dirname(cc_db_name)
        write_build_files(cc_db_dir, modules, main_module_for_build_files,
                          cross_checks, use_fakechecks, cross_check_config)

    successes, failures = 0, 0
    for (fname, retcode, stdout, stderr, _) in results:
        if not retcode:
            successes += 1
            print(Colors.OKGREEN + " import successful" + Colors.NO_COLOR)
            logging.debug(" import successful")
        else:  # non-zero retcode
            failures += 1
            if verbose:
                print(Colors.FAIL + " import failed" + Colors.NO_COLOR)
                logging.debug(" import failed")
                logging.warning(stderr)
            else:
                print(Colors.FAIL + " import failed (error in log)" +
                      Colors.NO_COLOR)
                logging.debug(" import failed")
                logging.debug(stderr)
    print("translations: " + str(successes + failures))
    print("successes...: " + str(successes))
    print("failures....: " + str(failures))
    return failures == 0
예제 #15
0
파일: transpile.py 프로젝트: Laeeth/c2rust
def transpile_files(cc_db: TextIO,
                    filter: Optional[Callable[[str], bool]] = None,
                    extra_impo_args: List[str] = [],
                    import_only: bool = False,
                    verbose: bool = False,
                    emit_build_files: bool = True,
                    emit_modules: bool = False,
                    main_module_for_build_files: str = None,
                    cross_checks: bool = False,
                    use_fakechecks: bool = False,
                    cross_check_config: List[str] = [],
                    reloop_cfgs: bool = True,
                    reorganize_definitions: bool = False) -> bool:
    """
    run the ast-exporter and ast-importer on all C files
    in a compile commands database.
    """
    rustfmt = os.path.join(get_rust_toolchain_binpath(), "rustfmt")
    rustfmt = get_cmd_or_die(rustfmt)
    ast_expo = get_cmd_or_die(c.AST_EXPO)
    ast_impo = get_cmd_or_die(c.AST_IMPO)
    cc_db_name = cc_db.name
    cc_db = json.load(cc_db)

    check_main_module(main_module_for_build_files, cc_db)

    if filter:  # skip commands not matching file filter
        cc_db = [cmd for cmd in cc_db if filter(cmd['file'])]

    if not on_mac():
        ensure_code_compiled_with_clang(cc_db)

    # MacOS Mojave does not have `/usr/include` even if the command line
    # tools are installed. The fix is to run the developer package:
    # `macOS_SDK_headers_for_macOS_10.14.pkg` in
    # `/Library/Developer/CommandLineTools/Packages`.
    # Source https://forums.developer.apple.com/thread/104296
    if on_mac() and not os.path.isdir('/usr/include'):
        emsg = ("directory /usr/include not found. "
                "Please install the following package: "
                "/Library/Developer/CommandLineTools/Packages/"
                "macOS_SDK_headers_for_macOS_10.14.pkg "
                "or the equivalent version on your host.")
        die(emsg, errno.ENOENT)

    impo_args = ['--translate-entry']
    if emit_build_files or emit_modules:
        impo_args.append('--emit-module')
    if cross_checks:
        impo_args.append('--cross-checks')
        for ccc in cross_check_config:
            impo_args.append('--cross-check-config')
            impo_args.append(ccc)
    if reloop_cfgs:
        impo_args.append('--reloop-cfgs')
    if reorganize_definitions:
        impo_args.append('--reorganize-definitions')

    def transpile_single(cmd) -> Tuple[str, int, str, str, str]:

        if import_only:
            cbor_file = os.path.join(cmd['directory'], cmd['file'] + ".cbor")
        else:
            cbor_file = export_ast_from(ast_expo, cc_db_name, **cmd)
        assert os.path.isfile(cbor_file), "missing: " + cbor_file

        ld_lib_path = get_rust_toolchain_libpath()

        # don't overwrite existing ld lib path if any...
        if 'LD_LIBRARY_PATH' in pb.local.env:
            ld_lib_path += ':' + pb.local.env['LD_LIBRARY_PATH']

        # import ast
        with pb.local.env(RUST_BACKTRACE='1', LD_LIBRARY_PATH=ld_lib_path):
            file_basename = os.path.basename(cmd['file'])
            cbor_basename = os.path.basename(cbor_file)
            logging.info(" importing ast from %s", cbor_basename)
            translation_cmd = "RUST_BACKTRACE=1 \\\n"
            translation_cmd += "LD_LIBRARY_PATH=" + ld_lib_path + " \\\n"
            translation_cmd += str(ast_impo[cbor_file, impo_args,
                                            extra_impo_args])
            logging.debug("translation command:\n %s", translation_cmd)
            try:
                ast_impo_cmd = ast_impo[cbor_file, impo_args, extra_impo_args]
                # NOTE: this will log ast-importer output but not in color
                retcode, stdout, importer_warnings = ast_impo_cmd.run()
                if importer_warnings:
                    if verbose:
                        logging.warning(importer_warnings)
                    else:
                        logging.debug(importer_warnings)

                e = "Expected file suffix `.c.cbor`; actual: " + cbor_basename
                assert cbor_file.endswith(".c.cbor"), e
                rust_file = cbor_file[:-7] + ".rs"
                path, file_name = os.path.split(rust_file)
                file_name = file_name.replace('-', '_')
                rust_file = os.path.join(path, file_name)

                rustfmt(rust_file)

                return (file_basename, retcode, stdout, importer_warnings,
                        os.path.abspath(rust_file))
            except pb.ProcessExecutionError as pee:
                return (file_basename, pee.retcode, pee.stdout, pee.stderr,
                        None)

    commands = sorted(cc_db, key=lambda cmd: os.path.basename(cmd['file']))
    results = [transpile_single(cmd) for cmd in commands]

    if emit_build_files:
        modules = [(rust_src, retcode == 0)
                   for (_, retcode, _, _, rust_src) in results
                   if rust_src is not None]
        cc_db_dir = os.path.dirname(cc_db_name)
        write_build_files(cc_db_dir, modules, main_module_for_build_files,
                          cross_checks, reorganize_definitions, use_fakechecks,
                          cross_check_config)

    successes, failures = 0, 0
    for (fname, retcode, stdout, stderr, _) in results:
        if not retcode:
            successes += 1
            print(Colors.OKGREEN + " import successful" + Colors.NO_COLOR)
            logging.debug(" import successful")
        else:  # non-zero retcode
            failures += 1
            if verbose:
                print(Colors.FAIL + " import failed" + Colors.NO_COLOR)
                logging.debug(" import failed")
                logging.warning(stderr)
            else:
                print(Colors.FAIL + " import failed (error in log)" +
                      Colors.NO_COLOR)
                logging.debug(" import failed")
                logging.debug(stderr)
    print("translations: " + str(successes + failures))
    print("successes...: " + str(successes))
    print("failures....: " + str(failures))
    return failures == 0