/**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "buildconsolebuildstep.h" #include "commandbuilderaspect.h" #include "incredibuildconstants.h" #include #include #include #include #include #include #include #include #include using namespace ProjectExplorer; using namespace Utils; namespace IncrediBuild { namespace Internal { namespace Constants { const QLatin1String BUILDCONSOLE_AVOIDLOCAL("IncrediBuild.BuildConsole.AvoidLocal"); const QLatin1String BUILDCONSOLE_PROFILEXML("IncrediBuild.BuildConsole.ProfileXml"); const QLatin1String BUILDCONSOLE_MAXCPU("IncrediBuild.BuildConsole.MaxCpu"); const QLatin1String BUILDCONSOLE_MAXWINVER("IncrediBuild.BuildConsole.MaxWinVer"); const QLatin1String BUILDCONSOLE_MINWINVER("IncrediBuild.BuildConsole.MinWinVer"); const QLatin1String BUILDCONSOLE_TITLE("IncrediBuild.BuildConsole.Title"); const QLatin1String BUILDCONSOLE_MONFILE("IncrediBuild.BuildConsole.MonFile"); const QLatin1String BUILDCONSOLE_SUPPRESSSTDOUT("IncrediBuild.BuildConsole.SuppressStdOut"); const QLatin1String BUILDCONSOLE_LOGFILE("IncrediBuild.BuildConsole.LogFile"); const QLatin1String BUILDCONSOLE_SHOWCMD("IncrediBuild.BuildConsole.ShowCmd"); const QLatin1String BUILDCONSOLE_SHOWAGENTS("IncrediBuild.BuildConsole.ShowAgents"); const QLatin1String BUILDCONSOLE_SHOWTIME("IncrediBuild.BuildConsole.ShowTime"); const QLatin1String BUILDCONSOLE_HIDEHEADER("IncrediBuild.BuildConsole.HideHeader"); const QLatin1String BUILDCONSOLE_LOGLEVEL("IncrediBuild.BuildConsole.LogLevel"); const QLatin1String BUILDCONSOLE_SETENV("IncrediBuild.BuildConsole.SetEnv"); const QLatin1String BUILDCONSOLE_STOPONERROR("IncrediBuild.BuildConsole.StopOnError"); const QLatin1String BUILDCONSOLE_ADDITIONALARGUMENTS("IncrediBuild.BuildConsole.AdditionalArguments"); const QLatin1String BUILDCONSOLE_OPENMONITOR("IncrediBuild.BuildConsole.OpenMonitor"); const QLatin1String BUILDCONSOLE_KEEPJOBNUM("IncrediBuild.BuildConsole.KeepJobNum"); const QLatin1String BUILDCONSOLE_COMMANDBUILDER("IncrediBuild.BuildConsole.CommandBuilder"); } static QString normalizeWinVerArgument(QString winVer) { winVer.remove("Windows "); winVer.remove("Server "); return winVer.toUpper(); } const QStringList &supportedWindowsVersions() { static QStringList list({QString(), "Windows 7", "Windows 8", "Windows 10", "Windows Vista", "Windows XP", "Windows Server 2003", "Windows Server 2008", "Windows Server 2012"}); return list; } class BuildConsoleBuildStep : public AbstractProcessStep { Q_DECLARE_TR_FUNCTIONS(IncrediBuild::Internal::BuildConsoleBuildStep) public: BuildConsoleBuildStep(BuildStepList *buildStepList, Id id); void setupOutputFormatter(OutputFormatter *formatter) final; }; BuildConsoleBuildStep::BuildConsoleBuildStep(BuildStepList *buildStepList, Id id) : AbstractProcessStep(buildStepList, id) { setDisplayName(tr("IncrediBuild for Windows")); addAspect("" + tr("Target and Configuration")); auto commandBuilder = addAspect(this); commandBuilder->setSettingsKey(Constants::BUILDCONSOLE_COMMANDBUILDER); addAspect("" + tr("Enter the appropriate arguments to your build command.")); addAspect("" + tr("Make sure the build command's multi-job " "parameter value is large enough " "(such as -j200 for the JOM or Make build tools)")); auto keepJobNum = addAspect(); keepJobNum->setSettingsKey(Constants::BUILDCONSOLE_KEEPJOBNUM); keepJobNum->setLabel(tr("Keep Original Jobs Num:")); keepJobNum->setToolTip(tr("Setting this option to true, forces IncrediBuild to not override " "the -j command line switch.

The default IncrediBuild " "behavior is to set a high value to the -j command line switch " "which controls the number of processes that the build tools " "executed by Qt Creator will execute in parallel (the default " "IncrediBuild behavior will set this value to 200)")); addAspect("" + tr("IncrediBuild Distribution Control")); auto profileXml = addAspect(); profileXml->setSettingsKey(Constants::BUILDCONSOLE_PROFILEXML); profileXml->setLabelText(tr("Profile.xml:")); profileXml->setDisplayStyle(StringAspect::PathChooserDisplay); profileXml->setExpectedKind(PathChooser::Kind::File); profileXml->setBaseFileName(FilePath::fromString(PathChooser::homePath())); profileXml->setHistoryCompleter("IncrediBuild.BuildConsole.ProfileXml.History"); profileXml->setToolTip(tr("The Profile XML file is used to define how Automatic " "Interception Interface should handle the various processes " "involved in a distributed job. It is not necessary for " "\"Visual Studio\" or \"Make and Build tools\" builds, " "but can be used to provide configuration options if those " "builds use additional processes that are not included in " "those packages. It is required to configure distributable " "processes in \"Dev Tools\" builds.")); auto avoidLocal = addAspect(); avoidLocal->setSettingsKey(Constants::BUILDCONSOLE_AVOIDLOCAL); avoidLocal->setLabel(tr("Avoid Local:")); avoidLocal->setToolTip(tr("Overrides the Agent Settings dialog Avoid task execution on local " "machine when possible option. This allows to free more resources " "on the initiator machine and could be beneficial to distribution " "in scenarios where the initiating machine is bottlenecking the " "build with High CPU usage.")); auto maxCpu = addAspect(); maxCpu->setSettingsKey(Constants::BUILDCONSOLE_MAXCPU); maxCpu->setToolTip(tr("Determines the maximum number of CPU cores that can be used in a " "build, regardless of the number of available Agents. " "It takes into account both local and remote cores, even if the " "Avoid Task Execution on Local Machine option is selected.")); maxCpu->setLabel(tr("Maximum CPUs to utilize in the build:")); maxCpu->setRange(0, 65536); auto maxWinVer = addAspect(); maxWinVer->setSettingsKey(Constants::BUILDCONSOLE_MAXWINVER); maxWinVer->setDisplayName(tr("Newest allowed helper machine OS:")); maxWinVer->setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); maxWinVer->setToolTip(tr("Specifies the newest operating system installed on a helper " "machine to be allowed to participate as helper in the build.")); for (const QString &version : supportedWindowsVersions()) maxWinVer->addOption(version); auto minWinVer = addAspect(); minWinVer->setSettingsKey(Constants::BUILDCONSOLE_MINWINVER); minWinVer->setDisplayName(tr("Oldest allowed helper machine OS:")); minWinVer->setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); minWinVer->setToolTip(tr("Specifies the oldest operating system installed on a helper " "machine to be allowed to participate as helper in the build.")); for (const QString &version : supportedWindowsVersions()) minWinVer->addOption(version); addAspect("" + tr("Output and Logging")); auto title = addAspect(); title->setSettingsKey(Constants::BUILDCONSOLE_TITLE); title->setLabelText(tr("Build Title:")); title->setDisplayStyle(StringAspect::LineEditDisplay); title->setToolTip(tr("Specifies a custom header line which will be displayed in the " "beginning of the build output text. This title will also be used " "for the Build History and Build Monitor displays.")); auto monFile = addAspect(); monFile->setSettingsKey(Constants::BUILDCONSOLE_MONFILE); monFile->setLabelText(tr("Save IncrediBuild monitor file:")); monFile->setDisplayStyle(StringAspect::PathChooserDisplay); monFile->setExpectedKind(PathChooser::Kind::Any); monFile->setBaseFileName(FilePath::fromString(PathChooser::homePath())); monFile->setHistoryCompleter(QLatin1String("IncrediBuild.BuildConsole.MonFile.History")); monFile->setToolTip(tr("Writes a copy of the build progress (.ib_mon) file to the specified " "location. - If only a folder name is given, IncrediBuild generates a " "GUID for the file name. - A message containing the location of the " "saved .ib_mon file is added to the end of the build output")); auto suppressStdOut = addAspect(); suppressStdOut->setSettingsKey(Constants::BUILDCONSOLE_SUPPRESSSTDOUT); suppressStdOut->setLabel(tr("Suppress STDOUT:")); suppressStdOut->setToolTip(tr("Does not write anything to the standard output.")); auto logFile = addAspect(); logFile->setSettingsKey(Constants::BUILDCONSOLE_LOGFILE); logFile->setLabelText(tr("Output Log file:")); logFile->setDisplayStyle(StringAspect::PathChooserDisplay); logFile->setExpectedKind(PathChooser::Kind::SaveFile); logFile->setBaseFileName(FilePath::fromString(PathChooser::homePath())); logFile->setHistoryCompleter(QLatin1String("IncrediBuild.BuildConsole.LogFile.History")); logFile->setToolTip(tr("Writes build output to a file.")); auto showCmd = addAspect(); showCmd->setSettingsKey(Constants::BUILDCONSOLE_SHOWCMD); showCmd->setLabel(tr("Show Commands in output:")); showCmd->setToolTip(tr("Shows, for each file built, the command-line used by IncrediBuild " "to build the file.")); auto showAgents = addAspect(); showAgents->setSettingsKey(Constants::BUILDCONSOLE_SHOWAGENTS); showAgents->setLabel(tr("Show Agents in output:")); showAgents->setToolTip(tr("Shows the Agent used to build each file.")); auto showTime = addAspect(); showTime->setSettingsKey(Constants::BUILDCONSOLE_SHOWTIME); showTime->setLabel(tr("Show Time in output:")); showTime->setToolTip(tr("Shows the Start and Finish time for each file built.")); auto hideHeader = addAspect(); hideHeader->setSettingsKey(Constants::BUILDCONSOLE_HIDEHEADER); hideHeader->setLabel(tr("Hide IncrediBuild Header in output:")); hideHeader->setToolTip(tr("Suppresses the \"IncrediBuild\" header in the build output")); auto logLevel = addAspect(); logLevel->setSettingsKey(Constants::BUILDCONSOLE_LOGLEVEL); logLevel->setDisplayName(tr("Internal IncrediBuild logging level:")); logLevel->setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); logLevel->addOption(QString()); logLevel->addOption("Minimal"); logLevel->addOption("Extended"); logLevel->addOption("Detailed"); logLevel->setToolTip(tr("Overrides the internal Incredibuild logging level for this build. " "Does not affect output or any user accessible logging. Used mainly " "to troubleshoot issues with the help of IncrediBuild support")); addAspect("" + tr("Miscellaneous")); auto setEnv = addAspect(); setEnv->setSettingsKey(Constants::BUILDCONSOLE_SETENV); setEnv->setLabelText(tr("Set an Environment Variable:")); setEnv->setDisplayStyle(StringAspect::LineEditDisplay); setEnv->setToolTip(tr("Sets or overrides environment variables for the context of the build.")); auto stopOnError = addAspect(); stopOnError->setSettingsKey(Constants::BUILDCONSOLE_STOPONERROR); stopOnError->setLabel(tr("Stop On Errors:")); stopOnError->setToolTip(tr("When specified, the execution will stop as soon as an error " "is encountered. This is the default behavior in " "\"Visual Studio\" builds, but not the default for " "\"Make and Build tools\" or \"Dev Tools\" builds")); auto additionalArguments = addAspect(); additionalArguments->setSettingsKey(Constants::BUILDCONSOLE_ADDITIONALARGUMENTS); additionalArguments->setLabelText(tr("Additional Arguments:")); additionalArguments->setDisplayStyle(StringAspect::LineEditDisplay); additionalArguments->setToolTip(tr("Add additional buildconsole arguments manually. " "The value of this field will be concatenated to the " "final buildconsole command line")); auto openMonitor = addAspect(); openMonitor->setSettingsKey(Constants::BUILDCONSOLE_OPENMONITOR); openMonitor->setLabel(tr("Open Monitor:")); openMonitor->setToolTip(tr("Opens an IncrediBuild Build Monitor that graphically displays " "the build progress once the build starts.")); setCommandLineProvider([=] { QStringList args; QString cmd("/Command= %1"); cmd = cmd.arg(commandBuilder->fullCommandFlag(keepJobNum->value())); args.append(cmd); if (!profileXml->value().isEmpty()) args.append("/Profile=" + profileXml->value()); args.append(QString("/AvoidLocal=%1").arg(avoidLocal->value() ? QString("ON") : QString("OFF"))); if (maxCpu->value() > 0) args.append(QString("/MaxCPUs=%1").arg(maxCpu->value())); if (!maxWinVer->stringValue().isEmpty()) args.append(QString("/MaxWinVer=%1").arg(normalizeWinVerArgument(maxWinVer->stringValue()))); if (!minWinVer->stringValue().isEmpty()) args.append(QString("/MinWinVer=%1").arg(normalizeWinVerArgument(minWinVer->stringValue()))); if (!title->value().isEmpty()) args.append(QString("/Title=" + title->value())); if (!monFile->value().isEmpty()) args.append(QString("/Mon=" + monFile->value())); if (suppressStdOut->value()) args.append("/Silent"); if (!logFile->value().isEmpty()) args.append(QString("/Log=" + logFile->value())); if (showCmd->value()) args.append("/ShowCmd"); if (showAgents->value()) args.append("/ShowAgent"); if (showAgents->value()) args.append("/ShowTime"); if (hideHeader->value()) args.append("/NoLogo"); if (!logLevel->stringValue().isEmpty()) args.append(QString("/LogLevel=" + logLevel->stringValue())); if (!setEnv->value().isEmpty()) args.append(QString("/SetEnv=" + setEnv->value())); if (stopOnError->value()) args.append("/StopOnErrors"); if (!additionalArguments->value().isEmpty()) args.append(additionalArguments->value()); if (openMonitor->value()) args.append("/OpenMonitor"); return CommandLine("BuildConsole.exe", args); }); } void BuildConsoleBuildStep::setupOutputFormatter(OutputFormatter *formatter) { formatter->addLineParser(new GnuMakeParser()); formatter->addLineParsers(kit()->createOutputParsers()); formatter->addSearchDir(processParameters()->effectiveWorkingDirectory()); AbstractProcessStep::setupOutputFormatter(formatter); } // BuildConsoleStepFactory BuildConsoleStepFactory::BuildConsoleStepFactory() { registerStep(IncrediBuild::Constants::BUILDCONSOLE_BUILDSTEP_ID); setDisplayName(BuildConsoleBuildStep::tr("IncrediBuild for Windows")); setSupportedStepLists({ProjectExplorer::Constants::BUILDSTEPS_BUILD, ProjectExplorer::Constants::BUILDSTEPS_CLEAN}); } } // namespace Internal } // namespace IncrediBuild