summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Goulet <robert.goulet@autodesk.com>2015-08-14 20:35:58 (GMT)
committerBrad King <brad.king@kitware.com>2015-08-20 13:56:45 (GMT)
commit3c37d2642d9000a2d01bc46ad0ea74a741bdb658 (patch)
treec1bb63b2a35fbb0de0691c88e1c4535cee6d0f4e
parenta38ea312c02eec6e4ee61015f70920999bf79ff9 (diff)
downloadCMake-3c37d2642d9000a2d01bc46ad0ea74a741bdb658.zip
CMake-3c37d2642d9000a2d01bc46ad0ea74a741bdb658.tar.gz
CMake-3c37d2642d9000a2d01bc46ad0ea74a741bdb658.tar.bz2
cmGeneratorTarget: Avoid recursion in GetOutputName method
Since support for generator expressions was added to OUTPUT_NAME it is possible for project code to cause recursion in this method by using a $<TARGET_FILE> genex. Detect and reject such cases.
-rw-r--r--Source/cmGeneratorTarget.cxx93
-rw-r--r--Source/cmGeneratorTarget.h4
-rw-r--r--Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion.cmake3
-rw-r--r--Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion.cmake1
7 files changed, 72 insertions, 35 deletions
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 299c112..530acfe 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -270,48 +270,71 @@ const char *cmGeneratorTarget::GetProperty(const std::string& prop) const
std::string cmGeneratorTarget::GetOutputName(const std::string& config,
bool implib) const
{
- std::vector<std::string> props;
- std::string type = this->Target->GetOutputTargetType(implib);
- std::string configUpper = cmSystemTools::UpperCase(config);
- if(!type.empty() && !configUpper.empty())
- {
- // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
- props.push_back(type + "_OUTPUT_NAME_" + configUpper);
- }
- if(!type.empty())
+ // Lookup/compute/cache the output name for this configuration.
+ OutputNameKey key(config, implib);
+ cmGeneratorTarget::OutputNameMapType::iterator i =
+ this->OutputNameMap.find(key);
+ if(i == this->OutputNameMap.end())
{
- // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME
- props.push_back(type + "_OUTPUT_NAME");
- }
- if(!configUpper.empty())
- {
- // OUTPUT_NAME_<CONFIG>
- props.push_back("OUTPUT_NAME_" + configUpper);
- // <CONFIG>_OUTPUT_NAME
- props.push_back(configUpper + "_OUTPUT_NAME");
- }
- // OUTPUT_NAME
- props.push_back("OUTPUT_NAME");
+ // Add empty name in map to detect potential recursion.
+ OutputNameMapType::value_type entry(key, "");
+ i = this->OutputNameMap.insert(entry).first;
- std::string outName;
- for(std::vector<std::string>::const_iterator i = props.begin();
- i != props.end(); ++i)
- {
- if (const char* outNameProp = this->Target->GetProperty(*i))
+ // Compute output name.
+ std::vector<std::string> props;
+ std::string type = this->Target->GetOutputTargetType(implib);
+ std::string configUpper = cmSystemTools::UpperCase(config);
+ if(!type.empty() && !configUpper.empty())
{
- outName = outNameProp;
- break;
+ // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
+ props.push_back(type + "_OUTPUT_NAME_" + configUpper);
+ }
+ if(!type.empty())
+ {
+ // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME
+ props.push_back(type + "_OUTPUT_NAME");
+ }
+ if(!configUpper.empty())
+ {
+ // OUTPUT_NAME_<CONFIG>
+ props.push_back("OUTPUT_NAME_" + configUpper);
+ // <CONFIG>_OUTPUT_NAME
+ props.push_back(configUpper + "_OUTPUT_NAME");
+ }
+ // OUTPUT_NAME
+ props.push_back("OUTPUT_NAME");
+
+ std::string outName;
+ for(std::vector<std::string>::const_iterator it = props.begin();
+ it != props.end(); ++it)
+ {
+ if (const char* outNameProp = this->Target->GetProperty(*it))
+ {
+ outName = outNameProp;
+ break;
+ }
}
- }
- if (outName.empty())
+ if(outName.empty())
+ {
+ outName = this->GetName();
+ }
+
+ // Now evaluate genex and update the previously-prepared map entry.
+ cmGeneratorExpression ge;
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(outName);
+ i->second = cge->Evaluate(this->Makefile, config);
+ }
+ else if(i->second.empty())
{
- outName = this->GetName();
+ // An empty map entry indicates we have been called recursively
+ // from the above block.
+ this->Makefile->GetCMakeInstance()->IssueMessage(
+ cmake::FATAL_ERROR,
+ "Target '" + this->GetName() + "' OUTPUT_NAME depends on itself.",
+ this->Target->GetBacktrace());
}
-
- cmGeneratorExpression ge;
- cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(outName);
- return cge->Evaluate(this->Makefile, config);
+ return i->second;
}
//----------------------------------------------------------------------------
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 68e7a8a..15b3335 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -375,6 +375,10 @@ private:
};
mutable std::map<std::string, LinkImplClosure> LinkImplClosureMap;
+ typedef std::pair<std::string, bool> OutputNameKey;
+ typedef std::map<OutputNameKey, std::string> OutputNameMapType;
+ mutable OutputNameMapType OutputNameMap;
+
public:
std::vector<cmTarget const*> const&
GetLinkImplementationClosure(const std::string& config) const;
diff --git a/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-result.txt b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-stderr.txt b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-stderr.txt
new file mode 100644
index 0000000..bf592e7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at OUTPUT_NAME-recursion.cmake:[0-9]+ \(add_executable\):
+ Target 'empty1' OUTPUT_NAME depends on itself.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion.cmake b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion.cmake
new file mode 100644
index 0000000..5cb8050
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+add_executable(empty1 empty.c)
+set_property(TARGET empty1 PROPERTY OUTPUT_NAME $<TARGET_FILE_NAME:empty1>)
diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
index 21fc851..0679024 100644
--- a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
@@ -26,6 +26,7 @@ run_cmake(COMPILE_LANGUAGE-add_library)
run_cmake(COMPILE_LANGUAGE-add_test)
run_cmake(COMPILE_LANGUAGE-unknown-lang)
run_cmake(TARGET_FILE-recursion)
+run_cmake(OUTPUT_NAME-recursion)
run_cmake(ImportedTarget-TARGET_PDB_FILE)
if(LINKER_SUPPORTS_PDB)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion.cmake
index 7633be1..e780103 100644
--- a/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion.cmake
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion.cmake
@@ -1,3 +1,4 @@
enable_language(C)
add_executable(empty1 empty.c)
+set_property(TARGET empty1 PROPERTY OUTPUT_NAME $<TARGET_FILE_NAME:empty1>)
set_property(TARGET empty1 PROPERTY RUNTIME_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:empty1>)