add_custom_command: Add DEPFILE option for Ninja
Provide a way for custom commands to inform the ninja build tool about their implicit dependencies. For now simply make use of the option an error on other generators. Closes: #15479
This commit is contained in:
parent
98caa14cc8
commit
048d1adb4e
|
@ -20,6 +20,7 @@ The first signature is for adding a custom command to produce an output::
|
|||
[<lang2> depend2] ...]
|
||||
[WORKING_DIRECTORY dir]
|
||||
[COMMENT comment]
|
||||
[DEPFILE depfile]
|
||||
[VERBATIM] [APPEND] [USES_TERMINAL])
|
||||
|
||||
This defines a command to generate specified ``OUTPUT`` file(s).
|
||||
|
@ -170,6 +171,12 @@ The options are:
|
|||
If it is a relative path it will be interpreted relative to the
|
||||
build tree directory corresponding to the current source directory.
|
||||
|
||||
``DEPFILE``
|
||||
Specify a ``.d`` depfile for the :generator:`Ninja` generator.
|
||||
A ``.d`` file holds dependencies usually emitted by the custom
|
||||
command itself.
|
||||
Using ``DEPFILE`` with other generators than Ninja is an error.
|
||||
|
||||
Build Events
|
||||
^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
ninja-add_custom_command-depfile
|
||||
--------------------------------
|
||||
|
||||
* The :command:`add_custom_command` command gained a new ``DEPFILE``
|
||||
option that works with the :generator:`Ninja` generator to provide
|
||||
implicit dependency information to the build tool.
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include "cmSourceFile.h"
|
||||
|
||||
#include "cmGlobalGenerator.h"
|
||||
|
||||
// cmAddCustomCommandCommand
|
||||
bool cmAddCustomCommandCommand::InitialPass(
|
||||
std::vector<std::string> const& args, cmExecutionStatus&)
|
||||
|
@ -28,7 +30,7 @@ bool cmAddCustomCommandCommand::InitialPass(
|
|||
return false;
|
||||
}
|
||||
|
||||
std::string source, target, main_dependency, working;
|
||||
std::string source, target, main_dependency, working, depfile;
|
||||
std::string comment_buffer;
|
||||
const char* comment = CM_NULLPTR;
|
||||
std::vector<std::string> depends, outputs, output, byproducts;
|
||||
|
@ -60,6 +62,7 @@ bool cmAddCustomCommandCommand::InitialPass(
|
|||
doing_byproducts,
|
||||
doing_comment,
|
||||
doing_working_directory,
|
||||
doing_depfile,
|
||||
doing_nothing
|
||||
};
|
||||
|
||||
|
@ -110,6 +113,13 @@ bool cmAddCustomCommandCommand::InitialPass(
|
|||
doing = doing_implicit_depends_lang;
|
||||
} else if (copy == "COMMENT") {
|
||||
doing = doing_comment;
|
||||
} else if (copy == "DEPFILE") {
|
||||
doing = doing_depfile;
|
||||
if (this->Makefile->GetGlobalGenerator()->GetName() != "Ninja") {
|
||||
this->SetError("Option DEPFILE not supported by " +
|
||||
this->Makefile->GetGlobalGenerator()->GetName());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
std::string filename;
|
||||
switch (doing) {
|
||||
|
@ -147,6 +157,9 @@ bool cmAddCustomCommandCommand::InitialPass(
|
|||
filename = cmSystemTools::CollapseFullPath(filename);
|
||||
}
|
||||
switch (doing) {
|
||||
case doing_depfile:
|
||||
depfile = copy;
|
||||
break;
|
||||
case doing_working_directory:
|
||||
working = copy;
|
||||
break;
|
||||
|
@ -269,12 +282,12 @@ bool cmAddCustomCommandCommand::InitialPass(
|
|||
std::vector<std::string> no_depends;
|
||||
this->Makefile->AddCustomCommandToTarget(
|
||||
target, byproducts, no_depends, commandLines, cctype, comment,
|
||||
working.c_str(), escapeOldStyle, uses_terminal);
|
||||
working.c_str(), escapeOldStyle, uses_terminal, depfile);
|
||||
} else if (target.empty()) {
|
||||
// Target is empty, use the output.
|
||||
this->Makefile->AddCustomCommandToOutput(
|
||||
output, byproducts, depends, main_dependency, commandLines, comment,
|
||||
working.c_str(), false, escapeOldStyle, uses_terminal);
|
||||
working.c_str(), false, escapeOldStyle, uses_terminal, depfile);
|
||||
|
||||
// Add implicit dependency scanning requests if any were given.
|
||||
if (!implicit_depends.empty()) {
|
||||
|
|
|
@ -135,3 +135,13 @@ void cmCustomCommand::SetUsesTerminal(bool b)
|
|||
{
|
||||
this->UsesTerminal = b;
|
||||
}
|
||||
|
||||
const std::string& cmCustomCommand::GetDepfile() const
|
||||
{
|
||||
return this->Depfile;
|
||||
}
|
||||
|
||||
void cmCustomCommand::SetDepfile(const std::string& depfile)
|
||||
{
|
||||
this->Depfile = depfile;
|
||||
}
|
||||
|
|
|
@ -88,6 +88,10 @@ public:
|
|||
bool GetUsesTerminal() const;
|
||||
void SetUsesTerminal(bool b);
|
||||
|
||||
/** Set/Get the depfile (used by the Ninja generator) */
|
||||
const std::string& GetDepfile() const;
|
||||
void SetDepfile(const std::string& depfile);
|
||||
|
||||
private:
|
||||
std::vector<std::string> Outputs;
|
||||
std::vector<std::string> Byproducts;
|
||||
|
@ -97,6 +101,7 @@ private:
|
|||
ImplicitDependsList ImplicitDepends;
|
||||
std::string Comment;
|
||||
std::string WorkingDirectory;
|
||||
std::string Depfile;
|
||||
bool HaveComment;
|
||||
bool EscapeAllowMakeVars;
|
||||
bool EscapeOldStyle;
|
||||
|
|
|
@ -251,8 +251,8 @@ void cmGlobalNinjaGenerator::AddCustomCommandRule()
|
|||
|
||||
void cmGlobalNinjaGenerator::WriteCustomCommandBuild(
|
||||
const std::string& command, const std::string& description,
|
||||
const std::string& comment, bool uses_terminal, bool restat,
|
||||
const cmNinjaDeps& outputs, const cmNinjaDeps& deps,
|
||||
const std::string& comment, const std::string& depfile, bool uses_terminal,
|
||||
bool restat, const cmNinjaDeps& outputs, const cmNinjaDeps& deps,
|
||||
const cmNinjaDeps& orderOnly)
|
||||
{
|
||||
std::string cmd = command;
|
||||
|
@ -273,7 +273,9 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild(
|
|||
if (uses_terminal && SupportsConsolePool()) {
|
||||
vars["pool"] = "console";
|
||||
}
|
||||
|
||||
if (!depfile.empty()) {
|
||||
vars["depfile"] = depfile;
|
||||
}
|
||||
this->WriteBuild(*this->BuildFileStream, comment, "CUSTOM_COMMAND", outputs,
|
||||
deps, cmNinjaDeps(), orderOnly, vars);
|
||||
|
||||
|
@ -839,7 +841,7 @@ void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies()
|
|||
std::copy(i->second.begin(), i->second.end(), std::back_inserter(deps));
|
||||
WriteCustomCommandBuild(/*command=*/"", /*description=*/"",
|
||||
"Assume dependencies for generated source file.",
|
||||
/*uses_terminal*/ false,
|
||||
/*depfile*/ "", /*uses_terminal*/ false,
|
||||
/*restat*/ true, cmNinjaDeps(1, i->first), deps);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,8 @@ public:
|
|||
|
||||
void WriteCustomCommandBuild(const std::string& command,
|
||||
const std::string& description,
|
||||
const std::string& comment, bool uses_terminal,
|
||||
const std::string& comment,
|
||||
const std::string& depfile, bool uses_terminal,
|
||||
bool restat, const cmNinjaDeps& outputs,
|
||||
const cmNinjaDeps& deps = cmNinjaDeps(),
|
||||
const cmNinjaDeps& orderOnly = cmNinjaDeps());
|
||||
|
|
|
@ -412,7 +412,8 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
|
|||
} else {
|
||||
this->GetGlobalNinjaGenerator()->WriteCustomCommandBuild(
|
||||
this->BuildCommandLine(cmdLines), this->ConstructComment(ccg),
|
||||
"Custom command for " + ninjaOutputs[0], cc->GetUsesTerminal(),
|
||||
"Custom command for " + ninjaOutputs[0], cc->GetDepfile(),
|
||||
cc->GetUsesTerminal(),
|
||||
/*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, ninjaDeps,
|
||||
orderOnlyDeps);
|
||||
}
|
||||
|
|
|
@ -701,7 +701,7 @@ void cmMakefile::AddCustomCommandToTarget(
|
|||
const std::vector<std::string>& depends,
|
||||
const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type,
|
||||
const char* comment, const char* workingDir, bool escapeOldStyle,
|
||||
bool uses_terminal)
|
||||
bool uses_terminal, const std::string& depfile)
|
||||
{
|
||||
// Find the target to which to add the custom command.
|
||||
cmTargets::iterator ti = this->Targets.find(target);
|
||||
|
@ -773,6 +773,7 @@ void cmMakefile::AddCustomCommandToTarget(
|
|||
cc.SetEscapeOldStyle(escapeOldStyle);
|
||||
cc.SetEscapeAllowMakeVars(true);
|
||||
cc.SetUsesTerminal(uses_terminal);
|
||||
cc.SetDepfile(depfile);
|
||||
switch (type) {
|
||||
case cmTarget::PRE_BUILD:
|
||||
ti->second.AddPreBuildCommand(cc);
|
||||
|
@ -792,7 +793,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
|
|||
const std::vector<std::string>& depends, const std::string& main_dependency,
|
||||
const cmCustomCommandLines& commandLines, const char* comment,
|
||||
const char* workingDir, bool replace, bool escapeOldStyle,
|
||||
bool uses_terminal)
|
||||
bool uses_terminal, const std::string& depfile)
|
||||
{
|
||||
// Make sure there is at least one output.
|
||||
if (outputs.empty()) {
|
||||
|
@ -886,6 +887,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
|
|||
cc->SetEscapeOldStyle(escapeOldStyle);
|
||||
cc->SetEscapeAllowMakeVars(true);
|
||||
cc->SetUsesTerminal(uses_terminal);
|
||||
cc->SetDepfile(depfile);
|
||||
file->SetCustomCommand(cc);
|
||||
this->UpdateOutputToSourceMap(outputs, file);
|
||||
}
|
||||
|
@ -923,14 +925,14 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
|
|||
const std::string& output, const std::vector<std::string>& depends,
|
||||
const std::string& main_dependency, const cmCustomCommandLines& commandLines,
|
||||
const char* comment, const char* workingDir, bool replace,
|
||||
bool escapeOldStyle, bool uses_terminal)
|
||||
bool escapeOldStyle, bool uses_terminal, const std::string& depfile)
|
||||
{
|
||||
std::vector<std::string> outputs;
|
||||
outputs.push_back(output);
|
||||
std::vector<std::string> no_byproducts;
|
||||
return this->AddCustomCommandToOutput(
|
||||
outputs, no_byproducts, depends, main_dependency, commandLines, comment,
|
||||
workingDir, replace, escapeOldStyle, uses_terminal);
|
||||
workingDir, replace, escapeOldStyle, uses_terminal, depfile);
|
||||
}
|
||||
|
||||
void cmMakefile::AddCustomCommandOldStyle(
|
||||
|
|
|
@ -135,14 +135,12 @@ public:
|
|||
void FinalPass();
|
||||
|
||||
/** Add a custom command to the build. */
|
||||
void AddCustomCommandToTarget(const std::string& target,
|
||||
const std::vector<std::string>& byproducts,
|
||||
const std::vector<std::string>& depends,
|
||||
const cmCustomCommandLines& commandLines,
|
||||
cmTarget::CustomCommandType type,
|
||||
const char* comment, const char* workingDir,
|
||||
bool escapeOldStyle = true,
|
||||
bool uses_terminal = false);
|
||||
void AddCustomCommandToTarget(
|
||||
const std::string& target, const std::vector<std::string>& byproducts,
|
||||
const std::vector<std::string>& depends,
|
||||
const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type,
|
||||
const char* comment, const char* workingDir, bool escapeOldStyle = true,
|
||||
bool uses_terminal = false, const std::string& depfile = "");
|
||||
cmSourceFile* AddCustomCommandToOutput(
|
||||
const std::vector<std::string>& outputs,
|
||||
const std::vector<std::string>& byproducts,
|
||||
|
@ -150,13 +148,13 @@ public:
|
|||
const std::string& main_dependency,
|
||||
const cmCustomCommandLines& commandLines, const char* comment,
|
||||
const char* workingDir, bool replace = false, bool escapeOldStyle = true,
|
||||
bool uses_terminal = false);
|
||||
bool uses_terminal = false, const std::string& depfile = "");
|
||||
cmSourceFile* AddCustomCommandToOutput(
|
||||
const std::string& output, const std::vector<std::string>& depends,
|
||||
const std::string& main_dependency,
|
||||
const cmCustomCommandLines& commandLines, const char* comment,
|
||||
const char* workingDir, bool replace = false, bool escapeOldStyle = true,
|
||||
bool uses_terminal = false);
|
||||
bool uses_terminal = false, const std::string& depfile = "");
|
||||
void AddCustomCommandOldStyle(const std::string& target,
|
||||
const std::vector<std::string>& outputs,
|
||||
const std::vector<std::string>& depends,
|
||||
|
|
|
@ -150,7 +150,7 @@ void cmNinjaUtilityTargetGenerator::Generate()
|
|||
|
||||
this->GetGlobalGenerator()->WriteCustomCommandBuild(
|
||||
command, desc, "Utility command for " + this->GetTargetName(),
|
||||
uses_terminal,
|
||||
/*depfile*/ "", uses_terminal,
|
||||
/*restat*/ true, util_outputs, deps);
|
||||
|
||||
this->GetGlobalGenerator()->WritePhonyBuild(
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
1
|
|
@ -0,0 +1,5 @@
|
|||
^CMake Error at CustomCommandDepfile-ERROR.cmake:1 \(add_custom_command\):
|
||||
add_custom_command Option DEPFILE not supported by [^
|
||||
]+
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)$
|
|
@ -0,0 +1,8 @@
|
|||
add_custom_command(
|
||||
OUTPUT hello.copy.c
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/hello.c"
|
||||
hello.copy.c
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
DEPFILE "test.d"
|
||||
)
|
|
@ -15,3 +15,5 @@ run_TargetMessages(OFF)
|
|||
|
||||
run_TargetMessages(VAR-ON -DCMAKE_TARGET_MESSAGES=ON)
|
||||
run_TargetMessages(VAR-OFF -DCMAKE_TARGET_MESSAGES=OFF)
|
||||
|
||||
run_cmake(CustomCommandDepfile-ERROR)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
set(log "${RunCMake_BINARY_DIR}/CustomCommandDepfile-build/build.ninja")
|
||||
file(READ "${log}" build_file)
|
||||
if(NOT "${build_file}" MATCHES "depfile = test\\.d")
|
||||
set(RunCMake_TEST_FAILED "Log file:\n ${log}\ndoes not have expected line: depfile = test.d")
|
||||
endif()
|
|
@ -0,0 +1,11 @@
|
|||
add_custom_command(
|
||||
OUTPUT hello.copy.c
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/hello.c"
|
||||
hello.copy.c
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
DEPFILE "test.d"
|
||||
)
|
||||
add_custom_target(copy ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/hello.copy.c")
|
||||
|
||||
include(CheckNoPrefixSubDir.cmake)
|
|
@ -32,6 +32,8 @@ run_CMP0058(WARN-by)
|
|||
run_CMP0058(NEW-no)
|
||||
run_CMP0058(NEW-by)
|
||||
|
||||
run_cmake(CustomCommandDepfile)
|
||||
|
||||
function(run_SubDir)
|
||||
# Use a single build tree for a few tests without cleaning.
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SubDir-build)
|
||||
|
|
Loading…
Reference in New Issue