mirror of
https://github.com/darlinghq/xcbuild.git
synced 2025-02-23 09:52:33 +00:00
Delay resolving executable paths until execution time.
Rather than looking at the filesystem to find an executable path at configuration time, find the executable at execution time. This allows different executors to handle searching for paths differently (for example, using internal or external builtin tools), and avoids using the filesystem during configuration.
This commit is contained in:
parent
fd3a151699
commit
ef95e55f47
@ -28,7 +28,6 @@ class Context {
|
||||
private:
|
||||
xcsdk::SDK::Target::shared_ptr _sdk;
|
||||
std::vector<xcsdk::SDK::Toolchain::shared_ptr> _toolchains;
|
||||
std::vector<std::string> _executablePaths;
|
||||
std::string _workingDirectory;
|
||||
|
||||
private:
|
||||
@ -49,7 +48,6 @@ public:
|
||||
Context(
|
||||
xcsdk::SDK::Target::shared_ptr const &sdk,
|
||||
std::vector<xcsdk::SDK::Toolchain::shared_ptr> const &toolchains,
|
||||
std::vector<std::string> const &executablePaths,
|
||||
std::string const &workingDirectory,
|
||||
SearchPaths const &searchPaths);
|
||||
~Context();
|
||||
@ -59,8 +57,6 @@ public:
|
||||
{ return _sdk; }
|
||||
std::vector<xcsdk::SDK::Toolchain::shared_ptr> const &toolchains() const
|
||||
{ return _toolchains; }
|
||||
std::vector<std::string> const &executablePaths() const
|
||||
{ return _executablePaths; }
|
||||
std::string const &workingDirectory() const
|
||||
{ return _workingDirectory; }
|
||||
|
||||
|
@ -98,57 +98,50 @@ public:
|
||||
*/
|
||||
class Executable {
|
||||
private:
|
||||
std::string _path;
|
||||
std::string _builtin;
|
||||
ext::optional<std::string> _external;
|
||||
ext::optional<std::string> _builtin;
|
||||
|
||||
public:
|
||||
Executable(std::string const &path, std::string const &builtin);
|
||||
private:
|
||||
Executable(
|
||||
ext::optional<std::string> const &external,
|
||||
ext::optional<std::string> const &builtin);
|
||||
|
||||
public:
|
||||
/*
|
||||
* The path to the executable. If this executable is a bulitin tool, points
|
||||
* to a standalone executable verison of that tool.
|
||||
* An external executable, relative or absolute path.
|
||||
*/
|
||||
std::string const &path() const
|
||||
{ return _path; }
|
||||
ext::optional<std::string> const &external() const
|
||||
{ return _external; }
|
||||
|
||||
/*
|
||||
* The name of the builtin tool this executable corresponds to.
|
||||
* A builtin executable name.
|
||||
*/
|
||||
std::string const &builtin() const
|
||||
ext::optional<std::string> const &builtin() const
|
||||
{ return _builtin; }
|
||||
|
||||
public:
|
||||
/*
|
||||
* The user-facing name to show for the executable. For builtin tools, this
|
||||
* uses the shorter name of the bulitin tool rather than the filesystem path.
|
||||
*/
|
||||
std::string const &displayName() const;
|
||||
|
||||
public:
|
||||
/*
|
||||
* Creates an executable from an unknown string. The executable could
|
||||
* be a builtin tool (starts with "builtin-"), an absolute path to a tool,
|
||||
* or a relative path to search in the executable paths.
|
||||
* Creates an executable with a known external path.
|
||||
*/
|
||||
static Executable
|
||||
Determine(std::string const &executable, std::vector<std::string> const &executablePaths);
|
||||
|
||||
/*
|
||||
* Creates an executable with a known absolute path.
|
||||
*/
|
||||
static Executable
|
||||
Absolute(std::string const &path);
|
||||
External(std::string const &path);
|
||||
|
||||
/*
|
||||
* Creates an executable for a known built-in tool.
|
||||
*/
|
||||
static Executable
|
||||
Builtin(std::string const &name);
|
||||
|
||||
/*
|
||||
* Creates an executable from an unknown string. The executable could
|
||||
* be a builtin tool (starts with "builtin-") or an external tool path.
|
||||
*/
|
||||
static ext::optional<Executable>
|
||||
Determine(std::string const &executable);
|
||||
};
|
||||
|
||||
private:
|
||||
Executable _executable;
|
||||
ext::optional<Executable> _executable;
|
||||
std::vector<std::string> _arguments;
|
||||
std::unordered_map<std::string, std::string> _environment;
|
||||
std::string _workingDirectory;
|
||||
@ -178,7 +171,7 @@ public:
|
||||
~Invocation();
|
||||
|
||||
public:
|
||||
Executable const &executable() const
|
||||
ext::optional<Executable> const &executable() const
|
||||
{ return _executable; }
|
||||
std::vector<std::string> const &arguments() const
|
||||
{ return _arguments; }
|
||||
@ -188,7 +181,7 @@ public:
|
||||
{ return _workingDirectory; }
|
||||
|
||||
public:
|
||||
Executable &executable()
|
||||
ext::optional<Executable> &executable()
|
||||
{ return _executable; }
|
||||
std::vector<std::string> &arguments()
|
||||
{ return _arguments; }
|
||||
|
@ -52,7 +52,6 @@ Create(Phase::Environment const &phaseEnvironment, pbxproj::PBX::Target::shared_
|
||||
Tool::Context toolContext = Tool::Context(
|
||||
targetEnvironment.sdk(),
|
||||
targetEnvironment.toolchains(),
|
||||
targetEnvironment.executablePaths(),
|
||||
targetEnvironment.workingDirectory(),
|
||||
searchPaths);
|
||||
|
||||
|
@ -101,7 +101,7 @@ resolve(
|
||||
* Create the asset catalog invocation.
|
||||
*/
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable());
|
||||
invocation.arguments() = arguments;
|
||||
invocation.environment() = environmentVariables;
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
|
@ -184,7 +184,7 @@ resolvePrecompiledHeader(
|
||||
}
|
||||
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable());
|
||||
invocation.arguments() = arguments;
|
||||
invocation.environment() = options.environment();
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
@ -282,7 +282,7 @@ resolveSource(
|
||||
}
|
||||
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable());
|
||||
invocation.arguments() = arguments;
|
||||
invocation.environment() = options.environment();
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
|
@ -15,12 +15,10 @@ Tool::Context::
|
||||
Context(
|
||||
xcsdk::SDK::Target::shared_ptr const &sdk,
|
||||
std::vector<xcsdk::SDK::Toolchain::shared_ptr> const &toolchains,
|
||||
std::vector<std::string> const &executablePaths,
|
||||
std::string const &workingDirectory,
|
||||
Tool::SearchPaths const &searchPaths) :
|
||||
_sdk (sdk),
|
||||
_toolchains (toolchains),
|
||||
_executablePaths (executablePaths),
|
||||
_workingDirectory(workingDirectory),
|
||||
_searchPaths (searchPaths)
|
||||
{
|
||||
|
@ -42,8 +42,8 @@ ResolveInternal(
|
||||
* Add the copy-specific build settings.
|
||||
*/
|
||||
pbxsetting::Level copyLevel = pbxsetting::Level({
|
||||
pbxsetting::Setting::Create("PBXCP_STRIP_TOOL", Filesystem::GetDefaultUNSAFE()->findExecutable("strip", toolContext->executablePaths()).value_or(std::string())),
|
||||
pbxsetting::Setting::Create("PBXCP_BITCODE_STRIP_TOOL", Filesystem::GetDefaultUNSAFE()->findExecutable("bitcode_strip", toolContext->executablePaths()).value_or(std::string())),
|
||||
// TODO: pbxsetting::Setting::Create("PBXCP_STRIP_TOOL", toolchain->path() + "/usr/bin/strip"),
|
||||
// TODO: pbxsetting::Setting::Create("PBXCP_BITCODE_STRIP_TOOL", toolchain->path() + "/usr/bin/bitcode_strip"),
|
||||
pbxsetting::Setting::Create("pbxcp_rule_name", logMessageTitle),
|
||||
});
|
||||
|
||||
@ -91,7 +91,7 @@ ResolveInternal(
|
||||
* Create the copy invocation.
|
||||
*/
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable());
|
||||
invocation.arguments() = tokens.arguments();
|
||||
invocation.environment() = options.environment();
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
|
@ -29,7 +29,7 @@ resolve(
|
||||
std::string logMessage = "Ditto " + targetPath + " " + sourcePath;
|
||||
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Absolute("/usr/bin/ditto"); // TODO(grp): Ditto is not portable.
|
||||
invocation.executable() = Tool::Invocation::Executable::External("/usr/bin/ditto"); // TODO(grp): Ditto is not portable.
|
||||
invocation.arguments() = { "-rsrc", sourcePath, targetPath };
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
invocation.inputs() = { FSUtil::ResolveRelativePath(sourcePath, toolContext->workingDirectory()) };
|
||||
|
@ -63,7 +63,7 @@ resolve(
|
||||
environmentVariables.insert(buildSettingValues.begin(), buildSettingValues.end());
|
||||
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable());
|
||||
invocation.arguments() = tokens.arguments();
|
||||
invocation.environment() = environmentVariables;
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
|
@ -98,7 +98,7 @@ resolve(
|
||||
* Create the invocation.
|
||||
*/
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable());
|
||||
invocation.arguments() = arguments;
|
||||
invocation.environment() = environmentVariables;
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
|
@ -80,7 +80,7 @@ resolve(
|
||||
* Create the invocation.
|
||||
*/
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable());
|
||||
invocation.arguments() = arguments;
|
||||
invocation.environment() = environmentVariables;
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
|
@ -13,9 +13,9 @@
|
||||
#include <process/Context.h>
|
||||
|
||||
namespace Tool = pbxbuild::Tool;
|
||||
using AuxiliaryFile = pbxbuild::Tool::Invocation::AuxiliaryFile;
|
||||
using DependencyInfo = pbxbuild::Tool::Invocation::DependencyInfo;
|
||||
using Executable = pbxbuild::Tool::Invocation::Executable;
|
||||
using AuxiliaryFile = Tool::Invocation::AuxiliaryFile;
|
||||
using DependencyInfo = Tool::Invocation::DependencyInfo;
|
||||
using Executable = Tool::Invocation::Executable;
|
||||
using libutil::Filesystem;
|
||||
using libutil::FSUtil;
|
||||
|
||||
@ -67,61 +67,45 @@ DependencyInfo(dependency::DependencyInfoFormat format, std::string const &path)
|
||||
}
|
||||
|
||||
Executable::
|
||||
Executable(std::string const &path, std::string const &builtin) :
|
||||
_path (path),
|
||||
_builtin(builtin)
|
||||
Executable(
|
||||
ext::optional<std::string> const &external,
|
||||
ext::optional<std::string> const &builtin) :
|
||||
_external(external),
|
||||
_builtin (builtin)
|
||||
{
|
||||
}
|
||||
|
||||
std::string const &Executable::
|
||||
displayName() const
|
||||
{
|
||||
/* If the tool is builtin. */
|
||||
bool builtin = !_builtin.empty();
|
||||
|
||||
/* The user-facing name of the executable. For builtin ones, prefer the shorter built-in name. */
|
||||
return (builtin ? _builtin : _path);
|
||||
}
|
||||
|
||||
Executable Executable::
|
||||
Determine(std::string const &executable, std::vector<std::string> const &executablePaths)
|
||||
External(std::string const &path)
|
||||
{
|
||||
std::string builtinPrefix = "builtin-";
|
||||
bool builtin = executable.compare(0, builtinPrefix.size(), builtinPrefix) == 0;
|
||||
|
||||
if (builtin) {
|
||||
/* Has a builtin prefix. */
|
||||
return Builtin(executable);
|
||||
} else {
|
||||
std::string path = executable;
|
||||
|
||||
if (!FSUtil::IsAbsolutePath(executable)) {
|
||||
/* Not absolute, look in the search paths. */
|
||||
// TODO(grp): Handle when the executable is not found.
|
||||
path = Filesystem::GetDefaultUNSAFE()->findExecutable(executable, executablePaths).value_or(std::string());
|
||||
}
|
||||
|
||||
return Absolute(path);
|
||||
}
|
||||
}
|
||||
|
||||
Executable Executable::
|
||||
Absolute(std::string const &path)
|
||||
{
|
||||
return Executable(path, std::string());
|
||||
return Executable(path, ext::nullopt);
|
||||
}
|
||||
|
||||
Executable Executable::
|
||||
Builtin(std::string const &name)
|
||||
{
|
||||
std::string executableRoot = FSUtil::GetDirectoryName(process::Context::GetDefaultUNSAFE()->executablePath());
|
||||
std::string path = executableRoot + "/" + name;
|
||||
return Executable(path, name);
|
||||
return Executable(ext::nullopt, name);
|
||||
}
|
||||
|
||||
ext::optional<Executable> Executable::
|
||||
Determine(std::string const &executable)
|
||||
{
|
||||
if (executable.empty()) {
|
||||
return ext::nullopt;
|
||||
}
|
||||
|
||||
std::string builtinPrefix = "builtin-";
|
||||
if (executable.compare(0, builtinPrefix.size(), builtinPrefix) == 0) {
|
||||
/* Has a builtin prefix. */
|
||||
return Builtin(executable);
|
||||
} else {
|
||||
/* Unknown external tool. */
|
||||
return External(executable);
|
||||
}
|
||||
}
|
||||
|
||||
Tool::Invocation::
|
||||
Invocation() :
|
||||
_executable (Executable(std::string(), std::string())),
|
||||
_showEnvironmentInLog (true),
|
||||
_createsProductStructure(false)
|
||||
{
|
||||
|
@ -120,7 +120,7 @@ resolve(
|
||||
}
|
||||
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable());
|
||||
invocation.arguments() = arguments;
|
||||
invocation.environment() = options.environment();
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
|
@ -29,7 +29,7 @@ resolve(
|
||||
std::string logMessage = "MkDir " + directory;
|
||||
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Absolute("/bin/mkdir");
|
||||
invocation.executable() = Tool::Invocation::Executable::External("/bin/mkdir");
|
||||
invocation.arguments() = { "-p", directory };
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
invocation.outputs() = { FSUtil::ResolveRelativePath(directory, toolContext->workingDirectory()) };
|
||||
|
@ -69,7 +69,7 @@ resolve(
|
||||
std::string fullWorkingDirectory = FSUtil::ResolveRelativePath(legacyTarget->buildWorkingDirectory(), toolContext->workingDirectory());
|
||||
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(legacyTarget->buildToolPath(), toolContext->executablePaths());
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(legacyTarget->buildToolPath());
|
||||
invocation.arguments() = pbxsetting::Type::ParseList(script);
|
||||
invocation.environment() = environmentVariables;
|
||||
invocation.workingDirectory() = fullWorkingDirectory;
|
||||
@ -115,7 +115,7 @@ resolve(
|
||||
std::unordered_map<std::string, std::string> environmentVariables = scriptEnvironment.computeValues(pbxsetting::Condition::Empty());
|
||||
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Absolute("/bin/sh");
|
||||
invocation.executable() = Tool::Invocation::Executable::External("/bin/sh");
|
||||
invocation.arguments() = { "-c", Escape::Shell(scriptFilePath) };
|
||||
invocation.environment() = environmentVariables;
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
@ -177,7 +177,7 @@ resolve(
|
||||
std::unordered_map<std::string, std::string> environmentVariables = ruleEnvironment.computeValues(pbxsetting::Condition::Empty());
|
||||
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Absolute("/bin/sh");
|
||||
invocation.executable() = Tool::Invocation::Executable::External("/bin/sh");
|
||||
invocation.arguments() = { "-c", buildRule->script() };
|
||||
invocation.environment() = environmentVariables;
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
|
@ -395,7 +395,7 @@ resolve(
|
||||
* Add the invocation.
|
||||
*/
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable());
|
||||
invocation.arguments() = arguments;
|
||||
invocation.environment() = options.environment();
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
|
@ -45,7 +45,7 @@ resolve(
|
||||
Tool::Tokens::ToolExpansions tokens = Tool::Tokens::ExpandTool(toolEnvironment, options);
|
||||
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable());
|
||||
invocation.arguments() = tokens.arguments();
|
||||
invocation.environment() = options.environment();
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
|
@ -31,7 +31,7 @@ resolve(
|
||||
std::string logMessage = "SymLink " + targetPath + " " + symlinkPath;
|
||||
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Absolute("/bin/ln");
|
||||
invocation.executable() = Tool::Invocation::Executable::External("/bin/ln");
|
||||
invocation.arguments() = { "-sfh", targetPath, symlinkPath };
|
||||
invocation.workingDirectory() = workingDirectory;
|
||||
invocation.phonyInputs() = { FSUtil::ResolveRelativePath(targetPath, workingDirectory) };
|
||||
|
@ -51,7 +51,7 @@ resolve(
|
||||
}
|
||||
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable());
|
||||
invocation.arguments() = tokens.arguments();
|
||||
invocation.environment() = options.environment();
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
@ -76,7 +76,7 @@ resolve(
|
||||
std::string const &resolvedLogMessage = (!logMessage.empty() ? logMessage : tokens.logMessage());
|
||||
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
|
||||
invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable());
|
||||
invocation.arguments() = tokens.arguments();
|
||||
invocation.environment() = options.environment();
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
|
@ -42,7 +42,7 @@ resolve(
|
||||
}
|
||||
|
||||
Tool::Invocation invocation;
|
||||
invocation.executable() = Tool::Invocation::Executable::Absolute("/usr/bin/touch");
|
||||
invocation.executable() = Tool::Invocation::Executable::External("/usr/bin/touch");
|
||||
invocation.arguments() = { "-c", input };
|
||||
invocation.workingDirectory() = toolContext->workingDirectory();
|
||||
invocation.outputs() = { output };
|
||||
|
@ -51,6 +51,7 @@ private:
|
||||
std::vector<pbxbuild::Tool::Invocation> const &invocations,
|
||||
std::unordered_set<std::string> *seenDirectories);
|
||||
bool buildTargetInvocations(
|
||||
process::Context const *processContext,
|
||||
libutil::Filesystem *filesystem,
|
||||
std::string const &dependencyInfoToolPath,
|
||||
pbxproj::PBX::Target::shared_ptr const &target,
|
||||
@ -65,6 +66,7 @@ private:
|
||||
bool buildInvocation(
|
||||
ninja::Writer *writer,
|
||||
pbxbuild::Tool::Invocation const &invocation,
|
||||
std::string const &executablePath,
|
||||
std::string const &dependencyInfoToolPath,
|
||||
std::string const &temporaryDirectory,
|
||||
std::string const &after);
|
||||
|
@ -114,6 +114,31 @@ NinjaHash(std::string const &input)
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static ext::optional<std::string>
|
||||
NinjaExecutablePath(
|
||||
process::Context const *processContext,
|
||||
Filesystem const *filesystem,
|
||||
std::vector<std::string> const &executablePaths,
|
||||
pbxbuild::Tool::Invocation::Executable const &executable)
|
||||
{
|
||||
if (ext::optional<std::string> const &builtin = executable.builtin()) {
|
||||
std::string path = FSUtil::GetDirectoryName(processContext->executablePath()) + "/" + *builtin;
|
||||
if (filesystem->isExecutable(path)) {
|
||||
return path;
|
||||
} else {
|
||||
return ext::nullopt;
|
||||
}
|
||||
} else if (ext::optional<std::string> const &external = executable.external()) {
|
||||
if (FSUtil::IsAbsolutePath(*external)) {
|
||||
return *external;
|
||||
} else {
|
||||
return filesystem->findExecutable(*external, executablePaths);
|
||||
}
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static std::string
|
||||
NinjaInvocationPhonyOutput(pbxbuild::Tool::Invocation const &invocation)
|
||||
{
|
||||
@ -128,7 +153,18 @@ NinjaInvocationPhonyOutput(pbxbuild::Tool::Invocation const &invocation)
|
||||
*/
|
||||
|
||||
// TODO(grp): Handle identical phony output invocations in a build.
|
||||
std::string key = invocation.executable().path();
|
||||
std::string key;
|
||||
|
||||
if (invocation.executable()) {
|
||||
if (invocation.executable()->builtin()) {
|
||||
key += *invocation.executable()->builtin();
|
||||
} else if (invocation.executable()->external()) {
|
||||
key += *invocation.executable()->external();
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
for (std::string const &arg : invocation.arguments()) {
|
||||
key += " " + arg;
|
||||
}
|
||||
@ -544,7 +580,7 @@ buildAction(
|
||||
/*
|
||||
* Write out the Ninja file to build this target.
|
||||
*/
|
||||
if (!buildTargetInvocations(filesystem, dependencyInfoToolPath, target, *targetEnvironment, phaseInvocations.invocations())) {
|
||||
if (!buildTargetInvocations(processContext, filesystem, dependencyInfoToolPath, target, *targetEnvironment, phaseInvocations.invocations())) {
|
||||
fprintf(stderr, "error: failed to build target ninja\n");
|
||||
return false;
|
||||
}
|
||||
@ -560,7 +596,7 @@ buildAction(
|
||||
*/
|
||||
std::unordered_set<std::string> invocationOutputs;
|
||||
for (pbxbuild::Tool::Invocation const &invocation : phaseInvocations.invocations()) {
|
||||
if (invocation.executable().path().empty()) {
|
||||
if (!invocation.executable()) {
|
||||
/* No outputs. */
|
||||
continue;
|
||||
}
|
||||
@ -629,6 +665,7 @@ buildAction(
|
||||
|
||||
bool NinjaExecutor::
|
||||
buildTargetInvocations(
|
||||
process::Context const *processContext,
|
||||
Filesystem *filesystem,
|
||||
std::string const &dependencyInfoToolPath,
|
||||
pbxproj::PBX::Target::shared_ptr const &target,
|
||||
@ -660,10 +697,18 @@ buildTargetInvocations(
|
||||
}
|
||||
}
|
||||
|
||||
/* Write invocations to run after auxiliary files. */
|
||||
// TODO(grp): This should perhaps be a separate flag for a 'phony' invocation.
|
||||
if (!invocation.executable().path().empty()) {
|
||||
if (!buildInvocation(&writer, invocation, dependencyInfoToolPath, temporaryDirectory, targetWriteAuxiliaryFiles)) {
|
||||
if (invocation.executable()) {
|
||||
/* Find invocation executable. */
|
||||
ext::optional<std::string> executablePath = NinjaExecutablePath(processContext, filesystem, targetEnvironment.executablePaths(), *invocation.executable());
|
||||
if (!executablePath) {
|
||||
fprintf(stderr, "unable to find executable: %s\n", invocation.executable()->builtin().value_or(invocation.executable()->external().value_or("<NONE>")).c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Write invocations to run after auxiliary files. */
|
||||
if (!buildInvocation(&writer, invocation, *executablePath, dependencyInfoToolPath, temporaryDirectory, targetWriteAuxiliaryFiles)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -745,6 +790,7 @@ bool NinjaExecutor::
|
||||
buildInvocation(
|
||||
ninja::Writer *writer,
|
||||
pbxbuild::Tool::Invocation const &invocation,
|
||||
std::string const &executablePath,
|
||||
std::string const &dependencyInfoToolPath,
|
||||
std::string const &temporaryDirectory,
|
||||
std::string const &after)
|
||||
@ -753,7 +799,7 @@ buildInvocation(
|
||||
* Build the invocation arguments. Must escape for shell arguments as Ninja passes
|
||||
* the command string directly to the shell, which would interpret spaces, etc as meaningful.
|
||||
*/
|
||||
std::string exec = Escape::Shell(invocation.executable().path());
|
||||
std::string exec = Escape::Shell(executablePath);
|
||||
for (std::string const &arg : invocation.arguments()) {
|
||||
exec += " " + Escape::Shell(arg);
|
||||
}
|
||||
@ -774,7 +820,8 @@ buildInvocation(
|
||||
/*
|
||||
* Determine the status message for Ninja to print for this invocation.
|
||||
*/
|
||||
std::string description = NinjaDescription(_formatter->beginInvocation(invocation, invocation.executable().displayName(), false));
|
||||
std::string executableDisplayName = invocation.executable()->builtin().value_or(executablePath);
|
||||
std::string description = NinjaDescription(_formatter->beginInvocation(invocation, executableDisplayName, false));
|
||||
|
||||
/*
|
||||
* Add the dependency info converter & file.
|
||||
|
@ -224,19 +224,18 @@ performInvocations(
|
||||
{
|
||||
for (pbxbuild::Tool::Invocation const &invocation : orderedInvocations) {
|
||||
// TODO(grp): This should perhaps be a separate flag for a 'phony' invocation.
|
||||
if (invocation.executable().path().empty()) {
|
||||
if (!invocation.executable()) {
|
||||
continue;
|
||||
}
|
||||
pbxbuild::Tool::Invocation::Executable const &executable = *invocation.executable();
|
||||
|
||||
if (invocation.createsProductStructure() != createProductStructure) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> sortedEnvironment = std::map<std::string, std::string>(invocation.environment().begin(), invocation.environment().end());
|
||||
|
||||
xcformatter::Formatter::Print(_formatter->beginInvocation(invocation, invocation.executable().displayName(), createProductStructure));
|
||||
|
||||
if (!_dryRun) {
|
||||
bool success = true;
|
||||
|
||||
for (std::string const &output : invocation.outputs()) {
|
||||
std::string directory = FSUtil::GetDirectoryName(output);
|
||||
|
||||
@ -245,39 +244,66 @@ performInvocations(
|
||||
}
|
||||
}
|
||||
|
||||
process::MemoryContext context = process::MemoryContext(
|
||||
invocation.executable().path(),
|
||||
invocation.workingDirectory(),
|
||||
invocation.arguments(),
|
||||
invocation.environment(),
|
||||
processContext->userID(),
|
||||
processContext->groupID(),
|
||||
processContext->userName(),
|
||||
processContext->groupName());
|
||||
if (ext::optional<std::string> const &builtin = executable.builtin()) {
|
||||
/* Builtin tool, find and run in-process. */
|
||||
if (std::shared_ptr<builtin::Driver> driver = _builtins.driver(*builtin)) {
|
||||
xcformatter::Formatter::Print(_formatter->beginInvocation(invocation, *builtin, createProductStructure));
|
||||
|
||||
if (!invocation.executable().builtin().empty()) {
|
||||
/* For built-in tools, run them in-process. */
|
||||
std::shared_ptr<builtin::Driver> driver = _builtins.driver(invocation.executable().builtin());
|
||||
if (driver == nullptr) {
|
||||
xcformatter::Formatter::Print(_formatter->finishInvocation(invocation, invocation.executable().displayName(), createProductStructure));
|
||||
process::MemoryContext context = process::MemoryContext(
|
||||
*builtin,
|
||||
invocation.workingDirectory(),
|
||||
invocation.arguments(),
|
||||
invocation.environment(),
|
||||
processContext->userID(),
|
||||
processContext->groupID(),
|
||||
processContext->userName(),
|
||||
processContext->groupName());
|
||||
success = driver->run(&context, filesystem) != 0;
|
||||
|
||||
xcformatter::Formatter::Print(_formatter->finishInvocation(invocation, *builtin, createProductStructure));
|
||||
} else {
|
||||
/* Failed to find builtin tool. */
|
||||
return std::make_pair(false, std::vector<pbxbuild::Tool::Invocation>({ invocation }));
|
||||
}
|
||||
} else if (ext::optional<std::string> const &external = executable.external()) {
|
||||
/* External tool, find on the filesystem. */
|
||||
ext::optional<std::string> path;
|
||||
if (FSUtil::IsAbsolutePath(*external)) {
|
||||
if (filesystem->isExecutable(*external)) {
|
||||
path = external;
|
||||
}
|
||||
} else {
|
||||
path = filesystem->findExecutable(*external, targetEnvironment.executablePaths());
|
||||
}
|
||||
|
||||
if (driver->run(&context, filesystem) != 0) {
|
||||
xcformatter::Formatter::Print(_formatter->finishInvocation(invocation, invocation.executable().displayName(), createProductStructure));
|
||||
if (path) {
|
||||
xcformatter::Formatter::Print(_formatter->beginInvocation(invocation, *path, createProductStructure));
|
||||
|
||||
process::MemoryContext context = process::MemoryContext(
|
||||
*path,
|
||||
invocation.workingDirectory(),
|
||||
invocation.arguments(),
|
||||
invocation.environment(),
|
||||
processContext->userID(),
|
||||
processContext->groupID(),
|
||||
processContext->userName(),
|
||||
processContext->groupName());
|
||||
ext::optional<int> exitCode = processLauncher->launch(filesystem, &context);
|
||||
success = (exitCode && *exitCode == 0);
|
||||
|
||||
xcformatter::Formatter::Print(_formatter->finishInvocation(invocation, *path, createProductStructure));
|
||||
} else {
|
||||
/* Failed to find executable. */
|
||||
return std::make_pair(false, std::vector<pbxbuild::Tool::Invocation>({ invocation }));
|
||||
}
|
||||
} else {
|
||||
/* External tool, run the tool externally. */
|
||||
ext::optional<int> exitCode = processLauncher->launch(filesystem, &context);
|
||||
if (!exitCode || *exitCode != 0) {
|
||||
xcformatter::Formatter::Print(_formatter->finishInvocation(invocation, invocation.executable().displayName(), createProductStructure));
|
||||
return std::make_pair(false, std::vector<pbxbuild::Tool::Invocation>({ invocation }));
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
return std::make_pair(false, std::vector<pbxbuild::Tool::Invocation>({ invocation }));
|
||||
}
|
||||
}
|
||||
|
||||
xcformatter::Formatter::Print(_formatter->finishInvocation(invocation, invocation.executable().displayName(), createProductStructure));
|
||||
}
|
||||
|
||||
return std::make_pair(true, std::vector<pbxbuild::Tool::Invocation>());
|
||||
|
Loading…
x
Reference in New Issue
Block a user