Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Source / cmCommonTargetGenerator.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 "cmCommonTargetGenerator.h"
4
5 #include <algorithm>
6 #include <sstream>
7 #include <utility>
8
9 #include "cmComputeLinkInformation.h"
10 #include "cmGeneratorTarget.h"
11 #include "cmGlobalCommonGenerator.h"
12 #include "cmGlobalGenerator.h"
13 #include "cmLocalCommonGenerator.h"
14 #include "cmLocalGenerator.h"
15 #include "cmMakefile.h"
16 #include "cmMessageType.h"
17 #include "cmOutputConverter.h"
18 #include "cmRange.h"
19 #include "cmSourceFile.h"
20 #include "cmState.h"
21 #include "cmStateTypes.h"
22 #include "cmStringAlgorithms.h"
23 #include "cmTarget.h"
24 #include "cmValue.h"
25
26 cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt)
27   : GeneratorTarget(gt)
28   , Makefile(gt->Makefile)
29   , LocalCommonGenerator(
30       static_cast<cmLocalCommonGenerator*>(gt->LocalGenerator))
31   , GlobalCommonGenerator(static_cast<cmGlobalCommonGenerator*>(
32       gt->LocalGenerator->GetGlobalGenerator()))
33   , ConfigNames(this->LocalCommonGenerator->GetConfigNames())
34 {
35 }
36
37 cmCommonTargetGenerator::~cmCommonTargetGenerator() = default;
38
39 std::vector<std::string> const& cmCommonTargetGenerator::GetConfigNames() const
40 {
41   return this->ConfigNames;
42 }
43
44 cmValue cmCommonTargetGenerator::GetFeature(const std::string& feature,
45                                             const std::string& config)
46 {
47   return this->GeneratorTarget->GetFeature(feature, config);
48 }
49
50 void cmCommonTargetGenerator::AppendFortranFormatFlags(
51   std::string& flags, cmSourceFile const& source)
52 {
53   const std::string srcfmt = source.GetSafeProperty("Fortran_FORMAT");
54   cmOutputConverter::FortranFormat format =
55     cmOutputConverter::GetFortranFormat(srcfmt);
56   if (format == cmOutputConverter::FortranFormatNone) {
57     std::string const& tgtfmt =
58       this->GeneratorTarget->GetSafeProperty("Fortran_FORMAT");
59     format = cmOutputConverter::GetFortranFormat(tgtfmt);
60   }
61   const char* var = nullptr;
62   switch (format) {
63     case cmOutputConverter::FortranFormatFixed:
64       var = "CMAKE_Fortran_FORMAT_FIXED_FLAG";
65       break;
66     case cmOutputConverter::FortranFormatFree:
67       var = "CMAKE_Fortran_FORMAT_FREE_FLAG";
68       break;
69     default:
70       break;
71   }
72   if (var) {
73     this->LocalCommonGenerator->AppendFlags(
74       flags, this->Makefile->GetSafeDefinition(var));
75   }
76 }
77
78 void cmCommonTargetGenerator::AppendFortranPreprocessFlags(
79   std::string& flags, cmSourceFile const& source,
80   PreprocessFlagsRequired requires_pp)
81 {
82   const std::string srcpp = source.GetSafeProperty("Fortran_PREPROCESS");
83   cmOutputConverter::FortranPreprocess preprocess =
84     cmOutputConverter::GetFortranPreprocess(srcpp);
85   if (preprocess == cmOutputConverter::FortranPreprocess::Unset) {
86     std::string const& tgtpp =
87       this->GeneratorTarget->GetSafeProperty("Fortran_PREPROCESS");
88     preprocess = cmOutputConverter::GetFortranPreprocess(tgtpp);
89   }
90   const char* var = nullptr;
91   switch (preprocess) {
92     case cmOutputConverter::FortranPreprocess::Needed:
93       if (requires_pp == PreprocessFlagsRequired::YES) {
94         var = "CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON";
95       }
96       break;
97     case cmOutputConverter::FortranPreprocess::NotNeeded:
98       var = "CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF";
99       break;
100     default:
101       break;
102   }
103   if (var) {
104     this->LocalCommonGenerator->AppendCompileOptions(
105       flags, this->Makefile->GetSafeDefinition(var));
106   }
107 }
108
109 std::string cmCommonTargetGenerator::GetFlags(const std::string& l,
110                                               const std::string& config,
111                                               const std::string& arch)
112 {
113   const std::string key = config + arch;
114
115   auto i = this->Configs[key].FlagsByLanguage.find(l);
116   if (i == this->Configs[key].FlagsByLanguage.end()) {
117     std::string flags;
118
119     this->LocalCommonGenerator->GetTargetCompileFlags(this->GeneratorTarget,
120                                                       config, l, flags, arch);
121
122     ByLanguageMap::value_type entry(l, flags);
123     i = this->Configs[key].FlagsByLanguage.insert(entry).first;
124   }
125   return i->second;
126 }
127
128 std::string cmCommonTargetGenerator::GetDefines(const std::string& l,
129                                                 const std::string& config)
130 {
131   auto i = this->Configs[config].DefinesByLanguage.find(l);
132   if (i == this->Configs[config].DefinesByLanguage.end()) {
133     std::set<std::string> defines;
134     this->LocalCommonGenerator->GetTargetDefines(this->GeneratorTarget, config,
135                                                  l, defines);
136
137     std::string definesString;
138     this->LocalCommonGenerator->JoinDefines(defines, definesString, l);
139
140     ByLanguageMap::value_type entry(l, definesString);
141     i = this->Configs[config].DefinesByLanguage.insert(entry).first;
142   }
143   return i->second;
144 }
145
146 std::string cmCommonTargetGenerator::GetIncludes(std::string const& l,
147                                                  const std::string& config)
148 {
149   auto i = this->Configs[config].IncludesByLanguage.find(l);
150   if (i == this->Configs[config].IncludesByLanguage.end()) {
151     std::string includes;
152     this->AddIncludeFlags(includes, l, config);
153     ByLanguageMap::value_type entry(l, includes);
154     i = this->Configs[config].IncludesByLanguage.insert(entry).first;
155   }
156   return i->second;
157 }
158
159 std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories(
160   const std::string& config) const
161 {
162   std::vector<std::string> dirs;
163   std::set<cmGeneratorTarget const*> emitted;
164   if (cmComputeLinkInformation* cli =
165         this->GeneratorTarget->GetLinkInformation(config)) {
166     cmComputeLinkInformation::ItemVector const& items = cli->GetItems();
167     for (auto const& item : items) {
168       cmGeneratorTarget const* linkee = item.Target;
169       if (linkee &&
170           !linkee->IsImported()
171           // We can ignore the INTERFACE_LIBRARY items because
172           // Target->GetLinkInformation already processed their
173           // link interface and they don't have any output themselves.
174           && linkee->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
175           emitted.insert(linkee).second) {
176         cmLocalGenerator* lg = linkee->GetLocalGenerator();
177         std::string di = cmStrCat(lg->GetCurrentBinaryDirectory(), '/',
178                                   lg->GetTargetDirectory(linkee));
179         if (lg->GetGlobalGenerator()->IsMultiConfig()) {
180           di = cmStrCat(di, '/', config);
181         }
182         dirs.push_back(std::move(di));
183       }
184     }
185   }
186   return dirs;
187 }
188
189 std::string cmCommonTargetGenerator::ComputeTargetCompilePDB(
190   const std::string& config) const
191 {
192   std::string compilePdbPath;
193   if (this->GeneratorTarget->GetType() > cmStateEnums::OBJECT_LIBRARY) {
194     return compilePdbPath;
195   }
196
197   compilePdbPath = this->GeneratorTarget->GetCompilePDBPath(config);
198   if (compilePdbPath.empty()) {
199     // Match VS default: `$(IntDir)vc$(PlatformToolsetVersion).pdb`.
200     // A trailing slash tells the toolchain to add its default file name.
201     compilePdbPath = this->GeneratorTarget->GetSupportDirectory();
202     if (this->GlobalCommonGenerator->IsMultiConfig()) {
203       compilePdbPath += "/";
204       compilePdbPath += config;
205     }
206     compilePdbPath += "/";
207     if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) {
208       // Match VS default for static libs: `$(IntDir)$(ProjectName).pdb`.
209       compilePdbPath += this->GeneratorTarget->GetName();
210       compilePdbPath += ".pdb";
211     }
212   }
213
214   return compilePdbPath;
215 }
216
217 std::string cmCommonTargetGenerator::GetManifests(const std::string& config)
218 {
219   std::vector<cmSourceFile const*> manifest_srcs;
220   this->GeneratorTarget->GetManifests(manifest_srcs, config);
221
222   std::vector<std::string> manifests;
223   manifests.reserve(manifest_srcs.size());
224
225   std::string lang = this->GeneratorTarget->GetLinkerLanguage(config);
226   std::string const& manifestFlag =
227     this->Makefile->GetDefinition("CMAKE_" + lang + "_LINKER_MANIFEST_FLAG");
228   for (cmSourceFile const* manifest_src : manifest_srcs) {
229     manifests.push_back(manifestFlag +
230                         this->LocalCommonGenerator->ConvertToOutputFormat(
231                           this->LocalCommonGenerator->MaybeRelativeToWorkDir(
232                             manifest_src->GetFullPath()),
233                           cmOutputConverter::SHELL));
234   }
235
236   return cmJoin(manifests, " ");
237 }
238
239 std::string cmCommonTargetGenerator::GetAIXExports(std::string const&)
240 {
241   std::string aixExports;
242   if (this->GeneratorTarget->Target->IsAIX()) {
243     if (cmValue exportAll =
244           this->GeneratorTarget->GetProperty("AIX_EXPORT_ALL_SYMBOLS")) {
245       if (cmIsOff(*exportAll)) {
246         aixExports = "-n";
247       }
248     }
249   }
250   return aixExports;
251 }
252
253 void cmCommonTargetGenerator::AppendOSXVerFlag(std::string& flags,
254                                                const std::string& lang,
255                                                const char* name, bool so)
256 {
257   // Lookup the flag to specify the version.
258   std::string fvar = cmStrCat("CMAKE_", lang, "_OSX_", name, "_VERSION_FLAG");
259   cmValue flag = this->Makefile->GetDefinition(fvar);
260
261   // Skip if no such flag.
262   if (!flag) {
263     return;
264   }
265
266   // Lookup the target version information.
267   int major;
268   int minor;
269   int patch;
270   std::string prop = cmStrCat("MACHO_", name, "_VERSION");
271   std::string fallback_prop = so ? "SOVERSION" : "VERSION";
272   this->GeneratorTarget->GetTargetVersionFallback(prop, fallback_prop, major,
273                                                   minor, patch);
274   if (major > 0 || minor > 0 || patch > 0) {
275     // Append the flag since a non-zero version is specified.
276     std::ostringstream vflag;
277     vflag << *flag << major << "." << minor << "." << patch;
278     this->LocalCommonGenerator->AppendFlags(flags, vflag.str());
279   }
280 }
281
282 std::string cmCommonTargetGenerator::GetLinkerLauncher(
283   const std::string& config)
284 {
285   std::string lang = this->GeneratorTarget->GetLinkerLanguage(config);
286   cmValue launcherProp =
287     this->GeneratorTarget->GetProperty(lang + "_LINKER_LAUNCHER");
288   if (cmNonempty(launcherProp)) {
289     // Convert ;-delimited list to single string
290     std::vector<std::string> args = cmExpandedList(*launcherProp, true);
291     if (!args.empty()) {
292       args[0] = this->LocalCommonGenerator->ConvertToOutputFormat(
293         args[0], cmOutputConverter::SHELL);
294       for (std::string& i : cmMakeRange(args.begin() + 1, args.end())) {
295         i = this->LocalCommonGenerator->EscapeForShell(i);
296       }
297       return cmJoin(args, " ");
298     }
299   }
300   return std::string();
301 }
302
303 bool cmCommonTargetGenerator::HaveRequiredLanguages(
304   const std::vector<cmSourceFile const*>& sources,
305   std::set<std::string>& languagesNeeded) const
306 {
307   for (cmSourceFile const* sf : sources) {
308     languagesNeeded.insert(sf->GetLanguage());
309   }
310
311   auto* makefile = this->Makefile;
312   auto* state = makefile->GetState();
313   auto unary = [&state, &makefile](const std::string& lang) -> bool {
314     const bool valid = state->GetLanguageEnabled(lang);
315     if (!valid) {
316       makefile->IssueMessage(
317         MessageType::FATAL_ERROR,
318         cmStrCat("The language ", lang,
319                  " was requested for compilation but was not enabled."
320                  " To enable a language it needs to be specified in a"
321                  " 'project' or 'enable_language' command in the root"
322                  " CMakeLists.txt"));
323     }
324     return valid;
325   };
326   return std::all_of(languagesNeeded.cbegin(), languagesNeeded.cend(), unary);
327 }