diff --git a/bin/BuildSystem/BuildSystemBase.py b/bin/BuildSystem/BuildSystemBase.py index cf2083546..eb0dc2545 100644 --- a/bin/BuildSystem/BuildSystemBase.py +++ b/bin/BuildSystem/BuildSystemBase.py @@ -1,162 +1,165 @@ # # copyright (c) 2009 Ralf Habacker # """ \package BuildSystemBase""" import multiprocessing import os import re from CraftBase import * from CraftOS.osutils import OsUtils class BuildSystemBase(CraftBase): """provides a generic interface for build systems and implements all stuff for all build systems""" debug = True def __init__(self, typeName=""): """constructor""" CraftBase.__init__(self) self.supportsNinja = False self.supportsCCACHE = CraftCore.settings.getboolean("Compile", "UseCCache", False) and CraftCore.compiler.isMinGW() self.supportsClang = True self.buildSystemType = typeName @property def makeProgram(self) -> str: if self.subinfo.options.make.supportsMultijob: if self.supportsNinja and CraftCore.settings.getboolean("Compile", "UseNinja", False): return "ninja" if ("Compile", "MakeProgram") in CraftCore.settings: CraftCore.log.debug("set custom make program: %s" % CraftCore.settings.get("Compile", "MakeProgram", "")) return CraftCore.settings.get("Compile", "MakeProgram", "") elif not self.subinfo.options.make.supportsMultijob: if "MAKE" in os.environ: del os.environ["MAKE"] if OsUtils.isWin(): if CraftCore.compiler.isMSVC() or CraftCore.compiler.isIntel(): return "nmake" elif CraftCore.compiler.isMinGW(): return "mingw32-make" else: CraftCore.log.critical(f"unknown {CraftCore.compiler} compiler") elif OsUtils.isUnix(): return "make" def compile(self): """convencience method - runs configure() and make()""" configure = getattr(self, 'configure') make = getattr(self, 'make') return configure() and make() def configureSourceDir(self): """returns source dir used for configure step""" # pylint: disable=E1101 # this class never defines self.source, that happens only # in MultiSource. sourcedir = self.sourceDir() if self.subinfo.hasConfigurePath(): sourcedir = os.path.join(sourcedir, self.subinfo.configurePath()) return sourcedir def configureOptions(self, defines=""): """return options for configure command line""" if self.subinfo.options.configure.args != None: defines += " %s" % self.subinfo.options.configure.args if self.supportsCCACHE: defines += " %s" % self.ccacheOptions() if CraftCore.compiler.isClang() and self.supportsClang: defines += " %s" % self.clangOptions() return defines def makeOptions(self, args): """return options for make command line""" defines = "" if self.subinfo.options.make.ignoreErrors: defines += " -i" defines += f" {args}" if self.makeProgram in {"make", "gmake", "mingw32-make"}: if self.subinfo.options.make.supportsMultijob: defines += f" -j{multiprocessing.cpu_count()}" - if CraftCore.debug.verbose() > 0: - if self.makeProgram == "ninja": + if self.makeProgram == "ninja": + if CraftCore.settings.getboolean("General", "AllowAnsiColor", False): + defines += " -c " + if CraftCore.debug.verbose() > 0: defines += " -v " - else: + else: + if CraftCore.debug.verbose() > 0: defines += " VERBOSE=1 V=1" return defines def configure(self): return True def make(self): return True def install(self) -> bool: return self.cleanImage() def unittest(self): """running unittests""" return True def ccacheOptions(self): return "" def clangOptions(self): return "" def _fixInstallPrefix(self, prefix=CraftStandardDirs.craftRoot()): CraftCore.log.debug(f"Begin: fixInstallPrefix {self}: {prefix}") def stripPath(path): rootPath = os.path.splitdrive(path)[1] if rootPath.startswith(os.path.sep) or rootPath.startswith("/"): rootPath = rootPath[1:] return rootPath badPrefix = os.path.join(self.installDir(), stripPath(prefix)) if os.path.exists(badPrefix) and not os.path.samefile(self.installDir(), badPrefix): if not utils.mergeTree(badPrefix, self.installDir()): return False if CraftCore.settings.getboolean("QtSDK", "Enabled", False): qtDir = os.path.join(CraftCore.settings.get("QtSDK", "Path"), CraftCore.settings.get("QtSDK", "Version"), CraftCore.settings.get("QtSDK", "Compiler")) path = os.path.join(self.installDir(), stripPath(qtDir)) if os.path.exists(path) and not os.path.samefile(self.installDir(), path): if not utils.mergeTree(path, self.installDir()): return False if stripPath(prefix): oldPrefix = OsUtils.toUnixPath(stripPath(prefix)).split("/", 1)[0] utils.rmtree(os.path.join(self.installDir(), oldPrefix)) CraftCore.log.debug(f"End: fixInstallPrefix {self}") return True def internlPostInstall(self): if not super().internlPostInstall(): return Fasle # a post install routine to fix the prefix (make things relocatable) pkgconfigPath = os.path.join(self.imageDir(), "lib", "pkgconfig") prefix_re = re.compile("^prefix=(.*)$", re.MULTILINE) newPrefix = OsUtils.toUnixPath(CraftCore.standardDirs.craftRoot()) if os.path.exists(pkgconfigPath): for pcFile in os.listdir(pkgconfigPath): if pcFile.endswith(".pc"): path = os.path.join(pkgconfigPath, pcFile) with open(path, "rt+") as f: config = f.read() prefix = prefix_re.findall(config) if len(prefix) != 1: CraftCore.log.error(f"Failed to patch {path}") return False prefix = prefix[0] CraftCore.log.info(f"Patching {path}, replacing {prefix} with {newPrefix}") config = config.replace(prefix, newPrefix) with open(path, "wt+") as f: f.write(config) return True diff --git a/blueprints/dev-utils/ninja/0001-Add-c-flag-to-force-color-output.patch b/blueprints/dev-utils/ninja/0001-Add-c-flag-to-force-color-output.patch new file mode 100644 index 000000000..2f86c7754 --- /dev/null +++ b/blueprints/dev-utils/ninja/0001-Add-c-flag-to-force-color-output.patch @@ -0,0 +1,85 @@ +From 1b5192e67afd7ba65a35f5f852d81410ab5e3b06 Mon Sep 17 00:00:00 2001 +From: Alexander Timin +Date: Wed, 12 Apr 2017 14:11:48 +0100 +Subject: [PATCH] Add -c flag to force color output. + +--- + src/build.cc | 3 +-- + src/build.h | 5 ++++- + src/ninja.cc | 8 ++++++-- + 3 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/src/build.cc b/src/build.cc +index 61ef0e8..4854f64 100644 +--- a/src/build.cc ++++ b/src/build.cc +@@ -154,9 +154,8 @@ void BuildStatus::BuildEdgeFinished(Edge* edge, + // (Launching subprocesses in pseudo ttys doesn't work because there are + // only a few hundred available on some systems, and ninja can launch + // thousands of parallel compile commands.) +- // TODO: There should be a flag to disable escape code stripping. + string final_output; +- if (!printer_.is_smart_terminal()) ++ if (!printer_.is_smart_terminal() && !config_.force_color_output) + final_output = StripAnsiEscapeCodes(output); + else + final_output = output; +diff --git a/src/build.h b/src/build.h +index 43786f1..e518172 100644 +--- a/src/build.h ++++ b/src/build.h +@@ -125,7 +125,8 @@ struct CommandRunner { + /// Options (e.g. verbosity, parallelism) passed to a build. + struct BuildConfig { + BuildConfig() : verbosity(NORMAL), dry_run(false), parallelism(1), +- failures_allowed(1), max_load_average(-0.0f) {} ++ failures_allowed(1), max_load_average(-0.0f), ++ force_color_output(false) {} + + enum Verbosity { + NORMAL, +@@ -139,6 +140,8 @@ struct BuildConfig { + /// The maximum load average we must not exceed. A negative value + /// means that we do not have any limit. + double max_load_average; ++ // Do not strip color marks even when writing to a non-terminal. ++ bool force_color_output; + }; + + /// Builder wraps the build process: starting commands, updating status. +diff --git a/src/ninja.cc b/src/ninja.cc +index 30f89c2..ee0d707 100644 +--- a/src/ninja.cc ++++ b/src/ninja.cc +@@ -215,7 +215,8 @@ void Usage(const BuildConfig& config) { + " -d MODE enable debugging (use '-d list' to list modes)\n" + " -t TOOL run a subtool (use '-t list' to list subtools)\n" + " terminates toplevel options; further flags are passed to the tool\n" +-" -w FLAG adjust warnings (use '-w list' to list warnings)\n", ++" -w FLAG adjust warnings (use '-w list' to list warnings)\n" ++" -c force using color output\n", + kNinjaVersion, config.parallelism); + } + +@@ -1047,7 +1048,7 @@ int ReadFlags(int* argc, char*** argv, + + int opt; + while (!options->tool && +- (opt = getopt_long(*argc, *argv, "d:f:j:k:l:nt:vw:C:h", kLongOptions, ++ (opt = getopt_long(*argc, *argv, "d:f:j:k:l:nt:vw:C:ch", kLongOptions, + NULL)) != -1) { + switch (opt) { + case 'd': +@@ -1103,6 +1104,9 @@ int ReadFlags(int* argc, char*** argv, + case 'C': + options->working_dir = optarg; + break; ++ case 'c': ++ config->force_color_output = true; ++ break; + case OPT_VERSION: + printf("%s\n", kNinjaVersion); + return 0; +-- +2.16.2.windows.1 + diff --git a/blueprints/dev-utils/ninja/ninja.py b/blueprints/dev-utils/ninja/ninja.py index 1217dd557..7b8d62264 100644 --- a/blueprints/dev-utils/ninja/ninja.py +++ b/blueprints/dev-utils/ninja/ninja.py @@ -1,41 +1,44 @@ # -*- coding: utf-8 -*- import sys import info from Package.CMakePackageBase import * class subinfo(info.infoclass): def setTargets(self): """ """ self.svnTargets['master'] = "https://github.com/martine/ninja.git" + if CraftCore.settings.getboolean("General", "AllowAnsiColor", False): + self.patchToApply["master"] = [("0001-Add-c-flag-to-force-color-output.patch", 1)] + for ver in ["1.6.0", "1.7.1", "1.7.2", "1.8.2"]: self.targets[ver] = f"https://github.com/ninja-build/ninja/archive/v{ver}.tar.gz" self.archiveNames[ver] = f"ninja-{ver}.tar.gz" self.targetInstSrc[ver] = f"ninja-{ver}" self.targetInstallPath[ver] = "dev-utils" self.targetDigests['1.6.0'] = 'a6ff055691f6d355234298c21cc18961b4ca2ed9' self.targetDigests['1.7.2'] = (['2edda0a5421ace3cf428309211270772dd35a91af60c96f93f90df6bc41b16d9'], CraftHash.HashAlgorithm.SHA256) self.targetDigests['1.8.2'] = (['86b8700c3d0880c2b44c2ff67ce42774aaf8c28cbf57725cb881569288c1c6f4'], CraftHash.HashAlgorithm.SHA256) self.defaultTarget = "1.8.2" class Package(CMakePackageBase): def __init__(self, **args): CMakePackageBase.__init__(self) def configure(self): return True def make(self): self.enterSourceDir() command = [sys.executable, "configure.py", "--bootstrap"] if CraftCore.compiler.isMinGW(): command += ["--platform=mingw"] return utils.system(command) def install(self): utils.copyFile(os.path.join(self.sourceDir(), f"ninja{CraftCore.compiler.executableSuffix}"), os.path.join(self.installDir(), "bin", f"ninja{CraftCore.compiler.executableSuffix}")) return True