Browse Source

Add a convenient way to add the includes install dir to the INTERFACE.

Export the INCLUDES DESTINATION without appending to the
INTERFACE_INCLUDE_DIRECTORIES of the target itself. That way, a target
can be exported multiple times with different INCLUDES DESTINATION
without unintended cross-pollution of export sets.
Stephen Kelly 12 years ago
parent
commit
650e61f833

+ 8 - 4
Source/cmExportFileGenerator.cxx

@@ -277,27 +277,31 @@ static bool checkInterfaceDirs(const std::string &prepro,
 
 //----------------------------------------------------------------------------
 void cmExportFileGenerator::PopulateIncludeDirectoriesInterface(
-                      cmTarget *target,
+                      cmTargetExport *tei,
                       cmGeneratorExpression::PreprocessContext preprocessRule,
                       ImportPropertyMap &properties,
                       std::vector<std::string> &missingTargets)
 {
+  cmTarget *target = tei->Target;
   assert(preprocessRule == cmGeneratorExpression::InstallInterface);
 
   const char *propName = "INTERFACE_INCLUDE_DIRECTORIES";
   const char *input = target->GetProperty(propName);
-  if (!input)
+  if (!input && tei->InterfaceIncludeDirectories.empty())
     {
     return;
     }
-  if (!*input)
+  if (!*input && tei->InterfaceIncludeDirectories.empty())
     {
     // Set to empty
     properties[propName] = "";
     return;
     }
 
-  std::string prepro = cmGeneratorExpression::Preprocess(input,
+  std::string includes = (input?input:"");
+  const char* sep = input ? ";" : "";
+  includes += sep + tei->InterfaceIncludeDirectories;
+  std::string prepro = cmGeneratorExpression::Preprocess(includes,
                                                           preprocessRule);
   if (!prepro.empty())
     {

+ 3 - 1
Source/cmExportFileGenerator.h

@@ -15,6 +15,8 @@
 #include "cmCommand.h"
 #include "cmGeneratorExpression.h"
 
+class cmTargetExport;
+
 /** \class cmExportFileGenerator
  * \brief Generate a file exporting targets from a build or install tree.
  *
@@ -114,7 +116,7 @@ protected:
   void GenerateInterfaceProperties(cmTarget *target, std::ostream& os,
                                    const ImportPropertyMap &properties);
   void PopulateIncludeDirectoriesInterface(
-                      cmTarget *target,
+                      cmTargetExport *target,
                       cmGeneratorExpression::PreprocessContext preprocessRule,
                       ImportPropertyMap &properties,
                       std::vector<std::string> &missingTargets);

+ 6 - 6
Source/cmExportInstallFileGenerator.cxx

@@ -39,7 +39,7 @@ std::string cmExportInstallFileGenerator::GetConfigImportFileGlob()
 //----------------------------------------------------------------------------
 bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
 {
-  std::vector<cmTarget*> allTargets;
+  std::vector<cmTargetExport*> allTargets;
   {
   std::string expectedTargets;
   std::string sep;
@@ -49,10 +49,10 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
     {
     expectedTargets += sep + this->Namespace + (*tei)->Target->GetExportName();
     sep = " ";
-    cmTargetExport const* te = *tei;
+    cmTargetExport * te = *tei;
     if(this->ExportedTargets.insert(te->Target).second)
       {
-      allTargets.push_back(te->Target);
+      allTargets.push_back(te);
       }
     else
       {
@@ -115,16 +115,16 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
 
   bool require2_8_12 = false;
   // Create all the imported targets.
-  for(std::vector<cmTarget*>::const_iterator
+  for(std::vector<cmTargetExport*>::const_iterator
         tei = allTargets.begin();
       tei != allTargets.end(); ++tei)
     {
-    cmTarget* te = *tei;
+    cmTarget* te = (*tei)->Target;
     this->GenerateImportTargetCode(os, te);
 
     ImportPropertyMap properties;
 
-    this->PopulateIncludeDirectoriesInterface(te,
+    this->PopulateIncludeDirectoriesInterface(*tei,
                                   cmGeneratorExpression::InstallInterface,
                                   properties, missingTargets);
     this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES",

+ 24 - 0
Source/cmInstallCommand.cxx

@@ -219,6 +219,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
   cmCAStringVector runtimeArgVector      (&argHelper,"RUNTIME",&group);
   cmCAStringVector frameworkArgVector    (&argHelper,"FRAMEWORK",&group);
   cmCAStringVector bundleArgVector       (&argHelper,"BUNDLE",&group);
+  cmCAStringVector includesArgVector     (&argHelper,"INCLUDES",&group);
   cmCAStringVector privateHeaderArgVector(&argHelper,"PRIVATE_HEADER",&group);
   cmCAStringVector publicHeaderArgVector (&argHelper,"PUBLIC_HEADER",&group);
   cmCAStringVector resourceArgVector     (&argHelper,"RESOURCE",&group);
@@ -247,6 +248,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
   cmInstallCommandArguments privateHeaderArgs(this->DefaultComponentName);
   cmInstallCommandArguments publicHeaderArgs(this->DefaultComponentName);
   cmInstallCommandArguments resourceArgs(this->DefaultComponentName);
+  cmInstallCommandIncludesArgument includesArgs;
 
   // now parse the args for specific parts of the target (e.g. LIBRARY,
   // RUNTIME, ARCHIVE etc.
@@ -258,6 +260,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
   privateHeaderArgs.Parse(&privateHeaderArgVector.GetVector(), &unknownArgs);
   publicHeaderArgs.Parse (&publicHeaderArgVector.GetVector(),  &unknownArgs);
   resourceArgs.Parse     (&resourceArgVector.GetVector(),      &unknownArgs);
+  includesArgs.Parse     (&includesArgVector.GetVector(),      &unknownArgs);
 
   if(!unknownArgs.empty())
     {
@@ -292,6 +295,13 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
     return false;
     }
 
+  if(!includesArgs.GetIncludeDirs().empty() && exports.GetString().empty())
+    {
+    this->SetError("TARGETS given INCLUDES DESTINATION, but EXPORT set "
+      "not specified.");
+    return false;
+    }
+
   // Enforce argument rules too complex to specify for the
   // general-purpose parser.
   if(archiveArgs.GetNamelinkOnly() ||
@@ -747,6 +757,20 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
       te->RuntimeGenerator = runtimeGenerator;
       this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
         ->GetExportSets()[exports.GetString()]->AddTargetExport(te);
+
+      std::vector<std::string> dirs = includesArgs.GetIncludeDirs();
+      if(!dirs.empty())
+        {
+        std::string dirString;
+        const char *sep = "";
+        for (std::vector<std::string>::const_iterator it = dirs.begin();
+            it != dirs.end(); ++it)
+          {
+          te->InterfaceIncludeDirectories += sep;
+          te->InterfaceIncludeDirectories += *it;
+          sep = ";";
+          }
+        }
       }
     }
 

+ 5 - 0
Source/cmInstallCommand.h

@@ -102,6 +102,7 @@ public:
       "          [[ARCHIVE|LIBRARY|RUNTIME|FRAMEWORK|BUNDLE|\n"
       "            PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]\n"
       "           [DESTINATION <dir>]\n"
+      "           [INCLUDES DESTINATION [<dir> ...]]\n"
       "           [PERMISSIONS permissions...]\n"
       "           [CONFIGURATIONS [Debug|Release|...]]\n"
       "           [COMPONENT <component>]\n"
@@ -130,6 +131,10 @@ public:
       "all target types.  If only one is given then only targets of that "
       "type will be installed (which can be used to install just a DLL or "
       "just an import library)."
+      "The INCLUDES DESTINATION specifies a list of directories which will "
+      "be added to the INTERFACE_INCLUDE_DIRECTORIES of the <targets> when "
+      "exported by install(EXPORT).  If a relative path is specified, it is "
+      "treated as relative to the $<INSTALL_PREFIX>."
       "\n"
       "The PRIVATE_HEADER, PUBLIC_HEADER, and RESOURCE arguments cause "
       "subsequent properties to be applied to installing a FRAMEWORK "

+ 34 - 0
Source/cmInstallCommandArguments.cxx

@@ -203,3 +203,37 @@ bool cmInstallCommandArguments::CheckPermissions(
   // This is not a valid permission.
   return false;
 }
+
+cmInstallCommandIncludesArgument::cmInstallCommandIncludesArgument()
+{
+
+}
+
+const std::vector<std::string>&
+cmInstallCommandIncludesArgument::GetIncludeDirs() const
+{
+  return this->IncludeDirs;
+}
+
+void cmInstallCommandIncludesArgument::Parse(
+                                        const std::vector<std::string>* args,
+                                        std::vector<std::string>*)
+{
+  if(args->empty())
+    {
+    return;
+    }
+  std::vector<std::string>::const_iterator it = args->begin();
+  ++it;
+  for ( ; it != args->end(); ++it)
+    {
+    std::string dir = *it;
+    if (!cmSystemTools::FileIsFullPath(it->c_str())
+        && cmGeneratorExpression::Find(*it) == std::string::npos)
+      {
+      dir = "$<INSTALL_PREFIX>/" + dir;
+      }
+    cmSystemTools::ConvertToUnixSlashes(dir);
+    this->IncludeDirs.push_back(dir);
+    }
+}

+ 13 - 0
Source/cmInstallCommandArguments.h

@@ -65,4 +65,17 @@ class cmInstallCommandArguments
     bool CheckPermissions();
 };
 
+class cmInstallCommandIncludesArgument
+{
+  public:
+    cmInstallCommandIncludesArgument();
+    void Parse(const std::vector<std::string>* args,
+               std::vector<std::string>* unconsumedArgs);
+
+    const std::vector<std::string>& GetIncludeDirs() const;
+
+  private:
+    std::vector<std::string> IncludeDirs;
+};
+
 #endif

+ 3 - 0
Source/cmTargetExport.h

@@ -12,6 +12,8 @@
 #ifndef cmTargetExport_h
 #define cmTargetExport_h
 
+#include "cmStandardIncludes.h"
+
 class cmTarget;
 class cmInstallTargetGenerator;
 class cmInstallFilesGenerator;
@@ -33,6 +35,7 @@ public:
   cmInstallTargetGenerator* FrameworkGenerator;
   cmInstallTargetGenerator* BundleGenerator;
   cmInstallFilesGenerator* HeaderGenerator;
+  std::string InterfaceIncludeDirectories;
   ///@}
 };
 

+ 18 - 1
Tests/ExportImport/Export/CMakeLists.txt

@@ -270,9 +270,26 @@ install(TARGETS testLibRequired
                 testLibIncludeRequired5
                 testLibIncludeRequired6
                 testSharedLibRequired
-        EXPORT RequiredExp DESTINATION lib )
+        EXPORT RequiredExp DESTINATION lib
+        INCLUDES DESTINATION
+          installIncludesTest
+          $<INSTALL_PREFIX>/installIncludesTest2)
 install(EXPORT RequiredExp NAMESPACE Req:: FILE testLibRequiredTargets.cmake DESTINATION lib/cmake/testLibRequired)
 
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest/installIncludesTest.h" "// No content\n")
+
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest2")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest2/installIncludesTest2.h" "// No content\n")
+install(FILES
+  "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest/installIncludesTest.h"
+  DESTINATION installIncludesTest
+)
+install(FILES
+  "${CMAKE_CURRENT_BINARY_DIR}/installIncludesTest2/installIncludesTest2.h"
+  DESTINATION installIncludesTest2
+)
+
 install(TARGETS testLibDepends testSharedLibDepends EXPORT DependsExp DESTINATION lib )
 install(EXPORT DependsExp FILE testLibDependsTargets.cmake DESTINATION lib/cmake/testLibDepends)
 

+ 3 - 0
Tests/ExportImport/Import/A/deps_iface.c

@@ -3,6 +3,9 @@
 #include "testLibIncludeRequired2.h"
 #include "testLibIncludeRequired6.h"
 
+#include "installIncludesTest.h"
+#include "installIncludesTest2.h"
+
 #ifndef testLibRequired_IFACE_DEFINE
 #error Expected testLibRequired_IFACE_DEFINE
 #endif

+ 1 - 0
Tests/RunCMake/include_directories/RunCMakeTest.cmake

@@ -9,3 +9,4 @@ run_cmake(RelativePathInInterface)
 run_cmake(ImportedTarget)
 run_cmake(RelativePathInGenex)
 run_cmake(CMP0021)
+run_cmake(TargetInterfaceIncludes)

+ 1 - 0
Tests/RunCMake/include_directories/TargetInterfaceIncludes-result.txt

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

+ 4 - 0
Tests/RunCMake/include_directories/TargetInterfaceIncludes-stderr.txt

@@ -0,0 +1,4 @@
+CMake Error at TargetInterfaceIncludes.cmake:3 \(install\):
+  install TARGETS given INCLUDES DESTINATION, but EXPORT set not specified.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 4 - 0
Tests/RunCMake/include_directories/TargetInterfaceIncludes.cmake

@@ -0,0 +1,4 @@
+
+add_library(empty empty.cpp)
+install(TARGETS empty DESTINATION lib INCLUDES DESTINATION include)
+# install(EXPORT )