#!/usr/bin/env python import sys, os, re class single(object): undef_macros = [] define_macros = [] include_files = {} _include_dirs = [] _include_files = [] @property def include_dirs(self): return self._include_dirs @include_dirs.setter def include_dirs(self, values): for value in values: value = os.path.relpath(value) self._include_dirs.append(value) def read(self, name): self.name = os.path.relpath(name).replace("\\", "/") with open(self.name, "r") as f: self.source = f.read() return self def write(self, name): with open(name, "wb") as f: f.write(self.source.encode()) return self def stdout(self): sys.stdout.write(self.source) def __call__(self, *args): macros = "" if args: name = args[0] else: name = self.name name = name.replace("\\", "/") if not os.path.exists(name): return "" if name in self._include_files: return "" if args: with open(name, "r") as f: source = f.read() else: source = self.source include_dirs = [os.path.dirname(name)] + self._include_dirs includes = re.findall(r"#include \"([^\"]+)\"", source) for include in includes: cur = '#include "{}"\n'.format(include) for include_dir in include_dirs: new = os.path.join(include_dir, include) if not os.path.exists(new): continue new = self.__call__(new) source = source.replace(cur, new) self._include_files.append(name) if name == self.name: for define_macro in self.define_macros: macros += "#define %s\n" % define_macro for undef_macro in self.undef_macros: macros += "#undef %s\n" % undef_macro self.include_files[name] = { "header": tuple(self._include_files), "source": source, } self.source = macros + source self._include_files.clear() return source if __name__ == "__main__": import argparse o = single() parser = argparse.ArgumentParser() parser.add_argument("-v", "--verbose", action="store_true") parser.add_argument("-D", default=[], action="append") parser.add_argument("-U", default=[], action="append") parser.add_argument("-I", default=[], action="append") parser.add_argument("-H") parser.add_argument("-C") parser.add_argument("-c") parser.add_argument("-O") parser.add_argument("-o") args = parser.parse_known_args() o.define_macros = args[0].D o.undef_macros = args[0].U o.include_dirs = args[0].I if args[0].c: o.read(args[0].c)() if args[0].o: o.write(args[0].o) elif args[0].O: outname = os.path.relpath(args[0].c) outname = os.path.join(args[0].O, outname) outpath = os.path.dirname(outname) os.makedirs(outpath, exist_ok=True) o.write(outname) else: o.stdout() if args[0].O and args[0].H: for dirpath, dirnames, filenames in os.walk(args[0].H): outpath = os.path.relpath(dirpath, args[0].H) outpath = os.path.join(args[0].O, outpath) os.makedirs(outpath, exist_ok=True) for filename in filenames: header = os.path.join(dirpath, filename) output = os.path.join(outpath, filename) prefix, suffix = os.path.splitext(header) if suffix in (".h", ".hh", ".hpp", ".hxx"): o.read(header)() o.write(output) if args[0].O and args[0].C: for dirpath, dirnames, filenames in os.walk(args[0].C): outpath = os.path.relpath(dirpath, args[0].C) outpath = os.path.join(args[0].O, outpath) os.makedirs(outpath, exist_ok=True) for filename in filenames: source = os.path.join(dirpath, filename) output = os.path.join(outpath, filename) prefix, suffix = os.path.splitext(source) if suffix in (".c", ".cc", ".cpp", ".cxx"): o.read(source)() o.write(output) if args[0].verbose: sources = " ".join(o.include_files) objects = ".o ".join(o.include_files) + ".o" for key in o.include_files: item = o.include_files[key] item = " ".join(reversed(item["header"])) sys.stderr.write(key + ".o:%s\n" % item) sys.stderr.write("SOURCES = %s\n" % sources) sys.stderr.write("OBJECTS = %s\n" % objects)