Prechádzať zdrojové kódy

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.
Brad King 12 rokov pred
rodič
commit
f8241136b4
71 zmenil súbory, kde vykonal 771 pridanie a 65 odobranie
  1. 38 2
      Source/cmAddLibraryCommand.cxx
  2. 10 0
      Source/cmAddLibraryCommand.h
  3. 7 0
      Source/cmComputeLinkDepends.cxx
  4. 5 0
      Source/cmComputeLinkInformation.cxx
  5. 1 0
      Source/cmCoreTryCompile.cxx
  6. 17 7
      Source/cmExportBuildFileGenerator.cxx
  7. 2 1
      Source/cmExportCommand.cxx
  8. 11 5
      Source/cmExportFileGenerator.cxx
  9. 18 1
      Source/cmExportInstallFileGenerator.cxx
  10. 4 0
      Source/cmGlobalGenerator.cxx
  11. 6 1
      Source/cmGlobalNinjaGenerator.cxx
  12. 8 0
      Source/cmGlobalUnixMakefileGenerator3.cxx
  13. 4 0
      Source/cmGlobalVisualStudio6Generator.cxx
  14. 4 0
      Source/cmGlobalVisualStudio7Generator.cxx
  15. 4 0
      Source/cmGlobalVisualStudio8Generator.cxx
  16. 4 0
      Source/cmGlobalVisualStudioGenerator.cxx
  17. 24 1
      Source/cmGlobalXCodeGenerator.cxx
  18. 7 1
      Source/cmInstallCommand.cxx
  19. 5 0
      Source/cmInstallTargetGenerator.cxx
  20. 8 0
      Source/cmLocalGenerator.cxx
  21. 4 0
      Source/cmLocalVisualStudio10Generator.cxx
  22. 9 1
      Source/cmLocalVisualStudio6Generator.cxx
  23. 11 1
      Source/cmLocalVisualStudio7Generator.cxx
  24. 4 1
      Source/cmMakefile.cxx
  25. 6 1
      Source/cmMakefileTargetGenerator.cxx
  26. 71 40
      Source/cmTarget.cxx
  27. 1 0
      Source/cmTarget.h
  28. 14 0
      Source/cmTargetLinkLibrariesCommand.cxx
  29. 9 0
      Source/cmTargetPropCommandBase.cxx
  30. 7 1
      Source/cmVisualStudio10TargetGenerator.cxx
  31. 3 0
      Tests/AliasTarget/CMakeLists.txt
  32. 1 0
      Tests/CMakeLists.txt
  33. 1 1
      Tests/CompatibleInterface/CMakeLists.txt
  34. 2 0
      Tests/ExportImport/Export/CMakeLists.txt
  35. 49 0
      Tests/ExportImport/Export/Interface/CMakeLists.txt
  36. 7 0
      Tests/ExportImport/Export/Interface/headeronly/headeronly.h
  37. 7 0
      Tests/ExportImport/Export/Interface/sharedlib.cpp
  38. 7 0
      Tests/ExportImport/Export/Interface/sharedlib/sharedlib.h
  39. 3 0
      Tests/ExportImport/Import/CMakeLists.txt
  40. 55 0
      Tests/ExportImport/Import/Interface/CMakeLists.txt
  41. 17 0
      Tests/ExportImport/Import/Interface/headeronlytest.cpp
  42. 20 0
      Tests/ExportImport/Import/Interface/interfacetest.cpp
  43. 15 0
      Tests/InterfaceLibrary/CMakeLists.txt
  44. 9 0
      Tests/InterfaceLibrary/definetestexe.cpp
  45. 26 0
      Tests/InterfaceLibrary/libsdir/CMakeLists.txt
  46. 7 0
      Tests/InterfaceLibrary/libsdir/shareddependlib.cpp
  47. 12 0
      Tests/InterfaceLibrary/libsdir/shareddependlib/shareddependlib.h
  48. 12 0
      Tests/InterfaceLibrary/libsdir/sharedlib.cpp
  49. 15 0
      Tests/InterfaceLibrary/libsdir/sharedlib/sharedlib.h
  50. 19 0
      Tests/InterfaceLibrary/sharedlibtestexe.cpp
  51. 1 0
      Tests/PositionIndependentTargets/CMakeLists.txt
  52. 27 0
      Tests/PositionIndependentTargets/interface/CMakeLists.txt
  53. 1 0
      Tests/RunCMake/CMakeLists.txt
  54. 1 0
      Tests/RunCMake/PositionIndependentCode/Conflict4-result.txt
  55. 4 0
      Tests/RunCMake/PositionIndependentCode/Conflict4-stderr.txt
  56. 8 0
      Tests/RunCMake/PositionIndependentCode/Conflict4.cmake
  57. 1 0
      Tests/RunCMake/PositionIndependentCode/Conflict5-result.txt
  58. 3 0
      Tests/RunCMake/PositionIndependentCode/Conflict5-stderr.txt
  59. 9 0
      Tests/RunCMake/PositionIndependentCode/Conflict5.cmake
  60. 1 0
      Tests/RunCMake/PositionIndependentCode/Conflict6-result.txt
  61. 4 0
      Tests/RunCMake/PositionIndependentCode/Conflict6-stderr.txt
  62. 8 0
      Tests/RunCMake/PositionIndependentCode/Conflict6.cmake
  63. 3 0
      Tests/RunCMake/PositionIndependentCode/RunCMakeTest.cmake
  64. 3 0
      Tests/RunCMake/interface_library/CMakeLists.txt
  65. 4 0
      Tests/RunCMake/interface_library/RunCMakeTest.cmake
  66. 1 0
      Tests/RunCMake/interface_library/invalid_name-result.txt
  67. 15 0
      Tests/RunCMake/interface_library/invalid_name-stderr.txt
  68. 6 0
      Tests/RunCMake/interface_library/invalid_name.cmake
  69. 1 0
      Tests/RunCMake/interface_library/target_commands-result.txt
  70. 47 0
      Tests/RunCMake/interface_library/target_commands-stderr.txt
  71. 13 0
      Tests/RunCMake/interface_library/target_commands.cmake

+ 38 - 2
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<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())
     {
     std::string msg = "You have called ADD_LIBRARY for library ";
@@ -258,7 +295,6 @@ bool cmAddLibraryCommand
     cmSystemTools::Message(msg.c_str() ,"Warning");
     }
 
-  std::vector<std::string> srclists;
   while (s != args.end())
     {
     srclists.push_back(*s);

+ 10 - 0
Source/cmAddLibraryCommand.h

@@ -151,6 +151,16 @@ public:
       "properties of <target>, that is, it may not be used as the operand of "
       "set_property, set_target_properties, target_link_libraries etc.  An "
       "ALIAS target may not be installed of exported."
+      "\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."
       ;
     }
 

+ 7 - 0
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);
 

+ 5 - 0
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 ||

+ 1 - 0
Source/cmCoreTryCompile.cxx

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

+ 17 - 7
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

+ 2 - 1
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);
         }

+ 11 - 5
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;
     }

+ 18 - 1
Source/cmExportInstallFileGenerator.cxx

@@ -114,6 +114,7 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
   std::vector<std::string> missingTargets;
 
   bool require2_8_12 = false;
+  bool require2_8_13 = false;
   // Create all the imported targets.
   for(std::vector<cmTargetExport*>::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<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,
                                     properties, importedLocations);
     this->SetImportLocationProperty(config, suffix, te->LibraryGenerator,

+ 4 - 0
Source/cmGlobalGenerator.cxx

@@ -2563,6 +2563,10 @@ void cmGlobalGenerator::WriteSummary()
   for(std::map<cmStdString,cmTarget *>::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";
     }

+ 6 - 1
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);
     }
   }

+ 8 - 0
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<cmLocalUnixMakefileGenerator3*>
       (dep->GetMakefile()->GetLocalGenerator());

+ 4 - 0
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)

+ 4 - 0
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");

+ 4 - 0
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";
     }

+ 4 - 0
Source/cmGlobalVisualStudioGenerator.cxx

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

+ 24 - 1
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

+ 7 - 1
Source/cmInstallCommand.cxx

@@ -379,7 +379,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> 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<std::string> 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.

+ 5 - 0
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:

+ 8 - 0
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

+ 4 - 0
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<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator)
        ->TargetIsFortranOnly(l->second))
       {

+ 9 - 1
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;
       }

+ 11 - 1
Source/cmLocalVisualStudio7Generator.cxx

@@ -78,6 +78,10 @@ void cmLocalVisualStudio7Generator::AddHelperCommands()
     static_cast<cmGlobalVisualStudio7Generator *>(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 << " ";
       }

+ 4 - 1
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.");

+ 6 - 1
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();

+ 71 - 40
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.

+ 1 - 0
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 };

+ 14 - 0
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<std::string> const& debugConfigs =
     this->Makefile->GetCMakeInstance()->GetDebugConfigs();

+ 9 - 0
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<std::string> content;

+ 7 - 1
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 += "</ConfigurationType>\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<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator)

+ 3 - 0
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)

+ 1 - 0
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)

+ 1 - 1
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

+ 2 - 0
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)

+ 49 - 0
Tests/ExportImport/Export/Interface/CMakeLists.txt

@@ -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)

+ 7 - 0
Tests/ExportImport/Export/Interface/headeronly/headeronly.h

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

+ 7 - 0
Tests/ExportImport/Export/Interface/sharedlib.cpp

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

+ 7 - 0
Tests/ExportImport/Export/Interface/sharedlib/sharedlib.h

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

+ 3 - 0
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)

+ 55 - 0
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_)

+ 17 - 0
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();
+}

+ 20 - 0
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();
+}

+ 15 - 0
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)

+ 9 - 0
Tests/InterfaceLibrary/definetestexe.cpp

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

+ 26 - 0
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)

+ 7 - 0
Tests/InterfaceLibrary/libsdir/shareddependlib.cpp

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

+ 12 - 0
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

+ 12 - 0
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;
+}

+ 15 - 0
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

+ 19 - 0
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();
+}

+ 1 - 0
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)

+ 27 - 0
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)

+ 1 - 0
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)

+ 1 - 0
Tests/RunCMake/PositionIndependentCode/Conflict4-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
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.

+ 8 - 0
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 $<$<BOOL:$<TARGET_PROPERTY:POSITION_INDEPENDENT_CODE>>:piciface>)

+ 1 - 0
Tests/RunCMake/PositionIndependentCode/Conflict5-result.txt

@@ -0,0 +1 @@
+1

+ 3 - 0
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".

+ 9 - 0
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)

+ 1 - 0
Tests/RunCMake/PositionIndependentCode/Conflict6-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
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.

+ 8 - 0
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 $<$<NOT:$<BOOL:$<TARGET_PROPERTY:POSITION_INDEPENDENT_CODE>>>:picoff>)

+ 3 - 0
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)

+ 3 - 0
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)

+ 4 - 0
Tests/RunCMake/interface_library/RunCMakeTest.cmake

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

+ 1 - 0
Tests/RunCMake/interface_library/invalid_name-result.txt

@@ -0,0 +1 @@
+1

+ 15 - 0
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\)

+ 6 - 0
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)

+ 1 - 0
Tests/RunCMake/interface_library/target_commands-result.txt

@@ -0,0 +1 @@
+1

+ 47 - 0
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\)

+ 13 - 0
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)