1# Licensed to the Apache Software Foundation (ASF) under one 2# or more contributor license agreements. See the NOTICE file 3# distributed with this work for additional information 4# regarding copyright ownership. The ASF licenses this file 5# to you under the Apache License, Version 2.0 (the 6# "License"); you may not use this file except in compliance 7# with the License. You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, 12# software distributed under the License is distributed on an 13# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14# KIND, either express or implied. See the License for the 15# specific language governing permissions and limitations 16# under the License. 17 18"""Defines top-level glue functions for building microTVM artifacts.""" 19 20import copy 21import logging 22import os 23import re 24from tvm.contrib import util 25 26 27_LOG = logging.getLogger(__name__) 28 29 30class Workspace: 31 """Defines helper functions for manipulating temporary compilation workspaces.""" 32 33 def __init__(self, root=None, debug=False): 34 if debug or root is not None: 35 with util.TempDirectory.set_keep_for_debug(): 36 self.tempdir = util.tempdir(custom_path=root) 37 _LOG.info("Created debug mode workspace at: %s", self.tempdir.temp_dir) 38 else: 39 self.tempdir = util.tempdir() 40 41 def relpath(self, path): 42 return self.tempdir.relpath(path) 43 44 def listdir(self): 45 return self.tempdir.listdir() 46 47 @property 48 def path(self): 49 return self.tempdir.temp_dir 50 51 52# Required C runtime libraries, in link order. 53CRT_RUNTIME_LIB_NAMES = ["utvm_rpc_server", "utvm_rpc_common", "common"] 54 55 56TVM_ROOT_DIR = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..", "..")) 57 58 59CRT_ROOT_DIR = os.path.join(TVM_ROOT_DIR, "src", "runtime", "crt") 60 61 62RUNTIME_LIB_SRC_DIRS = [os.path.join(CRT_ROOT_DIR, n) for n in CRT_RUNTIME_LIB_NAMES] + [ 63 os.path.join(TVM_ROOT_DIR, "3rdparty/libcrc/src") 64] 65 66 67RUNTIME_SRC_REGEX = re.compile(r"^.*\.cc?$", re.IGNORECASE) 68 69 70_CRT_DEFAULT_OPTIONS = { 71 "ccflags": ["-std=c++11"], 72 "ldflags": ["-std=gnu++14"], 73 "include_dirs": [ 74 f"{TVM_ROOT_DIR}/include", 75 f"{TVM_ROOT_DIR}/3rdparty/dlpack/include", 76 f"{TVM_ROOT_DIR}/3rdparty/libcrc/include", 77 f"{TVM_ROOT_DIR}/3rdparty/dmlc-core/include", 78 f"{CRT_ROOT_DIR}/include", 79 ], 80 "profile": {"common": ["-Wno-unused-variable"]}, 81} 82 83 84def default_options(target_include_dir): 85 """Return default opts passed to Compile commands.""" 86 bin_opts = copy.deepcopy(_CRT_DEFAULT_OPTIONS) 87 bin_opts["include_dirs"].append(target_include_dir) 88 lib_opts = copy.deepcopy(bin_opts) 89 lib_opts["profile"]["common"].append("-Werror") 90 lib_opts["cflags"] = ["-Wno-error=incompatible-pointer-types"] 91 return {"bin_opts": bin_opts, "lib_opts": lib_opts} 92 93 94def build_static_runtime(workspace, compiler, module, lib_opts=None, bin_opts=None): 95 """Build the on-device runtime, statically linking the given modules. 96 97 Parameters 98 ---------- 99 compiler : tvm.micro.Compiler 100 Compiler instance used to build the runtime. 101 102 module : IRModule 103 Module to statically link. 104 105 lib_opts : dict 106 Extra kwargs passed to library(), 107 108 bin_opts : dict 109 Extra kwargs passed to binary(), 110 111 Returns 112 ------- 113 MicroBinary : 114 The compiled runtime. 115 """ 116 lib_opts = _CRT_DEFAULT_OPTIONS if lib_opts is None else lib_opts 117 bin_opts = _CRT_DEFAULT_OPTIONS if bin_opts is None else bin_opts 118 119 mod_build_dir = workspace.relpath(os.path.join("build", "module")) 120 os.makedirs(mod_build_dir) 121 mod_src_dir = workspace.relpath(os.path.join("src", "module")) 122 os.makedirs(mod_src_dir) 123 mod_src_path = os.path.join(mod_src_dir, "module.c") 124 module.save(mod_src_path, "cc") 125 126 libs = [] 127 for lib_src_dir in RUNTIME_LIB_SRC_DIRS: 128 lib_name = os.path.basename(lib_src_dir) 129 lib_build_dir = workspace.relpath(f"build/{lib_name}") 130 os.makedirs(lib_build_dir) 131 132 lib_srcs = [] 133 for p in os.listdir(lib_src_dir): 134 if RUNTIME_SRC_REGEX.match(p): 135 lib_srcs.append(os.path.join(lib_src_dir, p)) 136 137 libs.append(compiler.library(lib_build_dir, lib_srcs, lib_opts)) 138 139 libs.append(compiler.library(mod_build_dir, [mod_src_path], lib_opts)) 140 141 runtime_build_dir = workspace.relpath(f"build/runtime") 142 os.makedirs(runtime_build_dir) 143 return compiler.binary(runtime_build_dir, libs, bin_opts) 144