Beispiel #1
0
    def binary(self,
               output,
               objects,
               options=None,
               link_main=True,
               main_options=None):
        assert self.target is not None, (
            "must specify target= to constructor, or compile sources which specify the target "
            "first")

        args = [self._autodetect_toolchain_prefix(self.target) + "g++"]
        args.extend(self._defaults_from_target(self.target))
        if options is not None:
            args.extend(options.get("ldflags", []))

            for include_dir in options.get("include_dirs", []):
                args.extend(["-I", include_dir])

        output_filename = os.path.basename(output)
        output_abspath = os.path.join(output, output_filename)
        args.extend(["-g", "-o", output_abspath])

        if link_main:
            host_main_srcs = glob.glob(
                os.path.join(build.CRT_ROOT_DIR, "host", "*.cc"))
            if main_options:
                main_lib = self.library(os.path.join(output, "host"),
                                        host_main_srcs, main_options)
                for lib_name in main_lib.library_files:
                    args.append(main_lib.abspath(lib_name))
            else:
                args.extend(host_main_srcs)

        for obj in objects:
            for lib_name in obj.library_files:
                args.append(obj.abspath(lib_name))

        binutil.run_cmd(args)
        return tvm.micro.MicroBinary(output, output_filename, [])
Beispiel #2
0
    def library(self, output, sources, options=None):
        options = options if options is not None else {}
        try:
            target = self._target_from_sources(sources)
        except DetectTargetError:
            assert self.target is not None, (
                "Must specify target= to constructor when compiling sources which don't specify a "
                "target")

            target = self.target

        if self.target is not None and str(self.target) != str(target):
            raise IncompatibleTargetError(
                f"auto-detected target {target} differs from configured {self.target}"
            )

        prefix = self._autodetect_toolchain_prefix(target)
        outputs = []
        for src in sources:
            src_base, src_ext = os.path.splitext(os.path.basename(src))

            compiler_name = {".c": "gcc", ".cc": "g++", ".cpp": "g++"}[src_ext]
            args = [prefix + compiler_name, "-g"]
            args.extend(self._defaults_from_target(target))

            args.extend(options.get(f"{src_ext[1:]}flags", []))

            for include_dir in options.get("include_dirs", []):
                args.extend(["-I", include_dir])

            output_filename = f"{src_base}.o"
            output_abspath = os.path.join(output, output_filename)
            binutil.run_cmd(args + ["-c", "-o", output_abspath, src])
            outputs.append(output_abspath)

        output_filename = f"{os.path.basename(output)}.a"
        output_abspath = os.path.join(output, output_filename)
        binutil.run_cmd([prefix + "ar", "-r", output_abspath] + outputs)
        binutil.run_cmd([prefix + "ranlib", output_abspath])

        return tvm.micro.MicroLibrary(output, [output_filename])
Beispiel #3
0
def create_micro_lib_base(
    out_obj_path,
    in_src_path,
    toolchain_prefix,
    device_id,
    lib_type,
    options=None,
    lib_src_paths=None,
):
    """Compiles code into a binary for the target micro device.

    Parameters
    ----------
    out_obj_path : str
        path to generated object file

    in_src_path : str
        path to source file

    toolchain_prefix : str
        toolchain prefix to be used. For example, a prefix of
        "riscv64-unknown-elf-" means "riscv64-unknown-elf-gcc" is used as
        the compiler and "riscv64-unknown-elf-ld" is used as the linker,
        etc.

    device_id : str
        unique identifier for the target device

    lib_type : micro.LibType
        whether to compile a MicroTVM runtime or operator library

    options : List[str]
        additional options to pass to GCC

    lib_src_paths : Optional[List[str]]
        paths to additional source files to be compiled into the library
    """
    # look at these (specifically `strip`):
    #   https://stackoverflow.com/questions/15314581/g-compiler-flag-to-minimize-binary-size
    base_compile_cmd = [
        f"{toolchain_prefix}gcc",
        "-std=gnu11",
        "-Wall",
        "-Wextra",
        "--pedantic",
        "-c",
        "-g",
        "-nostartfiles",
        "-nodefaultlibs",
        "-nostdlib",
        "-fdata-sections",
        "-ffunction-sections",
    ]
    if options is not None:
        base_compile_cmd += options

    src_paths = []
    include_paths = find_include_path() + [get_micro_host_driven_dir()]
    tmp_dir = _util.tempdir()
    # we need to create a new src file in the operator branch
    new_in_src_path = in_src_path
    if lib_type == LibType.RUNTIME:
        dev_dir = _get_device_source_dir(device_id)
        print(dev_dir)
        dev_src_paths = glob.glob(f"{dev_dir}/*.[csS]")
        # there needs to at least be a utvm_timer.c file
        assert dev_src_paths
        assert "utvm_timer.c" in map(os.path.basename, dev_src_paths)

        src_paths += dev_src_paths
    elif lib_type == LibType.OPERATOR:
        # create a temporary copy of the operator source, so we can inject the dev lib
        # header without modifying the original.
        temp_src_path = tmp_dir.relpath("temp.c")
        with open(in_src_path, "r") as f:
            src_lines = f.read().splitlines()
        src_lines.insert(0, '#include "utvm_device_dylib_redirect.c"')
        with open(temp_src_path, "w") as f:
            f.write("\n".join(src_lines))
        new_in_src_path = temp_src_path
    else:
        raise RuntimeError("unknown lib type")

    src_paths += [new_in_src_path]

    # add any src paths required by the operator
    if lib_src_paths is not None:
        src_paths += lib_src_paths

    # print(f"include paths: {include_paths}")
    for path in include_paths:
        base_compile_cmd += ["-I", path]

    prereq_obj_paths = []
    # print(src_paths)
    for src_path in src_paths:
        curr_obj_path = tmp_dir.relpath(
            pathlib.Path(src_path).with_suffix(".o").name)
        assert curr_obj_path not in prereq_obj_paths
        prereq_obj_paths.append(curr_obj_path)
        curr_compile_cmd = base_compile_cmd + [src_path, "-o", curr_obj_path]
        # TODO(weberlo): make compilation fail if there are any warnings
        run_cmd(curr_compile_cmd)

    ld_cmd = [f"{toolchain_prefix}ld", "-relocatable"]
    ld_cmd += prereq_obj_paths
    ld_cmd += ["-o", out_obj_path]
    run_cmd(ld_cmd)
def create_micro_lib_base(out_obj_path,
                          in_src_path,
                          toolchain_prefix,
                          device_id,
                          lib_type,
                          options=None):
    """Compiles code into a binary for the target micro device.

    Parameters
    ----------
    out_obj_path : str
        path to generated object file

    in_src_path : str
        path to source file

    toolchain_prefix : str
        toolchain prefix to be used. For example, a prefix of
        "riscv64-unknown-elf-" means "riscv64-unknown-elf-gcc" is used as
        the compiler and "riscv64-unknown-elf-ld" is used as the linker,
        etc.

    device_id : str
        unique identifier for the target device

    lib_type : micro.LibType
        whether to compile a MicroTVM runtime or operator library

    options : List[str]
        additional options to pass to GCC
    """
    base_compile_cmd = [
        f"{toolchain_prefix}gcc",
        "-std=c11",
        "-Wall",
        "-Wextra",
        "--pedantic",
        "-c",
        "-O0",
        "-g",
        "-nostartfiles",
        "-nodefaultlibs",
        "-nostdlib",
        "-fdata-sections",
        "-ffunction-sections",
    ]
    if options is not None:
        base_compile_cmd += options

    src_paths = []
    include_paths = find_include_path() + [get_micro_host_driven_dir()]
    tmp_dir = _util.tempdir()
    # we might transform the src path in one of the branches below
    new_in_src_path = in_src_path
    if lib_type == LibType.RUNTIME:
        dev_dir = _get_device_source_dir(device_id)
        dev_src_paths = glob.glob(f"{dev_dir}/*.[csS]")
        # there needs to at least be a utvm_timer.c file
        assert dev_src_paths
        assert "utvm_timer.c" in map(os.path.basename, dev_src_paths)
        src_paths += dev_src_paths
    elif lib_type == LibType.OPERATOR:
        # create a temporary copy of the source, so we can inject the dev lib
        # header without modifying the original.
        temp_src_path = tmp_dir.relpath("temp.c")
        with open(in_src_path, "r") as f:
            src_lines = f.read().splitlines()
        src_lines.insert(0, "#include \"utvm_device_dylib_redirect.c\"")
        with open(temp_src_path, "w") as f:
            f.write("\n".join(src_lines))
        new_in_src_path = temp_src_path
        base_compile_cmd += ["-c"]
    else:
        raise RuntimeError("unknown lib type")

    src_paths += [new_in_src_path]

    for path in include_paths:
        base_compile_cmd += ["-I", path]

    prereq_obj_paths = []
    for src_path in src_paths:
        curr_obj_path = Path(src_path).with_suffix(".o").name
        assert curr_obj_path not in prereq_obj_paths
        prereq_obj_paths.append(curr_obj_path)
        curr_compile_cmd = base_compile_cmd + [src_path, "-o", curr_obj_path]
        run_cmd(curr_compile_cmd)

    ld_cmd = [f"{toolchain_prefix}ld", "-relocatable"]
    ld_cmd += prereq_obj_paths
    ld_cmd += ["-o", out_obj_path]
    run_cmd(ld_cmd)