a5066cc2a5650c514aca29f20b2414610250c6ad
[platform/upstream/cmake.git] / Source / cmTargetPrecompileHeadersCommand.cxx
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include "cmTargetPrecompileHeadersCommand.h"
4
5 #include <utility>
6
7 #include "cmGeneratorExpression.h"
8 #include "cmMakefile.h"
9 #include "cmMessageType.h"
10 #include "cmStringAlgorithms.h"
11 #include "cmSystemTools.h"
12 #include "cmTarget.h"
13 #include "cmTargetPropCommandBase.h"
14
15 namespace {
16
17 std::vector<std::string> ConvertToAbsoluteContent(
18   const std::vector<std::string>& content, std::string const& baseDir)
19 {
20   std::vector<std::string> absoluteContent;
21   absoluteContent.reserve(content.size());
22   for (std::string const& src : content) {
23     std::string absoluteSrc;
24     // Use '<foo.h>' and '"foo.h"' includes and absolute paths as-is.
25     // Interpret relative paths with respect to the source directory.
26     // If the path starts in a generator expression, assume it is absolute.
27     if (cmHasLiteralPrefix(src, "<") || cmHasLiteralPrefix(src, "\"") ||
28         cmSystemTools::FileIsFullPath(src) ||
29         cmGeneratorExpression::Find(src) == 0) {
30       absoluteSrc = src;
31     } else {
32       absoluteSrc = cmStrCat(baseDir, '/', src);
33     }
34     absoluteContent.emplace_back(std::move(absoluteSrc));
35   }
36   return absoluteContent;
37 }
38
39 class TargetPrecompileHeadersImpl : public cmTargetPropCommandBase
40 {
41 public:
42   using cmTargetPropCommandBase::cmTargetPropCommandBase;
43
44 private:
45   bool HandleDirectContent(cmTarget* tgt,
46                            const std::vector<std::string>& content,
47                            bool /*prepend*/, bool /*system*/) override
48   {
49     std::string const& base = this->Makefile->GetCurrentSourceDirectory();
50     tgt->AppendProperty("PRECOMPILE_HEADERS",
51                         this->Join(ConvertToAbsoluteContent(content, base)));
52     return true;
53   }
54
55   void HandleInterfaceContent(cmTarget* tgt,
56                               const std::vector<std::string>& content,
57                               bool prepend, bool system) override
58   {
59     std::string const& base = this->Makefile->GetCurrentSourceDirectory();
60     this->cmTargetPropCommandBase::HandleInterfaceContent(
61       tgt, ConvertToAbsoluteContent(content, base), prepend, system);
62   }
63
64   void HandleMissingTarget(const std::string& name) override
65   {
66     this->Makefile->IssueMessage(
67       MessageType::FATAL_ERROR,
68       cmStrCat("Cannot specify precompile headers for target \"", name,
69                "\" which is not built by this project."));
70   }
71
72   std::string Join(const std::vector<std::string>& content) override
73   {
74     return cmJoin(content, ";");
75   }
76 };
77
78 } // namespace
79
80 bool cmTargetPrecompileHeadersCommand(std::vector<std::string> const& args,
81                                       cmExecutionStatus& status)
82 {
83   return TargetPrecompileHeadersImpl(status).HandleArguments(
84     args, "PRECOMPILE_HEADERS",
85     TargetPrecompileHeadersImpl::PROCESS_REUSE_FROM);
86 }