Browse Source

GenEx: Remove unneeded dependencies from target info queries

Only generate a graph dependency between a custom command and
a target when the custom command queries for the file path
of an artifact of the target.

This makes generator expressions such as `TARGET_FILE_DIR`
behave the same way as `TARGET_PROPERTY` which never generated
a graph dependency.
Robert Maynard 5 years ago
parent
commit
f14b390198

+ 16 - 7
Help/command/add_custom_command.rst

@@ -102,13 +102,22 @@ The options are:
   a target later in the command line (i.e. as a command argument rather
   a target later in the command line (i.e. as a command argument rather
   than as the command to execute).
   than as the command to execute).
 
 
-  Whenever a target is used as a command to execute or is mentioned in a
-  generator expression as a command argument, a target-level dependency
-  will be added automatically so that the mentioned target will be built
-  before any target using this custom command.  However this does NOT add
-  a file-level dependency that would cause the custom command to re-run
-  whenever the executable is recompiled.  List target names with
-  the ``DEPENDS`` option to add such file-level dependencies.
+  Whenever one of the following target based generator expressions are used as
+  a command to execute or is mentioned in a command argument, a target-level
+  dependency will be added automatically so that the mentioned target will be
+  built before any target using this custom command
+  (see policy :policy:`CMP0112`).
+
+    * ``TARGET_FILE``
+    * ``TARGET_LINKER_FILE``
+    * ``TARGET_SONAME_FILE``
+    * ``TARGET_PDB_FILE``
+
+  This target-level dependency does NOT add a file-level dependency that would
+  cause the custom command to re-run whenever the executable is recompiled.
+  List target names with the ``DEPENDS`` option to add such file-level
+  dependencies.
+
 
 
 ``COMMENT``
 ``COMMENT``
   Display the given message before the commands are executed at
   Display the given message before the commands are executed at

+ 9 - 4
Help/command/add_custom_target.rst

@@ -81,10 +81,15 @@ The options are:
   a target later in the command line (i.e. as a command argument rather
   a target later in the command line (i.e. as a command argument rather
   than as the command to execute).
   than as the command to execute).
 
 
-  Whenever a target is used as a command to execute or is mentioned in a
-  generator expression as a command argument, a target-level dependency
-  will be added automatically so that the mentioned target will be built
-  before this custom target.
+  Whenever one of the following target based generator expressions are used as
+  a command to execute or is mentioned in a command argument, a target-level
+  dependency will be added automatically so that the mentioned target will be
+  built before this custom target (see policy :policy:`CMP0112`).
+
+    * ``TARGET_FILE``
+    * ``TARGET_LINKER_FILE``
+    * ``TARGET_SONAME_FILE``
+    * ``TARGET_PDB_FILE``
 
 
   The command and arguments are optional and if not specified an empty
   The command and arguments are optional and if not specified an empty
   target will be created.
   target will be created.

+ 30 - 0
Help/manual/cmake-generator-expressions.7.rst

@@ -596,6 +596,9 @@ which is just the string ``tgt``.
 
 
 ``$<TARGET_NAME_IF_EXISTS:tgt>``
 ``$<TARGET_NAME_IF_EXISTS:tgt>``
   The target name ``tgt`` if the target exists, an empty string otherwise.
   The target name ``tgt`` if the target exists, an empty string otherwise.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on.
 ``$<TARGET_FILE:tgt>``
 ``$<TARGET_FILE:tgt>``
   Full path to the ``tgt`` binary file.
   Full path to the ``tgt`` binary file.
 ``$<TARGET_FILE_BASE_NAME:tgt>``
 ``$<TARGET_FILE_BASE_NAME:tgt>``
@@ -633,6 +636,9 @@ which is just the string ``tgt``.
   The ``tgt`` filename.
   The ``tgt`` filename.
 ``$<TARGET_FILE_DIR:tgt>``
 ``$<TARGET_FILE_DIR:tgt>``
   Directory of the ``tgt`` binary file.
   Directory of the ``tgt`` binary file.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on (see policy :policy:`CMP0112`).
 ``$<TARGET_LINKER_FILE:tgt>``
 ``$<TARGET_LINKER_FILE:tgt>``
   File used when linking to the ``tgt`` target.  This will usually
   File used when linking to the ``tgt`` target.  This will usually
   be the library that ``tgt`` represents (``.a``, ``.lib``, ``.so``),
   be the library that ``tgt`` represents (``.a``, ``.lib``, ``.so``),
@@ -674,14 +680,26 @@ which is just the string ``tgt``.
   expression is evaluated on.
   expression is evaluated on.
 ``$<TARGET_LINKER_FILE_NAME:tgt>``
 ``$<TARGET_LINKER_FILE_NAME:tgt>``
   Name of file used to link target ``tgt``.
   Name of file used to link target ``tgt``.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on (see policy :policy:`CMP0112`).
 ``$<TARGET_LINKER_FILE_DIR:tgt>``
 ``$<TARGET_LINKER_FILE_DIR:tgt>``
   Directory of file used to link target ``tgt``.
   Directory of file used to link target ``tgt``.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on (see policy :policy:`CMP0112`).
 ``$<TARGET_SONAME_FILE:tgt>``
 ``$<TARGET_SONAME_FILE:tgt>``
   File with soname (``.so.3``) where ``tgt`` is the name of a target.
   File with soname (``.so.3``) where ``tgt`` is the name of a target.
 ``$<TARGET_SONAME_FILE_NAME:tgt>``
 ``$<TARGET_SONAME_FILE_NAME:tgt>``
   Name of file with soname (``.so.3``).
   Name of file with soname (``.so.3``).
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on (see policy :policy:`CMP0112`).
 ``$<TARGET_SONAME_FILE_DIR:tgt>``
 ``$<TARGET_SONAME_FILE_DIR:tgt>``
   Directory of with soname (``.so.3``).
   Directory of with soname (``.so.3``).
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on (see policy :policy:`CMP0112`).
 ``$<TARGET_PDB_FILE:tgt>``
 ``$<TARGET_PDB_FILE:tgt>``
   Full path to the linker generated program database file (.pdb)
   Full path to the linker generated program database file (.pdb)
   where ``tgt`` is the name of a target.
   where ``tgt`` is the name of a target.
@@ -707,17 +725,29 @@ which is just the string ``tgt``.
   expression is evaluated on.
   expression is evaluated on.
 ``$<TARGET_PDB_FILE_NAME:tgt>``
 ``$<TARGET_PDB_FILE_NAME:tgt>``
   Name of the linker generated program database file (.pdb).
   Name of the linker generated program database file (.pdb).
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on (see policy :policy:`CMP0112`).
 ``$<TARGET_PDB_FILE_DIR:tgt>``
 ``$<TARGET_PDB_FILE_DIR:tgt>``
   Directory of the linker generated program database file (.pdb).
   Directory of the linker generated program database file (.pdb).
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on (see policy :policy:`CMP0112`).
 ``$<TARGET_BUNDLE_DIR:tgt>``
 ``$<TARGET_BUNDLE_DIR:tgt>``
   Full path to the bundle directory (``my.app``, ``my.framework``, or
   Full path to the bundle directory (``my.app``, ``my.framework``, or
   ``my.bundle``) where ``tgt`` is the name of a target.
   ``my.bundle``) where ``tgt`` is the name of a target.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on (see policy :policy:`CMP0112`).
 ``$<TARGET_BUNDLE_CONTENT_DIR:tgt>``
 ``$<TARGET_BUNDLE_CONTENT_DIR:tgt>``
   Full path to the bundle content directory where ``tgt`` is the name of a
   Full path to the bundle content directory where ``tgt`` is the name of a
   target. For the macOS SDK it leads to ``my.app/Contents``, ``my.framework``,
   target. For the macOS SDK it leads to ``my.app/Contents``, ``my.framework``,
   or ``my.bundle/Contents``. For all other SDKs (e.g. iOS) it leads to
   or ``my.bundle/Contents``. For all other SDKs (e.g. iOS) it leads to
   ``my.app``, ``my.framework``, or ``my.bundle`` due to the flat bundle
   ``my.app``, ``my.framework``, or ``my.bundle`` due to the flat bundle
   structure.
   structure.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on (see policy :policy:`CMP0112`).
 ``$<TARGET_PROPERTY:tgt,prop>``
 ``$<TARGET_PROPERTY:tgt,prop>``
   Value of the property ``prop`` on the target ``tgt``.
   Value of the property ``prop`` on the target ``tgt``.
 
 

+ 1 - 0
Help/manual/cmake-policies.7.rst

@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.19
 .. toctree::
 .. toctree::
    :maxdepth: 1
    :maxdepth: 1
 
 
+   CMP0112: Target file component generator expressions do not add target dependencies. </policy/CMP0112>
    CMP0111: An imported target with a missing location fails during generation. </policy/CMP0111>
    CMP0111: An imported target with a missing location fails during generation. </policy/CMP0111>
    CMP0110: add_test() supports arbitrary characters in test names. </policy/CMP0110>
    CMP0110: add_test() supports arbitrary characters in test names. </policy/CMP0110>
    CMP0109: find_program() requires permission to execute but not to read. </policy/CMP0109>
    CMP0109: find_program() requires permission to execute but not to read. </policy/CMP0109>

+ 39 - 0
Help/policy/CMP0112.rst

@@ -0,0 +1,39 @@
+CMP0112
+-------
+
+.. versionadded:: 3.19
+
+Target file component generator expressions do not add target dependencies.
+
+The following target-based generator expressions that query for directory or
+file name components no longer add a dependency on the evaluated target.
+
+    - ``TARGET_FILE_DIR``
+    - ``TARGET_LINKER_FILE_BASE_NAME``
+    - ``TARGET_LINKER_FILE_NAME``
+    - ``TARGET_LINKER_FILE_DIR``
+    - ``TARGET_SONAME_FILE_NAME``
+    - ``TARGET_SONAME_FILE_DIR``
+    - ``TARGET_PDB_FILE_NAME``
+    - ``TARGET_PDB_FILE_DIR``
+    - ``TARGET_BUNDLE_DIR``
+    - ``TARGET_BUNDLE_CONTENT_DIR``
+
+
+In CMake 3.18 and lower a dependency on the evaluated target of the above
+generator expressions would be always added.  CMake 3.19 and above prefer
+to not add this dependency.  This policy provides compatibility for projects
+that have not been updated to expect the new behavior.
+
+The ``OLD`` behavior for this policy is to add a dependency on the evaluated
+target for the the above generator expressions.  The ``NEW`` behavior of
+this policy is to not add a dependency on the evaluated target for the the
+above generator expressions.
+
+This policy was introduced in CMake version 3.19.  Unlike many policies,
+CMake version |release| does *not* warn by default when this policy
+is not set and simply uses ``OLD`` behavior.  See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0112 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
+
+.. include:: DEPRECATED.txt

+ 17 - 0
Help/release/dev/relax-target-generator-expression-dependency-addition.rst

@@ -0,0 +1,17 @@
+relax-target-generator-expression-dependency-addition
+-----------------------------------------------------
+
+* The following target-based generator expressions that query for directory or
+  file name components no longer add a dependency on the evaluated target.
+  See policy :policy:`CMP0112`.
+
+    - ``TARGET_FILE_DIR``
+    - ``TARGET_LINKER_FILE_BASE_NAME``
+    - ``TARGET_LINKER_FILE_NAME``
+    - ``TARGET_LINKER_FILE_DIR``
+    - ``TARGET_SONAME_FILE_NAME``
+    - ``TARGET_SONAME_FILE_DIR``
+    - ``TARGET_PDB_FILE_NAME``
+    - ``TARGET_PDB_FILE_DIR``
+    - ``TARGET_BUNDLE_DIR``
+    - ``TARGET_BUNDLE_CONTENT_DIR``

+ 2 - 0
Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst

@@ -25,6 +25,8 @@ warn by default:
   policy :policy:`CMP0089`.
   policy :policy:`CMP0089`.
 * ``CMAKE_POLICY_WARNING_CMP0102`` controls the warning for
 * ``CMAKE_POLICY_WARNING_CMP0102`` controls the warning for
   policy :policy:`CMP0102`.
   policy :policy:`CMP0102`.
+* ``CMAKE_POLICY_WARNING_CMP0112`` controls the warning for
+  policy :policy:`CMP0112`.
 
 
 This variable should not be set by a project in CMake code.  Project
 This variable should not be set by a project in CMake code.  Project
 developers running CMake may set this variable in their cache to
 developers running CMake may set this variable in their cache to

+ 68 - 2
Source/cmGeneratorExpressionNode.cxx

@@ -1901,6 +1901,70 @@ class ArtifactSonameTag;
 class ArtifactBundleDirTag;
 class ArtifactBundleDirTag;
 class ArtifactBundleContentDirTag;
 class ArtifactBundleContentDirTag;
 
 
+template <typename ArtifactT, typename ComponentT>
+struct TargetFilesystemArtifactDependency
+{
+  static void AddDependency(cmGeneratorTarget* target,
+                            cmGeneratorExpressionContext* context)
+  {
+    context->DependTargets.insert(target);
+    context->AllTargets.insert(target);
+  }
+};
+
+struct TargetFilesystemArtifactDependencyCMP0112
+{
+  static void AddDependency(cmGeneratorTarget* target,
+                            cmGeneratorExpressionContext* context)
+  {
+    context->AllTargets.insert(target);
+    cmLocalGenerator* lg = context->LG;
+    switch (target->GetPolicyStatusCMP0112()) {
+      case cmPolicies::WARN:
+        if (lg->GetMakefile()->PolicyOptionalWarningEnabled(
+              "CMAKE_POLICY_WARNING_CMP0112")) {
+          std::string err =
+            cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0112),
+                     "\nDependency being added to target:\n  \"",
+                     target->GetName(), "\"\n");
+          lg->GetCMakeInstance()->IssueMessage(MessageType ::AUTHOR_WARNING,
+                                               err, context->Backtrace);
+        }
+        CM_FALLTHROUGH;
+      case cmPolicies::OLD:
+        context->DependTargets.insert(target);
+        break;
+      case cmPolicies::REQUIRED_IF_USED:
+      case cmPolicies::REQUIRED_ALWAYS:
+      case cmPolicies::NEW:
+        break;
+    }
+  }
+};
+
+template <typename ArtifactT>
+struct TargetFilesystemArtifactDependency<ArtifactT, ArtifactNameTag>
+  : TargetFilesystemArtifactDependencyCMP0112
+{
+};
+template <typename ArtifactT>
+struct TargetFilesystemArtifactDependency<ArtifactT, ArtifactDirTag>
+  : TargetFilesystemArtifactDependencyCMP0112
+{
+};
+template <>
+struct TargetFilesystemArtifactDependency<ArtifactBundleDirTag,
+                                          ArtifactPathTag>
+  : TargetFilesystemArtifactDependencyCMP0112
+{
+};
+template <>
+struct TargetFilesystemArtifactDependency<ArtifactBundleContentDirTag,
+                                          ArtifactPathTag>
+  : TargetFilesystemArtifactDependencyCMP0112
+{
+};
+
 template <typename ArtifactT>
 template <typename ArtifactT>
 struct TargetFilesystemArtifactResultCreator
 struct TargetFilesystemArtifactResultCreator
 {
 {
@@ -2153,8 +2217,10 @@ struct TargetFilesystemArtifact : public TargetArtifactBase
     if (!target) {
     if (!target) {
       return std::string();
       return std::string();
     }
     }
-    context->DependTargets.insert(target);
-    context->AllTargets.insert(target);
+    // Not a dependent target if we are querying for ArtifactDirTag,
+    // ArtifactNameTag, ArtifactBundleDirTag, and ArtifactBundleContentDirTag
+    TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency(
+      target, context);
 
 
     std::string result =
     std::string result =
       TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, context,
       TargetFilesystemArtifactResultCreator<ArtifactT>::Create(target, context,

+ 6 - 1
Source/cmPolicies.h

@@ -330,6 +330,10 @@ class cmMakefile;
   SELECT(POLICY, CMP0111,                                                     \
   SELECT(POLICY, CMP0111,                                                     \
          "An imported target with a missing location fails during "           \
          "An imported target with a missing location fails during "           \
          "generation.",                                                       \
          "generation.",                                                       \
+         3, 19, 0, cmPolicies::WARN)                                          \
+  SELECT(POLICY, CMP0112,                                                     \
+         "Target file component generator expressions do not add target "     \
+         "dependencies.",                                                     \
          3, 19, 0, cmPolicies::WARN)
          3, 19, 0, cmPolicies::WARN)
 
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
@@ -363,7 +367,8 @@ class cmMakefile;
   F(CMP0099)                                                                  \
   F(CMP0099)                                                                  \
   F(CMP0104)                                                                  \
   F(CMP0104)                                                                  \
   F(CMP0105)                                                                  \
   F(CMP0105)                                                                  \
-  F(CMP0108)
+  F(CMP0108)                                                                  \
+  F(CMP0112)
 
 
 /** \class cmPolicies
 /** \class cmPolicies
  * \brief Handles changes in CMake behavior and policies
  * \brief Handles changes in CMake behavior and policies

+ 3 - 1
Tests/RunCMake/GenEx-TARGET_FILE/RunCMakeTest.cmake

@@ -2,8 +2,10 @@ include(RunCMake)
 
 
 run_cmake(TARGET_FILE-recursion)
 run_cmake(TARGET_FILE-recursion)
 run_cmake(OUTPUT_NAME-recursion)
 run_cmake(OUTPUT_NAME-recursion)
-run_cmake(TARGET_FILE_PREFIX)
+run_cmake(TARGET_FILE_DIR-dependency)
+run_cmake(TARGET_FILE_DIR-no-dependency)
 run_cmake(TARGET_FILE_PREFIX-imported-target)
 run_cmake(TARGET_FILE_PREFIX-imported-target)
+run_cmake(TARGET_FILE_PREFIX)
 run_cmake(TARGET_FILE_PREFIX-non-valid-target)
 run_cmake(TARGET_FILE_PREFIX-non-valid-target)
 run_cmake(TARGET_LINKER_FILE_PREFIX-non-valid-target)
 run_cmake(TARGET_LINKER_FILE_PREFIX-non-valid-target)
 run_cmake(TARGET_FILE_SUFFIX)
 run_cmake(TARGET_FILE_SUFFIX)

+ 1 - 0
Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_DIR-dependency-result.txt

@@ -0,0 +1 @@
+1

+ 6 - 0
Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_DIR-dependency-stderr.txt

@@ -0,0 +1,6 @@
+.*Policy CMP0112 is not set.*
+.*Dependency being added to target.*
+.*exec1.*
+CMake Error: The inter-target dependency graph.*
+.*"exec1" of type EXECUTABLE
+    depends on "copyFile" \(strong\)

+ 12 - 0
Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_DIR-dependency.cmake

@@ -0,0 +1,12 @@
+set(CMAKE_POLICY_WARNING_CMP0112 TRUE)
+
+enable_language (C)
+
+add_executable (exec1 empty.c)
+
+add_custom_target(copyFile
+  COMMAND ${CMAKE_COMMAND} -E copy_if_different
+        "${CMAKE_CURRENT_SOURCE_DIR}/empty.c"
+        "$<TARGET_FILE_DIR:exec1>/$<TARGET_FILE_BASE_NAME:exec1>_e.c"
+)
+add_dependencies(exec1 copyFile)

+ 12 - 0
Tests/RunCMake/GenEx-TARGET_FILE/TARGET_FILE_DIR-no-dependency.cmake

@@ -0,0 +1,12 @@
+cmake_policy(SET CMP0112 NEW)
+
+enable_language (C)
+
+add_executable (exec1 empty.c)
+
+add_custom_target(copyFile
+  COMMAND ${CMAKE_COMMAND} -E copy_if_different
+        "${CMAKE_CURRENT_SOURCE_DIR}/empty.c"
+        "$<TARGET_FILE_DIR:exec1>/$<TARGET_FILE_BASE_NAME:exec1>_e.c"
+)
+add_dependencies(exec1 copyFile)

+ 1 - 0
Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt

@@ -32,6 +32,7 @@
    \* CMP0104
    \* CMP0104
    \* CMP0105
    \* CMP0105
    \* CMP0108
    \* CMP0108
+   \* CMP0112
 
 
 Call Stack \(most recent call first\):
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
   CMakeLists.txt:3 \(include\)