1*4882a593Smuzhiyunimport os 2*4882a593Smuzhiyunimport shutil 3*4882a593Smuzhiyunimport subprocess 4*4882a593Smuzhiyun 5*4882a593Smuzhiyunimport infra 6*4882a593Smuzhiyun 7*4882a593Smuzhiyun 8*4882a593Smuzhiyunclass Builder(object): 9*4882a593Smuzhiyun def __init__(self, config, builddir, logtofile): 10*4882a593Smuzhiyun self.config = '\n'.join([line.lstrip() for line in 11*4882a593Smuzhiyun config.splitlines()]) + '\n' 12*4882a593Smuzhiyun self.builddir = builddir 13*4882a593Smuzhiyun self.logfile = infra.open_log_file(builddir, "build", logtofile) 14*4882a593Smuzhiyun 15*4882a593Smuzhiyun def is_defconfig_valid(self, configfile, defconfig): 16*4882a593Smuzhiyun """Check if the .config is contains all lines present in the defconfig.""" 17*4882a593Smuzhiyun with open(configfile) as configf: 18*4882a593Smuzhiyun configlines = configf.readlines() 19*4882a593Smuzhiyun 20*4882a593Smuzhiyun defconfiglines = defconfig.split("\n") 21*4882a593Smuzhiyun 22*4882a593Smuzhiyun # Check that all the defconfig lines are still present 23*4882a593Smuzhiyun for defconfigline in defconfiglines: 24*4882a593Smuzhiyun if defconfigline + "\n" not in configlines: 25*4882a593Smuzhiyun self.logfile.write("WARN: defconfig can't be used\n") 26*4882a593Smuzhiyun self.logfile.write(" Missing: %s\n" % defconfigline.strip()) 27*4882a593Smuzhiyun self.logfile.flush() 28*4882a593Smuzhiyun return False 29*4882a593Smuzhiyun 30*4882a593Smuzhiyun return True 31*4882a593Smuzhiyun 32*4882a593Smuzhiyun def configure(self, make_extra_opts=[], make_extra_env={}): 33*4882a593Smuzhiyun """Configure the build. 34*4882a593Smuzhiyun 35*4882a593Smuzhiyun make_extra_opts: a list of arguments to be passed to the make 36*4882a593Smuzhiyun command. 37*4882a593Smuzhiyun e.g. make_extra_opts=["BR2_EXTERNAL=/path"] 38*4882a593Smuzhiyun 39*4882a593Smuzhiyun make_extra_env: a dict of variables to be appended (or replaced) 40*4882a593Smuzhiyun in the environment that calls make. 41*4882a593Smuzhiyun e.g. make_extra_env={"BR2_DL_DIR": "/path"} 42*4882a593Smuzhiyun """ 43*4882a593Smuzhiyun if not os.path.isdir(self.builddir): 44*4882a593Smuzhiyun os.makedirs(self.builddir) 45*4882a593Smuzhiyun 46*4882a593Smuzhiyun config_file = os.path.join(self.builddir, ".config") 47*4882a593Smuzhiyun with open(config_file, "w+") as cf: 48*4882a593Smuzhiyun cf.write(self.config) 49*4882a593Smuzhiyun # dump the defconfig to the logfile for easy debugging 50*4882a593Smuzhiyun self.logfile.write("> start defconfig\n" + self.config + 51*4882a593Smuzhiyun "> end defconfig\n") 52*4882a593Smuzhiyun self.logfile.flush() 53*4882a593Smuzhiyun 54*4882a593Smuzhiyun env = {"PATH": os.environ["PATH"]} 55*4882a593Smuzhiyun env.update(make_extra_env) 56*4882a593Smuzhiyun 57*4882a593Smuzhiyun cmd = ["make", 58*4882a593Smuzhiyun "O={}".format(self.builddir)] 59*4882a593Smuzhiyun cmd += make_extra_opts 60*4882a593Smuzhiyun cmd += ["olddefconfig"] 61*4882a593Smuzhiyun 62*4882a593Smuzhiyun ret = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile, 63*4882a593Smuzhiyun cwd=infra.basepath(), env=env) 64*4882a593Smuzhiyun if ret != 0: 65*4882a593Smuzhiyun raise SystemError("Cannot olddefconfig") 66*4882a593Smuzhiyun 67*4882a593Smuzhiyun if not self.is_defconfig_valid(config_file, self.config): 68*4882a593Smuzhiyun raise SystemError("The defconfig is not valid") 69*4882a593Smuzhiyun 70*4882a593Smuzhiyun def build(self, make_extra_opts=[], make_extra_env={}): 71*4882a593Smuzhiyun """Perform the build. 72*4882a593Smuzhiyun 73*4882a593Smuzhiyun make_extra_opts: a list of arguments to be passed to the make 74*4882a593Smuzhiyun command. It can include a make target. 75*4882a593Smuzhiyun e.g. make_extra_opts=["foo-source"] 76*4882a593Smuzhiyun 77*4882a593Smuzhiyun make_extra_env: a dict of variables to be appended (or replaced) 78*4882a593Smuzhiyun in the environment that calls make. 79*4882a593Smuzhiyun e.g. make_extra_env={"BR2_DL_DIR": "/path"} 80*4882a593Smuzhiyun """ 81*4882a593Smuzhiyun env = {"PATH": os.environ["PATH"]} 82*4882a593Smuzhiyun if "http_proxy" in os.environ: 83*4882a593Smuzhiyun self.logfile.write("Using system proxy: " + 84*4882a593Smuzhiyun os.environ["http_proxy"] + "\n") 85*4882a593Smuzhiyun env['http_proxy'] = os.environ["http_proxy"] 86*4882a593Smuzhiyun env['https_proxy'] = os.environ["http_proxy"] 87*4882a593Smuzhiyun env.update(make_extra_env) 88*4882a593Smuzhiyun 89*4882a593Smuzhiyun cmd = ["make", "-C", self.builddir] 90*4882a593Smuzhiyun cmd += make_extra_opts 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun ret = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile, 93*4882a593Smuzhiyun env=env) 94*4882a593Smuzhiyun if ret != 0: 95*4882a593Smuzhiyun raise SystemError("Build failed") 96*4882a593Smuzhiyun 97*4882a593Smuzhiyun open(self.stamp_path(), 'a').close() 98*4882a593Smuzhiyun 99*4882a593Smuzhiyun def stamp_path(self): 100*4882a593Smuzhiyun return os.path.join(self.builddir, "build-done") 101*4882a593Smuzhiyun 102*4882a593Smuzhiyun def is_finished(self): 103*4882a593Smuzhiyun return os.path.exists(self.stamp_path()) 104*4882a593Smuzhiyun 105*4882a593Smuzhiyun def delete(self): 106*4882a593Smuzhiyun if os.path.exists(self.builddir): 107*4882a593Smuzhiyun shutil.rmtree(self.builddir) 108