Commit af81a3c3 authored by Stephen Kelly's avatar Stephen Kelly Committed by Brad King

install(EXPORT): Ensure clean INTERFACE_INCLUDE_DIRECTORIES

Check that source and binary directories are not part of the
INTERFACE_INCLUDE_DIRECTORIES for installed IMPORTED targets.

This is limited to directories which do not contain generator
expressions to evaluate. Such paths can only be checked at time
of use of the imported target, which will be done in a follow up
patch.
parent ddbe2e1d
......@@ -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,
......
......@@ -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,
......
......@@ -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",
......
......@@ -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>>
......
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.
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)
CMake Error in CMakeLists.txt:
Target "testTarget" INTERFACE_INCLUDE_DIRECTORIES property contains
relative path:
"foo"
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)
......@@ -3,3 +3,6 @@ include(RunCMake)
run_cmake(NotFoundContent)
run_cmake(DebugIncludes)
run_cmake(TID-bad-target)
run_cmake(SourceDirectoryInInterface)
run_cmake(BinaryDirectoryInInterface)
run_cmake(RelativePathInInterface)
CMake Error in CMakeLists.txt:
Target "testTarget" INTERFACE_INCLUDE_DIRECTORIES property contains path:
".*RunCMake/include_directories/foo"
which is prefixed in the source directory.
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)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment