1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
12 #include "cmTargetLinkLibrariesCommand.h"
14 #include "cmGeneratorExpression.h"
16 const char* cmTargetLinkLibrariesCommand::LinkLibraryTypeNames[3] =
23 // cmTargetLinkLibrariesCommand
24 bool cmTargetLinkLibrariesCommand
25 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
27 // must have one argument
30 this->SetError("called with incorrect number of arguments");
34 if (this->Makefile->IsAlias(args[0].c_str()))
36 this->SetError("can not be used on an ALIAS target.");
39 // Lookup the target for which libraries are specified.
41 this->Makefile->GetCMakeInstance()
42 ->GetGlobalGenerator()->FindTarget(0, args[0].c_str());
45 cmake::MessageType t = cmake::FATAL_ERROR; // fail by default
47 e << "Cannot specify link libraries for target \"" << args[0] << "\" "
48 << "which is not built by this project.";
49 // The bad target is the only argument. Check how policy CMP0016 is set,
50 // and accept, warn or fail respectively:
53 switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0016))
55 case cmPolicies::WARN:
56 t = cmake::AUTHOR_WARNING;
59 << "CMake does not support this but it used to work accidentally "
60 << "and is being allowed for compatibility."
61 << "\n" << this->Makefile->GetPolicies()->
62 GetPolicyWarning(cmPolicies::CMP0016);
64 case cmPolicies::OLD: // OLD behavior does not warn.
67 case cmPolicies::REQUIRED_IF_USED:
68 case cmPolicies::REQUIRED_ALWAYS:
69 e << "\n" << this->Makefile->GetPolicies()->
70 GetRequiredPolicyError(cmPolicies::CMP0016);
72 case cmPolicies::NEW: // NEW behavior prints the error.
78 // now actually print the message
81 case cmake::AUTHOR_WARNING:
82 this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, e.str());
84 case cmake::FATAL_ERROR:
85 this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
86 cmSystemTools::SetFatalErrorOccured();
94 if(this->Target->GetType() == cmTarget::OBJECT_LIBRARY)
97 e << "Object library target \"" << args[0] << "\" "
98 << "may not link to anything.";
99 this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
100 cmSystemTools::SetFatalErrorOccured();
104 // but we might not have any libs after variable expansion
110 // Keep track of link configuration specifiers.
111 cmTarget::LinkLibraryType llt = cmTarget::GENERAL;
112 bool haveLLT = false;
114 // Start with primary linking and switch to link interface
115 // specification if the keyword is encountered as the first argument.
116 this->CurrentProcessingState = ProcessingLinkLibraries;
118 // add libraries, note that there is an optional prefix
119 // of debug and optimized that can be used
120 for(unsigned int i=1; i < args.size(); ++i)
122 if(args[i] == "LINK_INTERFACE_LIBRARIES")
124 this->CurrentProcessingState = ProcessingPlainLinkInterface;
127 this->Makefile->IssueMessage(
129 "The LINK_INTERFACE_LIBRARIES option must appear as the second "
130 "argument, just after the target name."
135 else if(args[i] == "INTERFACE")
138 && this->CurrentProcessingState != ProcessingKeywordPrivateInterface
139 && this->CurrentProcessingState != ProcessingKeywordPublicInterface
140 && this->CurrentProcessingState != ProcessingKeywordLinkInterface)
142 this->Makefile->IssueMessage(
144 "The INTERFACE option must appear as the second "
145 "argument, just after the target name."
149 this->CurrentProcessingState = ProcessingKeywordLinkInterface;
151 else if(args[i] == "LINK_PUBLIC")
154 && this->CurrentProcessingState != ProcessingPlainPrivateInterface)
156 this->Makefile->IssueMessage(
158 "The LINK_PUBLIC or LINK_PRIVATE option must appear as the second "
159 "argument, just after the target name."
163 this->CurrentProcessingState = ProcessingPlainPublicInterface;
165 else if(args[i] == "PUBLIC")
168 && this->CurrentProcessingState != ProcessingKeywordPrivateInterface
169 && this->CurrentProcessingState != ProcessingKeywordPublicInterface
170 && this->CurrentProcessingState != ProcessingKeywordLinkInterface)
172 this->Makefile->IssueMessage(
174 "The PUBLIC or PRIVATE option must appear as the second "
175 "argument, just after the target name."
179 this->CurrentProcessingState = ProcessingKeywordPublicInterface;
181 else if(args[i] == "LINK_PRIVATE")
184 && this->CurrentProcessingState != ProcessingPlainPublicInterface)
186 this->Makefile->IssueMessage(
188 "The LINK_PUBLIC or LINK_PRIVATE option must appear as the second "
189 "argument, just after the target name."
193 this->CurrentProcessingState = ProcessingPlainPrivateInterface;
195 else if(args[i] == "PRIVATE")
198 && this->CurrentProcessingState != ProcessingKeywordPrivateInterface
199 && this->CurrentProcessingState != ProcessingKeywordPublicInterface
200 && this->CurrentProcessingState != ProcessingKeywordLinkInterface)
202 this->Makefile->IssueMessage(
204 "The PUBLIC or PRIVATE option must appear as the second "
205 "argument, just after the target name."
209 this->CurrentProcessingState = ProcessingKeywordPrivateInterface;
211 else if(args[i] == "debug")
215 this->LinkLibraryTypeSpecifierWarning(llt, cmTarget::DEBUG);
217 llt = cmTarget::DEBUG;
220 else if(args[i] == "optimized")
224 this->LinkLibraryTypeSpecifierWarning(llt, cmTarget::OPTIMIZED);
226 llt = cmTarget::OPTIMIZED;
229 else if(args[i] == "general")
233 this->LinkLibraryTypeSpecifierWarning(llt, cmTarget::GENERAL);
235 llt = cmTarget::GENERAL;
240 // The link type was specified by the previous argument.
242 if (!this->HandleLibrary(args[i].c_str(), llt))
249 // Lookup old-style cache entry if type is unspecified. So if you
250 // do a target_link_libraries(foo optimized bar) it will stay optimized
251 // and not use the lookup. As there maybe the case where someone has
252 // specifed that a library is both debug and optimized. (this check is
253 // only there for backwards compatibility when mixing projects built
254 // with old versions of CMake and new)
255 llt = cmTarget::GENERAL;
256 std::string linkType = args[0];
257 linkType += "_LINK_TYPE";
258 const char* linkTypeString =
259 this->Makefile->GetDefinition( linkType.c_str() );
262 if(strcmp(linkTypeString, "debug") == 0)
264 llt = cmTarget::DEBUG;
266 if(strcmp(linkTypeString, "optimized") == 0)
268 llt = cmTarget::OPTIMIZED;
271 if (!this->HandleLibrary(args[i].c_str(), llt))
278 // Make sure the last argument was not a library type specifier.
282 e << "The \"" << this->LinkLibraryTypeNames[llt]
283 << "\" argument must be followed by a library.";
284 this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
285 cmSystemTools::SetFatalErrorOccured();
288 const cmPolicies::PolicyStatus policy22Status
289 = this->Target->GetPolicyStatusCMP0022();
291 // If any of the LINK_ options were given, make sure the
292 // LINK_INTERFACE_LIBRARIES target property exists.
293 // Use of any of the new keywords implies awareness of
294 // this property. And if no libraries are named, it should
295 // result in an empty link interface.
296 if((policy22Status == cmPolicies::OLD ||
297 policy22Status == cmPolicies::WARN) &&
298 this->CurrentProcessingState != ProcessingLinkLibraries &&
299 !this->Target->GetProperty("LINK_INTERFACE_LIBRARIES"))
301 this->Target->SetProperty("LINK_INTERFACE_LIBRARIES", "");
307 //----------------------------------------------------------------------------
309 cmTargetLinkLibrariesCommand
310 ::LinkLibraryTypeSpecifierWarning(int left, int right)
313 w << "Link library type specifier \""
314 << this->LinkLibraryTypeNames[left] << "\" is followed by specifier \""
315 << this->LinkLibraryTypeNames[right] << "\" instead of a library name. "
316 << "The first specifier will be ignored.";
317 this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
320 //----------------------------------------------------------------------------
322 cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
323 cmTarget::LinkLibraryType llt)
325 cmTarget::TLLSignature sig =
326 (this->CurrentProcessingState == ProcessingPlainPrivateInterface
327 || this->CurrentProcessingState == ProcessingPlainPublicInterface
328 || this->CurrentProcessingState == ProcessingKeywordPrivateInterface
329 || this->CurrentProcessingState == ProcessingKeywordPublicInterface
330 || this->CurrentProcessingState == ProcessingKeywordLinkInterface)
331 ? cmTarget::KeywordTLLSignature : cmTarget::PlainTLLSignature;
332 if (!this->Target->PushTLLCommandTrace(sig))
334 const char *modal = 0;
335 cmake::MessageType messageType = cmake::AUTHOR_WARNING;
336 switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0023))
338 case cmPolicies::WARN:
340 case cmPolicies::OLD:
342 case cmPolicies::REQUIRED_ALWAYS:
343 case cmPolicies::REQUIRED_IF_USED:
344 case cmPolicies::NEW:
346 messageType = cmake::FATAL_ERROR;
352 // If the sig is a keyword form and there is a conflict, the existing
353 // form must be the plain form.
354 const char *existingSig
355 = (sig == cmTarget::KeywordTLLSignature ? "plain"
357 e << this->Makefile->GetPolicies()
358 ->GetPolicyWarning(cmPolicies::CMP0023) << "\n"
359 "The " << existingSig << " signature for target_link_libraries "
360 "has already been used with the target \""
361 << this->Target->GetName() << "\". All uses of "
362 "target_link_libraries with a target " << modal << " be either "
363 "all-keyword or all-plain.\n";
364 this->Target->GetTllSignatureTraces(e,
365 sig == cmTarget::KeywordTLLSignature
366 ? cmTarget::PlainTLLSignature
367 : cmTarget::KeywordTLLSignature);
368 this->Makefile->IssueMessage(messageType, e.str().c_str());
369 if(messageType == cmake::FATAL_ERROR)
376 // Handle normal case first.
377 if(this->CurrentProcessingState != ProcessingKeywordLinkInterface
378 && this->CurrentProcessingState != ProcessingPlainLinkInterface)
381 ->AddLinkLibraryForTarget(this->Target->GetName(), lib, llt);
382 if(this->CurrentProcessingState == ProcessingLinkLibraries)
384 this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES",
385 this->Target->GetDebugGeneratorExpressions(lib, llt).c_str());
388 else if(this->CurrentProcessingState != ProcessingKeywordPublicInterface
389 && this->CurrentProcessingState != ProcessingPlainPublicInterface)
391 if (this->Target->GetType() == cmTarget::STATIC_LIBRARY)
393 std::string configLib = this->Target
394 ->GetDebugGeneratorExpressions(lib, llt);
395 if (cmGeneratorExpression::IsValidTargetName(lib)
396 || cmGeneratorExpression::Find(lib) != std::string::npos)
398 configLib = "$<LINK_ONLY:" + configLib + ">";
400 this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES",
403 // Not a 'public' or 'interface' library. Do not add to interface
409 this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES",
410 this->Target->GetDebugGeneratorExpressions(lib, llt).c_str());
412 const cmPolicies::PolicyStatus policy22Status
413 = this->Target->GetPolicyStatusCMP0022();
415 if (policy22Status != cmPolicies::OLD
416 && policy22Status != cmPolicies::WARN)
421 // Get the list of configurations considered to be DEBUG.
422 std::vector<std::string> const& debugConfigs =
423 this->Makefile->GetCMakeInstance()->GetDebugConfigs();
426 // Include this library in the link interface for the target.
427 if(llt == cmTarget::DEBUG || llt == cmTarget::GENERAL)
429 // Put in the DEBUG configuration interfaces.
430 for(std::vector<std::string>::const_iterator i = debugConfigs.begin();
431 i != debugConfigs.end(); ++i)
433 prop = "LINK_INTERFACE_LIBRARIES_";
435 this->Target->AppendProperty(prop.c_str(), lib);
438 if(llt == cmTarget::OPTIMIZED || llt == cmTarget::GENERAL)
440 // Put in the non-DEBUG configuration interfaces.
441 this->Target->AppendProperty("LINK_INTERFACE_LIBRARIES", lib);
443 // Make sure the DEBUG configuration interfaces exist so that the
444 // general one will not be used as a fall-back.
445 for(std::vector<std::string>::const_iterator i = debugConfigs.begin();
446 i != debugConfigs.end(); ++i)
448 prop = "LINK_INTERFACE_LIBRARIES_";
450 if(!this->Target->GetProperty(prop.c_str()))
452 this->Target->SetProperty(prop.c_str(), "");