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