diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index cbc6ed1e9..0e61c9956 100644 --- a/Source/cmAddLibraryCommand.cxx +++ b/Source/cmAddLibraryCommand.cxx @@ -82,6 +82,12 @@ bool cmAddLibraryCommand ++s; isAlias = true; } + else if(libType == "INTERFACE") + { + ++s; + type = cmTarget::INTERFACE_LIBRARY; + haveSpecifiedType = true; + } else if(*s == "EXCLUDE_FROM_ALL") { ++s; @@ -151,7 +157,8 @@ bool cmAddLibraryCommand if(aliasedType != cmTarget::SHARED_LIBRARY && aliasedType != cmTarget::STATIC_LIBRARY && aliasedType != cmTarget::MODULE_LIBRARY - && aliasedType != cmTarget::OBJECT_LIBRARY) + && aliasedType != cmTarget::OBJECT_LIBRARY + && aliasedType != cmTarget::INTERFACE_LIBRARY) { cmOStringStream e; e << "cannot create ALIAS target \"" << libName @@ -213,6 +220,16 @@ bool cmAddLibraryCommand ); 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. if(this->Makefile->FindTargetToUse(libName.c_str())) @@ -249,6 +266,26 @@ bool cmAddLibraryCommand } } + std::vector 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()) { std::string msg = "You have called ADD_LIBRARY for library "; @@ -258,7 +295,6 @@ bool cmAddLibraryCommand cmSystemTools::Message(msg.c_str() ,"Warning"); } - std::vector srclists; while (s != args.end()) { srclists.push_back(*s); diff --git a/Source/cmAddLibraryCommand.h b/Source/cmAddLibraryCommand.h index 59354b0f5..64d048b27 100644 --- a/Source/cmAddLibraryCommand.h +++ b/Source/cmAddLibraryCommand.h @@ -151,6 +151,16 @@ public: "properties of , that is, it may not be used as the operand of " "set_property, set_target_properties, target_link_libraries etc. An " "ALIAS target may not be installed of exported." + "\n" + "The signature\n" + " add_library( 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." ; } diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index dec2b54d1..a2f3f7d8f 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -355,9 +355,16 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe) if(cmTarget::LinkInterface const* iface = 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->AddLinkEntries(depender_index, iface->Libraries); + if (isIface) + { + return; + } + // Handle dependent shared libraries. this->FollowSharedDeps(depender_index, iface); diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index fb7b5b67d..d3b28ed95 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -655,6 +655,11 @@ void cmComputeLinkInformation::AddItem(std::string const& item, cmTarget* tgt) (this->UseImportLibrary && (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. std::string lib = tgt->GetFullPath(config, implib, true); if(!this->LinkDependsNoShared || diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 8dfaf3b92..bc4bf184e 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -99,6 +99,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector const& argv) { case cmTarget::SHARED_LIBRARY: case cmTarget::STATIC_LIBRARY: + case cmTarget::INTERFACE_LIBRARY: case cmTarget::UNKNOWN_LIBRARY: break; case cmTarget::EXECUTABLE: diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index cdc3316c4..243e5ce54 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -47,6 +47,10 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) } return false; } + if (te->GetType() == cmTarget::INTERFACE_LIBRARY) + { + this->GenerateRequiredCMakeVersion(os, "2.8.12.20131007"); // 2.8.13 + } } this->GenerateExpectedTargetsCode(os, expectedTargets); @@ -118,16 +122,22 @@ cmExportBuildFileGenerator // Collect import properties for this target. cmTarget* target = *tei; ImportPropertyMap properties; - this->SetImportLocationProperty(config, suffix, target, properties); + + if (target->GetType() != cmTarget::INTERFACE_LIBRARY) + { + this->SetImportLocationProperty(config, suffix, target, properties); + } if(!properties.empty()) { // Get the rest of the target details. - this->SetImportDetailProperties(config, suffix, - target, properties, missingTargets); - this->SetImportLinkInterface(config, suffix, - cmGeneratorExpression::BuildInterface, - target, properties, missingTargets); - + if (target->GetType() != cmTarget::INTERFACE_LIBRARY) + { + this->SetImportDetailProperties(config, suffix, + target, properties, missingTargets); + this->SetImportLinkInterface(config, suffix, + cmGeneratorExpression::BuildInterface, + target, properties, missingTargets); + } // TOOD: PUBLIC_HEADER_LOCATION // This should wait until the build feature propagation stuff diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index f059ceba6..be2ee3116 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -130,7 +130,8 @@ bool cmExportCommand if((target->GetType() == cmTarget::EXECUTABLE) || (target->GetType() == cmTarget::STATIC_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); } diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 0a9353386..25c57100c 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -378,11 +378,14 @@ void getCompatibleInterfaceProperties(cmTarget *target, if (!info) { - cmMakefile* mf = target->GetMakefile(); - cmOStringStream e; - e << "Exporting the target \"" << target->GetName() << "\" is not " - "allowed since its linker language cannot be determined"; - mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + if (target->GetType() != cmTarget::INTERFACE_LIBRARY) + { + cmMakefile* mf = target->GetMakefile(); + cmOStringStream e; + e << "Exporting the target \"" << target->GetName() << "\" is not " + "allowed since its linker language cannot be determined"; + mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + } return; } @@ -888,6 +891,9 @@ cmExportFileGenerator case cmTarget::UNKNOWN_LIBRARY: os << "add_library(" << targetName << " UNKNOWN IMPORTED)\n"; break; + case cmTarget::INTERFACE_LIBRARY: + os << "add_library(" << targetName << " INTERFACE IMPORTED)\n"; + break; default: // should never happen break; } diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index c8b4a7985..c71008e2c 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -114,6 +114,7 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) std::vector missingTargets; bool require2_8_12 = false; + bool require2_8_13 = false; // Create all the imported targets. for(std::vector::const_iterator tei = allTargets.begin(); @@ -153,6 +154,10 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) require2_8_12 = true; } } + if (te->GetType() == cmTarget::INTERFACE_LIBRARY) + { + require2_8_13 = true; + } this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", te, properties); this->PopulateCompatibleInterfaceProperties(te, properties); @@ -160,7 +165,11 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) 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"); } @@ -286,6 +295,14 @@ cmExportInstallFileGenerator cmTargetExport const* te = *tei; ImportPropertyMap properties; std::set 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, properties, importedLocations); this->SetImportLocationProperty(config, suffix, te->LibraryGenerator, diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 799bbdbae..dc4bf5053 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -2563,6 +2563,10 @@ void cmGlobalGenerator::WriteSummary() for(std::map::const_iterator ti = this->TotalTargets.begin(); ti != this->TotalTargets.end(); ++ti) { + if ((ti->second)->GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } this->WriteSummary(ti->second); fout << ti->second->GetSupportDirectory() << "\n"; } diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 61d02726e..e45d02456 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -877,7 +877,12 @@ cmGlobalNinjaGenerator cmTargetDependSet const& targetDeps = this->GetTargetDirectDepends(*target); 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); } } diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 3a9dc4466..9e23ae903 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -881,6 +881,10 @@ cmGlobalUnixMakefileGenerator3 for(TargetDependSet::const_iterator di = depends.begin(); di != depends.end(); ++di) { + if ((*di)->GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } count += this->CountProgressMarksInTarget(*di, emitted); } } @@ -967,6 +971,10 @@ cmGlobalUnixMakefileGenerator3 { // Create the target-level dependency. cmTarget const* dep = *i; + if (dep->GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } cmLocalUnixMakefileGenerator3* lg3 = static_cast (dep->GetMakefile()->GetLocalGenerator()); diff --git a/Source/cmGlobalVisualStudio6Generator.cxx b/Source/cmGlobalVisualStudio6Generator.cxx index b3fabdade..5296248db 100644 --- a/Source/cmGlobalVisualStudio6Generator.cxx +++ b/Source/cmGlobalVisualStudio6Generator.cxx @@ -200,6 +200,10 @@ void cmGlobalVisualStudio6Generator tt != orderedProjectTargets.end(); ++tt) { cmTarget* target = *tt; + if(target->GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } // Write the project into the DSW file const char* expath = target->GetProperty("EXTERNAL_MSPROJECT"); if(expath) diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index b47566561..65eb3a9e1 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -392,6 +392,10 @@ void cmGlobalVisualStudio7Generator::WriteTargetDepends( projectTargets.begin(); tt != projectTargets.end(); ++tt) { cmTarget* target = *tt; + if(target->GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } cmMakefile* mf = target->GetMakefile(); const char *vcprojName = target->GetProperty("GENERATOR_FILE_NAME"); diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index 1a4c7ffc4..92e40a864 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -409,6 +409,10 @@ void cmGlobalVisualStudio8Generator::WriteProjectDepends( for(OrderedTargetDependSet::const_iterator i = depends.begin(); i != depends.end(); ++i) { + if((*i)->GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } std::string guid = this->GetGUID((*i)->GetName()); fout << "\t\t{" << guid << "} = {" << guid << "}\n"; } diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index 59310162c..af80070c3 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -349,6 +349,10 @@ cmGlobalVisualStudioGenerator::GetTargetLinkClosure(cmTarget* target) void cmGlobalVisualStudioGenerator::FollowLinkDepends( cmTarget* target, std::set& linked) { + if(target->GetType() == cmTarget::INTERFACE_LIBRARY) + { + return; + } if(linked.insert(target).second && target->GetType() == cmTarget::STATIC_LIBRARY) { diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 0a2b32b4f..5a0fb0794 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -976,6 +976,11 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, continue; } + if(cmtarget.GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } + if(cmtarget.GetType() == cmTarget::UTILITY || cmtarget.GetType() == cmTarget::GLOBAL_TARGET) { @@ -1686,6 +1691,11 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, cmXCodeObject* buildSettings, const char* configName) { + if(target.GetType() == cmTarget::INTERFACE_LIBRARY) + { + return; + } + std::string flags; std::string defFlags; bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) || @@ -2550,6 +2560,10 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeTarget(cmTarget& cmtarget, cmXCodeObject* buildPhases) { + if(cmtarget.GetType() == cmTarget::INTERFACE_LIBRARY) + { + return 0; + } cmXCodeObject* target = this->CreateObject(cmXCodeObject::PBXNativeTarget); target->AddAttribute("buildPhases", buildPhases); @@ -2756,6 +2770,10 @@ void cmGlobalXCodeGenerator ::AddDependAndLinkInformation(cmXCodeObject* target) { cmTarget* cmtarget = target->GetTarget(); + if(cmtarget->GetType() == cmTarget::INTERFACE_LIBRARY) + { + return; + } if(!cmtarget) { cmSystemTools::Error("Error no target on xobject\n"); @@ -2867,7 +2885,8 @@ void cmGlobalXCodeGenerator { linkLibs += this->XCodeEscapePath(li->Value.c_str()); } - else + else if (!li->Target + || li->Target->GetType() != cmTarget::INTERFACE_LIBRARY) { linkLibs += li->Value; } @@ -2909,6 +2928,10 @@ void cmGlobalXCodeGenerator::CreateGroups(cmLocalGenerator* root, { continue; } + if(cmtarget.GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } // add the soon to be generated Info.plist file as a source for a // MACOSX_BUNDLE file diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 3c76bd638..d309a2ab1 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -379,7 +379,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector const& args) target->GetType() != cmTarget::STATIC_LIBRARY && target->GetType() != cmTarget::SHARED_LIBRARY && target->GetType() != cmTarget::MODULE_LIBRARY && - target->GetType() != cmTarget::OBJECT_LIBRARY) + target->GetType() != cmTarget::OBJECT_LIBRARY && + target->GetType() != cmTarget::INTERFACE_LIBRARY) { cmOStringStream e; e << "TARGETS given target \"" << (*targetIt) @@ -626,6 +627,11 @@ bool cmInstallCommand::HandleTargetsMode(std::vector const& args) } } 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: // This should never happen due to the above type check. // Ignore the case. diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index d0768c8b8..7b9109e8e 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -90,6 +90,11 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os, case cmTarget::STATIC_LIBRARY: type = cmInstallType_STATIC_LIBRARY; break; case cmTarget::SHARED_LIBRARY: type = cmInstallType_SHARED_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::UTILITY: case cmTarget::GLOBAL_TARGET: diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index afc04b9ce..b4cb5bd1f 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1794,6 +1794,10 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, ItemVector const& items = cli.GetItems(); for(ItemVector::const_iterator li = items.begin(); li != items.end(); ++li) { + if(li->Target && li->Target->GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } if(li->IsPath) { 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. // This was listed to get the target-level dependency. 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::GLOBAL_TARGET: // A utility target has no file on which to depend. This was listed diff --git a/Source/cmLocalVisualStudio10Generator.cxx b/Source/cmLocalVisualStudio10Generator.cxx index c3789a022..aedd6edbf 100644 --- a/Source/cmLocalVisualStudio10Generator.cxx +++ b/Source/cmLocalVisualStudio10Generator.cxx @@ -76,6 +76,10 @@ void cmLocalVisualStudio10Generator::Generate() cmTargets &tgts = this->Makefile->GetTargets(); for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); ++l) { + if(l->second.GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } if(static_cast(this->GlobalGenerator) ->TargetIsFortranOnly(l->second)) { diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx index f00a93772..a665b938b 100644 --- a/Source/cmLocalVisualStudio6Generator.cxx +++ b/Source/cmLocalVisualStudio6Generator.cxx @@ -91,6 +91,11 @@ void cmLocalVisualStudio6Generator::AddCMakeListsRules() for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++) { + if (l->second.GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } + // Add a rule to regenerate the build system when the target // specification source changes. const char* suppRegenRule = @@ -146,6 +151,8 @@ void cmLocalVisualStudio6Generator::OutputDSPFile() case cmTarget::GLOBAL_TARGET: this->SetBuildType(UTILITY, l->first.c_str(), l->second); break; + case cmTarget::INTERFACE_LIBRARY: + continue; default: cmSystemTools::Error("Bad target type: ", l->first.c_str()); break; @@ -1839,7 +1846,8 @@ void cmLocalVisualStudio6Generator options += this->ConvertToOptionallyRelativeOutputPath(l->Value.c_str()); } - else + else if (!l->Target + || l->Target->GetType() != cmTarget::INTERFACE_LIBRARY) { options += l->Value; } diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index bd6c86004..64de448dc 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -78,6 +78,10 @@ void cmLocalVisualStudio7Generator::AddHelperCommands() static_cast(this->GlobalGenerator); 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"); if(path) { @@ -181,6 +185,10 @@ void cmLocalVisualStudio7Generator::WriteProjectFiles() for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++) { + if(l->second.GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } // INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace // so don't build a projectfile for it if(!l->second.GetProperty("EXTERNAL_MSPROJECT")) @@ -1258,6 +1266,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, } case cmTarget::UTILITY: case cmTarget::GLOBAL_TARGET: + case cmTarget::INTERFACE_LIBRARY: break; } } @@ -1288,7 +1297,8 @@ cmLocalVisualStudio7GeneratorInternals cmLocalGenerator::UNCHANGED); fout << lg->ConvertToXMLOutputPath(rel.c_str()) << " "; } - else + else if (!l->Target + || l->Target->GetType() != cmTarget::INTERFACE_LIBRARY) { fout << l->Value << " "; } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 34541e996..40e55c238 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -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(!((tgt->GetType() == cmTarget::STATIC_LIBRARY) || (tgt->GetType() == cmTarget::SHARED_LIBRARY) || + (tgt->GetType() == cmTarget::INTERFACE_LIBRARY) || tgt->IsExecutableWithExports())) { cmOStringStream e; @@ -1990,6 +1991,7 @@ void cmMakefile::AddGlobalLinkInformation(const char* name, cmTarget& target) { case cmTarget::UTILITY: case cmTarget::GLOBAL_TARGET: + case cmTarget::INTERFACE_LIBRARY: return; default:; } @@ -2017,7 +2019,8 @@ cmTarget* cmMakefile::AddLibrary(const char* lname, cmTarget::TargetType type, if ( (type != cmTarget::STATIC_LIBRARY) && (type != cmTarget::SHARED_LIBRARY) && (type != cmTarget::MODULE_LIBRARY) - && (type != cmTarget::OBJECT_LIBRARY)) + && (type != cmTarget::OBJECT_LIBRARY) + && (type != cmTarget::INTERFACE_LIBRARY)) { this->IssueMessage(cmake::INTERNAL_ERROR, "cmMakefile::AddLibrary given invalid target type."); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 33974ae13..42091e305 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1004,7 +1004,12 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() i = items.begin(); i != items.end(); ++i) { 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(); cmLocalGenerator* lg = mf->GetLocalGenerator(); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 10b577f1e..1c04e4edf 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -47,6 +47,8 @@ const char* cmTarget::GetTargetTypeName(TargetType targetType) return "UTILITY"; case cmTarget::GLOBAL_TARGET: return "GLOBAL_TARGET"; + case cmTarget::INTERFACE_LIBRARY: + return "INTERFACE_LIBRARY"; case cmTarget::UNKNOWN_LIBRARY: return "UNKNOWN_LIBRARY"; } @@ -1743,6 +1745,14 @@ void cmTarget::SetMakefile(cmMakefile* mf) CM_FOR_EACH_TARGET_POLICY(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::MODULE_LIBRARY || this->GetType() == cmTarget::UNKNOWN_LIBRARY || + this->GetType() == cmTarget::INTERFACE_LIBRARY || this->IsExecutableWithExports()); } @@ -2579,8 +2590,8 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, return; } - { cmTarget *tgt = this->Makefile->FindTargetToUse(lib); + { const bool isNonImportedTarget = tgt && !tgt->IsImported(); const std::string libName = (isNonImportedTarget && llt != GENERAL) @@ -2591,7 +2602,8 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, llt).c_str()); } - if (cmGeneratorExpression::Find(lib) != std::string::npos) + if (cmGeneratorExpression::Find(lib) != std::string::npos + || (tgt && tgt->GetType() == INTERFACE_LIBRARY)) { return; } @@ -4137,6 +4149,7 @@ const char *cmTarget::GetProperty(const char* prop, this->GetType() == cmTarget::STATIC_LIBRARY || this->GetType() == cmTarget::SHARED_LIBRARY || this->GetType() == cmTarget::MODULE_LIBRARY || + this->GetType() == cmTarget::INTERFACE_LIBRARY || this->GetType() == cmTarget::UNKNOWN_LIBRARY) { if(strcmp(prop,"LOCATION") == 0) @@ -6061,6 +6074,10 @@ cmTarget::GetImportInfo(const char* config, cmTarget *headTarget) 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 // this configuration. 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* imp = 0; 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; } @@ -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. { 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 // 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); 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 // on other shared libraries that are not in the interface. diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 527cbc797..a88c5ec31 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -72,6 +72,7 @@ public: enum TargetType { EXECUTABLE, STATIC_LIBRARY, SHARED_LIBRARY, MODULE_LIBRARY, OBJECT_LIBRARY, UTILITY, GLOBAL_TARGET, + INTERFACE_LIBRARY, UNKNOWN_LIBRARY}; static const char* GetTargetTypeName(TargetType targetType); enum CustomCommandType { PRE_BUILD, PRE_LINK, POST_BUILD }; diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index 863b3917e..22f6a0361 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -322,6 +322,15 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib, 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 = (this->CurrentProcessingState == ProcessingPlainPrivateInterface || this->CurrentProcessingState == ProcessingPlainPublicInterface @@ -407,6 +416,11 @@ cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib, return true; } + if (this->Target->GetType() == cmTarget::INTERFACE_LIBRARY) + { + return true; + } + // Get the list of configurations considered to be DEBUG. std::vector const& debugConfigs = this->Makefile->GetCMakeInstance()->GetDebugConfigs(); diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx index 1862cb696..e7b699932 100644 --- a/Source/cmTargetPropCommandBase.cxx +++ b/Source/cmTargetPropCommandBase.cxx @@ -47,6 +47,7 @@ bool cmTargetPropCommandBase && (this->Target->GetType() != cmTarget::STATIC_LIBRARY) && (this->Target->GetType() != cmTarget::OBJECT_LIBRARY) && (this->Target->GetType() != cmTarget::MODULE_LIBRARY) + && (this->Target->GetType() != cmTarget::INTERFACE_LIBRARY) && (this->Target->GetType() != cmTarget::EXECUTABLE)) { this->SetError("called with non-compilable target type"); @@ -112,6 +113,14 @@ bool cmTargetPropCommandBase 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; std::vector content; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index a26b2913a..0dbb5ebbf 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -490,6 +490,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues() break; case cmTarget::GLOBAL_TARGET: case cmTarget::UNKNOWN_LIBRARY: + case cmTarget::INTERFACE_LIBRARY: break; } configType += "\n"; @@ -1701,7 +1702,8 @@ void cmVisualStudio10TargetGenerator::AddLibraries( libstring += sep; libstring += path; } - else + else if (!l->Target + || l->Target->GetType() != cmTarget::INTERFACE_LIBRARY) { libstring += sep; libstring += l->Value; @@ -1836,6 +1838,10 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() i != depends.end(); ++i) { cmTarget* dt = *i; + if(dt->GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } // skip fortran targets as they can not be processed by MSBuild // the only reference will be in the .sln file if(static_cast(this->GlobalGenerator) diff --git a/Tests/AliasTarget/CMakeLists.txt b/Tests/AliasTarget/CMakeLists.txt index a5eb0f6de..fdb163840 100644 --- a/Tests/AliasTarget/CMakeLists.txt +++ b/Tests/AliasTarget/CMakeLists.txt @@ -45,3 +45,6 @@ get_property(_alt2 TARGET PREFIX::Foo PROPERTY ALIASED_TARGET) if (NOT ${_alt2} STREQUAL foo) message(SEND_ERROR "ALIASED_TARGET is not foo.") endif() + +add_library(iface INTERFACE) +add_library(Alias::Iface ALIAS iface) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 504f4bb41..9afc11258 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -246,6 +246,7 @@ if(BUILD_TESTING) ADD_TEST_MACRO(CompileOptions CompileOptions) ADD_TEST_MACRO(CompatibleInterface CompatibleInterface) ADD_TEST_MACRO(AliasTarget AliasTarget) + ADD_TEST_MACRO(InterfaceLibrary InterfaceLibrary) set_tests_properties(EmptyLibrary PROPERTIES PASS_REGULAR_EXPRESSION "CMake Error: CMake can not determine linker language for target: test") ADD_TEST_MACRO(CrossCompile CrossCompile) diff --git a/Tests/CompatibleInterface/CMakeLists.txt b/Tests/CompatibleInterface/CMakeLists.txt index ae1d2fa43..5ee9fd7a6 100644 --- a/Tests/CompatibleInterface/CMakeLists.txt +++ b/Tests/CompatibleInterface/CMakeLists.txt @@ -6,7 +6,7 @@ project(CompatibleInterface) include(GenerateExportHeader) set(CMAKE_INCLUDE_CURRENT_DIR ON) -add_library(iface1 empty.cpp) +add_library(iface1 INTERFACE) set_property(TARGET iface1 APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL BOOL_PROP1 diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt index f225ce1a0..cbae967a4 100644 --- a/Tests/ExportImport/Export/CMakeLists.txt +++ b/Tests/ExportImport/Export/CMakeLists.txt @@ -436,3 +436,5 @@ export(TARGETS testExe2 testLib4 testLib5 testLib6 testExe3 testExe2lib NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake ) + +add_subdirectory(Interface) diff --git a/Tests/ExportImport/Export/Interface/CMakeLists.txt b/Tests/ExportImport/Export/Interface/CMakeLists.txt new file mode 100644 index 000000000..fc9c0c7c1 --- /dev/null +++ b/Tests/ExportImport/Export/Interface/CMakeLists.txt @@ -0,0 +1,49 @@ + +add_library(headeronly INTERFACE) +set_property(TARGET headeronly PROPERTY INTERFACE_INCLUDE_DIRECTORIES + "$" + "$" +) +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 + "$" + "$/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) diff --git a/Tests/ExportImport/Export/Interface/headeronly/headeronly.h b/Tests/ExportImport/Export/Interface/headeronly/headeronly.h new file mode 100644 index 000000000..3673c2187 --- /dev/null +++ b/Tests/ExportImport/Export/Interface/headeronly/headeronly.h @@ -0,0 +1,7 @@ + +enum { one }; + +struct HeaderOnly +{ + int foo() const { return 0; } +}; diff --git a/Tests/ExportImport/Export/Interface/sharedlib.cpp b/Tests/ExportImport/Export/Interface/sharedlib.cpp new file mode 100644 index 000000000..88ca7130f --- /dev/null +++ b/Tests/ExportImport/Export/Interface/sharedlib.cpp @@ -0,0 +1,7 @@ + +#include "sharedlib.h" + +int SharedLibObject::foo() const +{ + return 0; +} diff --git a/Tests/ExportImport/Export/Interface/sharedlib/sharedlib.h b/Tests/ExportImport/Export/Interface/sharedlib/sharedlib.h new file mode 100644 index 000000000..aad9ef3f4 --- /dev/null +++ b/Tests/ExportImport/Export/Interface/sharedlib/sharedlib.h @@ -0,0 +1,7 @@ + +#include "sharedlib_export.h" + +struct SHAREDLIB_EXPORT SharedLibObject +{ + int foo() const; +}; diff --git a/Tests/ExportImport/Import/CMakeLists.txt b/Tests/ExportImport/Import/CMakeLists.txt index 9c2d5977c..5e809a27d 100644 --- a/Tests/ExportImport/Import/CMakeLists.txt +++ b/Tests/ExportImport/Import/CMakeLists.txt @@ -19,3 +19,6 @@ add_executable(imp_testTransExe1b imp_testTransExe1.c) target_link_libraries(imp_testTransExe1b imp_lib1b) add_subdirectory(try_compile) + +# Test package INTERFACE controls +add_subdirectory(Interface) diff --git a/Tests/ExportImport/Import/Interface/CMakeLists.txt b/Tests/ExportImport/Import/Interface/CMakeLists.txt new file mode 100644 index 000000000..c7bd13e85 --- /dev/null +++ b/Tests/ExportImport/Import/Interface/CMakeLists.txt @@ -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_) diff --git a/Tests/ExportImport/Import/Interface/headeronlytest.cpp b/Tests/ExportImport/Import/Interface/headeronlytest.cpp new file mode 100644 index 000000000..20674a725 --- /dev/null +++ b/Tests/ExportImport/Import/Interface/headeronlytest.cpp @@ -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(); +} diff --git a/Tests/ExportImport/Import/Interface/interfacetest.cpp b/Tests/ExportImport/Import/Interface/interfacetest.cpp new file mode 100644 index 000000000..786458d19 --- /dev/null +++ b/Tests/ExportImport/Import/Interface/interfacetest.cpp @@ -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(); +} diff --git a/Tests/InterfaceLibrary/CMakeLists.txt b/Tests/InterfaceLibrary/CMakeLists.txt new file mode 100644 index 000000000..53aeb036b --- /dev/null +++ b/Tests/InterfaceLibrary/CMakeLists.txt @@ -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) diff --git a/Tests/InterfaceLibrary/definetestexe.cpp b/Tests/InterfaceLibrary/definetestexe.cpp new file mode 100644 index 000000000..decd37c51 --- /dev/null +++ b/Tests/InterfaceLibrary/definetestexe.cpp @@ -0,0 +1,9 @@ + +#ifndef IFACE_DEFINE +#error Expected IFACE_DEFINE +#endif + +int main(int,char**) +{ + return 0; +} diff --git a/Tests/InterfaceLibrary/libsdir/CMakeLists.txt b/Tests/InterfaceLibrary/libsdir/CMakeLists.txt new file mode 100644 index 000000000..699964656 --- /dev/null +++ b/Tests/InterfaceLibrary/libsdir/CMakeLists.txt @@ -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) diff --git a/Tests/InterfaceLibrary/libsdir/shareddependlib.cpp b/Tests/InterfaceLibrary/libsdir/shareddependlib.cpp new file mode 100644 index 000000000..378ba8165 --- /dev/null +++ b/Tests/InterfaceLibrary/libsdir/shareddependlib.cpp @@ -0,0 +1,7 @@ + +#include "shareddependlib.h" + +int SharedDependLibObject::foo() const +{ + return 0; +} diff --git a/Tests/InterfaceLibrary/libsdir/shareddependlib/shareddependlib.h b/Tests/InterfaceLibrary/libsdir/shareddependlib/shareddependlib.h new file mode 100644 index 000000000..ad9b484b7 --- /dev/null +++ b/Tests/InterfaceLibrary/libsdir/shareddependlib/shareddependlib.h @@ -0,0 +1,12 @@ + +#ifndef SHAREDDEPENDLIB_H +#define SHAREDDEPENDLIB_H + +#include "shareddependlib_export.h" + +struct SHAREDDEPENDLIB_EXPORT SharedDependLibObject +{ + int foo() const; +}; + +#endif diff --git a/Tests/InterfaceLibrary/libsdir/sharedlib.cpp b/Tests/InterfaceLibrary/libsdir/sharedlib.cpp new file mode 100644 index 000000000..c49ce905b --- /dev/null +++ b/Tests/InterfaceLibrary/libsdir/sharedlib.cpp @@ -0,0 +1,12 @@ + +#include "sharedlib.h" + +SharedDependLibObject SharedLibObject::object() const +{ + SharedDependLibObject sdlo; + return sdlo; +} +int SharedLibObject::foo() const +{ + return 0; +} diff --git a/Tests/InterfaceLibrary/libsdir/sharedlib/sharedlib.h b/Tests/InterfaceLibrary/libsdir/sharedlib/sharedlib.h new file mode 100644 index 000000000..5b3c7db73 --- /dev/null +++ b/Tests/InterfaceLibrary/libsdir/sharedlib/sharedlib.h @@ -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 diff --git a/Tests/InterfaceLibrary/sharedlibtestexe.cpp b/Tests/InterfaceLibrary/sharedlibtestexe.cpp new file mode 100644 index 000000000..c677f7067 --- /dev/null +++ b/Tests/InterfaceLibrary/sharedlibtestexe.cpp @@ -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(); +} diff --git a/Tests/PositionIndependentTargets/CMakeLists.txt b/Tests/PositionIndependentTargets/CMakeLists.txt index eec893d32..e79f3b74b 100644 --- a/Tests/PositionIndependentTargets/CMakeLists.txt +++ b/Tests/PositionIndependentTargets/CMakeLists.txt @@ -9,5 +9,6 @@ include_directories("${CMAKE_CURRENT_SOURCE_DIR}") # For pic_test.h add_subdirectory(global) add_subdirectory(targets) +add_subdirectory(interface) add_executable(PositionIndependentTargets main.cpp) diff --git a/Tests/PositionIndependentTargets/interface/CMakeLists.txt b/Tests/PositionIndependentTargets/interface/CMakeLists.txt new file mode 100644 index 000000000..65f3b767e --- /dev/null +++ b/Tests/PositionIndependentTargets/interface/CMakeLists.txt @@ -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) diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 35c8e132e..ee490b817 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -100,6 +100,7 @@ add_RunCMake_test(variable_watch) add_RunCMake_test(CMP0004) add_RunCMake_test(TargetPolicies) add_RunCMake_test(alias_targets) +add_RunCMake_test(interface_library) find_package(Qt4 QUIET) find_package(Qt5Core QUIET) diff --git a/Tests/RunCMake/PositionIndependentCode/Conflict4-result.txt b/Tests/RunCMake/PositionIndependentCode/Conflict4-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/PositionIndependentCode/Conflict4-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/PositionIndependentCode/Conflict4-stderr.txt b/Tests/RunCMake/PositionIndependentCode/Conflict4-stderr.txt new file mode 100644 index 000000000..76d5ea08a --- /dev/null +++ b/Tests/RunCMake/PositionIndependentCode/Conflict4-stderr.txt @@ -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. diff --git a/Tests/RunCMake/PositionIndependentCode/Conflict4.cmake b/Tests/RunCMake/PositionIndependentCode/Conflict4.cmake new file mode 100644 index 000000000..ff5dfb353 --- /dev/null +++ b/Tests/RunCMake/PositionIndependentCode/Conflict4.cmake @@ -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 $<$>:piciface>) diff --git a/Tests/RunCMake/PositionIndependentCode/Conflict5-result.txt b/Tests/RunCMake/PositionIndependentCode/Conflict5-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/PositionIndependentCode/Conflict5-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/PositionIndependentCode/Conflict5-stderr.txt b/Tests/RunCMake/PositionIndependentCode/Conflict5-stderr.txt new file mode 100644 index 000000000..ecd04928d --- /dev/null +++ b/Tests/RunCMake/PositionIndependentCode/Conflict5-stderr.txt @@ -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". diff --git a/Tests/RunCMake/PositionIndependentCode/Conflict5.cmake b/Tests/RunCMake/PositionIndependentCode/Conflict5.cmake new file mode 100644 index 000000000..e6055f450 --- /dev/null +++ b/Tests/RunCMake/PositionIndependentCode/Conflict5.cmake @@ -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) diff --git a/Tests/RunCMake/PositionIndependentCode/Conflict6-result.txt b/Tests/RunCMake/PositionIndependentCode/Conflict6-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/PositionIndependentCode/Conflict6-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/PositionIndependentCode/Conflict6-stderr.txt b/Tests/RunCMake/PositionIndependentCode/Conflict6-stderr.txt new file mode 100644 index 000000000..0254e5557 --- /dev/null +++ b/Tests/RunCMake/PositionIndependentCode/Conflict6-stderr.txt @@ -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. diff --git a/Tests/RunCMake/PositionIndependentCode/Conflict6.cmake b/Tests/RunCMake/PositionIndependentCode/Conflict6.cmake new file mode 100644 index 000000000..7ea7c5f73 --- /dev/null +++ b/Tests/RunCMake/PositionIndependentCode/Conflict6.cmake @@ -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 $<$>>:picoff>) diff --git a/Tests/RunCMake/PositionIndependentCode/RunCMakeTest.cmake b/Tests/RunCMake/PositionIndependentCode/RunCMakeTest.cmake index 64a340c9c..3a2009b48 100644 --- a/Tests/RunCMake/PositionIndependentCode/RunCMakeTest.cmake +++ b/Tests/RunCMake/PositionIndependentCode/RunCMakeTest.cmake @@ -3,3 +3,6 @@ include(RunCMake) run_cmake(Conflict1) run_cmake(Conflict2) run_cmake(Conflict3) +run_cmake(Conflict4) +run_cmake(Conflict5) +run_cmake(Conflict6) diff --git a/Tests/RunCMake/interface_library/CMakeLists.txt b/Tests/RunCMake/interface_library/CMakeLists.txt new file mode 100644 index 000000000..12cd3c775 --- /dev/null +++ b/Tests/RunCMake/interface_library/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.4) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/interface_library/RunCMakeTest.cmake b/Tests/RunCMake/interface_library/RunCMakeTest.cmake new file mode 100644 index 000000000..56caf683f --- /dev/null +++ b/Tests/RunCMake/interface_library/RunCMakeTest.cmake @@ -0,0 +1,4 @@ +include(RunCMake) + +run_cmake(invalid_name) +run_cmake(target_commands) diff --git a/Tests/RunCMake/interface_library/invalid_name-result.txt b/Tests/RunCMake/interface_library/invalid_name-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/interface_library/invalid_name-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/interface_library/invalid_name-stderr.txt b/Tests/RunCMake/interface_library/invalid_name-stderr.txt new file mode 100644 index 000000000..e14fcdedb --- /dev/null +++ b/Tests/RunCMake/interface_library/invalid_name-stderr.txt @@ -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\) diff --git a/Tests/RunCMake/interface_library/invalid_name.cmake b/Tests/RunCMake/interface_library/invalid_name.cmake new file mode 100644 index 000000000..9a965aa8a --- /dev/null +++ b/Tests/RunCMake/interface_library/invalid_name.cmake @@ -0,0 +1,6 @@ + +add_library(if$ace INTERFACE) + +add_library(iface::target INTERFACE) + +add_library(if$target_imported INTERFACE IMPORTED) diff --git a/Tests/RunCMake/interface_library/target_commands-result.txt b/Tests/RunCMake/interface_library/target_commands-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/interface_library/target_commands-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/interface_library/target_commands-stderr.txt b/Tests/RunCMake/interface_library/target_commands-stderr.txt new file mode 100644 index 000000000..be11b7754 --- /dev/null +++ b/Tests/RunCMake/interface_library/target_commands-stderr.txt @@ -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\) diff --git a/Tests/RunCMake/interface_library/target_commands.cmake b/Tests/RunCMake/interface_library/target_commands.cmake new file mode 100644 index 000000000..3182e8933 --- /dev/null +++ b/Tests/RunCMake/interface_library/target_commands.cmake @@ -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)