mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
Merge topic 'tll-genex-concat'
c1e812ad4ftarget_link_libraries: Improve tolerance of unquoted generator expressions5571a31648target_link_libraries: Handle keyword arguments in dedicated code path42590df9f9target_link_libraries: Remove likely-broken ancient compatibility check Acked-by: Kitware Robot <kwrobot@kitware.com> Acked-by: buildbot <buildbot@kitware.com> Merge-request: !6989
This commit is contained in:
@@ -2,11 +2,14 @@
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#include "cmTargetLinkLibrariesCommand.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
#include <cm/optional>
|
||||
|
||||
#include "cmExecutionStatus.h"
|
||||
#include "cmGeneratorExpression.h"
|
||||
#include "cmGlobalGenerator.h"
|
||||
@@ -178,123 +181,156 @@ bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args,
|
||||
// specification if the keyword is encountered as the first argument.
|
||||
ProcessingState currentProcessingState = ProcessingLinkLibraries;
|
||||
|
||||
// Accumulate consectuive non-keyword arguments into one entry in
|
||||
// order to handle unquoted generator expressions containing ';'.
|
||||
cm::optional<std::string> currentEntry;
|
||||
auto processCurrentEntry = [&]() -> bool {
|
||||
if (currentEntry) {
|
||||
assert(!haveLLT);
|
||||
if (!tll.HandleLibrary(currentProcessingState, *currentEntry,
|
||||
GENERAL_LibraryType)) {
|
||||
return false;
|
||||
}
|
||||
currentEntry = cm::nullopt;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
auto extendCurrentEntry = [¤tEntry](std::string const& arg) {
|
||||
if (currentEntry) {
|
||||
currentEntry = cmStrCat(*currentEntry, ';', arg);
|
||||
} else {
|
||||
currentEntry = arg;
|
||||
}
|
||||
};
|
||||
|
||||
// Keep this list in sync with the keyword dispatch below.
|
||||
static std::unordered_set<std::string> const keywords{
|
||||
"LINK_INTERFACE_LIBRARIES",
|
||||
"INTERFACE",
|
||||
"LINK_PUBLIC",
|
||||
"PUBLIC",
|
||||
"LINK_PRIVATE",
|
||||
"PRIVATE",
|
||||
"debug",
|
||||
"optimized",
|
||||
"general",
|
||||
};
|
||||
|
||||
// Add libraries, note that there is an optional prefix
|
||||
// of debug and optimized that can be used.
|
||||
for (unsigned int i = 1; i < args.size(); ++i) {
|
||||
if (args[i] == "LINK_INTERFACE_LIBRARIES") {
|
||||
currentProcessingState = ProcessingPlainLinkInterface;
|
||||
if (i != 1) {
|
||||
mf.IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
"The LINK_INTERFACE_LIBRARIES option must appear as the second "
|
||||
"argument, just after the target name.");
|
||||
return true;
|
||||
if (keywords.count(args[i])) {
|
||||
// A keyword argument terminates any preceding accumulated entry.
|
||||
if (!processCurrentEntry()) {
|
||||
return false;
|
||||
}
|
||||
} else if (args[i] == "INTERFACE") {
|
||||
if (i != 1 &&
|
||||
currentProcessingState != ProcessingKeywordPrivateInterface &&
|
||||
currentProcessingState != ProcessingKeywordPublicInterface &&
|
||||
currentProcessingState != ProcessingKeywordLinkInterface) {
|
||||
mf.IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
"The INTERFACE, PUBLIC or PRIVATE option must appear as the second "
|
||||
"argument, just after the target name.");
|
||||
return true;
|
||||
|
||||
// Process this keyword argument.
|
||||
if (args[i] == "LINK_INTERFACE_LIBRARIES") {
|
||||
currentProcessingState = ProcessingPlainLinkInterface;
|
||||
if (i != 1) {
|
||||
mf.IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
"The LINK_INTERFACE_LIBRARIES option must appear as the "
|
||||
"second argument, just after the target name.");
|
||||
return true;
|
||||
}
|
||||
} else if (args[i] == "INTERFACE") {
|
||||
if (i != 1 &&
|
||||
currentProcessingState != ProcessingKeywordPrivateInterface &&
|
||||
currentProcessingState != ProcessingKeywordPublicInterface &&
|
||||
currentProcessingState != ProcessingKeywordLinkInterface) {
|
||||
mf.IssueMessage(MessageType::FATAL_ERROR,
|
||||
"The INTERFACE, PUBLIC or PRIVATE option must "
|
||||
"appear as the second argument, just after the "
|
||||
"target name.");
|
||||
return true;
|
||||
}
|
||||
currentProcessingState = ProcessingKeywordLinkInterface;
|
||||
} else if (args[i] == "LINK_PUBLIC") {
|
||||
if (i != 1 &&
|
||||
currentProcessingState != ProcessingPlainPrivateInterface &&
|
||||
currentProcessingState != ProcessingPlainPublicInterface) {
|
||||
mf.IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
"The LINK_PUBLIC or LINK_PRIVATE option must appear as the "
|
||||
"second argument, just after the target name.");
|
||||
return true;
|
||||
}
|
||||
currentProcessingState = ProcessingPlainPublicInterface;
|
||||
} else if (args[i] == "PUBLIC") {
|
||||
if (i != 1 &&
|
||||
currentProcessingState != ProcessingKeywordPrivateInterface &&
|
||||
currentProcessingState != ProcessingKeywordPublicInterface &&
|
||||
currentProcessingState != ProcessingKeywordLinkInterface) {
|
||||
mf.IssueMessage(MessageType::FATAL_ERROR,
|
||||
"The INTERFACE, PUBLIC or PRIVATE option must "
|
||||
"appear as the second argument, just after the "
|
||||
"target name.");
|
||||
return true;
|
||||
}
|
||||
currentProcessingState = ProcessingKeywordPublicInterface;
|
||||
} else if (args[i] == "LINK_PRIVATE") {
|
||||
if (i != 1 &&
|
||||
currentProcessingState != ProcessingPlainPublicInterface &&
|
||||
currentProcessingState != ProcessingPlainPrivateInterface) {
|
||||
mf.IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
"The LINK_PUBLIC or LINK_PRIVATE option must appear as the "
|
||||
"second argument, just after the target name.");
|
||||
return true;
|
||||
}
|
||||
currentProcessingState = ProcessingPlainPrivateInterface;
|
||||
} else if (args[i] == "PRIVATE") {
|
||||
if (i != 1 &&
|
||||
currentProcessingState != ProcessingKeywordPrivateInterface &&
|
||||
currentProcessingState != ProcessingKeywordPublicInterface &&
|
||||
currentProcessingState != ProcessingKeywordLinkInterface) {
|
||||
mf.IssueMessage(MessageType::FATAL_ERROR,
|
||||
"The INTERFACE, PUBLIC or PRIVATE option must "
|
||||
"appear as the second argument, just after the "
|
||||
"target name.");
|
||||
return true;
|
||||
}
|
||||
currentProcessingState = ProcessingKeywordPrivateInterface;
|
||||
} else if (args[i] == "debug") {
|
||||
if (haveLLT) {
|
||||
LinkLibraryTypeSpecifierWarning(mf, llt, DEBUG_LibraryType);
|
||||
}
|
||||
llt = DEBUG_LibraryType;
|
||||
haveLLT = true;
|
||||
} else if (args[i] == "optimized") {
|
||||
if (haveLLT) {
|
||||
LinkLibraryTypeSpecifierWarning(mf, llt, OPTIMIZED_LibraryType);
|
||||
}
|
||||
llt = OPTIMIZED_LibraryType;
|
||||
haveLLT = true;
|
||||
} else if (args[i] == "general") {
|
||||
if (haveLLT) {
|
||||
LinkLibraryTypeSpecifierWarning(mf, llt, GENERAL_LibraryType);
|
||||
}
|
||||
llt = GENERAL_LibraryType;
|
||||
haveLLT = true;
|
||||
}
|
||||
currentProcessingState = ProcessingKeywordLinkInterface;
|
||||
} else if (args[i] == "LINK_PUBLIC") {
|
||||
if (i != 1 &&
|
||||
currentProcessingState != ProcessingPlainPrivateInterface &&
|
||||
currentProcessingState != ProcessingPlainPublicInterface) {
|
||||
mf.IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
"The LINK_PUBLIC or LINK_PRIVATE option must appear as the second "
|
||||
"argument, just after the target name.");
|
||||
return true;
|
||||
}
|
||||
currentProcessingState = ProcessingPlainPublicInterface;
|
||||
} else if (args[i] == "PUBLIC") {
|
||||
if (i != 1 &&
|
||||
currentProcessingState != ProcessingKeywordPrivateInterface &&
|
||||
currentProcessingState != ProcessingKeywordPublicInterface &&
|
||||
currentProcessingState != ProcessingKeywordLinkInterface) {
|
||||
mf.IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
"The INTERFACE, PUBLIC or PRIVATE option must appear as the second "
|
||||
"argument, just after the target name.");
|
||||
return true;
|
||||
}
|
||||
currentProcessingState = ProcessingKeywordPublicInterface;
|
||||
} else if (args[i] == "LINK_PRIVATE") {
|
||||
if (i != 1 && currentProcessingState != ProcessingPlainPublicInterface &&
|
||||
currentProcessingState != ProcessingPlainPrivateInterface) {
|
||||
mf.IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
"The LINK_PUBLIC or LINK_PRIVATE option must appear as the second "
|
||||
"argument, just after the target name.");
|
||||
return true;
|
||||
}
|
||||
currentProcessingState = ProcessingPlainPrivateInterface;
|
||||
} else if (args[i] == "PRIVATE") {
|
||||
if (i != 1 &&
|
||||
currentProcessingState != ProcessingKeywordPrivateInterface &&
|
||||
currentProcessingState != ProcessingKeywordPublicInterface &&
|
||||
currentProcessingState != ProcessingKeywordLinkInterface) {
|
||||
mf.IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
"The INTERFACE, PUBLIC or PRIVATE option must appear as the second "
|
||||
"argument, just after the target name.");
|
||||
return true;
|
||||
}
|
||||
currentProcessingState = ProcessingKeywordPrivateInterface;
|
||||
} else if (args[i] == "debug") {
|
||||
if (haveLLT) {
|
||||
LinkLibraryTypeSpecifierWarning(mf, llt, DEBUG_LibraryType);
|
||||
}
|
||||
llt = DEBUG_LibraryType;
|
||||
haveLLT = true;
|
||||
} else if (args[i] == "optimized") {
|
||||
if (haveLLT) {
|
||||
LinkLibraryTypeSpecifierWarning(mf, llt, OPTIMIZED_LibraryType);
|
||||
}
|
||||
llt = OPTIMIZED_LibraryType;
|
||||
haveLLT = true;
|
||||
} else if (args[i] == "general") {
|
||||
if (haveLLT) {
|
||||
LinkLibraryTypeSpecifierWarning(mf, llt, GENERAL_LibraryType);
|
||||
}
|
||||
llt = GENERAL_LibraryType;
|
||||
haveLLT = true;
|
||||
} else if (haveLLT) {
|
||||
// The link type was specified by the previous argument.
|
||||
haveLLT = false;
|
||||
assert(!currentEntry);
|
||||
if (!tll.HandleLibrary(currentProcessingState, args[i], llt)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Lookup old-style cache entry if type is unspecified. So if you
|
||||
// do a target_link_libraries(foo optimized bar) it will stay optimized
|
||||
// and not use the lookup. As there may be the case where someone has
|
||||
// specified that a library is both debug and optimized. (this check is
|
||||
// only there for backwards compatibility when mixing projects built
|
||||
// with old versions of CMake and new)
|
||||
llt = GENERAL_LibraryType;
|
||||
std::string linkType = cmStrCat(args[0], "_LINK_TYPE");
|
||||
cmValue linkTypeString = mf.GetDefinition(linkType);
|
||||
if (linkTypeString) {
|
||||
if (*linkTypeString == "debug") {
|
||||
llt = DEBUG_LibraryType;
|
||||
}
|
||||
if (*linkTypeString == "optimized") {
|
||||
llt = OPTIMIZED_LibraryType;
|
||||
}
|
||||
}
|
||||
if (!tll.HandleLibrary(currentProcessingState, args[i], llt)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Accumulate this argument in the current entry.
|
||||
extendCurrentEntry(args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Process the last accumulated entry, if any.
|
||||
if (!processCurrentEntry()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the last argument was not a library type specifier.
|
||||
if (haveLLT) {
|
||||
mf.IssueMessage(MessageType::FATAL_ERROR,
|
||||
|
||||
Reference in New Issue
Block a user