def _test_minimal(code_snippet: str) -> bool: ast_expo = get_cmd_or_die(c.AST_EXPO) ast_impo = get_cmd_or_die(c.AST_IMPO) tempdir = tempfile.gettempdir() cfile = os.path.join(tempdir, "test.c") with open(cfile, 'w') as fh: fh.write(code_snippet) # avoid warnings about missing compiler flags, not strictly required cc_json = os.path.join(tempdir, "compile_commands.json") with open(cc_json, 'w') as fh: fh.write(minimal_cc_db) cborfile = cfile + '.cbor' invoke(ast_expo[cfile]) ld_lib_path = get_rust_toolchain_libpath(c.CUSTOM_RUST_NAME) # 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'] args = [] args += ['--ddump-untyped-clang-ast'] args += [cborfile] # import ast with pb.local.env(RUST_BACKTRACE='1', LD_LIBRARY_PATH=ld_lib_path): invoke(ast_impo, args) return True # if we get this far, test passed
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")
def run_tests(testcases: List[str]) -> None: ipath = os.path.join(c.RREF_DIR, "target/debug/idiomize") # refactor = '{ip} -P ../.. -p plugin_stub -r alongside'.format(ip=ipath) # NOTE:PL: I removed the plugin options (-P, -p) to get the tests to run. refactor = '{ip} -r alongside'.format(ip=ipath) # help plumbum find rust ld_lib_path = get_rust_toolchain_libpath(c.CUSTOM_RUST_NAME) if 'LD_LIBRARY_PATH' in pb.local.env: ld_lib_path += ':' + pb.local.env['LD_LIBRARY_PATH'] rustflags = "-L {rust_lib_dir}/rustlib/{triplet}/lib" rustflags = rustflags.format(rust_lib_dir=ld_lib_path, triplet=get_host_triplet()) with pb.local.env(RUST_BACKTRACE='1', RUST_LOG="idiomize=info", LD_LIBRARY_PATH=ld_lib_path, not_LD_LIBRARY_PATH=ld_lib_path, refactor=refactor, rustflags=rustflags): for test in testcases: script = pb.local.get(test) testdir = os.path.dirname(test) testname = os.path.basename(testdir) try: with pb.local.cwd(testdir): logging.debug("testing: %s", testdir) script.run() old_new_rust = os.path.join(testdir, "old.rs.new") assert os.path.isfile( old_new_rust), "missing rewritten rust" mode = "overwrite" # set to 'replace' to generate backups rustfmt["--force", "--write-mode", mode, old_new_rust].run() new_rust = os.path.join(testdir, "new.rs") diff["-wB", new_rust, old_new_rust].run() print(" {}[ OK ]{} ".format(Colors.OKGREEN, Colors.NO_COLOR) + testname) logging.debug(" [ OK ] " + testname) except pb.ProcessExecutionError as pee: print(" {}[FAIL]{} ".format(Colors.FAIL, Colors.NO_COLOR) + testname) logging.debug(" [FAIL] " + testname) logfile = os.path.join(testdir, "log") if os.path.exists(logfile): with open(logfile, "r") as fh: lines = fh.readlines() logging.debug("".join(lines))
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: ast_impo_cmd = ast_impo[cbor_file, impo_args, extra_impo_args] # NOTE: this will log ast-importer output but not in color retcode, rust_output, 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" with open(rust_file, "w") as rust_fh: rust_fh.writelines(rust_output) logging.debug("wrote output rust to %s", rust_file) rustfmt(rust_file) return (file_basename, retcode, rust_output, importer_warnings, os.path.abspath(rust_file)) except pb.ProcessExecutionError as pee: return (file_basename, pee.retcode, pee.stdout, pee.stderr, None)
def translate(self) -> RustFile: c_file_path, _ = os.path.splitext(self.path) extensionless_file, _ = os.path.splitext(c_file_path) rust_src = extensionless_file + ".rs" # 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 importer ast_importer = get_cmd_or_die(c.AST_IMPO) args = [ self.path, "--prefix-function-names", "rust_", ] if self.enable_relooper: args.append("--reloop-cfgs") # args.append("--use-c-loop-info") # args.append("--use-c-multiple-info") if self.disallow_current_block: args.append("--fail-on-multiple") 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(ast_importer[args] > rust_src) logging.debug("translation command:\n %s", translation_cmd) retcode, stdout, stderr = (ast_importer[args] > rust_src).run( retcode=None) logging.debug("stdout:\n%s", stdout) if retcode != 0: raise NonZeroReturn(stderr) return RustFile(extensionless_file + ".rs")
def run(self) -> List[TestOutcome]: outcomes = [] any_tests = any(test_fn for test_file in self.rs_test_files for test_fn in test_file.test_functions) if not any_tests: description = "No tests were found..." logging.debug("%s:", self.name) logging.debug("%s [ SKIPPED ] %s %s", Colors.OKBLUE, Colors.NO_COLOR, description) return [] if not self.c_files: description = "No c files were found..." logging.debug("%s:", self.name) logging.debug("%s [ SKIPPED ] %s %s", Colors.OKBLUE, Colors.NO_COLOR, description) return [] sys.stdout.write("{}:\n".format(self.name)) # .c -> .a description = "libtest.a: creating a static C library..." self.print_status(Colors.WARNING, "RUNNING", description) try: static_library = build_static_library(self.c_files, self.full_path) except NonZeroReturn as exception: self.print_status(Colors.FAIL, "FAILED", "create libtest.a") sys.stdout.write('\n') sys.stdout.write(str(exception)) outcomes.append(TestOutcome.UnexpectedFailure) return outcomes self.generated_files["c_lib"].append(static_library) self.generated_files["c_obj"].extend(static_library.obj_files) rust_file_builder = RustFileBuilder() rust_file_builder.add_features([ "libc", "extern_types", "simd_ffi", "stdsimd", "const_transmute", "nll", "linkage", "register_tool", ]) rust_file_builder.add_pragma("register_tool", ["c2rust"]) # Ensure that path to rustc's lib dir is in`LD_LIBRARY_PATH` ld_lib_path = get_rust_toolchain_libpath() if 'LD_LIBRARY_PATH' in pb.local.env: ld_lib_path += ':' + pb.local.env['LD_LIBRARY_PATH'] # .c -> .rs for c_file in self.c_files: _, c_file_short = os.path.split(c_file.path) description = "{}: translating the C file into Rust...".format( c_file_short) # Run the step self.print_status(Colors.WARNING, "RUNNING", description) self._generate_cc_db(c_file.path) try: logging.debug("translating %s", c_file_short) translated_rust_file = c_file.translate( self.generated_files["cc_db"], ld_lib_path, extra_args=["-march=native"]) except NonZeroReturn as exception: self.print_status(Colors.FAIL, "FAILED", "translate " + c_file_short) sys.stdout.write('\n') sys.stdout.write(str(exception)) outcomes.append(TestOutcome.UnexpectedFailure) continue self.generated_files["rust_src"].append(translated_rust_file) if c_file.emit_build_files: self.generated_files["rust_src"].append(self.full_path + "/src/Cargo.toml") self.generated_files["rust_src"].append(self.full_path + "/src/build.rs") self.generated_files["rust_src"].append(self.full_path + "/src/c2rust-lib.rs") self.generated_files["rust_src"].append(self.full_path + "/src/rust-toolchain") _, rust_file_short = os.path.split(translated_rust_file.path) extensionless_rust_file, _ = os.path.splitext(rust_file_short) rust_file_builder.add_mod( RustMod(extensionless_rust_file, RustVisibility.Public)) match_arms = [] rustc_extra_args = ["-C", "target-cpu=native"] # Build one binary that can call all the tests for test_file in self.rs_test_files: # rustc_extra_args.append(["-L", "crate={}".format(c.TARGET_DIR)]) rust_file_builder.add_features(test_file.features) rust_file_builder.add_extern_crates(test_file.extern_crates) _, file_name = os.path.split(test_file.path) extensionless_file_name, _ = os.path.splitext(file_name) if not test_file.pass_expected: try: test_file.compile(CrateType.Library, save_output=False, extra_args=rustc_extra_args) self.print_status( Colors.FAIL, "OK", "Unexpected success {}".format(file_name)) sys.stdout.write('\n') outcomes.append(TestOutcome.UnexpectedSuccess) except NonZeroReturn as exception: self.print_status(Colors.OKBLUE, "FAILED", "Expected failure {}".format(file_name)) sys.stdout.write('\n') logging.error("stderr:%s\n", str(exception)) outcomes.append(TestOutcome.Failure) continue for test_function in test_file.test_functions: rust_file_builder.add_mod( RustMod(extensionless_file_name, RustVisibility.Public)) left = "Some(\"{}::{}\")".format(extensionless_file_name, test_function.name) right = "{}::{}()".format(extensionless_file_name, test_function.name) match_arms.append((left, right)) match_arms.append( ("e", "panic!(\"Tried to run unknown test: {:?}\", e)")) test_main_body = [ RustMatch( "std::env::args().nth(1).as_ref().map(AsRef::<str>::as_ref)", match_arms), ] test_main = RustFunction("main", visibility=RustVisibility.Public, body=test_main_body) rust_file_builder.add_function(test_main) main_file = rust_file_builder.build(self.full_path + "/src/main.rs") self.generated_files["rust_src"].append(main_file) # Try and build test binary with pb.local.cwd(self.full_path): args = ["build"] if c.BUILD_TYPE == 'release': args.append('--release') retcode, stdout, stderr = cargo[args].run(retcode=None) if retcode != 0: _, main_file_path_short = os.path.split(main_file.path) self.print_status(Colors.FAIL, "FAILED", "compile {}".format(main_file_path_short)) sys.stdout.write('\n') sys.stdout.write(stderr) outcomes.append(TestOutcome.UnexpectedFailure) return outcomes for test_file in self.rs_test_files: if not test_file.pass_expected: continue _, file_name = os.path.split(test_file.path) extensionless_file_name, _ = os.path.splitext(file_name) for test_function in test_file.test_functions: args = [ "run", "{}::{}".format(extensionless_file_name, test_function.name) ] if c.BUILD_TYPE == 'release': args.append('--release') with pb.local.cwd(self.full_path): retcode, stdout, stderr = cargo[args].run(retcode=None) logging.debug("stdout:%s\n", stdout) test_str = file_name + ' - ' + test_function.name if retcode == 0: if test_function.pass_expected: self.print_status(Colors.OKGREEN, "OK", " test " + test_str) sys.stdout.write('\n') outcomes.append(TestOutcome.Success) else: self.print_status(Colors.FAIL, "FAILED", "test " + test_str) sys.stdout.write('\n') outcomes.append(TestOutcome.UnexpectedSuccess) elif retcode != 0: if test_function.pass_expected: self.print_status(Colors.FAIL, "FAILED", "test " + test_str) sys.stdout.write('\n') sys.stdout.write(stderr) outcomes.append(TestOutcome.UnexpectedFailure) else: self.print_status(Colors.OKBLUE, "FAILED", "test " + test_str) sys.stdout.write('\n') outcomes.append(TestOutcome.Failure) if not outcomes: display_text = " No rust file(s) matching " + self.files.pattern display_text += " within this folder\n" self.print_status(Colors.OKBLUE, "N/A", display_text) return outcomes