1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-16 14:08:35 +08:00

Xcode: Add support of DEPFILE for add_custom_command

Issue: #20286
This commit is contained in:
Marc Chevrier
2021-04-15 14:13:57 +02:00
committed by Brad King
parent 498b916cdd
commit d67cc4882d
9 changed files with 115 additions and 27 deletions

View File

@@ -271,32 +271,42 @@ The options are:
``DEPFILE`` ``DEPFILE``
.. versionadded:: 3.7 .. versionadded:: 3.7
Specify a ``.d`` depfile for the :generator:`Ninja` generator and Specify a ``.d`` depfile for the :generator:`Ninja`, :generator:`Xcode` and
:ref:`Makefile Generators`. The depfile may use "generator expressions" with :ref:`Makefile <Makefile Generators>` generators. The depfile may use
the syntax ``$<...>``. See the :manual:`generator-expressions(7) "generator expressions" with the syntax ``$<...>``. See the
<cmake-generator-expressions(7)>` manual for available expressions. :manual:`generator-expressions(7) <cmake-generator-expressions(7)>` manual
A ``.d`` file holds dependencies usually emitted by the custom for available expressions. A ``.d`` file holds dependencies usually emitted
command itself. by the custom command itself.
Using ``DEPFILE`` with other generators than :generator:`Ninja` or
:ref:`Makefile Generators` is an error. Using ``DEPFILE`` with other generators than :generator:`Ninja`,
:generator:`Xcode` or :ref:`Makefile <Makefile Generators>` is an error.
.. versionadded:: 3.20 .. versionadded:: 3.20
Added the support of :ref:`Makefile Generators`. Added the support of :ref:`Makefile Generators`.
.. versionadded:: 3.21 .. 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 If the ``DEPFILE`` argument is relative, it should be relative to
:variable:`CMAKE_CURRENT_BINARY_DIR`, and any relative paths inside the :variable:`CMAKE_CURRENT_BINARY_DIR`, and any relative paths inside the
``DEPFILE`` should also be relative to :variable:`CMAKE_CURRENT_BINARY_DIR` ``DEPFILE`` should also be relative to :variable:`CMAKE_CURRENT_BINARY_DIR`
(see policy :policy:`CMP0116`. This policy is always ``NEW`` for (see policy :policy:`CMP0116`. This policy is always ``NEW`` for
:ref:`Makefile Generators`). :ref:`Makefile <Makefile Generators>` and :generator:`Xcode` generators).
.. note:: .. note::
For :ref:`Makefile Generators`, this option cannot be specified at the For :ref:`Makefile Generators`, this option cannot be specified at the
same time as ``IMPLICIT_DEPENDS`` option. 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 Examples: Generating Files
^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@@ -0,0 +1,5 @@
Xcode-add_custom_command-DEPFILE
--------------------------------
* The :command:`add_custom_command` command gained ``DEPFILE`` support on
:generator:`Xcode` generator.

View File

@@ -151,7 +151,9 @@ std::string EvaluateDepfile(std::string const& path,
cmCustomCommandGenerator::cmCustomCommandGenerator( cmCustomCommandGenerator::cmCustomCommandGenerator(
cmCustomCommand const& cc, std::string config, cmLocalGenerator* lg, 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) : CC(&cc)
, OutputConfig(crossConfig ? *crossConfig : config) , OutputConfig(crossConfig ? *crossConfig : config)
, CommandConfig(std::move(config)) , CommandConfig(std::move(config))
@@ -159,7 +161,15 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(
, OldStyle(cc.GetEscapeOldStyle()) , OldStyle(cc.GetEscapeOldStyle())
, MakeVars(cc.GetEscapeAllowMakeVars()) , MakeVars(cc.GetEscapeAllowMakeVars())
, EmulatorsWithArguments(cc.GetCommandLines().size()) , 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()); cmGeneratorExpression ge(cc.GetBacktrace());
const cmCustomCommandLines& cmdlines = this->CC->GetCommandLines(); const cmCustomCommandLines& cmdlines = this->CC->GetCommandLines();
@@ -413,13 +423,9 @@ std::string cmCustomCommandGenerator::GetFullDepfile() const
return cmSystemTools::CollapseFullPath(depfile); 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); cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
std::string extension; std::string extension;
switch (*this->LG->GetGlobalGenerator()->DepfileFormat()) { switch (*this->LG->GetGlobalGenerator()->DepfileFormat()) {
@@ -434,6 +440,16 @@ std::string cmCustomCommandGenerator::GetInternalDepfile() const
hash.HashString(depfile), extension); 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 const char* cmCustomCommandGenerator::GetComment() const
{ {
return this->CC->GetComment(); return this->CC->GetComment();

View File

@@ -4,6 +4,7 @@
#include "cmConfigure.h" // IWYU pragma: keep #include "cmConfigure.h" // IWYU pragma: keep
#include <functional>
#include <set> #include <set>
#include <string> #include <string>
#include <utility> #include <utility>
@@ -19,6 +20,8 @@ class cmLocalGenerator;
class cmCustomCommandGenerator class cmCustomCommandGenerator
{ {
std::string GetInternalDepfileName(const std::string&, const std::string&);
cmCustomCommand const* CC; cmCustomCommand const* CC;
std::string OutputConfig; std::string OutputConfig;
std::string CommandConfig; std::string CommandConfig;
@@ -32,15 +35,19 @@ class cmCustomCommandGenerator
std::vector<std::string> Depends; std::vector<std::string> Depends;
std::string WorkingDirectory; std::string WorkingDirectory;
std::set<BT<std::pair<std::string, bool>>> Utilities; std::set<BT<std::pair<std::string, bool>>> Utilities;
std::function<std::string(const std::string&, const std::string&)>
ComputeInternalDepfile;
void FillEmulatorsWithArguments(); void FillEmulatorsWithArguments();
std::vector<std::string> GetCrossCompilingEmulator(unsigned int c) const; std::vector<std::string> GetCrossCompilingEmulator(unsigned int c) const;
const char* GetArgv0Location(unsigned int c) const; const char* GetArgv0Location(unsigned int c) const;
public: public:
cmCustomCommandGenerator(cmCustomCommand const& cc, std::string config, cmCustomCommandGenerator(
cmLocalGenerator* lg, bool transformDepfile = true, cmCustomCommand const& cc, std::string config, cmLocalGenerator* lg,
cm::optional<std::string> crossConfig = {}); bool transformDepfile = true, cm::optional<std::string> crossConfig = {},
std::function<std::string(const std::string&, const std::string&)>
computeInternalDepfile = {});
cmCustomCommandGenerator(const cmCustomCommandGenerator&) = delete; cmCustomCommandGenerator(const cmCustomCommandGenerator&) = delete;
cmCustomCommandGenerator(cmCustomCommandGenerator&&) = default; cmCustomCommandGenerator(cmCustomCommandGenerator&&) = default;
cmCustomCommandGenerator& operator=(const cmCustomCommandGenerator&) = cmCustomCommandGenerator& operator=(const cmCustomCommandGenerator&) =

View File

@@ -17,6 +17,7 @@
#include "cmsys/RegularExpression.hxx" #include "cmsys/RegularExpression.hxx"
#include "cmCMakePath.h"
#include "cmComputeLinkInformation.h" #include "cmComputeLinkInformation.h"
#include "cmCryptoHash.h" #include "cmCryptoHash.h"
#include "cmCustomCommand.h" #include "cmCustomCommand.h"
@@ -1864,9 +1865,20 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase(
std::set<std::string> allConfigInputs; std::set<std::string> allConfigInputs;
std::set<std::string> allConfigOutputs; 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"; std::string shellScript = "set -e\n";
for (std::string const& configName : this->CurrentConfigurationTypes) { 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; std::vector<std::string> realDepends;
realDepends.reserve(ccg.GetDepends().size()); realDepends.reserve(ccg.GetDepends().size());
for (auto const& d : ccg.GetDepends()) { for (auto const& d : ccg.GetDepends()) {
@@ -1886,9 +1898,22 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase(
"\"; then :\n", this->ConstructScript(ccg), "fi\n"); "\"; then :\n", this->ConstructScript(ccg), "fi\n");
} }
cmXCodeObject* buildPhase = if (!cc.GetDepfile().empty()) {
this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase, buildPhase->AddAttribute(
cmStrCat(gt->GetName(), ':', sf->GetFullPath())); "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", buildPhase->AddAttribute("buildActionMask",
this->CreateString("2147483647")); this->CreateString("2147483647"));
cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);

View File

@@ -14,6 +14,7 @@
#include <cm/string_view> #include <cm/string_view>
#include "cmGlobalGenerator.h" #include "cmGlobalGenerator.h"
#include "cmTransformDepfile.h"
#include "cmXCodeObject.h" #include "cmXCodeObject.h"
class cmCustomCommand; class cmCustomCommand;
@@ -111,6 +112,18 @@ public:
bool ShouldStripResourcePath(cmMakefile*) const override; 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 SetSystemName(std::string const& s, cmMakefile* mf) override;
bool SetGeneratorToolset(std::string const& ts, bool build, bool SetGeneratorToolset(std::string const& ts, bool build,
cmMakefile* mf) override; cmMakefile* mf) override;

View File

@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmTransformDepfile.h" #include "cmTransformDepfile.h"
#include <functional>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@@ -13,6 +14,7 @@
#include "cmGccDepfileReader.h" #include "cmGccDepfileReader.h"
#include "cmGccDepfileReaderTypes.h" #include "cmGccDepfileReaderTypes.h"
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h" #include "cmLocalGenerator.h"
#include "cmSystemTools.h" #include "cmSystemTools.h"
@@ -38,6 +40,14 @@ void WriteGccDepfile(cmsys::ofstream& fout, const cmLocalGenerator& lg,
const cmGccDepfileContent& content) const cmGccDepfileContent& content)
{ {
const auto& binDir = lg.GetBinaryDirectory(); 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) { for (auto const& dep : content) {
bool first = true; bool first = true;
@@ -46,12 +56,12 @@ void WriteGccDepfile(cmsys::ofstream& fout, const cmLocalGenerator& lg,
fout << " \\\n "; fout << " \\\n ";
} }
first = false; first = false;
WriteFilenameGcc(fout, lg.MaybeConvertToRelativePath(binDir, rule)); WriteFilenameGcc(fout, formatPath(rule));
} }
fout << ':'; fout << ':';
for (auto const& path : dep.paths) { for (auto const& path : dep.paths) {
fout << " \\\n "; fout << " \\\n ";
WriteFilenameGcc(fout, lg.MaybeConvertToRelativePath(binDir, path)); WriteFilenameGcc(fout, formatPath(path));
} }
fout << '\n'; fout << '\n';
} }

View File

@@ -155,7 +155,8 @@ if (RunCMake_GENERATOR MATCHES "Makefiles")
run_cmake(CustomCommandDependencies-BadArgs) run_cmake(CustomCommandDependencies-BadArgs)
endif() 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) unset(run_BuildDepends_skip_step_3)
run_BuildDepends(CustomCommandDepfile) run_BuildDepends(CustomCommandDepfile)
set(run_BuildDepends_skip_step_3 1) set(run_BuildDepends_skip_step_3 1)

View File

@@ -222,6 +222,7 @@ endif()
add_RunCMake_test(BuildDepends add_RunCMake_test(BuildDepends
-DMSVC_VERSION=${MSVC_VERSION} -DMSVC_VERSION=${MSVC_VERSION}
-DCMAKE_XCODE_BUILD_SYSTEM=${CMAKE_XCODE_BUILD_SYSTEM}
-DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID} -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
-DCMake_TEST_BuildDepends_GNU_AS=${CMake_TEST_BuildDepends_GNU_AS} -DCMake_TEST_BuildDepends_GNU_AS=${CMake_TEST_BuildDepends_GNU_AS}
) )