summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2023-02-15 13:57:24 (GMT)
committerKitware Robot <kwrobot@kitware.com>2023-02-15 13:57:32 (GMT)
commite2ed34abf899ebe528709c2850503fd7ead544a9 (patch)
tree8ddec9a1d0ba63ef3e3548ed77616ccf8cbd93fb
parenta550db0d45ed8c56f642b07d05c9b18f7b6ed224 (diff)
parent082ccd75301cd02efd09bb9882bb9d2a8957193b (diff)
downloadCMake-e2ed34abf899ebe528709c2850503fd7ead544a9.zip
CMake-e2ed34abf899ebe528709c2850503fd7ead544a9.tar.gz
CMake-e2ed34abf899ebe528709c2850503fd7ead544a9.tar.bz2
Merge topic 'ninja-custom-command-depends'
082ccd7530 add_custom_command: Add DEPENDS_EXPLICIT_ONLY option for Ninja Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !8198
-rw-r--r--Help/command/add_custom_command.rst18
-rw-r--r--Help/release/dev/ninja-custom-command-depends.rst7
-rw-r--r--Source/cmAddCustomCommandCommand.cxx8
-rw-r--r--Source/cmCustomCommand.cxx10
-rw-r--r--Source/cmCustomCommand.h6
-rw-r--r--Source/cmLocalNinjaGenerator.cxx52
-rw-r--r--Tests/RunCMake/Ninja/CustomCommandExplicitDepends.cmake18
-rw-r--r--Tests/RunCMake/Ninja/RunCMakeTest.cmake12
8 files changed, 104 insertions, 27 deletions
diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst
index 293d3f0..2cf88fc 100644
--- a/Help/command/add_custom_command.rst
+++ b/Help/command/add_custom_command.rst
@@ -25,7 +25,8 @@ The first signature is for adding a custom command to produce an output:
[DEPFILE depfile]
[JOB_POOL job_pool]
[VERBATIM] [APPEND] [USES_TERMINAL]
- [COMMAND_EXPAND_LISTS])
+ [COMMAND_EXPAND_LISTS]
+ [DEPENDS_EXPLICIT_ONLY])
This defines a command to generate specified ``OUTPUT`` file(s).
A target created in the same directory (``CMakeLists.txt`` file)
@@ -357,6 +358,21 @@ The options are:
:ref:`Makefile Generators`, :ref:`Visual Studio Generators`,
and the :generator:`Xcode` generator.
+``DEPENDS_EXPLICIT_ONLY``
+
+ .. versionadded:: 3.27
+
+ Indicate that the command's ``DEPENDS`` argument represents all files
+ required by the command and implicit dependencies are not required.
+
+ Without this option, if any target uses the output of the custom command,
+ CMake will consider that target's dependencies as implicit dependencies for
+ the custom command in case this custom command requires files implicitly
+ created by those targets.
+
+ Only the :ref:`Ninja Generators` actually use this information to remove
+ unnecessary implicit dependencies.
+
Examples: Generating Files
^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Help/release/dev/ninja-custom-command-depends.rst b/Help/release/dev/ninja-custom-command-depends.rst
new file mode 100644
index 0000000..10c68cf
--- /dev/null
+++ b/Help/release/dev/ninja-custom-command-depends.rst
@@ -0,0 +1,7 @@
+ninja-custom-command-depends
+----------------------------
+
+* The :command:`add_custom_command` command gained a new
+ ``DEPENDS_EXPLICIT_ONLY`` option to tell the :ref:`Ninja Generators`
+ not to add any dependencies implied by the target to which it is
+ attached.
diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx
index 831e9c7..65a8eb5 100644
--- a/Source/cmAddCustomCommandCommand.cxx
+++ b/Source/cmAddCustomCommandCommand.cxx
@@ -49,6 +49,7 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
bool append = false;
bool uses_terminal = false;
bool command_expand_lists = false;
+ bool depends_explicit_only = false;
std::string implicit_depends_lang;
cmImplicitDependsList implicit_depends;
@@ -104,6 +105,7 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
MAKE_STATIC_KEYWORD(USES_TERMINAL);
MAKE_STATIC_KEYWORD(VERBATIM);
MAKE_STATIC_KEYWORD(WORKING_DIRECTORY);
+ MAKE_STATIC_KEYWORD(DEPENDS_EXPLICIT_ONLY);
#undef MAKE_STATIC_KEYWORD
static std::unordered_set<std::string> const keywords{
keyAPPEND,
@@ -126,7 +128,8 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
keyTARGET,
keyUSES_TERMINAL,
keyVERBATIM,
- keyWORKING_DIRECTORY
+ keyWORKING_DIRECTORY,
+ keyDEPENDS_EXPLICIT_ONLY
};
for (std::string const& copy : args) {
@@ -155,6 +158,8 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
uses_terminal = true;
} else if (copy == keyCOMMAND_EXPAND_LISTS) {
command_expand_lists = true;
+ } else if (copy == keyDEPENDS_EXPLICIT_ONLY) {
+ depends_explicit_only = true;
} else if (copy == keyTARGET) {
doing = doing_target;
} else if (copy == keyARGS) {
@@ -329,6 +334,7 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
cc->SetDepfile(depfile);
cc->SetJobPool(job_pool);
cc->SetCommandExpandLists(command_expand_lists);
+ cc->SetDependsExplicitOnly(depends_explicit_only);
if (source.empty() && output.empty()) {
// Source is empty, use the target.
mf.AddCustomCommandToTarget(target, cctype, std::move(cc));
diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx
index 5b63996..e12cf70 100644
--- a/Source/cmCustomCommand.cxx
+++ b/Source/cmCustomCommand.cxx
@@ -164,6 +164,16 @@ void cmCustomCommand::SetCommandExpandLists(bool b)
this->CommandExpandLists = b;
}
+bool cmCustomCommand::GetDependsExplicitOnly() const
+{
+ return this->DependsExplicitOnly;
+}
+
+void cmCustomCommand::SetDependsExplicitOnly(bool b)
+{
+ this->DependsExplicitOnly = b;
+}
+
const std::string& cmCustomCommand::GetDepfile() const
{
return this->Depfile;
diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h
index 3671ad9..1e68dbf 100644
--- a/Source/cmCustomCommand.h
+++ b/Source/cmCustomCommand.h
@@ -102,6 +102,11 @@ public:
bool GetCommandExpandLists() const;
void SetCommandExpandLists(bool b);
+ /** Set/Get whether to use additional dependencies coming from
+ users of OUTPUT of the custom command. */
+ bool GetDependsExplicitOnly() const;
+ void SetDependsExplicitOnly(bool b);
+
/** Set/Get the depfile (used by the Ninja generator) */
const std::string& GetDepfile() const;
void SetDepfile(const std::string& depfile);
@@ -141,6 +146,7 @@ private:
bool CommandExpandLists = false;
bool StdPipesUTF8 = false;
bool HasMainDependency_ = false;
+ bool DependsExplicitOnly = false;
// Policies are NEW for synthesized custom commands, and set by cmMakefile for
// user-created custom commands.
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index 1e2ea2a..f8027c0 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -586,32 +586,34 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
cmNinjaDeps orderOnlyDeps;
- // A custom command may appear on multiple targets. However, some build
- // systems exist where the target dependencies on some of the targets are
- // overspecified, leading to a dependency cycle. If we assume all target
- // dependencies are a superset of the true target dependencies for this
- // custom command, we can take the set intersection of all target
- // dependencies to obtain a correct dependency list.
- //
- // FIXME: This won't work in certain obscure scenarios involving indirect
- // dependencies.
- auto j = targets.begin();
- assert(j != targets.end());
- this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(
- *j, orderOnlyDeps, ccg.GetOutputConfig(), fileConfig, ccgs.size() > 1);
- std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end());
- ++j;
-
- for (; j != targets.end(); ++j) {
- std::vector<std::string> jDeps;
- std::vector<std::string> depsIntersection;
+ if (!cc->GetDependsExplicitOnly()) {
+ // A custom command may appear on multiple targets. However, some build
+ // systems exist where the target dependencies on some of the targets are
+ // overspecified, leading to a dependency cycle. If we assume all target
+ // dependencies are a superset of the true target dependencies for this
+ // custom command, we can take the set intersection of all target
+ // dependencies to obtain a correct dependency list.
+ //
+ // FIXME: This won't work in certain obscure scenarios involving indirect
+ // dependencies.
+ auto j = targets.begin();
+ assert(j != targets.end());
this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(
- *j, jDeps, ccg.GetOutputConfig(), fileConfig, ccgs.size() > 1);
- std::sort(jDeps.begin(), jDeps.end());
- std::set_intersection(orderOnlyDeps.begin(), orderOnlyDeps.end(),
- jDeps.begin(), jDeps.end(),
- std::back_inserter(depsIntersection));
- orderOnlyDeps = depsIntersection;
+ *j, orderOnlyDeps, ccg.GetOutputConfig(), fileConfig, ccgs.size() > 1);
+ std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end());
+ ++j;
+
+ for (; j != targets.end(); ++j) {
+ std::vector<std::string> jDeps;
+ std::vector<std::string> depsIntersection;
+ this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(
+ *j, jDeps, ccg.GetOutputConfig(), fileConfig, ccgs.size() > 1);
+ std::sort(jDeps.begin(), jDeps.end());
+ std::set_intersection(orderOnlyDeps.begin(), orderOnlyDeps.end(),
+ jDeps.begin(), jDeps.end(),
+ std::back_inserter(depsIntersection));
+ orderOnlyDeps = depsIntersection;
+ }
}
const std::vector<std::string>& outputs = ccg.GetOutputs();
diff --git a/Tests/RunCMake/Ninja/CustomCommandExplicitDepends.cmake b/Tests/RunCMake/Ninja/CustomCommandExplicitDepends.cmake
new file mode 100644
index 0000000..e0c2434
--- /dev/null
+++ b/Tests/RunCMake/Ninja/CustomCommandExplicitDepends.cmake
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.26)
+project(CustomCommandExplicitDepends C)
+
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/command.h"
+ COMMAND "${CMAKE_COMMAND}" -E touch
+ "${CMAKE_CURRENT_BINARY_DIR}/command.h"
+ COMMENT "Creating command.h"
+ DEPENDS_EXPLICIT_ONLY
+)
+
+add_library(dep STATIC dep.c)
+
+add_library(top STATIC
+ top.c
+ "${CMAKE_CURRENT_BINARY_DIR}/command.h"
+)
+target_link_libraries(top PRIVATE dep)
diff --git a/Tests/RunCMake/Ninja/RunCMakeTest.cmake b/Tests/RunCMake/Ninja/RunCMakeTest.cmake
index 9214e90..17ad035 100644
--- a/Tests/RunCMake/Ninja/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Ninja/RunCMakeTest.cmake
@@ -190,6 +190,18 @@ function (run_LooseObjectDepends)
endfunction ()
run_LooseObjectDepends()
+function (run_CustomCommandExplictDepends)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CustomCommandExplicitDepends-build)
+ run_cmake(CustomCommandExplicitDepends)
+ run_ninja("${RunCMake_TEST_BINARY_DIR}" "command.h")
+ if (EXISTS "${RunCMake_TEST_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}dep${CMAKE_STATIC_LIBRARY_SUFFIX}")
+ message(FATAL_ERROR
+ "The `dep` library was created when requesting an custom command to be "
+ "generated; this should no longer be necessary when passing DEPENDS_EXPLICIT_ONLY keyword.")
+ endif ()
+endfunction ()
+run_CustomCommandExplictDepends()
+
function (run_AssumedSources)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/AssumedSources-build)
run_cmake(AssumedSources)