Browse Source

Merge topic 'error-on-exported-missing-include-dir'

28051f1 Report an error on IMPORTED targets with a faulty INTERFACE
af81a3c install(EXPORT): Ensure clean INTERFACE_INCLUDE_DIRECTORIES
Brad King 12 years ago
parent
commit
b9e4a5abb4

+ 111 - 0
Source/cmExportFileGenerator.cxx

@@ -24,6 +24,7 @@
 #include "cmComputeLinkInformation.h"
 
 #include <cmsys/auto_ptr.hxx>
+#include <assert.h>
 
 //----------------------------------------------------------------------------
 cmExportFileGenerator::cmExportFileGenerator()
@@ -167,6 +168,116 @@ void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName,
     }
 }
 
+//----------------------------------------------------------------------------
+static bool isSubDirectory(const char* a, const char* b)
+{
+  return (cmSystemTools::ComparePath(a, b) ||
+          cmSystemTools::IsSubDirectory(a, b));
+}
+
+//----------------------------------------------------------------------------
+static bool checkInterfaceDirs(const std::string &prepro,
+                      cmTarget *target)
+{
+  const char* installDir =
+            target->GetMakefile()->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
+  const char* topSourceDir = target->GetMakefile()->GetHomeDirectory();
+  const char* topBinaryDir = target->GetMakefile()->GetHomeOutputDirectory();
+
+  std::vector<std::string> parts;
+  cmGeneratorExpression::Split(prepro, parts);
+
+  const bool inSourceBuild = strcmp(topSourceDir, topBinaryDir) == 0;
+
+  for(std::vector<std::string>::iterator li = parts.begin();
+      li != parts.end(); ++li)
+    {
+    if (cmGeneratorExpression::Find(*li) != std::string::npos)
+      {
+      continue;
+      }
+    if (strncmp(li->c_str(), "${_IMPORT_PREFIX}", 17) == 0)
+      {
+      continue;
+      }
+    if (!cmSystemTools::FileIsFullPath(li->c_str()))
+      {
+      cmOStringStream e;
+      e << "Target \"" << target->GetName() << "\" "
+           "INTERFACE_INCLUDE_DIRECTORIES property contains relative path:\n"
+           "  \"" << *li << "\"";
+      target->GetMakefile()->IssueMessage(cmake::FATAL_ERROR,
+                                          e.str().c_str());
+      return false;
+      }
+    if (isSubDirectory(li->c_str(), installDir))
+      {
+      continue;
+      }
+    if (isSubDirectory(li->c_str(), topBinaryDir))
+      {
+      cmOStringStream e;
+      e << "Target \"" << target->GetName() << "\" "
+           "INTERFACE_INCLUDE_DIRECTORIES property contains path:\n"
+           "  \"" << *li << "\"\nwhich is prefixed in the build directory.";
+      target->GetMakefile()->IssueMessage(cmake::FATAL_ERROR,
+                                          e.str().c_str());
+      return false;
+      }
+    if (!inSourceBuild)
+      {
+      if (isSubDirectory(li->c_str(), topSourceDir))
+        {
+        cmOStringStream e;
+        e << "Target \"" << target->GetName() << "\" "
+            "INTERFACE_INCLUDE_DIRECTORIES property contains path:\n"
+            "  \"" << *li << "\"\nwhich is prefixed in the source directory.";
+        target->GetMakefile()->IssueMessage(cmake::FATAL_ERROR,
+                                            e.str().c_str());
+        return false;
+        }
+      }
+    }
+  return true;
+}
+
+//----------------------------------------------------------------------------
+void cmExportFileGenerator::PopulateIncludeDirectoriesInterface(
+                      cmTarget *target,
+                      cmGeneratorExpression::PreprocessContext preprocessRule,
+                      ImportPropertyMap &properties,
+                      std::vector<std::string> &missingTargets)
+{
+  assert(preprocessRule == cmGeneratorExpression::InstallInterface);
+
+  const char *propName = "INTERFACE_INCLUDE_DIRECTORIES";
+  const char *input = target->GetProperty(propName);
+  if (!input)
+    {
+    return;
+    }
+  if (!*input)
+    {
+    // Set to empty
+    properties[propName] = "";
+    return;
+    }
+
+  std::string prepro = cmGeneratorExpression::Preprocess(input,
+                                                          preprocessRule);
+  if (!prepro.empty())
+    {
+    this->ResolveTargetsInGeneratorExpressions(prepro, target,
+                                                missingTargets);
+
+    if (!checkInterfaceDirs(prepro, target))
+      {
+      return;
+      }
+    properties[propName] = prepro;
+    }
+}
+
 //----------------------------------------------------------------------------
 void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName,
                       cmTarget *target,

+ 5 - 0
Source/cmExportFileGenerator.h

@@ -107,6 +107,11 @@ protected:
                                  ImportPropertyMap &properties);
   void GenerateInterfaceProperties(cmTarget *target, std::ostream& os,
                                    const ImportPropertyMap &properties);
+  void PopulateIncludeDirectoriesInterface(
+                      cmTarget *target,
+                      cmGeneratorExpression::PreprocessContext preprocessRule,
+                      ImportPropertyMap &properties,
+                      std::vector<std::string> &missingTargets);
 
   void SetImportLinkInterface(const char* config, std::string const& suffix,
                     cmGeneratorExpression::PreprocessContext preprocessRule,

+ 1 - 2
Source/cmExportInstallFileGenerator.cxx

@@ -120,8 +120,7 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
 
     ImportPropertyMap properties;
 
-    this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES",
-                                  te,
+    this->PopulateIncludeDirectoriesInterface(te,
                                   cmGeneratorExpression::InstallInterface,
                                   properties, missingTargets);
     this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS",

+ 28 - 3
Source/cmTarget.cxx

@@ -131,11 +131,13 @@ public:
   SourceEntriesType SourceEntries;
 
   struct IncludeDirectoriesEntry {
-    IncludeDirectoriesEntry(cmsys::auto_ptr<cmCompiledGeneratorExpression> cge)
-      : ge(cge)
+    IncludeDirectoriesEntry(cmsys::auto_ptr<cmCompiledGeneratorExpression> cge,
+      const std::string &targetName = std::string())
+      : ge(cge), TargetName(targetName)
     {}
     const cmsys::auto_ptr<cmCompiledGeneratorExpression> ge;
     std::vector<std::string> CachedIncludes;
+    const std::string TargetName;
   };
   std::vector<IncludeDirectoriesEntry*> IncludeDirectoriesEntries;
   std::vector<cmValueWithOrigin> LinkInterfaceIncludeDirectoriesEntries;
@@ -2818,6 +2820,28 @@ static void processIncludeDirectories(cmTarget *tgt,
     for(std::vector<std::string>::iterator
           li = entryIncludes.begin(); li != entryIncludes.end(); ++li)
       {
+      cmTarget *dependentTarget =
+                              mf->FindTargetToUse((*it)->TargetName.c_str());
+
+      const bool fromImported = dependentTarget
+                             && dependentTarget->IsImported();
+
+      if (fromImported && !cmSystemTools::FileExists(li->c_str()))
+        {
+        cmOStringStream e;
+        e << "Imported target \"" << (*it)->TargetName << "\" includes "
+             "non-existent path\n  \"" << *li << "\"\nin its "
+             "INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:\n"
+             "* The path was deleted, renamed, or moved to another "
+             "location.\n"
+             "* An install or uninstall procedure did not complete "
+             "successfully.\n"
+             "* The installation package was faulty and references files it "
+             "does not provide.\n";
+        tgt->GetMakefile()->IssueMessage(cmake::FATAL_ERROR, e.str().c_str());
+        return;
+        }
+
       if (testIsOff && !cmSystemTools::IsOff(li->c_str()))
         {
         cmSystemTools::ConvertToUnixSlashes(*li);
@@ -2913,7 +2937,8 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config)
                               it->Value + ",INTERFACE_INCLUDE_DIRECTORIES>");
 
       this->Internal->CachedLinkInterfaceIncludeDirectoriesEntries.push_back(
-                        new cmTargetInternals::IncludeDirectoriesEntry(cge));
+                        new cmTargetInternals::IncludeDirectoriesEntry(cge,
+                                                              it->Value));
       }
     }
 

+ 16 - 2
Tests/ExportImport/Export/CMakeLists.txt

@@ -174,9 +174,14 @@ set_property(TARGET testSharedLibRequired
 set_property(TARGET testSharedLibRequired APPEND PROPERTY
   INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}"
 )
+install(FILES
+  "${CMAKE_CURRENT_SOURCE_DIR}/testSharedLibRequired.h"
+  "${CMAKE_CURRENT_BINARY_DIR}/testsharedlibrequired_export.h"
+    DESTINATION include/testSharedLibRequired
+)
 set_property(TARGET testSharedLibRequired APPEND PROPERTY
-  INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}"
-                                "${CMAKE_CURRENT_SOURCE_DIR}"
+  INTERFACE_INCLUDE_DIRECTORIES "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include/testSharedLibRequired>"
+                                "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}>"
 )
 set_property(TARGET testSharedLibRequired
   APPEND PROPERTY
@@ -205,6 +210,15 @@ set_property(TARGET testSharedLibDepends APPEND PROPERTY
   INTERFACE_INCLUDE_DIRECTORIES
     $<TARGET_PROPERTY:testSharedLibRequired,INTERFACE_INCLUDE_DIRECTORIES>
 )
+install(FILES
+  "${CMAKE_CURRENT_SOURCE_DIR}/testSharedLibDepends.h"
+  "${CMAKE_CURRENT_BINARY_DIR}/testsharedlibdepends_export.h"
+    DESTINATION include/testSharedLibDepends
+)
+set_property(TARGET testSharedLibDepends APPEND PROPERTY
+  INTERFACE_INCLUDE_DIRECTORIES "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include/testSharedLibDepends>"
+                                "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}>"
+)
 set_property(TARGET testSharedLibDepends APPEND PROPERTY
   LINK_INTERFACE_LIBRARIES
     $<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:$<TARGET_NAME:testSharedLibRequired>>

+ 0 - 2
Tests/RunCMake/CompatibleInterface/InterfaceString-builtin-prop.cmake

@@ -3,8 +3,6 @@ add_library(foo UNKNOWN IMPORTED)
 add_library(bar UNKNOWN IMPORTED)
 
 set_property(TARGET foo APPEND PROPERTY COMPATIBLE_INTERFACE_STRING INCLUDE_DIRECTORIES)
-set_property(TARGET foo PROPERTY INTERFACE_INCLUDE_DIRECTORIES foo_inc)
-set_property(TARGET bar PROPERTY INTERFACE_INCLUDE_DIRECTORIES bar_inc)
 
 add_executable(user main.cpp)
 set_property(TARGET user PROPERTY INCLUDE_DIRECTORIES bar_inc)

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

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

+ 6 - 0
Tests/RunCMake/include_directories/BinaryDirectoryInInterface-stderr.txt

@@ -0,0 +1,6 @@
+CMake Error in CMakeLists.txt:
+  Target "testTarget" INTERFACE_INCLUDE_DIRECTORIES property contains path:
+
+    ".*RunCMake/include_directories/BinaryDirectoryInInterface-build/foo"
+
+  which is prefixed in the build directory.

+ 11 - 0
Tests/RunCMake/include_directories/BinaryDirectoryInInterface.cmake

@@ -0,0 +1,11 @@
+
+project(BinaryDirectoryInInterface)
+
+add_library(testTarget "${CMAKE_CURRENT_SOURCE_DIR}/empty.cpp")
+target_include_directories(testTarget INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/foo")
+
+install(TARGETS testTarget EXPORT testTargets
+  DESTINATION lib
+)
+
+install(EXPORT testTargets DESTINATION lib/cmake)

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

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

+ 13 - 0
Tests/RunCMake/include_directories/ImportedTarget-stderr.txt

@@ -0,0 +1,13 @@
+CMake Error in CMakeLists.txt:
+  Imported target "imported" includes non-existent path
+
+    "/does/not/exist"
+
+  in its INTERFACE_INCLUDE_DIRECTORIES.  Possible reasons include:
+
+  \* The path was deleted, renamed, or moved to another location.
+
+  \* An install or uninstall procedure did not complete successfully.
+
+  \* The installation package was faulty and references files it does not
+  provide.

+ 9 - 0
Tests/RunCMake/include_directories/ImportedTarget.cmake

@@ -0,0 +1,9 @@
+
+project(ImportedTarget)
+
+add_library(testTarget "${CMAKE_CURRENT_SOURCE_DIR}/empty.cpp")
+
+add_library(imported UNKNOWN IMPORTED)
+set_property(TARGET imported PROPERTY INTERFACE_INCLUDE_DIRECTORIES "/does/not/exist")
+
+target_link_libraries(testTarget imported)

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

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

+ 5 - 0
Tests/RunCMake/include_directories/RelativePathInInterface-stderr.txt

@@ -0,0 +1,5 @@
+CMake Error in CMakeLists.txt:
+  Target "testTarget" INTERFACE_INCLUDE_DIRECTORIES property contains
+  relative path:
+
+    "foo"

+ 11 - 0
Tests/RunCMake/include_directories/RelativePathInInterface.cmake

@@ -0,0 +1,11 @@
+
+project(RelativePathInInterface)
+
+add_library(testTarget "${CMAKE_CURRENT_SOURCE_DIR}/empty.cpp")
+set_property(TARGET testTarget PROPERTY INTERFACE_INCLUDE_DIRECTORIES "foo")
+
+install(TARGETS testTarget EXPORT testTargets
+  DESTINATION lib
+)
+
+install(EXPORT testTargets DESTINATION lib/cmake)

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

@@ -3,3 +3,7 @@ include(RunCMake)
 run_cmake(NotFoundContent)
 run_cmake(DebugIncludes)
 run_cmake(TID-bad-target)
+run_cmake(SourceDirectoryInInterface)
+run_cmake(BinaryDirectoryInInterface)
+run_cmake(RelativePathInInterface)
+run_cmake(ImportedTarget)

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

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

+ 6 - 0
Tests/RunCMake/include_directories/SourceDirectoryInInterface-stderr.txt

@@ -0,0 +1,6 @@
+CMake Error in CMakeLists.txt:
+  Target "testTarget" INTERFACE_INCLUDE_DIRECTORIES property contains path:
+
+    ".*RunCMake/include_directories/foo"
+
+  which is prefixed in the source directory.

+ 11 - 0
Tests/RunCMake/include_directories/SourceDirectoryInInterface.cmake

@@ -0,0 +1,11 @@
+
+project(SourceDirectoryInInterface)
+
+add_library(testTarget "${CMAKE_CURRENT_SOURCE_DIR}/empty.cpp")
+target_include_directories(testTarget INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/foo")
+
+install(TARGETS testTarget EXPORT testTargets
+  DESTINATION lib
+)
+
+install(EXPORT testTargets DESTINATION lib/cmake)

+ 0 - 0
Tests/RunCMake/include_directories/empty.cpp