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

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")
  • What if the value is empty?

    Recently I've noticed this in https://github.com/cartographer-project/cartographer/pull/1808

    When variable used in target_include_directories is empty or unset: target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC "${SOME_UNDEFINED_OR_EMPTY_VARIABLE}")

    the PROJECT_SOURCE_DIR ends in INTERFACE_INCLUDE_DIRECTORIES/INTERFACE_SYSTEM_INCLUDE_DIRECTORIES.

    Is this correct behavior? If it's unexpected I can create proper issue ticket with a test case showing this behavior.

  • @shr-project please ask coding and usage questions over on the discourse forum. The diff of a 7 year old commit is not a good place.

Please register or sign in to reply
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)
Supports Markdown
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