summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Chevrier <marc.chevrier@gmail.com>2021-04-15 14:13:57 +0200
committerBrad King <brad.king@kitware.com>2021-04-15 12:17:31 -0400
commitd67cc4882d54a18abbd5d01365ce1fc72d702a0e (patch)
treed609494ba1f13292a45d92630b47c4094ad2cc82
parent498b916cdd96330baa33bc10667b43cbb78674d4 (diff)
downloadcmake-d67cc4882d54a18abbd5d01365ce1fc72d702a0e.tar.gz
Xcode: Add support of DEPFILE for add_custom_command
Issue: #20286
-rw-r--r--Help/command/add_custom_command.rst30
-rw-r--r--Help/release/dev/Xcode-add_custom_command-DEPFILE.rst5
-rw-r--r--Source/cmCustomCommandGenerator.cxx30
-rw-r--r--Source/cmCustomCommandGenerator.h13
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx33
-rw-r--r--Source/cmGlobalXCodeGenerator.h13
-rw-r--r--Source/cmTransformDepfile.cxx14
-rw-r--r--Tests/RunCMake/BuildDepends/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/CMakeLists.txt1
9 files changed, 115 insertions, 27 deletions
diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst
index b6ff0ea35b..c0ff81ae83 100644
--- a/Help/command/add_custom_command.rst
+++ b/Help/command/add_custom_command.rst
@@ -271,32 +271,42 @@ The options are:
``DEPFILE``
.. versionadded:: 3.7
- Specify a ``.d`` depfile for the :generator:`Ninja` generator and
- :ref:`Makefile Generators`. The depfile may use "generator expressions" with
- the syntax ``$<...>``. See the :manual:`generator-expressions(7)
- <cmake-generator-expressions(7)>` manual for available expressions.
- A ``.d`` file holds dependencies usually emitted by the custom
- command itself.
- Using ``DEPFILE`` with other generators than :generator:`Ninja` or
- :ref:`Makefile Generators` is an error.
+ Specify a ``.d`` depfile for the :generator:`Ninja`, :generator:`Xcode` and
+ :ref:`Makefile <Makefile Generators>` generators. The depfile may use
+ "generator expressions" with the syntax ``$<...>``. See the
+ :manual:`generator-expressions(7) <cmake-generator-expressions(7)>` manual
+ for available expressions. A ``.d`` file holds dependencies usually emitted
+ by the custom command itself.
+
+ Using ``DEPFILE`` with other generators than :generator:`Ninja`,
+ :generator:`Xcode` or :ref:`Makefile <Makefile Generators>` is an error.
.. versionadded:: 3.20
Added the support of :ref:`Makefile Generators`.
.. versionadded:: 3.21
- Added the support of :manual:`generator expressions <cmake-generator-expressions(7)>`.
+ Added the support of :generator:`Xcode` generator and
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
If the ``DEPFILE`` argument is relative, it should be relative to
:variable:`CMAKE_CURRENT_BINARY_DIR`, and any relative paths inside the
``DEPFILE`` should also be relative to :variable:`CMAKE_CURRENT_BINARY_DIR`
(see policy :policy:`CMP0116`. This policy is always ``NEW`` for
- :ref:`Makefile Generators`).
+ :ref:`Makefile <Makefile Generators>` and :generator:`Xcode` generators).
.. note::
For :ref:`Makefile Generators`, this option cannot be specified at the
same time as ``IMPLICIT_DEPENDS`` option.
+ .. note::
+
+ For the :generator:`Xcode` generator, this option requires that the
+ :ref:`Xcode Build System Selection` uses the ``buildsystem=12`` variant
+ or higher. This is the default when using Xcode 12 or above.
+ The :variable:`CMAKE_XCODE_BUILD_SYSTEM` variable indicates which variant
+ of the Xcode build system is used.
+
Examples: Generating Files
^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Help/release/dev/Xcode-add_custom_command-DEPFILE.rst b/Help/release/dev/Xcode-add_custom_command-DEPFILE.rst
new file mode 100644
index 0000000000..4c4d48c769
--- /dev/null
+++ b/Help/release/dev/Xcode-add_custom_command-DEPFILE.rst
@@ -0,0 +1,5 @@
+Xcode-add_custom_command-DEPFILE
+--------------------------------
+
+* The :command:`add_custom_command` command gained ``DEPFILE`` support on
+ :generator:`Xcode` generator.
diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx
index 4705443190..7659792ddd 100644
--- a/Source/cmCustomCommandGenerator.cxx
+++ b/Source/cmCustomCommandGenerator.cxx
@@ -151,7 +151,9 @@ std::string EvaluateDepfile(std::string const& path,
cmCustomCommandGenerator::cmCustomCommandGenerator(
cmCustomCommand const& cc, std::string config, cmLocalGenerator* lg,
- bool transformDepfile, cm::optional<std::string> crossConfig)
+ bool transformDepfile, cm::optional<std::string> crossConfig,
+ std::function<std::string(const std::string&, const std::string&)>
+ computeInternalDepfile)
: CC(&cc)
, OutputConfig(crossConfig ? *crossConfig : config)
, CommandConfig(std::move(config))
@@ -159,7 +161,15 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(
, OldStyle(cc.GetEscapeOldStyle())
, MakeVars(cc.GetEscapeAllowMakeVars())
, EmulatorsWithArguments(cc.GetCommandLines().size())
+ , ComputeInternalDepfile(std::move(computeInternalDepfile))
{
+ if (!this->ComputeInternalDepfile) {
+ this->ComputeInternalDepfile =
+ [this](const std::string& cfg, const std::string& file) -> std::string {
+ return this->GetInternalDepfileName(cfg, file);
+ };
+ }
+
cmGeneratorExpression ge(cc.GetBacktrace());
const cmCustomCommandLines& cmdlines = this->CC->GetCommandLines();
@@ -413,13 +423,9 @@ std::string cmCustomCommandGenerator::GetFullDepfile() const
return cmSystemTools::CollapseFullPath(depfile);
}
-std::string cmCustomCommandGenerator::GetInternalDepfile() const
+std::string cmCustomCommandGenerator::GetInternalDepfileName(
+ const std::string& /*config*/, const std::string& depfile)
{
- std::string depfile = this->GetFullDepfile();
- if (depfile.empty()) {
- return "";
- }
-
cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
std::string extension;
switch (*this->LG->GetGlobalGenerator()->DepfileFormat()) {
@@ -434,6 +440,16 @@ std::string cmCustomCommandGenerator::GetInternalDepfile() const
hash.HashString(depfile), extension);
}
+std::string cmCustomCommandGenerator::GetInternalDepfile() const
+{
+ std::string depfile = this->GetFullDepfile();
+ if (depfile.empty()) {
+ return "";
+ }
+
+ return this->ComputeInternalDepfile(this->OutputConfig, depfile);
+}
+
const char* cmCustomCommandGenerator::GetComment() const
{
return this->CC->GetComment();
diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h
index 53e55737da..e70909a74a 100644
--- a/Source/cmCustomCommandGenerator.h
+++ b/Source/cmCustomCommandGenerator.h
@@ -4,6 +4,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <functional>
#include <set>
#include <string>
#include <utility>
@@ -19,6 +20,8 @@ class cmLocalGenerator;
class cmCustomCommandGenerator
{
+ std::string GetInternalDepfileName(const std::string&, const std::string&);
+
cmCustomCommand const* CC;
std::string OutputConfig;
std::string CommandConfig;
@@ -32,15 +35,19 @@ class cmCustomCommandGenerator
std::vector<std::string> Depends;
std::string WorkingDirectory;
std::set<BT<std::pair<std::string, bool>>> Utilities;
+ std::function<std::string(const std::string&, const std::string&)>
+ ComputeInternalDepfile;
void FillEmulatorsWithArguments();
std::vector<std::string> GetCrossCompilingEmulator(unsigned int c) const;
const char* GetArgv0Location(unsigned int c) const;
public:
- cmCustomCommandGenerator(cmCustomCommand const& cc, std::string config,
- cmLocalGenerator* lg, bool transformDepfile = true,
- cm::optional<std::string> crossConfig = {});
+ cmCustomCommandGenerator(
+ cmCustomCommand const& cc, std::string config, cmLocalGenerator* lg,
+ bool transformDepfile = true, cm::optional<std::string> crossConfig = {},
+ std::function<std::string(const std::string&, const std::string&)>
+ computeInternalDepfile = {});
cmCustomCommandGenerator(const cmCustomCommandGenerator&) = delete;
cmCustomCommandGenerator(cmCustomCommandGenerator&&) = default;
cmCustomCommandGenerator& operator=(const cmCustomCommandGenerator&) =
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 7dd17045ee..dc3d3f253e 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -17,6 +17,7 @@
#include "cmsys/RegularExpression.hxx"
+#include "cmCMakePath.h"
#include "cmComputeLinkInformation.h"
#include "cmCryptoHash.h"
#include "cmCustomCommand.h"
@@ -1864,9 +1865,20 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase(
std::set<std::string> allConfigInputs;
std::set<std::string> allConfigOutputs;
+ cmXCodeObject* buildPhase =
+ this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase,
+ cmStrCat(gt->GetName(), ':', sf->GetFullPath()));
+
+ auto depfilesDirectory = cmStrCat(
+ gt->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/CMakeFiles/d/");
+ auto depfilesPrefix = cmStrCat(depfilesDirectory, buildPhase->GetId(), ".");
+
std::string shellScript = "set -e\n";
for (std::string const& configName : this->CurrentConfigurationTypes) {
- cmCustomCommandGenerator ccg(cc, configName, this->CurrentLocalGenerator);
+ cmCustomCommandGenerator ccg(
+ cc, configName, this->CurrentLocalGenerator, true, {},
+ [&depfilesPrefix](const std::string& config, const std::string&)
+ -> std::string { return cmStrCat(depfilesPrefix, config, ".d"); });
std::vector<std::string> realDepends;
realDepends.reserve(ccg.GetDepends().size());
for (auto const& d : ccg.GetDepends()) {
@@ -1886,9 +1898,22 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase(
"\"; then :\n", this->ConstructScript(ccg), "fi\n");
}
- cmXCodeObject* buildPhase =
- this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase,
- cmStrCat(gt->GetName(), ':', sf->GetFullPath()));
+ if (!cc.GetDepfile().empty()) {
+ buildPhase->AddAttribute(
+ "dependencyFile",
+ this->CreateString(cmStrCat(depfilesDirectory, buildPhase->GetId(),
+ ".$(CONFIGURATION).d")));
+ // to avoid spurious errors during first build, create empty dependency
+ // files
+ cmSystemTools::MakeDirectory(depfilesDirectory);
+ for (std::string const& configName : this->CurrentConfigurationTypes) {
+ auto file = cmStrCat(depfilesPrefix, configName, ".d");
+ if (!cmSystemTools::FileExists(file)) {
+ cmSystemTools::Touch(file, true);
+ }
+ }
+ }
+
buildPhase->AddAttribute("buildActionMask",
this->CreateString("2147483647"));
cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index 1ab56e20eb..2406472351 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -14,6 +14,7 @@
#include <cm/string_view>
#include "cmGlobalGenerator.h"
+#include "cmTransformDepfile.h"
#include "cmXCodeObject.h"
class cmCustomCommand;
@@ -111,6 +112,18 @@ public:
bool ShouldStripResourcePath(cmMakefile*) const override;
+ /**
+ * Used to determine if this generator supports DEPFILE option.
+ */
+ bool SupportsCustomCommandDepfile() const override
+ {
+ return this->XcodeBuildSystem >= BuildSystem::Twelve;
+ }
+ virtual cm::optional<cmDepfileFormat> DepfileFormat() const override
+ {
+ return cmDepfileFormat::GccDepfile;
+ }
+
bool SetSystemName(std::string const& s, cmMakefile* mf) override;
bool SetGeneratorToolset(std::string const& ts, bool build,
cmMakefile* mf) override;
diff --git a/Source/cmTransformDepfile.cxx b/Source/cmTransformDepfile.cxx
index 78aa4b2df3..b693582ec3 100644
--- a/Source/cmTransformDepfile.cxx
+++ b/Source/cmTransformDepfile.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmTransformDepfile.h"
+#include <functional>
#include <string>
#include <type_traits>
#include <utility>
@@ -13,6 +14,7 @@
#include "cmGccDepfileReader.h"
#include "cmGccDepfileReaderTypes.h"
+#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
#include "cmSystemTools.h"
@@ -38,6 +40,14 @@ void WriteGccDepfile(cmsys::ofstream& fout, const cmLocalGenerator& lg,
const cmGccDepfileContent& content)
{
const auto& binDir = lg.GetBinaryDirectory();
+ std::function<std::string(const std::string&)> formatPath =
+ [&lg, &binDir](const std::string& path) -> std::string {
+ return lg.MaybeConvertToRelativePath(binDir, path);
+ };
+ if (lg.GetGlobalGenerator()->GetName() == "Xcode") {
+ // full paths must be preserved for Xcode compliance
+ formatPath = [](const std::string& path) -> std::string { return path; };
+ }
for (auto const& dep : content) {
bool first = true;
@@ -46,12 +56,12 @@ void WriteGccDepfile(cmsys::ofstream& fout, const cmLocalGenerator& lg,
fout << " \\\n ";
}
first = false;
- WriteFilenameGcc(fout, lg.MaybeConvertToRelativePath(binDir, rule));
+ WriteFilenameGcc(fout, formatPath(rule));
}
fout << ':';
for (auto const& path : dep.paths) {
fout << " \\\n ";
- WriteFilenameGcc(fout, lg.MaybeConvertToRelativePath(binDir, path));
+ WriteFilenameGcc(fout, formatPath(path));
}
fout << '\n';
}
diff --git a/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake b/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake
index 62326345e4..a6e08da51f 100644
--- a/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake
+++ b/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake
@@ -155,7 +155,8 @@ if (RunCMake_GENERATOR MATCHES "Makefiles")
run_cmake(CustomCommandDependencies-BadArgs)
endif()
-if(RunCMake_GENERATOR MATCHES "Make|Ninja")
+if(RunCMake_GENERATOR MATCHES "Make|Ninja" OR
+ (RunCMake_GENERATOR STREQUAL "Xcode" AND CMAKE_XCODE_BUILD_SYSTEM GREATER_EQUAL "12"))
unset(run_BuildDepends_skip_step_3)
run_BuildDepends(CustomCommandDepfile)
set(run_BuildDepends_skip_step_3 1)
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 5f23c0582c..be59a55eb2 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -222,6 +222,7 @@ endif()
add_RunCMake_test(BuildDepends
-DMSVC_VERSION=${MSVC_VERSION}
+ -DCMAKE_XCODE_BUILD_SYSTEM=${CMAKE_XCODE_BUILD_SYSTEM}
-DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
-DCMake_TEST_BuildDepends_GNU_AS=${CMake_TEST_BuildDepends_GNU_AS}
)