def compile(self, src: fbuild.db.SRC, dst=None, *, flags=[], **kwargs) -> fbuild.db.DST: """Compile a c file and cache the results.""" # Generate the dependencies while we compile the file. with tempfile() as dep: obj = self.uncached_compile(src, dst, flags=list( chain(('-MMD', '-MF', dep), flags)), **kwargs) with open(dep, 'rb') as f: # Parse the output and return the module dependencies. stdout = f.read().replace(b'\\\n', b'') # Parse the output and return the module dependencies. m = re.match(b'\s*\S+:(?: (.*))?$', stdout) if not m: raise fbuild.ExecutionError('unable to understand %r' % stdout) s = m.group(1) if s is not None: deps = s.decode().split() self.ctx.db.add_external_dependencies_to_call(srcs=deps) return obj
def modules(self, src:fbuild.db.SRC, *, preprocessor=None, flags=()): """Calculate the modules this ocaml file depends on.""" src = Path(src) cmd = [self.exe] cmd.extend(self.pre_flags) cmd.append('-modules') if preprocessor is not None: cmd.extend(('-pp', preprocessor)) cmd.extend(self.flags) cmd.extend(flags) cmd.append(src) # Now, run ocamldep stdout, stderr = self.ctx.execute(cmd, str(self), src, color='yellow', stdout_quieter=1) # Parse the output and return the module dependencies. m = re.match(b'\S+:(?: (.*))?$', stdout.strip()) if not m: raise fbuild.ExecutionError('unable to understand %r' % stdout) s = m.group(1) if s is None: return () else: return tuple(s.decode().split())
def execute(self, cmd, msg1=None, msg2=None, *, arch=None, color=None, quieter=0, stdout_quieter=None, stderr_quieter=None, input=None, stdin=None, stdout=fbuild.subprocess.PIPE, stderr=fbuild.subprocess.PIPE, timeout=None, env=None, runtime_libpaths=None, **kwargs): """Execute the command and return the output.""" if isinstance(cmd, str): cmd_string = cmd else: cmd_parts = [] # Wrap any space separated parts in quotes. for c in cmd: if ' ' in c: c = "'{}'".format(c.replace("'", "\\'")) cmd_parts.append(c) cmd_string = ' '.join(cmd_parts) if stdout_quieter is None: stdout_quieter = quieter if stderr_quieter is None: stderr_quieter = quieter # Windows needs something in the environment, so for the moment we'll # just make sure everything is passed on to the executable. if env is None: env = dict(os.environ) else: env = dict(os.environ, **env) # Add in the runtime library search paths. if runtime_libpaths: # Look up the current architecture runtime_env_libpath = \ fbuild.builders.platform.runtime_env_libpath(self) runtime_libpaths = os.pathsep.join(runtime_libpaths) try: libpaths = env[runtime_env_libpath] except KeyError: libpaths = runtime_libpaths else: libpaths += os.pathsep + runtime_libpaths env[runtime_env_libpath] = libpaths # Add the runtime libpaths to the command string. cmd_string = '{}={} {}'.format( runtime_env_libpath, libpaths, cmd_string) self.logger.write('%-10s: starting %r\n' % (threading.current_thread().name, cmd_string), verbose=4, buffer=False) if msg1: if msg2: self.logger.check(' * ' + str(msg1), str(msg2), color=color, verbose=quieter) else: self.logger.check(' * ' + str(msg1), color=color, verbose=quieter) # Define a function that gets called if execution times out. We will # raise an exception if the timeout occurs. if timeout: timed_out = False def timeout_function(p): nonlocal timed_out timed_out = True p.kill(group=True) # Set the timer to None for now to make sure it's defined. timer = None starttime = time.time() try: p = fbuild.subprocess.killableprocess.Popen(cmd, stdin=fbuild.subprocess.PIPE if input else stdin, stdout=stdout, stderr=stderr, env=env, **kwargs) try: if timeout: timer = threading.Timer(timeout, timeout_function, (p,)) timer.start() stdout, stderr = p.communicate(input) returncode = p.wait() except KeyboardInterrupt: # Make sure if we get a keyboard interrupt to kill the process. p.kill(group=True) raise else: # Detect Ctrl-C in subprocess. if returncode == -signal.SIGINT: raise KeyboardInterrupt except OSError as e: # flush the logger self.logger.log('command failed: ' + cmd_string, color='red') raise e from e finally: if timeout and timer is not None: timer.cancel() endtime = time.time() if returncode: self.logger.log(' + ' + cmd_string, verbose=quieter) else: self.logger.log(' + ' + cmd_string, verbose=1) if stdout: try: self.logger.log(stdout.rstrip().decode(), verbose=stdout_quieter) except UnicodeDecodeError: self.logger.log(repr(stdout.rstrip()), verbose=stdout_quieter) if stderr: try: self.logger.log(stderr.rstrip().decode(), verbose=stderr_quieter) except UnicodeDecodeError: self.logger.log(repr(stderr.rstrip()), verbose=stderr_quieter) self.logger.log( ' - exit %d, %.2f sec' % (returncode, endtime - starttime), verbose=2) if timeout and timed_out: raise fbuild.ExecutionTimedOut(cmd, stdout, stderr, returncode) elif returncode: raise fbuild.ExecutionError(cmd, stdout, stderr, returncode) return stdout, stderr