Merge topic 'INTERFACE_LIBRARY-target-type'

ce0c303 install: Teach EXPORT option to handle INTERFACE_LIBRARY targets
435c912 export: Add support for INTERFACE_LIBRARY targets
fe73226 Add the INTERFACE_LIBRARY target type.
This commit is contained in:
Brad King 2013-10-08 10:58:40 -04:00 committed by CMake Topic Stage
commit f8241136b4
71 changed files with 771 additions and 65 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
@ -213,6 +220,16 @@ bool cmAddLibraryCommand
); );
return true; return true;
} }
if(type == cmTarget::INTERFACE_LIBRARY)
{
if (!cmGeneratorExpression::IsValidTargetName(libName))
{
cmOStringStream e;
e << "Invalid name for IMPORTED INTERFACE library target: " << libName;
this->SetError(e.str().c_str());
return false;
}
}
// Make sure the target does not already exist. // Make sure the target does not already exist.
if(this->Makefile->FindTargetToUse(libName.c_str())) if(this->Makefile->FindTargetToUse(libName.c_str()))
@ -249,6 +266,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 +295,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

@ -99,6 +99,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
{ {
case cmTarget::SHARED_LIBRARY: case cmTarget::SHARED_LIBRARY:
case cmTarget::STATIC_LIBRARY: case cmTarget::STATIC_LIBRARY:
case cmTarget::INTERFACE_LIBRARY:
case cmTarget::UNKNOWN_LIBRARY: case cmTarget::UNKNOWN_LIBRARY:
break; break;
case cmTarget::EXECUTABLE: case cmTarget::EXECUTABLE:

View File

@ -47,6 +47,10 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
} }
return false; return false;
} }
if (te->GetType() == cmTarget::INTERFACE_LIBRARY)
{
this->GenerateRequiredCMakeVersion(os, "2.8.12.20131007"); // 2.8.13
}
} }
this->GenerateExpectedTargetsCode(os, expectedTargets); this->GenerateExpectedTargetsCode(os, expectedTargets);
@ -118,16 +122,22 @@ cmExportBuildFileGenerator
// Collect import properties for this target. // Collect import properties for this target.
cmTarget* target = *tei; cmTarget* target = *tei;
ImportPropertyMap properties; ImportPropertyMap properties;
this->SetImportLocationProperty(config, suffix, target, properties);
if (target->GetType() != cmTarget::INTERFACE_LIBRARY)
{
this->SetImportLocationProperty(config, suffix, target, properties);
}
if(!properties.empty()) if(!properties.empty())
{ {
// Get the rest of the target details. // Get the rest of the target details.
this->SetImportDetailProperties(config, suffix, if (target->GetType() != cmTarget::INTERFACE_LIBRARY)
target, properties, missingTargets); {
this->SetImportLinkInterface(config, suffix, this->SetImportDetailProperties(config, suffix,
cmGeneratorExpression::BuildInterface, target, properties, missingTargets);
target, properties, missingTargets); this->SetImportLinkInterface(config, suffix,
cmGeneratorExpression::BuildInterface,
target, properties, missingTargets);
}
// TOOD: PUBLIC_HEADER_LOCATION // TOOD: PUBLIC_HEADER_LOCATION
// This should wait until the build feature propagation stuff // This should wait until the build feature propagation stuff

View File

@ -130,7 +130,8 @@ bool cmExportCommand
if((target->GetType() == cmTarget::EXECUTABLE) || if((target->GetType() == cmTarget::EXECUTABLE) ||
(target->GetType() == cmTarget::STATIC_LIBRARY) || (target->GetType() == cmTarget::STATIC_LIBRARY) ||
(target->GetType() == cmTarget::SHARED_LIBRARY) || (target->GetType() == cmTarget::SHARED_LIBRARY) ||
(target->GetType() == cmTarget::MODULE_LIBRARY)) (target->GetType() == cmTarget::MODULE_LIBRARY) ||
(target->GetType() == cmTarget::INTERFACE_LIBRARY))
{ {
targets.push_back(target); targets.push_back(target);
} }

View File

@ -378,11 +378,14 @@ void getCompatibleInterfaceProperties(cmTarget *target,
if (!info) if (!info)
{ {
cmMakefile* mf = target->GetMakefile(); if (target->GetType() != cmTarget::INTERFACE_LIBRARY)
cmOStringStream e; {
e << "Exporting the target \"" << target->GetName() << "\" is not " cmMakefile* mf = target->GetMakefile();
"allowed since its linker language cannot be determined"; cmOStringStream e;
mf->IssueMessage(cmake::FATAL_ERROR, e.str()); e << "Exporting the target \"" << target->GetName() << "\" is not "
"allowed since its linker language cannot be determined";
mf->IssueMessage(cmake::FATAL_ERROR, e.str());
}
return; return;
} }
@ -888,6 +891,9 @@ cmExportFileGenerator
case cmTarget::UNKNOWN_LIBRARY: case cmTarget::UNKNOWN_LIBRARY:
os << "add_library(" << targetName << " UNKNOWN IMPORTED)\n"; os << "add_library(" << targetName << " UNKNOWN IMPORTED)\n";
break; break;
case cmTarget::INTERFACE_LIBRARY:
os << "add_library(" << targetName << " INTERFACE IMPORTED)\n";
break;
default: // should never happen default: // should never happen
break; break;
} }

View File

@ -114,6 +114,7 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
std::vector<std::string> missingTargets; std::vector<std::string> missingTargets;
bool require2_8_12 = false; bool require2_8_12 = false;
bool require2_8_13 = false;
// Create all the imported targets. // Create all the imported targets.
for(std::vector<cmTargetExport*>::const_iterator for(std::vector<cmTargetExport*>::const_iterator
tei = allTargets.begin(); tei = allTargets.begin();
@ -153,6 +154,10 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
require2_8_12 = true; require2_8_12 = true;
} }
} }
if (te->GetType() == cmTarget::INTERFACE_LIBRARY)
{
require2_8_13 = true;
}
this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE",
te, properties); te, properties);
this->PopulateCompatibleInterfaceProperties(te, properties); this->PopulateCompatibleInterfaceProperties(te, properties);
@ -160,7 +165,11 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
this->GenerateInterfaceProperties(te, os, properties); this->GenerateInterfaceProperties(te, os, properties);
} }
if (require2_8_12) if (require2_8_13)
{
this->GenerateRequiredCMakeVersion(os, "2.8.12.20131007");
}
else if (require2_8_12)
{ {
this->GenerateRequiredCMakeVersion(os, "2.8.12"); this->GenerateRequiredCMakeVersion(os, "2.8.12");
} }
@ -286,6 +295,14 @@ cmExportInstallFileGenerator
cmTargetExport const* te = *tei; cmTargetExport const* te = *tei;
ImportPropertyMap properties; ImportPropertyMap properties;
std::set<std::string> importedLocations; std::set<std::string> importedLocations;
if (!properties.empty()
&& te->Target->GetType() == cmTarget::INTERFACE_LIBRARY)
{
this->GenerateImportPropertyCode(os, config, te->Target, properties);
this->GenerateImportedFileChecksCode(os, te->Target, properties,
importedLocations);
continue;
}
this->SetImportLocationProperty(config, suffix, te->ArchiveGenerator, this->SetImportLocationProperty(config, suffix, te->ArchiveGenerator,
properties, importedLocations); properties, importedLocations);
this->SetImportLocationProperty(config, suffix, te->LibraryGenerator, this->SetImportLocationProperty(config, suffix, te->LibraryGenerator,

View File

@ -2563,6 +2563,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

@ -409,6 +409,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

@ -379,7 +379,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
target->GetType() != cmTarget::STATIC_LIBRARY && target->GetType() != cmTarget::STATIC_LIBRARY &&
target->GetType() != cmTarget::SHARED_LIBRARY && target->GetType() != cmTarget::SHARED_LIBRARY &&
target->GetType() != cmTarget::MODULE_LIBRARY && target->GetType() != cmTarget::MODULE_LIBRARY &&
target->GetType() != cmTarget::OBJECT_LIBRARY) target->GetType() != cmTarget::OBJECT_LIBRARY &&
target->GetType() != cmTarget::INTERFACE_LIBRARY)
{ {
cmOStringStream e; cmOStringStream e;
e << "TARGETS given target \"" << (*targetIt) e << "TARGETS given target \"" << (*targetIt)
@ -626,6 +627,11 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
} }
} }
break; break;
case cmTarget::INTERFACE_LIBRARY:
// Nothing to do. An INTERFACE_LIBRARY can be installed, but the
// only effect of that is to make it exportable. It installs no
// other files itself.
break;
default: default:
// This should never happen due to the above type check. // This should never happen due to the above type check.
// Ignore the case. // Ignore the case.

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

@ -1794,6 +1794,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);
@ -1997,6 +2001,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

@ -1004,7 +1004,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";
} }
@ -1743,6 +1745,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;
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -1808,6 +1818,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());
} }
@ -2579,8 +2590,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)
@ -2591,7 +2602,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;
} }
@ -4137,6 +4149,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)
@ -6061,6 +6074,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())
@ -6209,7 +6226,51 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config,
const char* loc = 0; const char* loc = 0;
const char* imp = 0; const char* imp = 0;
std::string suffix; std::string suffix;
if (!this->GetMappedConfig(desired_config, &loc, &imp, suffix)) if (this->GetType() != INTERFACE_LIBRARY &&
!this->GetMappedConfig(desired_config, &loc, &imp, suffix))
{
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; return;
} }
@ -6286,42 +6347,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";
@ -6582,6 +6607,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.
@ -6609,7 +6639,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

@ -436,3 +436,5 @@ export(TARGETS testExe2 testLib4 testLib5 testLib6 testExe3 testExe2lib
NAMESPACE bld_ NAMESPACE bld_
APPEND FILE ExportBuildTree.cmake APPEND FILE ExportBuildTree.cmake
) )
add_subdirectory(Interface)

View File

@ -0,0 +1,49 @@
add_library(headeronly INTERFACE)
set_property(TARGET headeronly PROPERTY INTERFACE_INCLUDE_DIRECTORIES
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/headeronly>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include/headeronly>"
)
set_property(TARGET headeronly PROPERTY INTERFACE_COMPILE_DEFINITIONS "HEADERONLY_DEFINE")
include(GenerateExportHeader)
add_library(sharedlib SHARED sharedlib.cpp)
generate_export_header(sharedlib)
set_property(TARGET sharedlib PROPERTY INCLUDE_DIRECTORIES
"${CMAKE_CURRENT_SOURCE_DIR}/sharedlib"
"${CMAKE_CURRENT_BINARY_DIR}"
)
set_property(TARGET sharedlib PROPERTY INTERFACE_INCLUDE_DIRECTORIES
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/sharedlib;${CMAKE_CURRENT_BINARY_DIR}>"
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include/sharedlib>"
)
set_property(TARGET sharedlib PROPERTY INTERFACE_COMPILE_DEFINITIONS "SHAREDLIB_DEFINE")
add_library(sharediface INTERFACE)
target_link_libraries(sharediface INTERFACE sharedlib)
export(TARGETS sharediface sharedlib headeronly
NAMESPACE bld_
FILE ../ExportInterfaceBuildTree.cmake
)
install(TARGETS headeronly sharediface sharedlib
EXPORT expInterface
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib NAMELINK_SKIP
ARCHIVE DESTINATION lib
FRAMEWORK DESTINATION Frameworks
BUNDLE DESTINATION Applications
)
install(FILES
headeronly/headeronly.h
DESTINATION include/headeronly
)
install(FILES
sharedlib/sharedlib.h
"${CMAKE_CURRENT_BINARY_DIR}/sharedlib_export.h"
DESTINATION include/sharedlib
)
install(EXPORT expInterface NAMESPACE exp_ DESTINATION lib/exp)

View File

@ -0,0 +1,7 @@
enum { one };
struct HeaderOnly
{
int foo() const { return 0; }
};

View File

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

View File

@ -0,0 +1,7 @@
#include "sharedlib_export.h"
struct SHAREDLIB_EXPORT SharedLibObject
{
int foo() const;
};

View File

@ -19,3 +19,6 @@ add_executable(imp_testTransExe1b imp_testTransExe1.c)
target_link_libraries(imp_testTransExe1b imp_lib1b) target_link_libraries(imp_testTransExe1b imp_lib1b)
add_subdirectory(try_compile) add_subdirectory(try_compile)
# Test package INTERFACE controls
add_subdirectory(Interface)

View File

@ -0,0 +1,55 @@
# Import targets from the exported build tree.
include(${Import_BINARY_DIR}/../Export/ExportInterfaceBuildTree.cmake)
# Import targets from the exported install tree.
include(${CMAKE_INSTALL_PREFIX}/lib/exp/expInterface.cmake)
add_library(define_iface INTERFACE)
set_property(TARGET define_iface PROPERTY
INTERFACE_COMPILE_DEFINITIONS DEFINE_IFACE_DEFINE)
add_executable(headeronlytest_bld headeronlytest.cpp)
target_link_libraries(headeronlytest_bld bld_headeronly)
set_property(TARGET bld_sharediface APPEND PROPERTY INTERFACE_LINK_LIBRARIES define_iface)
add_executable(interfacetest_bld interfacetest.cpp)
target_link_libraries(interfacetest_bld bld_sharediface)
include(CheckCXXSourceCompiles)
macro(do_try_compile prefix)
set(CMAKE_REQUIRED_LIBRARIES ${prefix}headeronly)
check_cxx_source_compiles(
"
#include \"headeronly.h\"
#ifndef HEADERONLY_DEFINE
#error Expected HEADERONLY_DEFINE
#endif
int main(int,char**)
{
HeaderOnly ho;
return ho.foo();
}
" ${prefix}IFACE_TRY_COMPILE)
if(NOT ${prefix}IFACE_TRY_COMPILE)
message(SEND_ERROR "${prefix} try_compile with IMPORTED INTERFACE target failed!\n\n${OUTPUT}")
endif()
endmacro()
do_try_compile(bld_)
add_executable(headeronlytest_exp headeronlytest.cpp)
target_link_libraries(headeronlytest_exp exp_headeronly)
set_property(TARGET exp_sharediface APPEND PROPERTY INTERFACE_LINK_LIBRARIES define_iface)
add_executable(interfacetest_exp interfacetest.cpp)
target_link_libraries(interfacetest_exp exp_sharediface)
do_try_compile(exp_)

View File

@ -0,0 +1,17 @@
#include "headeronly.h"
#ifndef HEADERONLY_DEFINE
#error Expected HEADERONLY_DEFINE
#endif
#ifdef SHAREDLIB_DEFINE
#error Unexpected SHAREDLIB_DEFINE
#endif
int main(int,char**)
{
HeaderOnly ho;
return ho.foo();
}

View File

@ -0,0 +1,20 @@
#include "sharedlib.h"
#ifndef SHAREDLIB_DEFINE
#error Expected SHAREDLIB_DEFINE
#endif
#ifdef HEADERONLY_DEFINE
#error Unexpected HEADERONLY_DEFINE
#endif
#ifndef DEFINE_IFACE_DEFINE
#error Expected DEFINE_IFACE_DEFINE
#endif
int main(int,char**)
{
SharedLibObject slo;
return slo.foo();
}

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,15 @@
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\)
+
CMake Error at invalid_name.cmake:6 \(add_library\):
add_library Invalid name for IMPORTED INTERFACE library target:
if\$target_imported
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

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

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)