| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #include "cmTransformDepfile.h" |
| |
| #include <algorithm> |
| #include <functional> |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| #include <vector> |
| |
| #include <cm/optional> |
| |
| #include "cmsys/FStream.hxx" |
| |
| #include "cmGccDepfileReader.h" |
| #include "cmGccDepfileReaderTypes.h" |
| #include "cmGlobalGenerator.h" |
| #include "cmLocalGenerator.h" |
| #include "cmSystemTools.h" |
| |
| namespace { |
| void WriteFilenameGcc(cmsys::ofstream& fout, const std::string& filename) |
| { |
| for (auto c : filename) { |
| switch (c) { |
| case ' ': |
| fout << "\\ "; |
| break; |
| case '\\': |
| fout << "\\\\"; |
| break; |
| default: |
| fout << c; |
| break; |
| } |
| } |
| } |
| |
| void WriteDepfile(cmDepfileFormat format, cmsys::ofstream& fout, |
| const cmLocalGenerator& lg, |
| const cmGccDepfileContent& content) |
| { |
| std::function<std::string(const std::string&)> formatPath = |
| [&lg](const std::string& path) -> std::string { |
| return lg.MaybeRelativeToTopBinDir(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; |
| for (auto const& rule : dep.rules) { |
| if (!first) { |
| fout << " \\\n "; |
| } |
| first = false; |
| WriteFilenameGcc(fout, formatPath(rule)); |
| } |
| fout << ':'; |
| for (auto const& path : dep.paths) { |
| fout << " \\\n "; |
| WriteFilenameGcc(fout, formatPath(path)); |
| } |
| fout << '\n'; |
| } |
| |
| if (format == cmDepfileFormat::MakeDepfile) { |
| // In this case, phony targets must be added for all dependencies |
| fout << "\n"; |
| for (auto const& dep : content) { |
| for (auto const& path : dep.paths) { |
| fout << "\n"; |
| WriteFilenameGcc(fout, formatPath(path)); |
| fout << ":\n"; |
| } |
| } |
| } |
| } |
| |
| void WriteMSBuildAdditionalInputs(cmsys::ofstream& fout, |
| cmLocalGenerator const& lg, |
| cmGccDepfileContent const& content) |
| { |
| if (content.empty()) { |
| return; |
| } |
| |
| // Write a UTF-8 BOM so MSBuild knows the encoding when reading the file. |
| static const char utf8bom[] = { char(0xEF), char(0xBB), char(0xBF) }; |
| fout.write(utf8bom, sizeof(utf8bom)); |
| |
| // Write the format expected by MSBuild CustomBuild AdditionalInputs. |
| const char* sep = ""; |
| for (const auto& c : content) { |
| for (std::string path : c.paths) { |
| if (!cmSystemTools::FileIsFullPath(path)) { |
| path = cmSystemTools::CollapseFullPath(path, |
| lg.GetCurrentBinaryDirectory()); |
| } |
| std::replace(path.begin(), path.end(), '/', '\\'); |
| fout << sep << path; |
| sep = ";"; |
| } |
| } |
| fout << "\n"; |
| } |
| } |
| |
| bool cmTransformDepfile(cmDepfileFormat format, const cmLocalGenerator& lg, |
| const std::string& infile, const std::string& outfile) |
| { |
| cmGccDepfileContent content; |
| if (cmSystemTools::FileExists(infile)) { |
| auto result = |
| cmReadGccDepfile(infile.c_str(), lg.GetCurrentBinaryDirectory()); |
| if (!result) { |
| return false; |
| } |
| content = *std::move(result); |
| } |
| |
| cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(outfile)); |
| cmsys::ofstream fout(outfile.c_str()); |
| if (!fout) { |
| return false; |
| } |
| switch (format) { |
| case cmDepfileFormat::GccDepfile: |
| case cmDepfileFormat::MakeDepfile: |
| WriteDepfile(format, fout, lg, content); |
| break; |
| case cmDepfileFormat::MSBuildAdditionalInputs: |
| WriteMSBuildAdditionalInputs(fout, lg, content); |
| break; |
| } |
| return true; |
| } |