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 "cmIncludeCommand.h"
4
5 #include <map>
6 #include <sstream>
7 #include <utility>
8
9 #include "cmExecutionStatus.h"
10 #include "cmGlobalGenerator.h"
11 #include "cmMakefile.h"
12 #include "cmMessageType.h"
13 #include "cmPolicies.h"
14 #include "cmStringAlgorithms.h"
15 #include "cmSystemTools.h"
16
17 // cmIncludeCommand
cmIncludeCommand(std::vector<std::string> const & args,cmExecutionStatus & status)18 bool cmIncludeCommand(std::vector<std::string> const& args,
19 cmExecutionStatus& status)
20 {
21 static std::map<std::string, cmPolicies::PolicyID> DeprecatedModules;
22 if (DeprecatedModules.empty()) {
23 DeprecatedModules["Documentation"] = cmPolicies::CMP0106;
24 DeprecatedModules["WriteCompilerDetectionHeader"] = cmPolicies::CMP0120;
25 }
26
27 if (args.empty() || args.size() > 4) {
28 status.SetError("called with wrong number of arguments. "
29 "include() only takes one file.");
30 return false;
31 }
32 bool optional = false;
33 bool noPolicyScope = false;
34 std::string fname = args[0];
35 std::string resultVarName;
36
37 for (unsigned int i = 1; i < args.size(); i++) {
38 if (args[i] == "OPTIONAL") {
39 if (optional) {
40 status.SetError("called with invalid arguments: OPTIONAL used twice");
41 return false;
42 }
43 optional = true;
44 } else if (args[i] == "RESULT_VARIABLE") {
45 if (!resultVarName.empty()) {
46 status.SetError("called with invalid arguments: "
47 "only one result variable allowed");
48 return false;
49 }
50 if (++i < args.size()) {
51 resultVarName = args[i];
52 } else {
53 status.SetError("called with no value for RESULT_VARIABLE.");
54 return false;
55 }
56 } else if (args[i] == "NO_POLICY_SCOPE") {
57 noPolicyScope = true;
58 } else if (i > 1) // compat.: in previous cmake versions the second
59 // parameter was ignored if it wasn't "OPTIONAL"
60 {
61 std::string errorText =
62 cmStrCat("called with invalid argument: ", args[i]);
63 status.SetError(errorText);
64 return false;
65 }
66 }
67
68 if (fname.empty()) {
69 status.GetMakefile().IssueMessage(
70 MessageType::AUTHOR_WARNING,
71 "include() given empty file name (ignored).");
72 return true;
73 }
74
75 if (!cmSystemTools::FileIsFullPath(fname)) {
76 bool system = false;
77 // Not a path. Maybe module.
78 std::string module = cmStrCat(fname, ".cmake");
79 std::string mfile = status.GetMakefile().GetModulesFile(module, system);
80
81 if (system) {
82 auto ModulePolicy = DeprecatedModules.find(fname);
83 if (ModulePolicy != DeprecatedModules.end()) {
84 cmPolicies::PolicyStatus PolicyStatus =
85 status.GetMakefile().GetPolicyStatus(ModulePolicy->second);
86 switch (PolicyStatus) {
87 case cmPolicies::WARN: {
88 status.GetMakefile().IssueMessage(
89 MessageType::AUTHOR_WARNING,
90 cmStrCat(cmPolicies::GetPolicyWarning(ModulePolicy->second),
91 "\n"));
92 CM_FALLTHROUGH;
93 }
94 case cmPolicies::OLD:
95 break;
96 case cmPolicies::REQUIRED_IF_USED:
97 case cmPolicies::REQUIRED_ALWAYS:
98 case cmPolicies::NEW:
99 mfile = "";
100 break;
101 }
102 }
103 }
104
105 if (!mfile.empty()) {
106 fname = mfile;
107 }
108 }
109
110 std::string fname_abs = cmSystemTools::CollapseFullPath(
111 fname, status.GetMakefile().GetCurrentSourceDirectory());
112
113 cmGlobalGenerator* gg = status.GetMakefile().GetGlobalGenerator();
114 if (gg->IsExportedTargetsFile(fname_abs)) {
115 const char* modal = nullptr;
116 std::ostringstream e;
117 MessageType messageType = MessageType::AUTHOR_WARNING;
118
119 switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0024)) {
120 case cmPolicies::WARN:
121 e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0024) << "\n";
122 modal = "should";
123 CM_FALLTHROUGH;
124 case cmPolicies::OLD:
125 break;
126 case cmPolicies::REQUIRED_IF_USED:
127 case cmPolicies::REQUIRED_ALWAYS:
128 case cmPolicies::NEW:
129 modal = "may";
130 messageType = MessageType::FATAL_ERROR;
131 }
132 if (modal) {
133 e << "The file\n " << fname_abs
134 << "\nwas generated by the export() "
135 "command. It "
136 << modal
137 << " not be used as the argument to the "
138 "include() command. Use ALIAS targets instead to refer to targets "
139 "by alternative names.\n";
140 status.GetMakefile().IssueMessage(messageType, e.str());
141 if (messageType == MessageType::FATAL_ERROR) {
142 return false;
143 }
144 }
145 gg->CreateGenerationObjects();
146 gg->GenerateImportFile(fname_abs);
147 }
148
149 std::string listFile = cmSystemTools::CollapseFullPath(
150 fname, status.GetMakefile().GetCurrentSourceDirectory());
151
152 const bool fileDoesnotExist = !cmSystemTools::FileExists(listFile);
153 const bool fileIsDirectory = cmSystemTools::FileIsDirectory(listFile);
154 if (fileDoesnotExist || fileIsDirectory) {
155 if (!resultVarName.empty()) {
156 status.GetMakefile().AddDefinition(resultVarName, "NOTFOUND");
157 }
158 if (optional) {
159 return true;
160 }
161 if (fileDoesnotExist) {
162 status.SetError(cmStrCat("could not find requested file:\n ", fname));
163 return false;
164 }
165 if (fileIsDirectory) {
166 status.SetError(cmStrCat("requested file is a directory:\n ", fname));
167 return false;
168 }
169 }
170
171 bool readit =
172 status.GetMakefile().ReadDependentFile(listFile, noPolicyScope);
173
174 // add the location of the included file if a result variable was given
175 if (!resultVarName.empty()) {
176 status.GetMakefile().AddDefinition(
177 resultVarName, readit ? fname_abs.c_str() : "NOTFOUND");
178 }
179
180 if (!optional && !readit && !cmSystemTools::GetFatalErrorOccured()) {
181 std::string m = cmStrCat("could not load requested file:\n ", fname);
182 status.SetError(m);
183 return false;
184 }
185 return true;
186 }
187