Add the ALIAS target concept for libraries and executables.

* The ALIAS name must match a validity regex.
* Executables and libraries may be aliased.
* An ALIAS acts immutable. It can not be used as the lhs
  of target_link_libraries or other commands.
* An ALIAS can be used with add_custom_command, add_custom_target,
  and add_test in the same way regular targets can.
* The target of an ALIAS can be retrieved with the ALIASED_TARGET
  target property.
* An ALIAS does not appear in the generated buildsystem. It
  is kept separate from cmMakefile::Targets for that reason.
* A target may have multiple aliases.
* An ALIAS target may not itself have an alias.
* An IMPORTED target may not have an alias.
* An ALIAS may not be exported or imported.
This commit is contained in:
Stephen Kelly 2013-07-12 09:14:31 +02:00
parent b341bf2178
commit 370bf55415
89 changed files with 740 additions and 19 deletions

View File

@ -24,6 +24,13 @@ bool cmAddDependenciesCommand
} }
std::string target_name = args[0]; std::string target_name = args[0];
if(this->Makefile->IsAlias(target_name.c_str()))
{
cmOStringStream e;
e << "Cannot add target-level dependencies to alias target \""
<< target_name << "\".\n";
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
}
if(cmTarget* target = this->Makefile->FindTargetToUse(target_name.c_str())) if(cmTarget* target = this->Makefile->FindTargetToUse(target_name.c_str()))
{ {
std::vector<std::string>::const_iterator s = args.begin(); std::vector<std::string>::const_iterator s = args.begin();

View File

@ -30,6 +30,7 @@ bool cmAddExecutableCommand
bool excludeFromAll = false; bool excludeFromAll = false;
bool importTarget = false; bool importTarget = false;
bool importGlobal = false; bool importGlobal = false;
bool isAlias = false;
while ( s != args.end() ) while ( s != args.end() )
{ {
if (*s == "WIN32") if (*s == "WIN32")
@ -57,6 +58,11 @@ bool cmAddExecutableCommand
++s; ++s;
importGlobal = true; importGlobal = true;
} }
else if(*s == "ALIAS")
{
++s;
isAlias = true;
}
else else
{ {
break; break;
@ -83,6 +89,72 @@ bool cmAddExecutableCommand
} }
return false; return false;
} }
if (isAlias)
{
if(!cmGeneratorExpression::IsValidTargetName(exename.c_str()))
{
this->SetError(("Invalid name for ALIAS: " + exename).c_str());
return false;
}
if(excludeFromAll)
{
this->SetError("EXCLUDE_FROM_ALL with ALIAS makes no sense.");
return false;
}
if(importTarget || importGlobal)
{
this->SetError("IMPORTED with ALIAS is not allowed.");
return false;
}
if(args.size() != 3)
{
cmOStringStream e;
e << "ALIAS requires exactly one target argument.";
this->SetError(e.str().c_str());
return false;
}
const char *aliasedName = s->c_str();
if(this->Makefile->IsAlias(aliasedName))
{
cmOStringStream e;
e << "cannot create ALIAS target \"" << exename
<< "\" because target \"" << aliasedName << "\" is itself an ALIAS.";
this->SetError(e.str().c_str());
return false;
}
cmTarget *aliasedTarget =
this->Makefile->FindTargetToUse(aliasedName, true);
if(!aliasedTarget)
{
cmOStringStream e;
e << "cannot create ALIAS target \"" << exename
<< "\" because target \"" << aliasedName << "\" does not already "
"exist.";
this->SetError(e.str().c_str());
return false;
}
cmTarget::TargetType type = aliasedTarget->GetType();
if(type != cmTarget::EXECUTABLE)
{
cmOStringStream e;
e << "cannot create ALIAS target \"" << exename
<< "\" because target \"" << aliasedName << "\" is not an "
"executable.";
this->SetError(e.str().c_str());
return false;
}
if(aliasedTarget->IsImported())
{
cmOStringStream e;
e << "cannot create ALIAS target \"" << exename
<< "\" because target \"" << aliasedName << "\" is IMPORTED.";
this->SetError(e.str().c_str());
return false;
}
this->Makefile->AddAlias(exename.c_str(), aliasedTarget);
return true;
}
// Handle imported target creation. // Handle imported target creation.
if(importTarget) if(importTarget)

View File

@ -107,6 +107,19 @@ public:
"(and its per-configuration version IMPORTED_LOCATION_<CONFIG>) " "(and its per-configuration version IMPORTED_LOCATION_<CONFIG>) "
"which specifies the location of the main executable file on disk. " "which specifies the location of the main executable file on disk. "
"See documentation of the IMPORTED_* properties for more information." "See documentation of the IMPORTED_* properties for more information."
"\n"
"The signature\n"
" add_executable(<name> ALIAS <target>)\n"
"creates an alias, such that <name> can be used to refer to <target> "
"in subsequent commands. The <name> does not appear in the generated "
"buildsystem as a make target. The <target> may not be an IMPORTED "
"target or an ALIAS. Alias targets can be used as linkable targets, "
"targets to read properties from, executables for custom commands and "
"custom targets. They can also be tested for existance with the "
"regular if(TARGET) subcommand. The <name> may not be used to modify "
"properties of <target>, that is, it may not be used as the operand of "
"set_property, set_target_properties, target_link_libraries etc. An "
"ALIAS target may not be installed of exported."
; ;
} }

View File

@ -43,6 +43,7 @@ bool cmAddLibraryCommand
// the type of library. Otherwise, it is treated as a source or // the type of library. Otherwise, it is treated as a source or
// source list name. There may be two keyword arguments, check for them // source list name. There may be two keyword arguments, check for them
bool haveSpecifiedType = false; bool haveSpecifiedType = false;
bool isAlias = false;
while ( s != args.end() ) while ( s != args.end() )
{ {
std::string libType = *s; std::string libType = *s;
@ -76,6 +77,11 @@ bool cmAddLibraryCommand
type = cmTarget::UNKNOWN_LIBRARY; type = cmTarget::UNKNOWN_LIBRARY;
haveSpecifiedType = true; haveSpecifiedType = true;
} }
else if(libType == "ALIAS")
{
++s;
isAlias = true;
}
else if(*s == "EXCLUDE_FROM_ALL") else if(*s == "EXCLUDE_FROM_ALL")
{ {
++s; ++s;
@ -96,6 +102,80 @@ bool cmAddLibraryCommand
break; break;
} }
} }
if (isAlias)
{
if(!cmGeneratorExpression::IsValidTargetName(libName.c_str()))
{
this->SetError(("Invalid name for ALIAS: " + libName).c_str());
return false;
}
if(excludeFromAll)
{
this->SetError("EXCLUDE_FROM_ALL with ALIAS makes no sense.");
return false;
}
if(importTarget || importGlobal)
{
this->SetError("IMPORTED with ALIAS is not allowed.");
return false;
}
if(args.size() != 3)
{
cmOStringStream e;
e << "ALIAS requires exactly one target argument.";
this->SetError(e.str().c_str());
return false;
}
const char *aliasedName = s->c_str();
if(this->Makefile->IsAlias(aliasedName))
{
cmOStringStream e;
e << "cannot create ALIAS target \"" << libName
<< "\" because target \"" << aliasedName << "\" is itself an ALIAS.";
this->SetError(e.str().c_str());
return false;
}
cmTarget *aliasedTarget =
this->Makefile->FindTargetToUse(aliasedName, true);
if(!aliasedTarget)
{
cmOStringStream e;
e << "cannot create ALIAS target \"" << libName
<< "\" because target \"" << aliasedName << "\" does not already "
"exist.";
this->SetError(e.str().c_str());
return false;
}
cmTarget::TargetType aliasedType = aliasedTarget->GetType();
if(aliasedType != cmTarget::SHARED_LIBRARY
&& aliasedType != cmTarget::STATIC_LIBRARY
&& aliasedType != cmTarget::MODULE_LIBRARY
&& aliasedType != cmTarget::OBJECT_LIBRARY)
{
cmOStringStream e;
e << "cannot create ALIAS target \"" << libName
<< "\" because target \"" << aliasedName << "\" is not a library.";
this->SetError(e.str().c_str());
return false;
}
if(aliasedTarget->IsImported())
{
cmOStringStream e;
e << "cannot create ALIAS target \"" << libName
<< "\" because target \"" << aliasedName << "\" is IMPORTED.";
this->SetError(e.str().c_str());
return false;
}
this->Makefile->AddAlias(libName.c_str(), aliasedTarget);
return true;
}
if(importTarget && excludeFromAll)
{
this->SetError("excludeFromAll with IMPORTED target makes no sense.");
return false;
}
/* ideally we should check whether for the linker language of the target /* ideally we should check whether for the linker language of the target
CMAKE_${LANG}_CREATE_SHARED_LIBRARY is defined and if not default to CMAKE_${LANG}_CREATE_SHARED_LIBRARY is defined and if not default to

View File

@ -138,6 +138,19 @@ public:
"Some native build systems may not like targets that have only " "Some native build systems may not like targets that have only "
"object files, so consider adding at least one real source file " "object files, so consider adding at least one real source file "
"to any target that references $<TARGET_OBJECTS:objlib>." "to any target that references $<TARGET_OBJECTS:objlib>."
"\n"
"The signature\n"
" add_library(<name> ALIAS <target>)\n"
"creates an alias, such that <name> can be used to refer to <target> "
"in subsequent commands. The <name> does not appear in the generated "
"buildsystem as a make target. The <target> may not be an IMPORTED "
"target or an ALIAS. Alias targets can be used as linkable targets, "
"targets to read properties from. They can also be tested for "
"existance with the "
"regular if(TARGET) subcommand. The <name> may not be used to modify "
"properties of <target>, that is, it may not be used as the operand of "
"set_property, set_target_properties, target_link_libraries etc. An "
"ALIAS target may not be installed of exported."
; ;
} }

View File

@ -114,6 +114,15 @@ bool cmExportCommand
currentTarget != this->Targets.GetVector().end(); currentTarget != this->Targets.GetVector().end();
++currentTarget) ++currentTarget)
{ {
if (this->Makefile->IsAlias(currentTarget->c_str()))
{
cmOStringStream e;
e << "given ALIAS target \"" << *currentTarget
<< "\" which may not be exported.";
this->SetError(e.str().c_str());
return false;
}
if(cmTarget* target = if(cmTarget* target =
this->Makefile->GetLocalGenerator()-> this->Makefile->GetLocalGenerator()->
GetGlobalGenerator()->FindTarget(0, currentTarget->c_str())) GetGlobalGenerator()->FindTarget(0, currentTarget->c_str()))

View File

@ -747,6 +747,18 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
"Target name not supported."); "Target name not supported.");
return std::string(); return std::string();
} }
if(propertyName == "ALIASED_TARGET")
{
if(context->Makefile->IsAlias(targetName.c_str()))
{
if(cmTarget* tgt =
context->Makefile->FindTargetToUse(targetName.c_str()))
{
return tgt->GetName();
}
}
return "";
}
target = context->Makefile->FindTargetToUse( target = context->Makefile->FindTargetToUse(
targetName.c_str()); targetName.c_str());

View File

@ -288,6 +288,18 @@ bool cmGetPropertyCommand::HandleTargetMode()
return false; return false;
} }
if(this->PropertyName == "ALIASED_TARGET")
{
if(this->Makefile->IsAlias(this->Name.c_str()))
{
if(cmTarget* target =
this->Makefile->FindTargetToUse(this->Name.c_str()))
{
return this->StoreResult(target->GetName());
}
}
return false;
}
if(cmTarget* target = this->Makefile->FindTargetToUse(this->Name.c_str())) if(cmTarget* target = this->Makefile->FindTargetToUse(this->Name.c_str()))
{ {
return this->StoreResult(target->GetProperty(this->PropertyName.c_str())); return this->StoreResult(target->GetProperty(this->PropertyName.c_str()));

View File

@ -22,16 +22,29 @@ bool cmGetTargetPropertyCommand
} }
std::string var = args[0].c_str(); std::string var = args[0].c_str();
const char* targetName = args[1].c_str(); const char* targetName = args[1].c_str();
const char *prop = 0;
if(cmTarget* tgt = this->Makefile->FindTargetToUse(targetName)) if(args[2] == "ALIASED_TARGET")
{
if(this->Makefile->IsAlias(targetName))
{
if(cmTarget* target =
this->Makefile->FindTargetToUse(targetName))
{
prop = target->GetName();
}
}
}
else if(cmTarget* tgt = this->Makefile->FindTargetToUse(targetName))
{ {
cmTarget& target = *tgt; cmTarget& target = *tgt;
const char *prop = target.GetProperty(args[2].c_str()); prop = target.GetProperty(args[2].c_str());
if (prop) }
{
this->Makefile->AddDefinition(var.c_str(), prop); if (prop)
return true; {
} this->Makefile->AddDefinition(var.c_str(), prop);
return true;
} }
this->Makefile->AddDefinition(var.c_str(), (var+"-NOTFOUND").c_str()); this->Makefile->AddDefinition(var.c_str(), (var+"-NOTFOUND").c_str());
return true; return true;

View File

@ -1769,10 +1769,22 @@ cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(const char* start_dir)
return 0; return 0;
} }
//----------------------------------------------------------------------------
void cmGlobalGenerator::AddAlias(const char *name, cmTarget *tgt)
{
this->AliasTargets[name] = tgt;
}
//----------------------------------------------------------------------------
bool cmGlobalGenerator::IsAlias(const char *name)
{
return this->AliasTargets.find(name) != this->AliasTargets.end();
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmTarget* cmTarget*
cmGlobalGenerator::FindTarget(const char* project, const char* name) cmGlobalGenerator::FindTarget(const char* project, const char* name,
bool excludeAliases)
{ {
// if project specific // if project specific
if(project) if(project)
@ -1780,7 +1792,8 @@ cmGlobalGenerator::FindTarget(const char* project, const char* name)
std::vector<cmLocalGenerator*>* gens = &this->ProjectMap[project]; std::vector<cmLocalGenerator*>* gens = &this->ProjectMap[project];
for(unsigned int i = 0; i < gens->size(); ++i) for(unsigned int i = 0; i < gens->size(); ++i)
{ {
cmTarget* ret = (*gens)[i]->GetMakefile()->FindTarget(name); cmTarget* ret = (*gens)[i]->GetMakefile()->FindTarget(name,
excludeAliases);
if(ret) if(ret)
{ {
return ret; return ret;
@ -1790,6 +1803,15 @@ cmGlobalGenerator::FindTarget(const char* project, const char* name)
// if all projects/directories // if all projects/directories
else else
{ {
if (!excludeAliases)
{
std::map<cmStdString, cmTarget*>::iterator ai
= this->AliasTargets.find(name);
if (ai != this->AliasTargets.end())
{
return ai->second;
}
}
std::map<cmStdString,cmTarget *>::iterator i = std::map<cmStdString,cmTarget *>::iterator i =
this->TotalTargets.find ( name ); this->TotalTargets.find ( name );
if ( i != this->TotalTargets.end() ) if ( i != this->TotalTargets.end() )

View File

@ -196,7 +196,11 @@ public:
void FindMakeProgram(cmMakefile*); void FindMakeProgram(cmMakefile*);
///! Find a target by name by searching the local generators. ///! Find a target by name by searching the local generators.
cmTarget* FindTarget(const char* project, const char* name); cmTarget* FindTarget(const char* project, const char* name,
bool excludeAliases = false);
void AddAlias(const char *name, cmTarget *tgt);
bool IsAlias(const char *name);
/** Determine if a name resolves to a framework on disk or a built target /** Determine if a name resolves to a framework on disk or a built target
that is a framework. */ that is a framework. */
@ -347,6 +351,7 @@ protected:
// All targets in the entire project. // All targets in the entire project.
std::map<cmStdString,cmTarget *> TotalTargets; std::map<cmStdString,cmTarget *> TotalTargets;
std::map<cmStdString,cmTarget *> AliasTargets;
std::map<cmStdString,cmTarget *> ImportedTargets; std::map<cmStdString,cmTarget *> ImportedTargets;
std::vector<cmGeneratorExpressionEvaluationFile*> EvaluationFiles; std::vector<cmGeneratorExpressionEvaluationFile*> EvaluationFiles;

View File

@ -362,6 +362,15 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
targetIt!=targetList.GetVector().end(); targetIt!=targetList.GetVector().end();
++targetIt) ++targetIt)
{ {
if (this->Makefile->IsAlias(targetIt->c_str()))
{
cmOStringStream e;
e << "TARGETS given target \"" << (*targetIt)
<< "\" which is an alias.";
this->SetError(e.str().c_str());
return false;
}
// Lookup this target in the current directory. // Lookup this target in the current directory.
if(cmTarget* target=this->Makefile->FindTarget(targetIt->c_str())) if(cmTarget* target=this->Makefile->FindTarget(targetIt->c_str()))
{ {

View File

@ -41,6 +41,7 @@
#include <stack> #include <stack>
#include <ctype.h> // for isspace #include <ctype.h> // for isspace
#include <assert.h>
class cmMakefile::Internals class cmMakefile::Internals
{ {
@ -1437,6 +1438,14 @@ void cmMakefile::AddLinkDirectoryForTarget(const char *target,
cmTargets::iterator i = this->Targets.find(target); cmTargets::iterator i = this->Targets.find(target);
if ( i != this->Targets.end()) if ( i != this->Targets.end())
{ {
if(this->IsAlias(target))
{
cmOStringStream e;
e << "ALIAS target \"" << target << "\" "
<< "may not be linked into another target.";
this->IssueMessage(cmake::FATAL_ERROR, e.str().c_str());
return;
}
i->second.AddLinkDirectory( d ); i->second.AddLinkDirectory( d );
} }
else else
@ -1923,6 +1932,12 @@ void cmMakefile::AddGlobalLinkInformation(const char* name, cmTarget& target)
} }
void cmMakefile::AddAlias(const char* lname, cmTarget *tgt)
{
this->AliasTargets[lname] = tgt;
this->LocalGenerator->GetGlobalGenerator()->AddAlias(lname, tgt);
}
cmTarget* cmMakefile::AddLibrary(const char* lname, cmTarget::TargetType type, cmTarget* cmMakefile::AddLibrary(const char* lname, cmTarget::TargetType type,
const std::vector<std::string> &srcs, const std::vector<std::string> &srcs,
bool excludeFromAll) bool excludeFromAll)
@ -3758,8 +3773,17 @@ const char* cmMakefile::GetFeature(const char* feature, const char* config)
return 0; return 0;
} }
cmTarget* cmMakefile::FindTarget(const char* name) cmTarget* cmMakefile::FindTarget(const char* name, bool excludeAliases)
{ {
if (!excludeAliases)
{
std::map<std::string, cmTarget*>::iterator i
= this->AliasTargets.find(name);
if (i != this->AliasTargets.end())
{
return i->second;
}
}
cmTargets& tgts = this->GetTargets(); cmTargets& tgts = this->GetTargets();
cmTargets::iterator i = tgts.find ( name ); cmTargets::iterator i = tgts.find ( name );
@ -4184,7 +4208,7 @@ cmMakefile::AddImportedTarget(const char* name, cmTarget::TargetType type,
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmTarget* cmMakefile::FindTargetToUse(const char* name) cmTarget* cmMakefile::FindTargetToUse(const char* name, bool excludeAliases)
{ {
// Look for an imported target. These take priority because they // Look for an imported target. These take priority because they
// are more local in scope and do not have to be globally unique. // are more local in scope and do not have to be globally unique.
@ -4196,15 +4220,25 @@ cmTarget* cmMakefile::FindTargetToUse(const char* name)
} }
// Look for a target built in this directory. // Look for a target built in this directory.
if(cmTarget* t = this->FindTarget(name)) if(cmTarget* t = this->FindTarget(name, excludeAliases))
{ {
return t; return t;
} }
// Look for a target built in this project. // Look for a target built in this project.
return this->LocalGenerator->GetGlobalGenerator()->FindTarget(0, name); return this->LocalGenerator->GetGlobalGenerator()->FindTarget(0, name,
excludeAliases);
} }
//----------------------------------------------------------------------------
bool cmMakefile::IsAlias(const char *name)
{
if (this->AliasTargets.find(name) != this->AliasTargets.end())
return true;
return this->GetLocalGenerator()->GetGlobalGenerator()->IsAlias(name);
}
//----------------------------------------------------------------------------
cmGeneratorTarget* cmMakefile::FindGeneratorTargetToUse(const char* name) cmGeneratorTarget* cmMakefile::FindGeneratorTargetToUse(const char* name)
{ {
cmTarget *t = this->FindTargetToUse(name); cmTarget *t = this->FindTargetToUse(name);
@ -4215,6 +4249,14 @@ cmGeneratorTarget* cmMakefile::FindGeneratorTargetToUse(const char* name)
bool cmMakefile::EnforceUniqueName(std::string const& name, std::string& msg, bool cmMakefile::EnforceUniqueName(std::string const& name, std::string& msg,
bool isCustom) bool isCustom)
{ {
if(this->IsAlias(name.c_str()))
{
cmOStringStream e;
e << "cannot create target \"" << name
<< "\" because an alias with the same name already exists.";
msg = e.str();
return false;
}
if(cmTarget* existing = this->FindTargetToUse(name.c_str())) if(cmTarget* existing = this->FindTargetToUse(name.c_str()))
{ {
// The name given conflicts with an existing target. Produce an // The name given conflicts with an existing target. Produce an

View File

@ -337,6 +337,7 @@ public:
cmTarget* AddLibrary(const char *libname, cmTarget::TargetType type, cmTarget* AddLibrary(const char *libname, cmTarget::TargetType type,
const std::vector<std::string> &srcs, const std::vector<std::string> &srcs,
bool excludeFromAll = false); bool excludeFromAll = false);
void AddAlias(const char *libname, cmTarget *tgt);
#if defined(CMAKE_BUILD_WITH_CMAKE) #if defined(CMAKE_BUILD_WITH_CMAKE)
/** /**
@ -536,11 +537,12 @@ public:
this->GeneratorTargets = targets; this->GeneratorTargets = targets;
} }
cmTarget* FindTarget(const char* name); cmTarget* FindTarget(const char* name, bool excludeAliases = false);
/** Find a target to use in place of the given name. The target /** Find a target to use in place of the given name. The target
returned may be imported or built within the project. */ returned may be imported or built within the project. */
cmTarget* FindTargetToUse(const char* name); cmTarget* FindTargetToUse(const char* name, bool excludeAliases = false);
bool IsAlias(const char *name);
cmGeneratorTarget* FindGeneratorTargetToUse(const char* name); cmGeneratorTarget* FindGeneratorTargetToUse(const char* name);
/** /**
@ -902,6 +904,7 @@ protected:
// libraries, classes, and executables // libraries, classes, and executables
cmTargets Targets; cmTargets Targets;
std::map<std::string, cmTarget*> AliasTargets;
cmGeneratorTargetsType GeneratorTargets; cmGeneratorTargetsType GeneratorTargets;
std::vector<cmSourceFile*> SourceFiles; std::vector<cmSourceFile*> SourceFiles;

View File

@ -244,6 +244,11 @@ bool cmSetPropertyCommand::HandleTargetMode()
for(std::set<cmStdString>::const_iterator ni = this->Names.begin(); for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
ni != this->Names.end(); ++ni) ni != this->Names.end(); ++ni)
{ {
if (this->Makefile->IsAlias(ni->c_str()))
{
this->SetError("can not be used on an ALIAS target.");
return false;
}
if(cmTarget* target = this->Makefile->FindTargetToUse(ni->c_str())) if(cmTarget* target = this->Makefile->FindTargetToUse(ni->c_str()))
{ {
// Handle the current target. // Handle the current target.

View File

@ -72,6 +72,11 @@ bool cmSetTargetPropertiesCommand
int i; int i;
for(i = 0; i < numFiles; ++i) for(i = 0; i < numFiles; ++i)
{ {
if (this->Makefile->IsAlias(args[i].c_str()))
{
this->SetError("can not be used on an ALIAS target.");
return false;
}
bool ret = cmSetTargetPropertiesCommand::SetOneTarget bool ret = cmSetTargetPropertiesCommand::SetOneTarget
(args[i].c_str(),propertyPairs,this->Makefile); (args[i].c_str(),propertyPairs,this->Makefile);
if (!ret) if (!ret)

View File

@ -968,6 +968,12 @@ void cmTarget::DefineProperties(cmake *cm)
"Per-configuration target file base name.", "Per-configuration target file base name.",
"This is the configuration-specific version of OUTPUT_NAME."); "This is the configuration-specific version of OUTPUT_NAME.");
cm->DefineProperty
("ALIASED_TARGET", cmProperty::TARGET,
"Name of target aliased by this target.",
"If this is an ALIAS target, this property contains the name of the "
"target aliased.");
cm->DefineProperty cm->DefineProperty
("<CONFIG>_OUTPUT_NAME", cmProperty::TARGET, ("<CONFIG>_OUTPUT_NAME", cmProperty::TARGET,
"Old per-configuration target file base name.", "Old per-configuration target file base name.",

View File

@ -31,6 +31,11 @@ bool cmTargetLinkLibrariesCommand
return false; return false;
} }
if (this->Makefile->IsAlias(args[0].c_str()))
{
this->SetError("can not be used on an ALIAS target.");
return false;
}
// Lookup the target for which libraries are specified. // Lookup the target for which libraries are specified.
this->Target = this->Target =
this->Makefile->GetCMakeInstance() this->Makefile->GetCMakeInstance()

View File

@ -26,6 +26,11 @@ bool cmTargetPropCommandBase
} }
// Lookup the target for which libraries are specified. // Lookup the target for which libraries are specified.
if (this->Makefile->IsAlias(args[0].c_str()))
{
this->SetError("can not be used on an ALIAS target.");
return false;
}
this->Target = this->Target =
this->Makefile->GetCMakeInstance() this->Makefile->GetCMakeInstance()
->GetGlobalGenerator()->FindTarget(0, args[0].c_str()); ->GetGlobalGenerator()->FindTarget(0, args[0].c_str());

View File

@ -0,0 +1,47 @@
cmake_minimum_required(VERSION 2.8.11)
project(AliasTarget)
add_library(foo SHARED empty.cpp)
add_library(PREFIX::Foo ALIAS foo)
add_library(Another::Alias ALIAS foo)
add_library(objects OBJECT object.cpp)
add_library(Alias::Objects ALIAS objects)
target_compile_definitions(foo PUBLIC FOO_DEFINE)
add_library(bar SHARED empty.cpp)
target_compile_definitions(bar PUBLIC BAR_DEFINE)
target_link_libraries(foo LINK_PUBLIC $<$<STREQUAL:$<TARGET_PROPERTY:PREFIX::Foo,ALIASED_TARGET>,foo>:bar>)
add_executable(AliasTarget commandgenerator.cpp $<TARGET_OBJECTS:Alias::Objects>)
add_executable(PREFIX::AliasTarget ALIAS AliasTarget)
add_executable(Generator::Command ALIAS AliasTarget)
add_custom_command(OUTPUT commandoutput.h COMMAND Generator::Command)
add_library(bat SHARED bat.cpp "${CMAKE_CURRENT_BINARY_DIR}/commandoutput.h")
target_link_libraries(bat PREFIX::Foo)
target_include_directories(bat PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
add_executable(targetgenerator targetgenerator.cpp)
add_executable(Generator::Target ALIAS targetgenerator)
add_custom_target(usealias Generator::Target)
add_dependencies(bat usealias)
if (NOT TARGET Another::Alias)
message(SEND_ERROR "Another::Alias is not considered a target.")
endif()
get_target_property(_alt PREFIX::Foo ALIASED_TARGET)
if (NOT ${_alt} STREQUAL foo)
message(SEND_ERROR "ALIASED_TARGET is not foo: ${_alt}")
endif()
get_property(_alt2 TARGET PREFIX::Foo PROPERTY ALIASED_TARGET)
if (NOT ${_alt2} STREQUAL foo)
message(SEND_ERROR "ALIASED_TARGET is not foo.")
endif()

28
Tests/AliasTarget/bat.cpp Normal file
View File

@ -0,0 +1,28 @@
#ifndef FOO_DEFINE
#error Expected FOO_DEFINE
#endif
#ifndef BAR_DEFINE
#error Expected Bar_DEFINE
#endif
#include "commandoutput.h"
#ifndef COMMANDOUTPUT_DEFINE
#error Expected COMMANDOUTPUT_DEFINE
#endif
#include "targetoutput.h"
#ifndef TARGETOUTPUT_DEFINE
#error Expected TARGETOUTPUT_DEFINE
#endif
#ifdef _WIN32
__declspec(dllexport)
#endif
int bar()
{
return 0;
}

View File

@ -0,0 +1,15 @@
#include <fstream>
#include "object.h"
int main(int argc, char **argv)
{
std::fstream fout;
fout.open("commandoutput.h", std::ios::out);
if (!fout)
return 1;
fout << "#define COMMANDOUTPUT_DEFINE\n";
fout.close();
return object();
}

View File

@ -0,0 +1,7 @@
#ifdef _WIN32
__declspec(dllexport)
#endif
int main(void)
{
return 0;
}

View File

@ -0,0 +1,5 @@
int object(void)
{
return 0;
}

View File

@ -0,0 +1,4 @@
#ifdef _WIN32
__declspec(dllexport)
#endif
int object(void);

View File

@ -0,0 +1,13 @@
#include <fstream>
int main(int argc, char **argv)
{
std::fstream fout;
fout.open("targetoutput.h", std::ios::out);
if (!fout)
return 1;
fout << "#define TARGETOUTPUT_DEFINE\n";
fout.close();
return 0;
}

View File

@ -245,6 +245,7 @@ if(BUILD_TESTING)
ADD_TEST_MACRO(CompileDefinitions CompileDefinitions) ADD_TEST_MACRO(CompileDefinitions CompileDefinitions)
ADD_TEST_MACRO(CompileOptions CompileOptions) ADD_TEST_MACRO(CompileOptions CompileOptions)
ADD_TEST_MACRO(CompatibleInterface CompatibleInterface) ADD_TEST_MACRO(CompatibleInterface CompatibleInterface)
ADD_TEST_MACRO(AliasTarget AliasTarget)
set_tests_properties(EmptyLibrary PROPERTIES set_tests_properties(EmptyLibrary PROPERTIES
PASS_REGULAR_EXPRESSION "CMake Error: CMake can not determine linker language for target: test") PASS_REGULAR_EXPRESSION "CMake Error: CMake can not determine linker language for target: test")
ADD_TEST_MACRO(CrossCompile CrossCompile) ADD_TEST_MACRO(CrossCompile CrossCompile)

View File

@ -3,7 +3,8 @@ project(CTestTestDepends)
include(CTest) include(CTest)
add_executable (simple simple.cxx) add_executable (simple simple.cxx)
add_test (one simple) add_executable (TestExe::Simple ALIAS simple)
add_test (NAME one COMMAND TestExe::Simple)
add_test (two simple) add_test (two simple)
add_test (three simple) add_test (three simple)

View File

@ -163,6 +163,11 @@ add_library(imported4 SHARED IMPORTED)
set_property(TARGET imported4 APPEND PROPERTY set_property(TARGET imported4 APPEND PROPERTY
INCLUDE_DIRECTORIES $<TARGET_PROPERTY:imported3,INTERFACE_INCLUDE_DIRECTORIES>) INCLUDE_DIRECTORIES $<TARGET_PROPERTY:imported3,INTERFACE_INCLUDE_DIRECTORIES>)
add_executable(someexe empty.cpp)
add_executable(Alias::SomeExe ALIAS someexe)
add_library(Alias::SomeLib ALIAS empty1)
add_custom_target(check-part3 ALL add_custom_target(check-part3 ALL
COMMAND ${CMAKE_COMMAND} COMMAND ${CMAKE_COMMAND}
-Dtest_version_greater_1=$<VERSION_GREATER:1.0,1.1.1> -Dtest_version_greater_1=$<VERSION_GREATER:1.0,1.1.1>
@ -176,6 +181,9 @@ add_custom_target(check-part3 ALL
-Dtest_imported_release=$<TARGET_PROPERTY:imported4,INCLUDE_DIRECTORIES> -Dtest_imported_release=$<TARGET_PROPERTY:imported4,INCLUDE_DIRECTORIES>
-Dtest_imported_relwithdebinfo=$<TARGET_PROPERTY:imported4,INCLUDE_DIRECTORIES> -Dtest_imported_relwithdebinfo=$<TARGET_PROPERTY:imported4,INCLUDE_DIRECTORIES>
-Dtest_imported_minsizerel=$<TARGET_PROPERTY:imported4,INCLUDE_DIRECTORIES> -Dtest_imported_minsizerel=$<TARGET_PROPERTY:imported4,INCLUDE_DIRECTORIES>
-Dtest_alias_file_exe=$<STREQUAL:$<TARGET_FILE:Alias::SomeExe>,$<TARGET_FILE:someexe>>
-Dtest_alias_file_lib=$<STREQUAL:$<TARGET_FILE:Alias::SomeLib>,$<TARGET_FILE:empty1>>
-Dtest_alias_target_name=$<STREQUAL:$<TARGET_PROPERTY:Alias::SomeLib,NAME>,$<TARGET_PROPERTY:empty1,NAME>>
-P ${CMAKE_CURRENT_SOURCE_DIR}/check-part3.cmake -P ${CMAKE_CURRENT_SOURCE_DIR}/check-part3.cmake
COMMAND ${CMAKE_COMMAND} -E echo "check done (part 3 of 3)" COMMAND ${CMAKE_COMMAND} -E echo "check done (part 3 of 3)"
VERBATIM VERBATIM

View File

@ -20,3 +20,7 @@ foreach(c debug release relwithdebinfo minsizerel)
endif() endif()
endif() endif()
endforeach() endforeach()
check(test_alias_file_exe "1")
check(test_alias_file_lib "1")
check(test_alias_target_name "1")

View File

@ -1,2 +1,4 @@
#ifdef _WIN32
// empty __declspec(dllexport)
#endif
int main() { return 0; }

View File

@ -98,6 +98,7 @@ add_RunCMake_test(try_compile)
add_RunCMake_test(variable_watch) add_RunCMake_test(variable_watch)
add_RunCMake_test(CMP0004) add_RunCMake_test(CMP0004)
add_RunCMake_test(TargetPolicies) add_RunCMake_test(TargetPolicies)
add_RunCMake_test(alias_targets)
find_package(Qt4 QUIET) find_package(Qt4 QUIET)
find_package(Qt5Core QUIET) find_package(Qt5Core QUIET)

View File

@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 2.8)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)

View File

@ -0,0 +1,20 @@
include(RunCMake)
run_cmake(no-targets)
run_cmake(multiple-targets)
run_cmake(exclude-from-all)
run_cmake(imported)
run_cmake(invalid-name)
run_cmake(invalid-target)
run_cmake(imported-target)
run_cmake(alias-target)
run_cmake(set_property)
run_cmake(set_target_properties)
run_cmake(target_link_libraries)
run_cmake(target_include_directories)
run_cmake(export)
run_cmake(install-export)
run_cmake(name-conflict)
run_cmake(add_dependencies)
run_cmake(add_executable-library)
run_cmake(add_library-executable)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,5 @@
CMake Error at add_dependencies.cmake:9 \(add_dependencies\):
Cannot add target-level dependencies to alias target "alias".
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,9 @@
enable_language(CXX)
add_library(foo empty.cpp)
add_library(bar empty.cpp)
add_library(alias ALIAS foo)
add_dependencies(alias bar)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,5 @@
CMake Error at add_executable-library.cmake:6 \(add_executable\):
add_executable cannot create ALIAS target "alias" because target "foo" is
not an executable.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,6 @@
enable_language(CXX)
add_library(foo empty.cpp)
add_executable(alias ALIAS foo)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,5 @@
CMake Error at add_library-executable.cmake:6 \(add_library\):
add_library cannot create ALIAS target "alias" because target "foo" is not
a library.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,6 @@
enable_language(CXX)
add_executable(foo empty.cpp)
add_library(alias ALIAS foo)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,5 @@
CMake Error at alias-target.cmake:8 \(add_library\):
add_library cannot create ALIAS target "next_alias" because target "alias"
is itself an ALIAS.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,8 @@
enable_language(CXX)
add_library(foo empty.cpp)
add_library(alias ALIAS foo)
add_library(next_alias ALIAS alias)

View File

@ -0,0 +1,7 @@
#ifdef _WIN32
__declspec(dllexport)
#endif
int empty()
{
return 0;
}

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at exclude-from-all.cmake:6 \(add_library\):
add_library EXCLUDE_FROM_ALL with ALIAS makes no sense.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,6 @@
enable_language(CXX)
add_library(foo empty.cpp)
add_library(alias ALIAS EXCLUDE_FROM_ALL foo)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at export.cmake:8 \(export\):
export given ALIAS target "alias" which may not be exported.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,8 @@
enable_language(CXX)
add_library(foo empty.cpp)
add_library(alias ALIAS foo)
export(TARGETS alias FILE someFile.cmake)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at imported.cmake:2 \(add_library\):
add_library IMPORTED with ALIAS is not allowed.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,5 @@
CMake Error at imported-target.cmake:6 \(add_library\):
add_library cannot create ALIAS target "alias" because target "foo" is
IMPORTED.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,6 @@
enable_language(CXX)
add_library(foo SHARED IMPORTED)
add_library(alias ALIAS foo)

View File

@ -0,0 +1,2 @@
add_library(alias IMPORTED ALIAS)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at install-export.cmake:8 \(install\):
install TARGETS given target "alias" which is an alias.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,9 @@
enable_language(CXX)
add_library(foo empty.cpp)
add_library(alias ALIAS foo)
install(TARGETS alias EXPORT theTargets DESTINATION prefix)
install(EXPORT theTargets DESTINATION lib/cmake)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at invalid-name.cmake:6 \(add_library\):
add_library Invalid name for ALIAS: invalid\$name
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,6 @@
enable_language(CXX)
add_library(foo empty.cpp)
add_library(invalid$name ALIAS foo)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,5 @@
CMake Error at invalid-target.cmake:2 \(add_library\):
add_library cannot create ALIAS target "alias" because target "foo" does
not already exist.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,2 @@
add_library(alias ALIAS foo)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at multiple-targets.cmake:7 \(add_library\):
add_library ALIAS requires exactly one target argument.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,7 @@
enable_language(CXX)
add_library(foo empty.cpp)
add_library(bar empty.cpp)
add_library(alias ALIAS foo bar)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,5 @@
CMake Error at name-conflict.cmake:8 \(add_library\):
add_library cannot create target "bar" because an alias with the same name
already exists.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,8 @@
enable_language(CXX)
add_library(foo empty.cpp)
add_library(bar ALIAS foo)
add_library(bar empty.cpp)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at no-targets.cmake:4 \(add_library\):
add_library ALIAS requires exactly one target argument.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,4 @@
enable_language(CXX)
add_library(alias ALIAS)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at set_property.cmake:8 \(set_property\):
set_property can not be used on an ALIAS target.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,8 @@
enable_language(CXX)
add_library(foo empty.cpp)
add_library(alias ALIAS foo)
set_property(TARGET alias PROPERTY ANYTHING 1)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at set_target_properties.cmake:8 \(set_target_properties\):
set_target_properties can not be used on an ALIAS target.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,8 @@
enable_language(CXX)
add_library(foo empty.cpp)
add_library(alias ALIAS foo)
set_target_properties(alias PROPERTIES ANYTHING 1)

View File

@ -0,0 +1,4 @@
CMake Error at target_include_directories.cmake:8 \(target_include_directories\):
target_include_directories can not be used on an ALIAS target.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,8 @@
enable_language(CXX)
add_library(foo empty.cpp)
add_library(alias ALIAS foo)
target_include_directories(alias PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at target_link_libraries.cmake:9 \(target_link_libraries\):
target_link_libraries can not be used on an ALIAS target.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,9 @@
enable_language(CXX)
add_library(foo empty.cpp)
add_library(bar empty.cpp)
add_library(alias ALIAS foo)
target_link_libraries(alias bar)