123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file LICENSE.rst or https://cmake.org/licensing for details. */
- #include "cmXCodeScheme.h"
- #include <iomanip>
- #include <sstream>
- #include <utility>
- #include <cmext/algorithm>
- #include <cmext/string_view>
- #include "cmsys/String.h"
- #include "cmGeneratedFileStream.h"
- #include "cmGeneratorExpression.h"
- #include "cmGeneratorTarget.h"
- #include "cmGlobalGenerator.h"
- #include "cmList.h"
- #include "cmStateTypes.h"
- #include "cmStringAlgorithms.h"
- #include "cmSystemTools.h"
- #include "cmValue.h"
- #include "cmXCodeObject.h"
- #include "cmXMLWriter.h"
- class cmLocalGenerator;
- cmXCodeScheme::cmXCodeScheme(cmLocalGenerator* lg, cmXCodeObject* xcObj,
- TestObjects tests,
- std::vector<std::string> const& configList,
- unsigned int xcVersion)
- : LocalGenerator(lg)
- , Target(xcObj)
- , Tests(std::move(tests))
- , TargetName(xcObj->GetTarget()->GetName())
- , ConfigList(configList)
- , XcodeVersion(xcVersion)
- {
- }
- void cmXCodeScheme::WriteXCodeSharedScheme(std::string const& xcProjDir,
- std::string const& container)
- {
- // Create shared scheme sub-directory tree
- //
- std::string xcodeSchemeDir = cmStrCat(xcProjDir, "/xcshareddata/xcschemes");
- cmSystemTools::MakeDirectory(xcodeSchemeDir);
- std::string xcodeSchemeFile =
- cmStrCat(xcodeSchemeDir, '/', this->TargetName, ".xcscheme");
- cmGeneratedFileStream fout(xcodeSchemeFile);
- fout.SetCopyIfDifferent(true);
- if (!fout) {
- return;
- }
- WriteXCodeXCScheme(fout, container);
- }
- void cmXCodeScheme::WriteXCodeXCScheme(std::ostream& fout,
- std::string const& container)
- {
- cmXMLWriter xout(fout);
- xout.SetIndentationElement(std::string(3, ' '));
- xout.StartDocument();
- xout.StartElement("Scheme");
- xout.BreakAttributes();
- xout.Attribute("LastUpgradeVersion", WriteVersionString());
- xout.Attribute("version", "1.3");
- cmValue propDftCfg =
- Target->GetTarget()->GetProperty("XCODE_SCHEME_LAUNCH_CONFIGURATION");
- std::string launchConfiguration =
- !propDftCfg.IsEmpty() ? *propDftCfg : "Debug";
- cmValue propTstCfg =
- Target->GetTarget()->GetProperty("XCODE_SCHEME_TEST_CONFIGURATION");
- std::string testConfiguration =
- !propTstCfg.IsEmpty() ? *propTstCfg : "Debug";
- WriteBuildAction(xout, container);
- WriteTestAction(xout, FindConfiguration(testConfiguration), container);
- WriteLaunchAction(xout, FindConfiguration(launchConfiguration), container);
- WriteProfileAction(xout, FindConfiguration("Release"), container);
- WriteAnalyzeAction(xout, FindConfiguration("Debug"));
- WriteArchiveAction(xout, FindConfiguration("Release"));
- xout.EndElement();
- }
- void cmXCodeScheme::WriteBuildAction(cmXMLWriter& xout,
- std::string const& container)
- {
- xout.StartElement("BuildAction");
- xout.BreakAttributes();
- xout.Attribute("parallelizeBuildables", "YES");
- xout.Attribute("buildImplicitDependencies", "YES");
- xout.StartElement("BuildActionEntries");
- xout.StartElement("BuildActionEntry");
- xout.BreakAttributes();
- xout.Attribute("buildForTesting", "YES");
- xout.Attribute("buildForRunning", "YES");
- xout.Attribute("buildForProfiling", "YES");
- xout.Attribute("buildForArchiving", "YES");
- xout.Attribute("buildForAnalyzing", "YES");
- WriteBuildableReference(xout, this->Target, container);
- xout.EndElement(); // BuildActionEntry
- xout.EndElement(); // BuildActionEntries
- xout.EndElement(); // BuildAction
- }
- void cmXCodeScheme::WriteTestAction(cmXMLWriter& xout,
- std::string const& configuration,
- std::string const& container)
- {
- xout.StartElement("TestAction");
- xout.BreakAttributes();
- xout.Attribute("buildConfiguration", configuration);
- xout.Attribute("selectedDebuggerIdentifier",
- "Xcode.DebuggerFoundation.Debugger.LLDB");
- xout.Attribute("selectedLauncherIdentifier",
- "Xcode.DebuggerFoundation.Launcher.LLDB");
- xout.Attribute("shouldUseLaunchSchemeArgsEnv", "YES");
- WriteCustomLLDBInitFile(xout, configuration);
- xout.StartElement("Testables");
- for (auto const* test : this->Tests) {
- xout.StartElement("TestableReference");
- xout.BreakAttributes();
- xout.Attribute("skipped", "NO");
- WriteBuildableReference(xout, test, container);
- xout.EndElement(); // TestableReference
- }
- xout.EndElement();
- if (IsTestable()) {
- xout.StartElement("MacroExpansion");
- WriteBuildableReference(xout, this->Target, container);
- xout.EndElement(); // MacroExpansion
- }
- xout.StartElement("AdditionalOptions");
- xout.EndElement();
- xout.EndElement(); // TestAction
- }
- void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout,
- std::string const& configuration,
- std::string const& container)
- {
- xout.StartElement("LaunchAction");
- xout.BreakAttributes();
- xout.Attribute("buildConfiguration", configuration);
- xout.Attribute("selectedDebuggerIdentifier",
- "Xcode.DebuggerFoundation.Debugger.LLDB");
- xout.Attribute("selectedLauncherIdentifier",
- "Xcode.DebuggerFoundation.Launcher.LLDB");
- {
- cmValue launchMode =
- this->Target->GetTarget()->GetProperty("XCODE_SCHEME_LAUNCH_MODE");
- std::string value = "0"; // == 'AUTO'
- if (launchMode && *launchMode == "WAIT"_s) {
- value = "1";
- }
- xout.Attribute("launchStyle", value);
- }
- WriteCustomWorkingDirectory(xout, configuration);
- WriteCustomLLDBInitFile(xout, configuration);
- xout.Attribute("ignoresPersistentStateOnLaunch", "NO");
- WriteLaunchActionBooleanAttribute(xout, "debugDocumentVersioning",
- "XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING",
- true);
- xout.Attribute("debugServiceExtension", "internal");
- xout.Attribute("allowLocationSimulation", "YES");
- if (cmValue gpuFrameCaptureMode = this->Target->GetTarget()->GetProperty(
- "XCODE_SCHEME_ENABLE_GPU_FRAME_CAPTURE_MODE")) {
- std::string value = *gpuFrameCaptureMode;
- if (cmsysString_strcasecmp(value.c_str(), "Metal") == 0) {
- value = "1";
- } else if (cmsysString_strcasecmp(value.c_str(), "Disabled") == 0) {
- value = "3";
- }
- xout.Attribute("enableGPUFrameCaptureMode", value);
- }
- // Diagnostics tab begin
- bool useAddressSanitizer = WriteLaunchActionAttribute(
- xout, "enableAddressSanitizer",
- "XCODE_SCHEME_ADDRESS_SANITIZER"); // not allowed with
- // enableThreadSanitizer=YES
- WriteLaunchActionAttribute(
- xout, "enableASanStackUseAfterReturn",
- "XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN");
- bool useThreadSanitizer = false;
- if (!useAddressSanitizer) {
- useThreadSanitizer = WriteLaunchActionAttribute(
- xout, "enableThreadSanitizer",
- "XCODE_SCHEME_THREAD_SANITIZER"); // not allowed with
- // enableAddressSanitizer=YES
- }
- WriteLaunchActionAttribute(xout, "stopOnEveryThreadSanitizerIssue",
- "XCODE_SCHEME_THREAD_SANITIZER_STOP");
- WriteLaunchActionAttribute(xout, "enableUBSanitizer",
- "XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER");
- if (cmValue value = this->Target->GetTarget()->GetProperty(
- "XCODE_SCHEME_ENABLE_GPU_API_VALIDATION")) {
- if (value.IsOff()) {
- xout.Attribute("enableGPUValidationMode",
- "1"); // unset means YES, "1" means NO
- }
- }
- if (cmValue value = this->Target->GetTarget()->GetProperty(
- "XCODE_SCHEME_ENABLE_GPU_SHADER_VALIDATION")) {
- if (value.IsOn()) {
- xout.Attribute("enableGPUShaderValidationMode",
- "2"); // unset means NO, "2" means YES
- }
- }
- WriteLaunchActionAttribute(
- xout, "stopOnEveryUBSanitizerIssue",
- "XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP");
- WriteLaunchActionAttribute(
- xout, "disableMainThreadChecker",
- "XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER"); // negative enabled!
- WriteLaunchActionAttribute(xout, "stopOnEveryMainThreadCheckerIssue",
- "XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP");
- if (this->Target->GetTarget()->GetPropertyAsBool(
- "XCODE_SCHEME_DEBUG_AS_ROOT")) {
- xout.Attribute("debugAsWhichUser", "root");
- }
- // Diagnostics tab end
- if (IsExecutable(this->Target)) {
- WriteBuildableProductRunnable(xout, this->Target, container);
- } else {
- xout.StartElement("MacroExpansion");
- WriteBuildableReference(xout, this->Target, container);
- xout.EndElement();
- }
- // Info tab begin
- if (cmValue exe =
- this->Target->GetTarget()->GetProperty("XCODE_SCHEME_EXECUTABLE")) {
- xout.StartElement("PathRunnable");
- xout.BreakAttributes();
- xout.Attribute("runnableDebuggingMode", "0");
- xout.Attribute("FilePath", *exe);
- xout.EndElement(); // PathRunnable
- }
- // Info tab end
- // Arguments tab begin
- if (cmValue argList =
- this->Target->GetTarget()->GetProperty("XCODE_SCHEME_ARGUMENTS")) {
- cmList arguments{ *argList };
- if (!arguments.empty()) {
- xout.StartElement("CommandLineArguments");
- for (auto const& argument : arguments) {
- xout.StartElement("CommandLineArgument");
- xout.BreakAttributes();
- xout.Attribute("argument", argument);
- xout.Attribute("isEnabled", "YES");
- xout.EndElement(); // CommandLineArgument
- }
- xout.EndElement(); // CommandLineArguments
- }
- }
- if (cmValue envList =
- this->Target->GetTarget()->GetProperty("XCODE_SCHEME_ENVIRONMENT")) {
- cmList envs{ *envList };
- if (!envs.empty()) {
- xout.StartElement("EnvironmentVariables");
- for (auto env : envs) {
- xout.StartElement("EnvironmentVariable");
- xout.BreakAttributes();
- std::string envValue;
- auto const p = env.find_first_of('=');
- if (p != std::string::npos) {
- envValue = env.substr(p + 1);
- env.resize(p);
- }
- xout.Attribute("key", env);
- xout.Attribute("value", envValue);
- xout.Attribute("isEnabled", "YES");
- xout.EndElement(); // EnvironmentVariable
- }
- xout.EndElement(); // EnvironmentVariables
- }
- }
- // Arguments tab end
- xout.StartElement("AdditionalOptions");
- if (!useThreadSanitizer) {
- WriteLaunchActionAdditionalOption(xout, "MallocScribble", "",
- "XCODE_SCHEME_MALLOC_SCRIBBLE");
- }
- if (!useThreadSanitizer && !useAddressSanitizer) {
- WriteLaunchActionAdditionalOption(xout, "MallocGuardEdges", "",
- "XCODE_SCHEME_MALLOC_GUARD_EDGES");
- }
- if (!useThreadSanitizer && !useAddressSanitizer) {
- WriteLaunchActionAdditionalOption(xout, "DYLD_INSERT_LIBRARIES",
- "/usr/lib/libgmalloc.dylib",
- "XCODE_SCHEME_GUARD_MALLOC");
- }
- WriteLaunchActionAdditionalOption(xout, "NSZombieEnabled", "YES",
- "XCODE_SCHEME_ZOMBIE_OBJECTS");
- if (!useThreadSanitizer && !useAddressSanitizer) {
- WriteLaunchActionAdditionalOption(xout, "MallocStackLogging", "",
- "XCODE_SCHEME_MALLOC_STACK");
- }
- WriteLaunchActionAdditionalOption(xout, "DYLD_PRINT_APIS", "",
- "XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE");
- WriteLaunchActionAdditionalOption(xout, "DYLD_PRINT_LIBRARIES", "",
- "XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS");
- xout.EndElement();
- xout.EndElement(); // LaunchAction
- }
- bool cmXCodeScheme::WriteLaunchActionAttribute(cmXMLWriter& xout,
- std::string const& attrName,
- std::string const& varName)
- {
- if (Target->GetTarget()->GetPropertyAsBool(varName)) {
- xout.Attribute(attrName.c_str(), "YES");
- return true;
- }
- return false;
- }
- bool cmXCodeScheme::WriteLaunchActionBooleanAttribute(
- cmXMLWriter& xout, std::string const& attrName, std::string const& varName,
- bool defaultValue)
- {
- cmValue property = Target->GetTarget()->GetProperty(varName);
- bool isOn = (!property && defaultValue) || property.IsOn();
- if (isOn) {
- xout.Attribute(attrName.c_str(), "YES");
- } else {
- xout.Attribute(attrName.c_str(), "NO");
- }
- return isOn;
- }
- bool cmXCodeScheme::WriteLaunchActionAdditionalOption(
- cmXMLWriter& xout, std::string const& key, std::string const& value,
- std::string const& varName)
- {
- if (Target->GetTarget()->GetPropertyAsBool(varName)) {
- xout.StartElement("AdditionalOption");
- xout.BreakAttributes();
- xout.Attribute("key", key);
- xout.Attribute("value", value);
- xout.Attribute("isEnabled", "YES");
- xout.EndElement(); // AdditionalOption
- return true;
- }
- return false;
- }
- void cmXCodeScheme::WriteProfileAction(cmXMLWriter& xout,
- std::string const& configuration,
- std::string const& container)
- {
- xout.StartElement("ProfileAction");
- xout.BreakAttributes();
- xout.Attribute("buildConfiguration", configuration);
- xout.Attribute("shouldUseLaunchSchemeArgsEnv", "YES");
- xout.Attribute("savedToolIdentifier", "");
- WriteCustomWorkingDirectory(xout, configuration);
- WriteLaunchActionBooleanAttribute(xout, "debugDocumentVersioning",
- "XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING",
- true);
- if (IsExecutable(this->Target)) {
- WriteBuildableProductRunnable(xout, this->Target, container);
- }
- xout.EndElement();
- }
- void cmXCodeScheme::WriteAnalyzeAction(cmXMLWriter& xout,
- std::string const& configuration)
- {
- xout.StartElement("AnalyzeAction");
- xout.BreakAttributes();
- xout.Attribute("buildConfiguration", configuration);
- xout.EndElement();
- }
- void cmXCodeScheme::WriteArchiveAction(cmXMLWriter& xout,
- std::string const& configuration)
- {
- xout.StartElement("ArchiveAction");
- xout.BreakAttributes();
- xout.Attribute("buildConfiguration", configuration);
- xout.Attribute("revealArchiveInOrganizer", "YES");
- xout.EndElement();
- }
- void cmXCodeScheme::WriteBuildableProductRunnable(cmXMLWriter& xout,
- cmXCodeObject const* xcObj,
- std::string const& container)
- {
- xout.StartElement("BuildableProductRunnable");
- xout.BreakAttributes();
- xout.Attribute("runnableDebuggingMode", "0");
- WriteBuildableReference(xout, xcObj, container);
- xout.EndElement();
- }
- void cmXCodeScheme::WriteBuildableReference(cmXMLWriter& xout,
- cmXCodeObject const* xcObj,
- std::string const& container)
- {
- xout.StartElement("BuildableReference");
- xout.BreakAttributes();
- xout.Attribute("BuildableIdentifier", "primary");
- xout.Attribute("BlueprintIdentifier", xcObj->GetId());
- std::string const noConfig; // FIXME: What config to use here?
- xout.Attribute("BuildableName", xcObj->GetTarget()->GetFullName(noConfig));
- xout.Attribute("BlueprintName", xcObj->GetTarget()->GetName());
- xout.Attribute("ReferencedContainer", cmStrCat("container:", container));
- xout.EndElement();
- }
- void cmXCodeScheme::WriteCustomWorkingDirectory(
- cmXMLWriter& xout, std::string const& configuration)
- {
- cmGlobalGenerator* gg = this->LocalGenerator->GetGlobalGenerator();
- cmValue propertyValue =
- gg->GetDebuggerWorkingDirectory(this->Target->GetTarget());
- if (!propertyValue) {
- xout.Attribute("useCustomWorkingDirectory", "NO");
- } else {
- xout.Attribute("useCustomWorkingDirectory", "YES");
- auto customWorkingDirectory = cmGeneratorExpression::Evaluate(
- *propertyValue, this->LocalGenerator, configuration);
- xout.Attribute("customWorkingDirectory", customWorkingDirectory);
- }
- }
- void cmXCodeScheme::WriteCustomLLDBInitFile(cmXMLWriter& xout,
- std::string const& configuration)
- {
- std::string const& propertyValue =
- this->Target->GetTarget()->GetSafeProperty("XCODE_SCHEME_LLDB_INIT_FILE");
- if (!propertyValue.empty()) {
- auto customLLDBInitFile = cmGeneratorExpression::Evaluate(
- propertyValue, this->LocalGenerator, configuration);
- xout.Attribute("customLLDBInitFile", customLLDBInitFile);
- }
- }
- std::string cmXCodeScheme::WriteVersionString()
- {
- std::ostringstream v;
- v << std::setfill('0') << std::setw(4) << this->XcodeVersion * 10;
- return v.str();
- }
- std::string cmXCodeScheme::FindConfiguration(std::string const& name)
- {
- // Try to find the desired configuration by name,
- // and if it's not found return first from the list
- //
- if (!cm::contains(this->ConfigList, name) && !this->ConfigList.empty()) {
- return this->ConfigList[0];
- }
- return name;
- }
- bool cmXCodeScheme::IsTestable() const
- {
- return !this->Tests.empty() || IsExecutable(this->Target);
- }
- bool cmXCodeScheme::IsExecutable(cmXCodeObject const* target)
- {
- cmGeneratorTarget* gt = target->GetTarget();
- if (!gt) {
- cmSystemTools::Error("Error no target on xobject\n");
- return false;
- }
- return gt->GetType() == cmStateEnums::EXECUTABLE;
- }
|