cmake/Source/cmXCodeScheme.cxx

456 lines
14 KiB
C++
Raw Normal View History

2017-07-20 19:35:53 +02:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmXCodeScheme.h"
#include <iomanip>
#include <iostream>
#include <sstream>
2019-11-11 23:01:05 +01:00
#include <utility>
2017-07-20 19:35:53 +02:00
2020-08-30 11:54:41 +02:00
#include <cmext/algorithm>
2017-07-20 19:35:53 +02:00
#include "cmGeneratedFileStream.h"
2020-08-30 11:54:41 +02:00
#include "cmGeneratorExpression.h"
2017-07-20 19:35:53 +02:00
#include "cmGeneratorTarget.h"
#include "cmXMLSafe.h"
2020-08-30 11:54:41 +02:00
cmXCodeScheme::cmXCodeScheme(cmLocalGenerator* lg, cmXCodeObject* xcObj,
TestObjects tests,
2017-07-20 19:35:53 +02:00
const std::vector<std::string>& configList,
unsigned int xcVersion)
2020-08-30 11:54:41 +02:00
: LocalGenerator(lg)
, Target(xcObj)
2019-11-11 23:01:05 +01:00
, Tests(std::move(tests))
2017-07-20 19:35:53 +02:00
, TargetName(xcObj->GetTarget()->GetName())
, ConfigList(configList)
, XcodeVersion(xcVersion)
{
}
void cmXCodeScheme::WriteXCodeSharedScheme(const std::string& xcProjDir,
const std::string& container)
{
// Create shared scheme sub-directory tree
//
2020-02-01 23:06:01 +01:00
std::string xcodeSchemeDir = cmStrCat(xcProjDir, "/xcshareddata/xcschemes");
2021-09-14 00:13:48 +02:00
cmSystemTools::MakeDirectory(xcodeSchemeDir);
2017-07-20 19:35:53 +02:00
2020-02-01 23:06:01 +01:00
std::string xcodeSchemeFile =
cmStrCat(xcodeSchemeDir, '/', this->TargetName, ".xcscheme");
2017-07-20 19:35:53 +02:00
2019-11-11 23:01:05 +01:00
cmGeneratedFileStream fout(xcodeSchemeFile);
2017-07-20 19:35:53 +02:00
fout.SetCopyIfDifferent(true);
if (!fout) {
return;
}
WriteXCodeXCScheme(fout, container);
}
void cmXCodeScheme::WriteXCodeXCScheme(std::ostream& fout,
const std::string& 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");
WriteBuildAction(xout, container);
2018-01-26 17:06:56 +01:00
WriteTestAction(xout, FindConfiguration("Debug"), container);
2017-07-20 19:35:53 +02:00
WriteLaunchAction(xout, FindConfiguration("Debug"), container);
WriteProfileAction(xout, FindConfiguration("Release"));
WriteAnalyzeAction(xout, FindConfiguration("Debug"));
WriteArchiveAction(xout, FindConfiguration("Release"));
xout.EndElement();
}
void cmXCodeScheme::WriteBuildAction(cmXMLWriter& xout,
const std::string& 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");
2018-01-26 17:06:56 +01:00
WriteBuildableReference(xout, this->Target, container);
2017-07-20 19:35:53 +02:00
xout.EndElement(); // BuildActionEntry
xout.EndElement(); // BuildActionEntries
xout.EndElement(); // BuildAction
}
void cmXCodeScheme::WriteTestAction(cmXMLWriter& xout,
2018-01-26 17:06:56 +01:00
const std::string& configuration,
const std::string& container)
2017-07-20 19:35:53 +02:00
{
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");
xout.StartElement("Testables");
2018-01-26 17:06:56 +01:00
for (auto test : this->Tests) {
xout.StartElement("TestableReference");
xout.BreakAttributes();
xout.Attribute("skipped", "NO");
WriteBuildableReference(xout, test, container);
xout.EndElement(); // TestableReference
}
2017-07-20 19:35:53 +02:00
xout.EndElement();
2018-01-26 17:06:56 +01:00
if (IsTestable()) {
xout.StartElement("MacroExpansion");
WriteBuildableReference(xout, this->Target, container);
xout.EndElement(); // MacroExpansion
}
2017-07-20 19:35:53 +02:00
xout.StartElement("AdditionalOptions");
xout.EndElement();
xout.EndElement(); // TestAction
}
void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout,
2018-01-26 17:06:56 +01:00
const std::string& configuration,
2017-07-20 19:35:53 +02:00
const std::string& container)
{
xout.StartElement("LaunchAction");
xout.BreakAttributes();
xout.Attribute("buildConfiguration", configuration);
xout.Attribute("selectedDebuggerIdentifier",
"Xcode.DebuggerFoundation.Debugger.LLDB");
xout.Attribute("selectedLauncherIdentifier",
"Xcode.DebuggerFoundation.Launcher.LLDB");
xout.Attribute("launchStyle", "0");
2020-08-30 11:54:41 +02:00
WriteCustomWorkingDirectory(xout, configuration);
2017-07-20 19:35:53 +02:00
xout.Attribute("ignoresPersistentStateOnLaunch", "NO");
2020-02-01 23:06:01 +01:00
WriteLaunchActionBooleanAttribute(xout, "debugDocumentVersioning",
"XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING",
true);
2017-07-20 19:35:53 +02:00
xout.Attribute("debugServiceExtension", "internal");
xout.Attribute("allowLocationSimulation", "YES");
2018-10-28 12:09:07 +01:00
// 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");
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");
2019-11-11 23:01:05 +01:00
if (this->Target->GetTarget()->GetPropertyAsBool(
"XCODE_SCHEME_DEBUG_AS_ROOT")) {
xout.Attribute("debugAsWhichUser", "root");
}
2018-10-28 12:09:07 +01:00
// Diagnostics tab end
2017-07-20 19:35:53 +02:00
if (IsExecutable(this->Target)) {
xout.StartElement("BuildableProductRunnable");
xout.BreakAttributes();
xout.Attribute("runnableDebuggingMode", "0");
} else {
xout.StartElement("MacroExpansion");
}
2018-01-26 17:06:56 +01:00
WriteBuildableReference(xout, this->Target, container);
2017-07-20 19:35:53 +02:00
xout.EndElement(); // MacroExpansion
2018-10-28 12:09:07 +01:00
// Info tab begin
2021-11-20 13:41:27 +01:00
if (cmValue exe =
2018-10-28 12:09:07 +01:00
this->Target->GetTarget()->GetProperty("XCODE_SCHEME_EXECUTABLE")) {
xout.StartElement("PathRunnable");
xout.BreakAttributes();
xout.Attribute("runnableDebuggingMode", "0");
2020-08-30 11:54:41 +02:00
xout.Attribute("FilePath", *exe);
2018-10-28 12:09:07 +01:00
xout.EndElement(); // PathRunnable
}
// Info tab end
// Arguments tab begin
2021-11-20 13:41:27 +01:00
if (cmValue argList =
2018-10-28 12:09:07 +01:00
this->Target->GetTarget()->GetProperty("XCODE_SCHEME_ARGUMENTS")) {
2020-08-30 11:54:41 +02:00
std::vector<std::string> arguments = cmExpandedList(*argList);
2018-10-28 12:09:07 +01:00
if (!arguments.empty()) {
xout.StartElement("CommandLineArguments");
2019-11-11 23:01:05 +01:00
for (auto const& argument : arguments) {
2018-10-28 12:09:07 +01:00
xout.StartElement("CommandLineArgument");
xout.BreakAttributes();
xout.Attribute("argument", argument);
xout.Attribute("isEnabled", "YES");
xout.EndElement(); // CommandLineArgument
}
xout.EndElement(); // CommandLineArguments
}
}
2021-11-20 13:41:27 +01:00
if (cmValue envList =
2018-10-28 12:09:07 +01:00
this->Target->GetTarget()->GetProperty("XCODE_SCHEME_ENVIRONMENT")) {
2020-08-30 11:54:41 +02:00
std::vector<std::string> envs = cmExpandedList(*envList);
2018-10-28 12:09:07 +01:00
if (!envs.empty()) {
xout.StartElement("EnvironmentVariables");
for (auto env : envs) {
xout.StartElement("EnvironmentVariable");
xout.BreakAttributes();
std::string envValue;
const auto 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
2017-07-20 19:35:53 +02:00
xout.StartElement("AdditionalOptions");
2018-10-28 12:09:07 +01:00
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");
2017-07-20 19:35:53 +02:00
xout.EndElement();
xout.EndElement(); // LaunchAction
}
2018-10-28 12:09:07 +01:00
bool cmXCodeScheme::WriteLaunchActionAttribute(cmXMLWriter& xout,
const std::string& attrName,
const std::string& varName)
{
if (Target->GetTarget()->GetPropertyAsBool(varName)) {
xout.Attribute(attrName.c_str(), "YES");
return true;
}
return false;
}
2020-02-01 23:06:01 +01:00
bool cmXCodeScheme::WriteLaunchActionBooleanAttribute(
cmXMLWriter& xout, const std::string& attrName, const std::string& varName,
bool defaultValue)
{
2021-11-20 13:41:27 +01:00
cmValue property = Target->GetTarget()->GetProperty(varName);
2021-09-14 00:13:48 +02:00
bool isOn = (!property && defaultValue) || cmIsOn(property);
2020-02-01 23:06:01 +01:00
if (isOn) {
xout.Attribute(attrName.c_str(), "YES");
} else {
xout.Attribute(attrName.c_str(), "NO");
}
return isOn;
}
2018-10-28 12:09:07 +01:00
bool cmXCodeScheme::WriteLaunchActionAdditionalOption(
cmXMLWriter& xout, const std::string& key, const std::string& value,
const std::string& 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;
}
2017-07-20 19:35:53 +02:00
void cmXCodeScheme::WriteProfileAction(cmXMLWriter& xout,
2018-01-26 17:06:56 +01:00
const std::string& configuration)
2017-07-20 19:35:53 +02:00
{
xout.StartElement("ProfileAction");
xout.BreakAttributes();
xout.Attribute("buildConfiguration", configuration);
xout.Attribute("shouldUseLaunchSchemeArgsEnv", "YES");
xout.Attribute("savedToolIdentifier", "");
2020-08-30 11:54:41 +02:00
WriteCustomWorkingDirectory(xout, configuration);
2020-02-01 23:06:01 +01:00
WriteLaunchActionBooleanAttribute(xout, "debugDocumentVersioning",
"XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING",
true);
2017-07-20 19:35:53 +02:00
xout.EndElement();
}
void cmXCodeScheme::WriteAnalyzeAction(cmXMLWriter& xout,
2018-01-26 17:06:56 +01:00
const std::string& configuration)
2017-07-20 19:35:53 +02:00
{
xout.StartElement("AnalyzeAction");
xout.BreakAttributes();
xout.Attribute("buildConfiguration", configuration);
xout.EndElement();
}
void cmXCodeScheme::WriteArchiveAction(cmXMLWriter& xout,
2018-01-26 17:06:56 +01:00
const std::string& configuration)
2017-07-20 19:35:53 +02:00
{
xout.StartElement("ArchiveAction");
xout.BreakAttributes();
xout.Attribute("buildConfiguration", configuration);
xout.Attribute("revealArchiveInOrganizer", "YES");
xout.EndElement();
}
2018-01-26 17:06:56 +01:00
void cmXCodeScheme::WriteBuildableReference(cmXMLWriter& xout,
const cmXCodeObject* xcObj,
const std::string& container)
{
xout.StartElement("BuildableReference");
xout.BreakAttributes();
xout.Attribute("BuildableIdentifier", "primary");
xout.Attribute("BlueprintIdentifier", xcObj->GetId());
2020-08-30 11:54:41 +02:00
std::string const noConfig; // FIXME: What config to use here?
xout.Attribute("BuildableName", xcObj->GetTarget()->GetFullName(noConfig));
2018-01-26 17:06:56 +01:00
xout.Attribute("BlueprintName", xcObj->GetTarget()->GetName());
xout.Attribute("ReferencedContainer", "container:" + container);
xout.EndElement();
}
2020-08-30 11:54:41 +02:00
void cmXCodeScheme::WriteCustomWorkingDirectory(
cmXMLWriter& xout, const std::string& configuration)
{
std::string const& propertyValue =
this->Target->GetTarget()->GetSafeProperty(
"XCODE_SCHEME_WORKING_DIRECTORY");
if (propertyValue.empty()) {
xout.Attribute("useCustomWorkingDirectory", "NO");
} else {
xout.Attribute("useCustomWorkingDirectory", "YES");
auto customWorkingDirectory = cmGeneratorExpression::Evaluate(
propertyValue, this->LocalGenerator, configuration);
xout.Attribute("customWorkingDirectory", customWorkingDirectory);
}
}
2017-07-20 19:35:53 +02:00
std::string cmXCodeScheme::WriteVersionString()
{
std::ostringstream v;
v << std::setfill('0') << std::setw(4) << this->XcodeVersion * 10;
return v.str();
}
std::string cmXCodeScheme::FindConfiguration(const std::string& name)
{
// Try to find the desired configuration by name,
// and if it's not found return first from the list
//
2020-08-30 11:54:41 +02:00
if (!cm::contains(this->ConfigList, name) && !this->ConfigList.empty()) {
2017-07-20 19:35:53 +02:00
return this->ConfigList[0];
2018-01-26 17:06:56 +01:00
}
2017-07-20 19:35:53 +02:00
return name;
}
2018-01-26 17:06:56 +01:00
bool cmXCodeScheme::IsTestable() const
{
return !this->Tests.empty() || IsExecutable(this->Target);
}
2017-07-20 19:35:53 +02:00
bool cmXCodeScheme::IsExecutable(const cmXCodeObject* target)
{
cmGeneratorTarget* gt = target->GetTarget();
if (!gt) {
cmSystemTools::Error("Error no target on xobject\n");
return false;
}
return gt->GetType() == cmStateEnums::EXECUTABLE;
}