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.
This commit is contained in:
parent
a38ea312c0
commit
3c37d2642d
|
@ -270,48 +270,71 @@ const char *cmGeneratorTarget::GetProperty(const std::string& prop) const
|
||||||
std::string cmGeneratorTarget::GetOutputName(const std::string& config,
|
std::string cmGeneratorTarget::GetOutputName(const std::string& config,
|
||||||
bool implib) const
|
bool implib) const
|
||||||
{
|
{
|
||||||
std::vector<std::string> props;
|
// Lookup/compute/cache the output name for this configuration.
|
||||||
std::string type = this->Target->GetOutputTargetType(implib);
|
OutputNameKey key(config, implib);
|
||||||
std::string configUpper = cmSystemTools::UpperCase(config);
|
cmGeneratorTarget::OutputNameMapType::iterator i =
|
||||||
if(!type.empty() && !configUpper.empty())
|
this->OutputNameMap.find(key);
|
||||||
|
if(i == this->OutputNameMap.end())
|
||||||
{
|
{
|
||||||
// <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
|
// Add empty name in map to detect potential recursion.
|
||||||
props.push_back(type + "_OUTPUT_NAME_" + configUpper);
|
OutputNameMapType::value_type entry(key, "");
|
||||||
}
|
i = this->OutputNameMap.insert(entry).first;
|
||||||
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;
|
// Compute output name.
|
||||||
for(std::vector<std::string>::const_iterator i = props.begin();
|
std::vector<std::string> props;
|
||||||
i != props.end(); ++i)
|
std::string type = this->Target->GetOutputTargetType(implib);
|
||||||
{
|
std::string configUpper = cmSystemTools::UpperCase(config);
|
||||||
if (const char* outNameProp = this->Target->GetProperty(*i))
|
if(!type.empty() && !configUpper.empty())
|
||||||
{
|
{
|
||||||
outName = outNameProp;
|
// <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
|
||||||
break;
|
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");
|
||||||
|
|
||||||
if (outName.empty())
|
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())
|
||||||
|
{
|
||||||
|
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());
|
||||||
}
|
}
|
||||||
|
return i->second;
|
||||||
cmGeneratorExpression ge;
|
|
||||||
cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(outName);
|
|
||||||
return cge->Evaluate(this->Makefile, config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -375,6 +375,10 @@ private:
|
||||||
};
|
};
|
||||||
mutable std::map<std::string, LinkImplClosure> LinkImplClosureMap;
|
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:
|
public:
|
||||||
std::vector<cmTarget const*> const&
|
std::vector<cmTarget const*> const&
|
||||||
GetLinkImplementationClosure(const std::string& config) const;
|
GetLinkImplementationClosure(const std::string& config) const;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
1
|
|
@ -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\)
|
|
@ -0,0 +1,3 @@
|
||||||
|
enable_language(C)
|
||||||
|
add_executable(empty1 empty.c)
|
||||||
|
set_property(TARGET empty1 PROPERTY OUTPUT_NAME $<TARGET_FILE_NAME:empty1>)
|
|
@ -26,6 +26,7 @@ run_cmake(COMPILE_LANGUAGE-add_library)
|
||||||
run_cmake(COMPILE_LANGUAGE-add_test)
|
run_cmake(COMPILE_LANGUAGE-add_test)
|
||||||
run_cmake(COMPILE_LANGUAGE-unknown-lang)
|
run_cmake(COMPILE_LANGUAGE-unknown-lang)
|
||||||
run_cmake(TARGET_FILE-recursion)
|
run_cmake(TARGET_FILE-recursion)
|
||||||
|
run_cmake(OUTPUT_NAME-recursion)
|
||||||
|
|
||||||
run_cmake(ImportedTarget-TARGET_PDB_FILE)
|
run_cmake(ImportedTarget-TARGET_PDB_FILE)
|
||||||
if(LINKER_SUPPORTS_PDB)
|
if(LINKER_SUPPORTS_PDB)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
enable_language(C)
|
enable_language(C)
|
||||||
add_executable(empty1 empty.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>)
|
set_property(TARGET empty1 PROPERTY RUNTIME_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:empty1>)
|
||||||
|
|
Loading…
Reference in New Issue