Add the INTERFACE_LIBRARY target type.

This target type only contains INTERFACE_* properties, so it can be
used as a structural node. The target-specific commands enforce
that they may only be used with the INTERFACE keyword when used
with INTERFACE_LIBRARY targets. The old-style target properties
matching LINK_INTERFACE_LIBRARIES_<CONFIG> are always ignored for
this target type.

The name of the INTERFACE_LIBRARY must match a validity generator
expression. The validity is similar to that of an ALIAS target,
but with the additional restriction that it may not contain
double colons. Double colons will carry the meaning of IMPORTED
or ALIAS targets in CMake 2.8.13.

An ALIAS target may be created for an INTERFACE library.

At this point it can not be exported and does not appear in the
buildsystem and project files are not created for them. That may
be added as a feature in a later commit.

The generators need some changes to handle the INTERFACE_LIBRARY
targets returned by cmComputeLinkInterface::GetItems. The Ninja
generator does not use that API, so it doesn't require changes
related to that.
This commit is contained in:
Stephen Kelly 2012-11-02 15:47:40 +01:00 committed by Brad King
parent d4134352ab
commit fe732264e9
56 changed files with 528 additions and 49 deletions

View File

@ -82,6 +82,12 @@ bool cmAddLibraryCommand
++s; ++s;
isAlias = true; isAlias = true;
} }
else if(libType == "INTERFACE")
{
++s;
type = cmTarget::INTERFACE_LIBRARY;
haveSpecifiedType = true;
}
else if(*s == "EXCLUDE_FROM_ALL") else if(*s == "EXCLUDE_FROM_ALL")
{ {
++s; ++s;
@ -151,7 +157,8 @@ bool cmAddLibraryCommand
if(aliasedType != cmTarget::SHARED_LIBRARY if(aliasedType != cmTarget::SHARED_LIBRARY
&& aliasedType != cmTarget::STATIC_LIBRARY && aliasedType != cmTarget::STATIC_LIBRARY
&& aliasedType != cmTarget::MODULE_LIBRARY && aliasedType != cmTarget::MODULE_LIBRARY
&& aliasedType != cmTarget::OBJECT_LIBRARY) && aliasedType != cmTarget::OBJECT_LIBRARY
&& aliasedType != cmTarget::INTERFACE_LIBRARY)
{ {
cmOStringStream e; cmOStringStream e;
e << "cannot create ALIAS target \"" << libName e << "cannot create ALIAS target \"" << libName
@ -249,6 +256,26 @@ bool cmAddLibraryCommand
} }
} }
std::vector<std::string> srclists;
if(type == cmTarget::INTERFACE_LIBRARY)
{
if (!cmGeneratorExpression::IsValidTargetName(libName)
|| libName.find("::") != std::string::npos)
{
cmOStringStream e;
e << "Invalid name for INTERFACE library target: " << libName;
this->SetError(e.str().c_str());
return false;
}
this->Makefile->AddLibrary(libName.c_str(),
type,
srclists,
excludeFromAll);
return true;
}
if (s == args.end()) if (s == args.end())
{ {
std::string msg = "You have called ADD_LIBRARY for library "; std::string msg = "You have called ADD_LIBRARY for library ";
@ -258,7 +285,6 @@ bool cmAddLibraryCommand
cmSystemTools::Message(msg.c_str() ,"Warning"); cmSystemTools::Message(msg.c_str() ,"Warning");
} }
std::vector<std::string> srclists;
while (s != args.end()) while (s != args.end())
{ {
srclists.push_back(*s); srclists.push_back(*s);

View File

@ -151,6 +151,16 @@ public:
"properties of <target>, that is, it may not be used as the operand of " "properties of <target>, that is, it may not be used as the operand of "
"set_property, set_target_properties, target_link_libraries etc. An " "set_property, set_target_properties, target_link_libraries etc. An "
"ALIAS target may not be installed of exported." "ALIAS target may not be installed of exported."
"\n"
"The signature\n"
" add_library(<name> INTERFACE)\n"
"creates an interface target. An interface target does not directly "
"create build output, though it may have properties set on it and it "
"may be installed, exported and imported. Typically the INTERFACE_* "
"properties are populated on the interface target using the "
"set_property(), target_link_libraries(), target_include_directories() "
"and target_compile_defintions() commands, and then it is used as an "
"argument to target_link_libraries() like any other target."
; ;
} }

View File

@ -355,9 +355,16 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
if(cmTarget::LinkInterface const* iface = if(cmTarget::LinkInterface const* iface =
entry.Target->GetLinkInterface(this->Config, this->HeadTarget)) entry.Target->GetLinkInterface(this->Config, this->HeadTarget))
{ {
const bool isIface =
entry.Target->GetType() == cmTarget::INTERFACE_LIBRARY;
// This target provides its own link interface information. // This target provides its own link interface information.
this->AddLinkEntries(depender_index, iface->Libraries); this->AddLinkEntries(depender_index, iface->Libraries);
if (isIface)
{
return;
}
// Handle dependent shared libraries. // Handle dependent shared libraries.
this->FollowSharedDeps(depender_index, iface); this->FollowSharedDeps(depender_index, iface);

View File

@ -655,6 +655,11 @@ void cmComputeLinkInformation::AddItem(std::string const& item, cmTarget* tgt)
(this->UseImportLibrary && (this->UseImportLibrary &&
(impexe || tgt->GetType() == cmTarget::SHARED_LIBRARY)); (impexe || tgt->GetType() == cmTarget::SHARED_LIBRARY));
if(tgt->GetType() == cmTarget::INTERFACE_LIBRARY)
{
this->Items.push_back(Item(std::string(), true, tgt));
return;
}
// Pass the full path to the target file. // Pass the full path to the target file.
std::string lib = tgt->GetFullPath(config, implib, true); std::string lib = tgt->GetFullPath(config, implib, true);
if(!this->LinkDependsNoShared || if(!this->LinkDependsNoShared ||

View File

@ -2555,6 +2555,10 @@ void cmGlobalGenerator::WriteSummary()
for(std::map<cmStdString,cmTarget *>::const_iterator ti = for(std::map<cmStdString,cmTarget *>::const_iterator ti =
this->TotalTargets.begin(); ti != this->TotalTargets.end(); ++ti) this->TotalTargets.begin(); ti != this->TotalTargets.end(); ++ti)
{ {
if ((ti->second)->GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
this->WriteSummary(ti->second); this->WriteSummary(ti->second);
fout << ti->second->GetSupportDirectory() << "\n"; fout << ti->second->GetSupportDirectory() << "\n";
} }

View File

@ -877,7 +877,12 @@ cmGlobalNinjaGenerator
cmTargetDependSet const& targetDeps = cmTargetDependSet const& targetDeps =
this->GetTargetDirectDepends(*target); this->GetTargetDirectDepends(*target);
for (cmTargetDependSet::const_iterator i = targetDeps.begin(); for (cmTargetDependSet::const_iterator i = targetDeps.begin();
i != targetDeps.end(); ++i) { i != targetDeps.end(); ++i)
{
if ((*i)->GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
this->AppendTargetOutputs(*i, outputs); this->AppendTargetOutputs(*i, outputs);
} }
} }

View File

@ -881,6 +881,10 @@ cmGlobalUnixMakefileGenerator3
for(TargetDependSet::const_iterator di = depends.begin(); for(TargetDependSet::const_iterator di = depends.begin();
di != depends.end(); ++di) di != depends.end(); ++di)
{ {
if ((*di)->GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
count += this->CountProgressMarksInTarget(*di, emitted); count += this->CountProgressMarksInTarget(*di, emitted);
} }
} }
@ -967,6 +971,10 @@ cmGlobalUnixMakefileGenerator3
{ {
// Create the target-level dependency. // Create the target-level dependency.
cmTarget const* dep = *i; cmTarget const* dep = *i;
if (dep->GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
cmLocalUnixMakefileGenerator3* lg3 = cmLocalUnixMakefileGenerator3* lg3 =
static_cast<cmLocalUnixMakefileGenerator3*> static_cast<cmLocalUnixMakefileGenerator3*>
(dep->GetMakefile()->GetLocalGenerator()); (dep->GetMakefile()->GetLocalGenerator());

View File

@ -200,6 +200,10 @@ void cmGlobalVisualStudio6Generator
tt != orderedProjectTargets.end(); ++tt) tt != orderedProjectTargets.end(); ++tt)
{ {
cmTarget* target = *tt; cmTarget* target = *tt;
if(target->GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
// Write the project into the DSW file // Write the project into the DSW file
const char* expath = target->GetProperty("EXTERNAL_MSPROJECT"); const char* expath = target->GetProperty("EXTERNAL_MSPROJECT");
if(expath) if(expath)

View File

@ -392,6 +392,10 @@ void cmGlobalVisualStudio7Generator::WriteTargetDepends(
projectTargets.begin(); tt != projectTargets.end(); ++tt) projectTargets.begin(); tt != projectTargets.end(); ++tt)
{ {
cmTarget* target = *tt; cmTarget* target = *tt;
if(target->GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
cmMakefile* mf = target->GetMakefile(); cmMakefile* mf = target->GetMakefile();
const char *vcprojName = const char *vcprojName =
target->GetProperty("GENERATOR_FILE_NAME"); target->GetProperty("GENERATOR_FILE_NAME");

View File

@ -406,6 +406,10 @@ void cmGlobalVisualStudio8Generator::WriteProjectDepends(
for(OrderedTargetDependSet::const_iterator i = depends.begin(); for(OrderedTargetDependSet::const_iterator i = depends.begin();
i != depends.end(); ++i) i != depends.end(); ++i)
{ {
if((*i)->GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
std::string guid = this->GetGUID((*i)->GetName()); std::string guid = this->GetGUID((*i)->GetName());
fout << "\t\t{" << guid << "} = {" << guid << "}\n"; fout << "\t\t{" << guid << "} = {" << guid << "}\n";
} }

View File

@ -349,6 +349,10 @@ cmGlobalVisualStudioGenerator::GetTargetLinkClosure(cmTarget* target)
void cmGlobalVisualStudioGenerator::FollowLinkDepends( void cmGlobalVisualStudioGenerator::FollowLinkDepends(
cmTarget* target, std::set<cmTarget*>& linked) cmTarget* target, std::set<cmTarget*>& linked)
{ {
if(target->GetType() == cmTarget::INTERFACE_LIBRARY)
{
return;
}
if(linked.insert(target).second && if(linked.insert(target).second &&
target->GetType() == cmTarget::STATIC_LIBRARY) target->GetType() == cmTarget::STATIC_LIBRARY)
{ {

View File

@ -976,6 +976,11 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
continue; continue;
} }
if(cmtarget.GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
if(cmtarget.GetType() == cmTarget::UTILITY || if(cmtarget.GetType() == cmTarget::UTILITY ||
cmtarget.GetType() == cmTarget::GLOBAL_TARGET) cmtarget.GetType() == cmTarget::GLOBAL_TARGET)
{ {
@ -1686,6 +1691,11 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
cmXCodeObject* buildSettings, cmXCodeObject* buildSettings,
const char* configName) const char* configName)
{ {
if(target.GetType() == cmTarget::INTERFACE_LIBRARY)
{
return;
}
std::string flags; std::string flags;
std::string defFlags; std::string defFlags;
bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) || bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) ||
@ -2550,6 +2560,10 @@ cmXCodeObject*
cmGlobalXCodeGenerator::CreateXCodeTarget(cmTarget& cmtarget, cmGlobalXCodeGenerator::CreateXCodeTarget(cmTarget& cmtarget,
cmXCodeObject* buildPhases) cmXCodeObject* buildPhases)
{ {
if(cmtarget.GetType() == cmTarget::INTERFACE_LIBRARY)
{
return 0;
}
cmXCodeObject* target = cmXCodeObject* target =
this->CreateObject(cmXCodeObject::PBXNativeTarget); this->CreateObject(cmXCodeObject::PBXNativeTarget);
target->AddAttribute("buildPhases", buildPhases); target->AddAttribute("buildPhases", buildPhases);
@ -2756,6 +2770,10 @@ void cmGlobalXCodeGenerator
::AddDependAndLinkInformation(cmXCodeObject* target) ::AddDependAndLinkInformation(cmXCodeObject* target)
{ {
cmTarget* cmtarget = target->GetTarget(); cmTarget* cmtarget = target->GetTarget();
if(cmtarget->GetType() == cmTarget::INTERFACE_LIBRARY)
{
return;
}
if(!cmtarget) if(!cmtarget)
{ {
cmSystemTools::Error("Error no target on xobject\n"); cmSystemTools::Error("Error no target on xobject\n");
@ -2867,7 +2885,8 @@ void cmGlobalXCodeGenerator
{ {
linkLibs += this->XCodeEscapePath(li->Value.c_str()); linkLibs += this->XCodeEscapePath(li->Value.c_str());
} }
else else if (!li->Target
|| li->Target->GetType() != cmTarget::INTERFACE_LIBRARY)
{ {
linkLibs += li->Value; linkLibs += li->Value;
} }
@ -2909,6 +2928,10 @@ void cmGlobalXCodeGenerator::CreateGroups(cmLocalGenerator* root,
{ {
continue; continue;
} }
if(cmtarget.GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
// add the soon to be generated Info.plist file as a source for a // add the soon to be generated Info.plist file as a source for a
// MACOSX_BUNDLE file // MACOSX_BUNDLE file

View File

@ -90,6 +90,11 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
case cmTarget::STATIC_LIBRARY: type = cmInstallType_STATIC_LIBRARY; break; case cmTarget::STATIC_LIBRARY: type = cmInstallType_STATIC_LIBRARY; break;
case cmTarget::SHARED_LIBRARY: type = cmInstallType_SHARED_LIBRARY; break; case cmTarget::SHARED_LIBRARY: type = cmInstallType_SHARED_LIBRARY; break;
case cmTarget::MODULE_LIBRARY: type = cmInstallType_MODULE_LIBRARY; break; case cmTarget::MODULE_LIBRARY: type = cmInstallType_MODULE_LIBRARY; break;
case cmTarget::INTERFACE_LIBRARY:
// Not reachable. We never create a cmInstallTargetGenerator for
// an INTERFACE_LIBRARY.
assert(!"INTERFACE_LIBRARY targets have no installable outputs.");
break;
case cmTarget::OBJECT_LIBRARY: case cmTarget::OBJECT_LIBRARY:
case cmTarget::UTILITY: case cmTarget::UTILITY:
case cmTarget::GLOBAL_TARGET: case cmTarget::GLOBAL_TARGET:

View File

@ -1793,6 +1793,10 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries,
ItemVector const& items = cli.GetItems(); ItemVector const& items = cli.GetItems();
for(ItemVector::const_iterator li = items.begin(); li != items.end(); ++li) for(ItemVector::const_iterator li = items.begin(); li != items.end(); ++li)
{ {
if(li->Target && li->Target->GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
if(li->IsPath) if(li->IsPath)
{ {
linkLibs += this->ConvertToLinkReference(li->Value); linkLibs += this->ConvertToLinkReference(li->Value);
@ -1996,6 +2000,10 @@ bool cmLocalGenerator::GetRealDependency(const char* inName,
// An object library has no single file on which to depend. // An object library has no single file on which to depend.
// This was listed to get the target-level dependency. // This was listed to get the target-level dependency.
return false; return false;
case cmTarget::INTERFACE_LIBRARY:
// An interface library has no file on which to depend.
// This was listed to get the target-level dependency.
return false;
case cmTarget::UTILITY: case cmTarget::UTILITY:
case cmTarget::GLOBAL_TARGET: case cmTarget::GLOBAL_TARGET:
// A utility target has no file on which to depend. This was listed // A utility target has no file on which to depend. This was listed

View File

@ -76,6 +76,10 @@ void cmLocalVisualStudio10Generator::Generate()
cmTargets &tgts = this->Makefile->GetTargets(); cmTargets &tgts = this->Makefile->GetTargets();
for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); ++l) for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); ++l)
{ {
if(l->second.GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
if(static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator) if(static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator)
->TargetIsFortranOnly(l->second)) ->TargetIsFortranOnly(l->second))
{ {

View File

@ -91,6 +91,11 @@ void cmLocalVisualStudio6Generator::AddCMakeListsRules()
for(cmTargets::iterator l = tgts.begin(); for(cmTargets::iterator l = tgts.begin();
l != tgts.end(); l++) l != tgts.end(); l++)
{ {
if (l->second.GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
// Add a rule to regenerate the build system when the target // Add a rule to regenerate the build system when the target
// specification source changes. // specification source changes.
const char* suppRegenRule = const char* suppRegenRule =
@ -146,6 +151,8 @@ void cmLocalVisualStudio6Generator::OutputDSPFile()
case cmTarget::GLOBAL_TARGET: case cmTarget::GLOBAL_TARGET:
this->SetBuildType(UTILITY, l->first.c_str(), l->second); this->SetBuildType(UTILITY, l->first.c_str(), l->second);
break; break;
case cmTarget::INTERFACE_LIBRARY:
continue;
default: default:
cmSystemTools::Error("Bad target type", l->first.c_str()); cmSystemTools::Error("Bad target type", l->first.c_str());
break; break;
@ -1839,7 +1846,8 @@ void cmLocalVisualStudio6Generator
options += options +=
this->ConvertToOptionallyRelativeOutputPath(l->Value.c_str()); this->ConvertToOptionallyRelativeOutputPath(l->Value.c_str());
} }
else else if (!l->Target
|| l->Target->GetType() != cmTarget::INTERFACE_LIBRARY)
{ {
options += l->Value; options += l->Value;
} }

View File

@ -78,6 +78,10 @@ void cmLocalVisualStudio7Generator::AddHelperCommands()
static_cast<cmGlobalVisualStudio7Generator *>(this->GlobalGenerator); static_cast<cmGlobalVisualStudio7Generator *>(this->GlobalGenerator);
for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++) for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
{ {
if(l->second.GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
const char* path = l->second.GetProperty("EXTERNAL_MSPROJECT"); const char* path = l->second.GetProperty("EXTERNAL_MSPROJECT");
if(path) if(path)
{ {
@ -181,6 +185,10 @@ void cmLocalVisualStudio7Generator::WriteProjectFiles()
for(cmTargets::iterator l = tgts.begin(); for(cmTargets::iterator l = tgts.begin();
l != tgts.end(); l++) l != tgts.end(); l++)
{ {
if(l->second.GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
// INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace // INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace
// so don't build a projectfile for it // so don't build a projectfile for it
if(!l->second.GetProperty("EXTERNAL_MSPROJECT")) if(!l->second.GetProperty("EXTERNAL_MSPROJECT"))
@ -1258,6 +1266,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
} }
case cmTarget::UTILITY: case cmTarget::UTILITY:
case cmTarget::GLOBAL_TARGET: case cmTarget::GLOBAL_TARGET:
case cmTarget::INTERFACE_LIBRARY:
break; break;
} }
} }
@ -1288,7 +1297,8 @@ cmLocalVisualStudio7GeneratorInternals
cmLocalGenerator::UNCHANGED); cmLocalGenerator::UNCHANGED);
fout << lg->ConvertToXMLOutputPath(rel.c_str()) << " "; fout << lg->ConvertToXMLOutputPath(rel.c_str()) << " ";
} }
else else if (!l->Target
|| l->Target->GetType() != cmTarget::INTERFACE_LIBRARY)
{ {
fout << l->Value << " "; fout << l->Value << " ";
} }

View File

@ -1463,6 +1463,7 @@ void cmMakefile::AddLinkLibraryForTarget(const char *target,
// if it is not a static or shared library then you can not link to it // if it is not a static or shared library then you can not link to it
if(!((tgt->GetType() == cmTarget::STATIC_LIBRARY) || if(!((tgt->GetType() == cmTarget::STATIC_LIBRARY) ||
(tgt->GetType() == cmTarget::SHARED_LIBRARY) || (tgt->GetType() == cmTarget::SHARED_LIBRARY) ||
(tgt->GetType() == cmTarget::INTERFACE_LIBRARY) ||
tgt->IsExecutableWithExports())) tgt->IsExecutableWithExports()))
{ {
cmOStringStream e; cmOStringStream e;
@ -1990,6 +1991,7 @@ void cmMakefile::AddGlobalLinkInformation(const char* name, cmTarget& target)
{ {
case cmTarget::UTILITY: case cmTarget::UTILITY:
case cmTarget::GLOBAL_TARGET: case cmTarget::GLOBAL_TARGET:
case cmTarget::INTERFACE_LIBRARY:
return; return;
default:; default:;
} }
@ -2017,7 +2019,8 @@ cmTarget* cmMakefile::AddLibrary(const char* lname, cmTarget::TargetType type,
if ( (type != cmTarget::STATIC_LIBRARY) if ( (type != cmTarget::STATIC_LIBRARY)
&& (type != cmTarget::SHARED_LIBRARY) && (type != cmTarget::SHARED_LIBRARY)
&& (type != cmTarget::MODULE_LIBRARY) && (type != cmTarget::MODULE_LIBRARY)
&& (type != cmTarget::OBJECT_LIBRARY)) && (type != cmTarget::OBJECT_LIBRARY)
&& (type != cmTarget::INTERFACE_LIBRARY))
{ {
this->IssueMessage(cmake::INTERNAL_ERROR, this->IssueMessage(cmake::INTERNAL_ERROR,
"cmMakefile::AddLibrary given invalid target type."); "cmMakefile::AddLibrary given invalid target type.");

View File

@ -996,7 +996,12 @@ void cmMakefileTargetGenerator::WriteTargetDependRules()
i = items.begin(); i != items.end(); ++i) i = items.begin(); i != items.end(); ++i)
{ {
cmTarget const* linkee = i->Target; cmTarget const* linkee = i->Target;
if(linkee && !linkee->IsImported() && emitted.insert(linkee).second) if(linkee && !linkee->IsImported()
// We can ignore the INTERFACE_LIBRARY items because
// Target->GetLinkInformation already processed their
// link interface and they don't have any output themselves.
&& linkee->GetType() != cmTarget::INTERFACE_LIBRARY
&& emitted.insert(linkee).second)
{ {
cmMakefile* mf = linkee->GetMakefile(); cmMakefile* mf = linkee->GetMakefile();
cmLocalGenerator* lg = mf->GetLocalGenerator(); cmLocalGenerator* lg = mf->GetLocalGenerator();

View File

@ -47,6 +47,8 @@ const char* cmTarget::GetTargetTypeName(TargetType targetType)
return "UTILITY"; return "UTILITY";
case cmTarget::GLOBAL_TARGET: case cmTarget::GLOBAL_TARGET:
return "GLOBAL_TARGET"; return "GLOBAL_TARGET";
case cmTarget::INTERFACE_LIBRARY:
return "INTERFACE_LIBRARY";
case cmTarget::UNKNOWN_LIBRARY: case cmTarget::UNKNOWN_LIBRARY:
return "UNKNOWN_LIBRARY"; return "UNKNOWN_LIBRARY";
} }
@ -1727,6 +1729,14 @@ void cmTarget::SetMakefile(cmMakefile* mf)
CM_FOR_EACH_TARGET_POLICY(CAPTURE_TARGET_POLICY) CM_FOR_EACH_TARGET_POLICY(CAPTURE_TARGET_POLICY)
#undef CAPTURE_TARGET_POLICY #undef CAPTURE_TARGET_POLICY
if (this->TargetTypeValue == INTERFACE_LIBRARY)
{
// This policy is checked in a few conditions. The properties relevant
// to the policy are always ignored for INTERFACE_LIBRARY targets,
// so ensure that the conditions don't lead to nonsense.
this->PolicyStatusCMP0022 = cmPolicies::NEW;
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -1792,6 +1802,7 @@ bool cmTarget::IsLinkable()
this->GetType() == cmTarget::SHARED_LIBRARY || this->GetType() == cmTarget::SHARED_LIBRARY ||
this->GetType() == cmTarget::MODULE_LIBRARY || this->GetType() == cmTarget::MODULE_LIBRARY ||
this->GetType() == cmTarget::UNKNOWN_LIBRARY || this->GetType() == cmTarget::UNKNOWN_LIBRARY ||
this->GetType() == cmTarget::INTERFACE_LIBRARY ||
this->IsExecutableWithExports()); this->IsExecutableWithExports());
} }
@ -2563,8 +2574,8 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf,
return; return;
} }
{
cmTarget *tgt = this->Makefile->FindTargetToUse(lib); cmTarget *tgt = this->Makefile->FindTargetToUse(lib);
{
const bool isNonImportedTarget = tgt && !tgt->IsImported(); const bool isNonImportedTarget = tgt && !tgt->IsImported();
const std::string libName = (isNonImportedTarget && llt != GENERAL) const std::string libName = (isNonImportedTarget && llt != GENERAL)
@ -2575,7 +2586,8 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf,
llt).c_str()); llt).c_str());
} }
if (cmGeneratorExpression::Find(lib) != std::string::npos) if (cmGeneratorExpression::Find(lib) != std::string::npos
|| (tgt && tgt->GetType() == INTERFACE_LIBRARY))
{ {
return; return;
} }
@ -4091,6 +4103,7 @@ const char *cmTarget::GetProperty(const char* prop,
this->GetType() == cmTarget::STATIC_LIBRARY || this->GetType() == cmTarget::STATIC_LIBRARY ||
this->GetType() == cmTarget::SHARED_LIBRARY || this->GetType() == cmTarget::SHARED_LIBRARY ||
this->GetType() == cmTarget::MODULE_LIBRARY || this->GetType() == cmTarget::MODULE_LIBRARY ||
this->GetType() == cmTarget::INTERFACE_LIBRARY ||
this->GetType() == cmTarget::UNKNOWN_LIBRARY) this->GetType() == cmTarget::UNKNOWN_LIBRARY)
{ {
if(strcmp(prop,"LOCATION") == 0) if(strcmp(prop,"LOCATION") == 0)
@ -5999,6 +6012,10 @@ cmTarget::GetImportInfo(const char* config, cmTarget *headTarget)
i = this->Internal->ImportInfoMap.insert(entry).first; i = this->Internal->ImportInfoMap.insert(entry).first;
} }
if(this->GetType() == INTERFACE_LIBRARY)
{
return &i->second;
}
// If the location is empty then the target is not available for // If the location is empty then the target is not available for
// this configuration. // this configuration.
if(i->second.Location.empty() && i->second.ImportLibrary.empty()) if(i->second.Location.empty() && i->second.ImportLibrary.empty())
@ -6152,6 +6169,49 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config,
return; return;
} }
// Get the link interface.
{
std::string linkProp = "INTERFACE_LINK_LIBRARIES";
const char *propertyLibs = this->GetProperty(linkProp.c_str());
if (this->GetType() != INTERFACE_LIBRARY)
{
if(!propertyLibs)
{
linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
linkProp += suffix;
propertyLibs = this->GetProperty(linkProp.c_str());
}
if(!propertyLibs)
{
linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
propertyLibs = this->GetProperty(linkProp.c_str());
}
}
if(propertyLibs)
{
cmListFileBacktrace lfbt;
cmGeneratorExpression ge(lfbt);
cmGeneratorExpressionDAGChecker dagChecker(lfbt,
this->GetName(),
linkProp, 0, 0);
cmSystemTools::ExpandListArgument(ge.Parse(propertyLibs)
->Evaluate(this->Makefile,
desired_config.c_str(),
false,
headTarget,
this,
&dagChecker),
info.LinkInterface.Libraries);
}
}
if(this->GetType() == INTERFACE_LIBRARY)
{
return;
}
// A provided configuration has been chosen. Load the // A provided configuration has been chosen. Load the
// configuration's properties. // configuration's properties.
@ -6224,42 +6284,6 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config,
} }
} }
// Get the link interface.
{
std::string linkProp = "INTERFACE_LINK_LIBRARIES";
const char *propertyLibs = this->GetProperty(linkProp.c_str());
if (!propertyLibs)
{
linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
linkProp += suffix;
propertyLibs = this->GetProperty(linkProp.c_str());
}
if(!propertyLibs)
{
linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
propertyLibs = this->GetProperty(linkProp.c_str());
}
if(propertyLibs)
{
cmListFileBacktrace lfbt;
cmGeneratorExpression ge(lfbt);
cmGeneratorExpressionDAGChecker dagChecker(lfbt,
this->GetName(),
linkProp, 0, 0);
cmSystemTools::ExpandListArgument(ge.Parse(propertyLibs)
->Evaluate(this->Makefile,
desired_config.c_str(),
false,
headTarget,
this,
&dagChecker),
info.LinkInterface.Libraries);
}
}
// Get the link dependencies. // Get the link dependencies.
{ {
std::string linkProp = "IMPORTED_LINK_DEPENDENT_LIBRARIES"; std::string linkProp = "IMPORTED_LINK_DEPENDENT_LIBRARIES";
@ -6520,6 +6544,11 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface,
} }
} }
} }
else if (this->GetType() == cmTarget::INTERFACE_LIBRARY)
{
explicitLibraries = newExplicitLibraries;
linkIfaceProp = "INTERFACE_LINK_LIBRARIES";
}
// There is no implicit link interface for executables or modules // There is no implicit link interface for executables or modules
// so if none was explicitly set then there is no link interface. // so if none was explicitly set then there is no link interface.
@ -6547,7 +6576,8 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface,
this, &dagChecker), iface.Libraries); this, &dagChecker), iface.Libraries);
if(this->GetType() == cmTarget::SHARED_LIBRARY if(this->GetType() == cmTarget::SHARED_LIBRARY
|| this->GetType() == cmTarget::STATIC_LIBRARY) || this->GetType() == cmTarget::STATIC_LIBRARY
|| this->GetType() == cmTarget::INTERFACE_LIBRARY)
{ {
// Shared libraries may have runtime implementation dependencies // Shared libraries may have runtime implementation dependencies
// on other shared libraries that are not in the interface. // on other shared libraries that are not in the interface.

View File

@ -72,6 +72,7 @@ public:
enum TargetType { EXECUTABLE, STATIC_LIBRARY, enum TargetType { EXECUTABLE, STATIC_LIBRARY,
SHARED_LIBRARY, MODULE_LIBRARY, SHARED_LIBRARY, MODULE_LIBRARY,
OBJECT_LIBRARY, UTILITY, GLOBAL_TARGET, OBJECT_LIBRARY, UTILITY, GLOBAL_TARGET,
INTERFACE_LIBRARY,
UNKNOWN_LIBRARY}; UNKNOWN_LIBRARY};
static const char* GetTargetTypeName(TargetType targetType); static const char* GetTargetTypeName(TargetType targetType);
enum CustomCommandType { PRE_BUILD, PRE_LINK, POST_BUILD }; enum CustomCommandType { PRE_BUILD, PRE_LINK, POST_BUILD };

View File

@ -322,6 +322,15 @@ bool
cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib, cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
cmTarget::LinkLibraryType llt) cmTarget::LinkLibraryType llt)
{ {
if(this->Target->GetType() == cmTarget::INTERFACE_LIBRARY
&& this->CurrentProcessingState != ProcessingKeywordLinkInterface)
{
this->Makefile->IssueMessage(cmake::FATAL_ERROR,
"INTERFACE library can only be used with the INTERFACE keyword of "
"target_link_libraries");
return false;
}
cmTarget::TLLSignature sig = cmTarget::TLLSignature sig =
(this->CurrentProcessingState == ProcessingPlainPrivateInterface (this->CurrentProcessingState == ProcessingPlainPrivateInterface
|| this->CurrentProcessingState == ProcessingPlainPublicInterface || this->CurrentProcessingState == ProcessingPlainPublicInterface
@ -407,6 +416,11 @@ cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
return true; return true;
} }
if (this->Target->GetType() == cmTarget::INTERFACE_LIBRARY)
{
return true;
}
// Get the list of configurations considered to be DEBUG. // Get the list of configurations considered to be DEBUG.
std::vector<std::string> const& debugConfigs = std::vector<std::string> const& debugConfigs =
this->Makefile->GetCMakeInstance()->GetDebugConfigs(); this->Makefile->GetCMakeInstance()->GetDebugConfigs();

View File

@ -47,6 +47,7 @@ bool cmTargetPropCommandBase
&& (this->Target->GetType() != cmTarget::STATIC_LIBRARY) && (this->Target->GetType() != cmTarget::STATIC_LIBRARY)
&& (this->Target->GetType() != cmTarget::OBJECT_LIBRARY) && (this->Target->GetType() != cmTarget::OBJECT_LIBRARY)
&& (this->Target->GetType() != cmTarget::MODULE_LIBRARY) && (this->Target->GetType() != cmTarget::MODULE_LIBRARY)
&& (this->Target->GetType() != cmTarget::INTERFACE_LIBRARY)
&& (this->Target->GetType() != cmTarget::EXECUTABLE)) && (this->Target->GetType() != cmTarget::EXECUTABLE))
{ {
this->SetError("called with non-compilable target type"); this->SetError("called with non-compilable target type");
@ -112,6 +113,14 @@ bool cmTargetPropCommandBase
return false; return false;
} }
if (this->Target->GetType() == cmTarget::INTERFACE_LIBRARY
&& scope != "INTERFACE")
{
this->SetError("may only be set INTERFACE properties on INTERFACE "
"targets");
return false;
}
++argIndex; ++argIndex;
std::vector<std::string> content; std::vector<std::string> content;

View File

@ -490,6 +490,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues()
break; break;
case cmTarget::GLOBAL_TARGET: case cmTarget::GLOBAL_TARGET:
case cmTarget::UNKNOWN_LIBRARY: case cmTarget::UNKNOWN_LIBRARY:
case cmTarget::INTERFACE_LIBRARY:
break; break;
} }
configType += "</ConfigurationType>\n"; configType += "</ConfigurationType>\n";
@ -1701,7 +1702,8 @@ void cmVisualStudio10TargetGenerator::AddLibraries(
libstring += sep; libstring += sep;
libstring += path; libstring += path;
} }
else else if (!l->Target
|| l->Target->GetType() != cmTarget::INTERFACE_LIBRARY)
{ {
libstring += sep; libstring += sep;
libstring += l->Value; libstring += l->Value;
@ -1836,6 +1838,10 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences()
i != depends.end(); ++i) i != depends.end(); ++i)
{ {
cmTarget* dt = *i; cmTarget* dt = *i;
if(dt->GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
// skip fortran targets as they can not be processed by MSBuild // skip fortran targets as they can not be processed by MSBuild
// the only reference will be in the .sln file // the only reference will be in the .sln file
if(static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator) if(static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator)

View File

@ -45,3 +45,6 @@ get_property(_alt2 TARGET PREFIX::Foo PROPERTY ALIASED_TARGET)
if (NOT ${_alt2} STREQUAL foo) if (NOT ${_alt2} STREQUAL foo)
message(SEND_ERROR "ALIASED_TARGET is not foo.") message(SEND_ERROR "ALIASED_TARGET is not foo.")
endif() endif()
add_library(iface INTERFACE)
add_library(Alias::Iface ALIAS iface)

View File

@ -246,6 +246,7 @@ if(BUILD_TESTING)
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) ADD_TEST_MACRO(AliasTarget AliasTarget)
ADD_TEST_MACRO(InterfaceLibrary InterfaceLibrary)
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

@ -6,7 +6,7 @@ project(CompatibleInterface)
include(GenerateExportHeader) include(GenerateExportHeader)
set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INCLUDE_CURRENT_DIR ON)
add_library(iface1 empty.cpp) add_library(iface1 INTERFACE)
set_property(TARGET iface1 APPEND PROPERTY set_property(TARGET iface1 APPEND PROPERTY
COMPATIBLE_INTERFACE_BOOL COMPATIBLE_INTERFACE_BOOL
BOOL_PROP1 BOOL_PROP1

View File

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 2.8)
project(InterfaceLibrary)
add_library(iface_nodepends INTERFACE)
target_compile_definitions(iface_nodepends INTERFACE IFACE_DEFINE)
add_executable(InterfaceLibrary definetestexe.cpp)
target_link_libraries(InterfaceLibrary iface_nodepends)
add_subdirectory(libsdir)
add_executable(sharedlibtestexe sharedlibtestexe.cpp)
target_link_libraries(sharedlibtestexe shared_iface)

View File

@ -0,0 +1,9 @@
#ifndef IFACE_DEFINE
#error Expected IFACE_DEFINE
#endif
int main(int,char**)
{
return 0;
}

View File

@ -0,0 +1,26 @@
include(GenerateExportHeader)
add_library(sharedlib SHARED sharedlib.cpp)
generate_export_header(sharedlib)
add_library(shareddependlib SHARED shareddependlib.cpp)
generate_export_header(shareddependlib)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
target_link_libraries(sharedlib PUBLIC shareddependlib)
target_include_directories(shareddependlib
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/shareddependlib")
target_compile_definitions(shareddependlib
INTERFACE $<1:SHAREDDEPENDLIB_DEFINE>)
target_include_directories(sharedlib
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/sharedlib")
target_compile_definitions(shareddependlib
INTERFACE $<1:SHAREDLIB_DEFINE>)
add_library(shared_iface INTERFACE)
target_link_libraries(shared_iface INTERFACE sharedlib)

View File

@ -0,0 +1,7 @@
#include "shareddependlib.h"
int SharedDependLibObject::foo() const
{
return 0;
}

View File

@ -0,0 +1,12 @@
#ifndef SHAREDDEPENDLIB_H
#define SHAREDDEPENDLIB_H
#include "shareddependlib_export.h"
struct SHAREDDEPENDLIB_EXPORT SharedDependLibObject
{
int foo() const;
};
#endif

View File

@ -0,0 +1,12 @@
#include "sharedlib.h"
SharedDependLibObject SharedLibObject::object() const
{
SharedDependLibObject sdlo;
return sdlo;
}
int SharedLibObject::foo() const
{
return 0;
}

View File

@ -0,0 +1,15 @@
#ifndef SHAREDLIB_H
#define SHAREDLIB_H
#include "sharedlib_export.h"
#include "shareddependlib.h"
struct SHAREDLIB_EXPORT SharedLibObject
{
SharedDependLibObject object() const;
int foo() const;
};
#endif

View File

@ -0,0 +1,19 @@
#ifndef SHAREDLIB_DEFINE
#error Expected SHAREDLIB_DEFINE
#endif
#ifndef SHAREDDEPENDLIB_DEFINE
#error Expected SHAREDDEPENDLIB_DEFINE
#endif
#include "sharedlib.h"
#include "shareddependlib.h"
int main(int,char**)
{
SharedLibObject sl;
SharedDependLibObject sdl = sl.object();
return sdl.foo() + sl.foo();
}

View File

@ -9,5 +9,6 @@ include_directories("${CMAKE_CURRENT_SOURCE_DIR}") # For pic_test.h
add_subdirectory(global) add_subdirectory(global)
add_subdirectory(targets) add_subdirectory(targets)
add_subdirectory(interface)
add_executable(PositionIndependentTargets main.cpp) add_executable(PositionIndependentTargets main.cpp)

View File

@ -0,0 +1,27 @@
add_library(piciface INTERFACE)
set_property(TARGET piciface PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON)
add_executable(test_empty_iface "${CMAKE_CURRENT_SOURCE_DIR}/../pic_main.cpp")
target_link_libraries(test_empty_iface piciface)
add_library(sharedlib SHARED "${CMAKE_CURRENT_SOURCE_DIR}/../pic_lib.cpp")
target_link_libraries(sharedlib piciface)
set_property(TARGET sharedlib PROPERTY DEFINE_SYMBOL PIC_TEST_BUILD_DLL)
add_executable(test_iface_via_shared "${CMAKE_CURRENT_SOURCE_DIR}/../pic_main.cpp")
target_link_libraries(test_iface_via_shared sharedlib)
add_library(sharedlibpic SHARED "${CMAKE_CURRENT_SOURCE_DIR}/../pic_lib.cpp")
set_property(TARGET sharedlibpic PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON)
set_property(TARGET sharedlibpic PROPERTY DEFINE_SYMBOL PIC_TEST_BUILD_DLL)
add_library(shared_iface INTERFACE)
target_link_libraries(shared_iface INTERFACE sharedlibpic)
add_executable(test_shared_via_iface "${CMAKE_CURRENT_SOURCE_DIR}/../pic_main.cpp")
target_link_libraries(test_shared_via_iface shared_iface)
add_executable(test_shared_via_iface_non_conflict "${CMAKE_CURRENT_SOURCE_DIR}/../pic_main.cpp")
set_property(TARGET test_shared_via_iface_non_conflict PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(test_shared_via_iface_non_conflict shared_iface)

View File

@ -100,6 +100,7 @@ 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) add_RunCMake_test(alias_targets)
add_RunCMake_test(interface_library)
find_package(Qt4 QUIET) find_package(Qt4 QUIET)
find_package(Qt5Core QUIET) find_package(Qt5Core QUIET)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error: Property POSITION_INDEPENDENT_CODE on target "conflict" is
implied to be FALSE because it was used to determine the link libraries
already. The INTERFACE_POSITION_INDEPENDENT_CODE property on
dependency "picon" is in conflict.

View File

@ -0,0 +1,8 @@
add_library(piciface INTERFACE)
add_library(picon INTERFACE)
set_property(TARGET picon PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON)
add_executable(conflict "main.cpp")
target_link_libraries(conflict picon $<$<BOOL:$<TARGET_PROPERTY:POSITION_INDEPENDENT_CODE>>:piciface>)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,3 @@
CMake Error: The INTERFACE_POSITION_INDEPENDENT_CODE property of "picoff" does
not agree with the value of POSITION_INDEPENDENT_CODE already determined
for "conflict".

View File

@ -0,0 +1,9 @@
add_library(picon INTERFACE)
set_property(TARGET picon PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON)
add_library(picoff INTERFACE)
set_property(TARGET picoff PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE OFF)
add_executable(conflict "main.cpp")
target_link_libraries(conflict picon picoff)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
Property POSITION_INDEPENDENT_CODE on target "conflict" is
implied to be FALSE because it was used to determine the link libraries
already. The INTERFACE_POSITION_INDEPENDENT_CODE property on
dependency "picon" is in conflict.

View File

@ -0,0 +1,8 @@
add_library(picoff INTERFACE)
add_library(picon INTERFACE)
set_property(TARGET picon PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON)
add_executable(conflict "main.cpp")
target_link_libraries(conflict picon $<$<NOT:$<BOOL:$<TARGET_PROPERTY:POSITION_INDEPENDENT_CODE>>>:picoff>)

View File

@ -3,3 +3,6 @@ include(RunCMake)
run_cmake(Conflict1) run_cmake(Conflict1)
run_cmake(Conflict2) run_cmake(Conflict2)
run_cmake(Conflict3) run_cmake(Conflict3)
run_cmake(Conflict4)
run_cmake(Conflict5)
run_cmake(Conflict6)

View File

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

View File

@ -0,0 +1,4 @@
include(RunCMake)
run_cmake(invalid_name)
run_cmake(target_commands)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,9 @@
CMake Error at invalid_name.cmake:2 \(add_library\):
add_library Invalid name for INTERFACE library target: if\$ace
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at invalid_name.cmake:4 \(add_library\):
add_library Invalid name for INTERFACE library target: iface::target
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,4 @@
add_library(if$ace INTERFACE)
add_library(iface::target INTERFACE)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,47 @@
CMake Error at target_commands.cmake:4 \(target_link_libraries\):
INTERFACE library can only be used with the INTERFACE keyword of
target_link_libraries
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at target_commands.cmake:5 \(target_link_libraries\):
INTERFACE library can only be used with the INTERFACE keyword of
target_link_libraries
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at target_commands.cmake:6 \(target_link_libraries\):
INTERFACE library can only be used with the INTERFACE keyword of
target_link_libraries
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at target_commands.cmake:7 \(target_link_libraries\):
INTERFACE library can only be used with the INTERFACE keyword of
target_link_libraries
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at target_commands.cmake:9 \(target_include_directories\):
target_include_directories may only be set INTERFACE properties on
INTERFACE targets
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at target_commands.cmake:10 \(target_include_directories\):
target_include_directories may only be set INTERFACE properties on
INTERFACE targets
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at target_commands.cmake:12 \(target_compile_definitions\):
target_compile_definitions may only be set INTERFACE properties on
INTERFACE targets
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
CMake Error at target_commands.cmake:13 \(target_compile_definitions\):
target_compile_definitions may only be set INTERFACE properties on
INTERFACE targets
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,13 @@
add_library(iface INTERFACE)
target_link_libraries(iface PRIVATE foo)
target_link_libraries(iface PUBLIC foo)
target_link_libraries(iface foo)
target_link_libraries(iface LINK_INTERFACE_LIBRARIES foo)
target_include_directories(iface PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
target_include_directories(iface PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
target_compile_definitions(iface PRIVATE SOME_DEFINE)
target_compile_definitions(iface PUBLIC SOME_DEFINE)