Export: Disallow exported interface includes in src/build tree (#14592).

Allow directories in the source tree or build tree only if the
install tree is a subdirectory of the source tree or build tree,
as appropriate.

Re-use the test files in the RunCMake.include_directories test
to run in multiple scenarios.  Bump the required CMake version
in the test to 3.0 to ensure that the new policy warnings are
emitted correctly.
This commit is contained in:
Stephen Kelly 2014-03-31 17:37:02 +02:00
parent c869984ea0
commit 783bce295b
33 changed files with 282 additions and 3 deletions

View File

@ -103,3 +103,4 @@ All Policies
/policy/CMP0049
/policy/CMP0050
/policy/CMP0051
/policy/CMP0052

21
Help/policy/CMP0052.rst Normal file
View File

@ -0,0 +1,21 @@
CMP0052
-------
Reject source and build dirs in installed INTERFACE_INCLUDE_DIRECTORIES.
CMake 3.0 and lower allowed subdirectories of the source directory or build
directory to be in the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of
installed and exported targets, if the directory was also a subdirectory of
the installation prefix. This makes the installation depend on the
existence of the source dir or binary dir, and the installation will be
broken if either are removed after installation.
The OLD behavior for this policy is to export the content of the
:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` with the source or binary
directory. The NEW behavior for this
policy is to issue an error if such a directory is used.
This policy was introduced in CMake version 3.1.
CMake version |release| warns when the policy is not set and uses
``OLD`` behavior. Use the :command:`cmake_policy` command to set it
to ``OLD`` or ``NEW`` explicitly.

View File

@ -0,0 +1,5 @@
CMP0052
-------
* Policy :policy:`CMP0052` introduced to control directories in the
:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of exported targets.

View File

@ -278,9 +278,45 @@ static bool checkInterfaceDirs(const std::string &prepro,
target->GetMakefile()->IssueMessage(messageType, e.str());
}
if (isSubDirectory(li->c_str(), installDir))
{
// The include directory is inside the install tree. If the
// install tree is not inside the source tree or build tree then
// fall through to the checks below that the include directory is not
// also inside the source tree or build tree.
bool shouldContinue =
isSubDirectory(installDir, topBinaryDir)
|| isSubDirectory(installDir, topSourceDir);
if (!shouldContinue)
{
switch(target->GetPolicyStatusCMP0052())
{
case cmPolicies::WARN:
{
cmOStringStream s;
s << target->GetMakefile()->GetPolicies()
->GetPolicyWarning(cmPolicies::CMP0052) << "\n";
s << "Directory:\n \"" << *li << "\"\nin "
"INTERFACE_INCLUDE_DIRECTORIES of target \""
<< target->GetName() << "\" is a subdirectory of the install "
"directory:\n \"" << installDir << "\"";
target->GetMakefile()->IssueMessage(cmake::AUTHOR_WARNING,
s.str());
}
case cmPolicies::OLD:
shouldContinue = true;
break;
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::NEW:
break;
}
}
if (shouldContinue)
{
continue;
}
}
if (isSubDirectory(li->c_str(), topBinaryDir))
{
e << "Target \"" << target->GetName() << "\" "

View File

@ -348,6 +348,12 @@ cmPolicies::cmPolicies()
CMP0051, "CMP0051",
"List TARGET_OBJECTS in SOURCES target property.",
3,1,0, cmPolicies::WARN);
this->DefinePolicy(
CMP0052, "CMP0052",
"Reject source and build dirs in installed "
"INTERFACE_INCLUDE_DIRECTORIES.",
3,1,0, cmPolicies::WARN);
}
cmPolicies::~cmPolicies()

View File

@ -105,6 +105,8 @@ public:
CMP0049, ///< Do not expand variables in target source entries
CMP0050, ///< Disallow add_custom_command SOURCE signatures
CMP0051, ///< List TARGET_OBJECTS in SOURCES target property
CMP0052, ///< Reject source and build dirs in installed
/// INTERFACE_INCLUDE_DIRECTORIES
/** \brief Always the last entry.
*

View File

@ -30,7 +30,8 @@
F(CMP0038) \
F(CMP0041) \
F(CMP0042) \
F(CMP0046)
F(CMP0046) \
F(CMP0052)
class cmake;
class cmMakefile;

View File

@ -16,6 +16,7 @@
\* CMP0041
\* CMP0042
\* CMP0046
\* CMP0052
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

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

View File

@ -0,0 +1,15 @@
CMake Warning \(dev\) in CMakeLists.txt:
Policy CMP0052 is not set: Reject source and build dirs in installed
INTERFACE_INCLUDE_DIRECTORIES. Run "cmake --help-policy CMP0052" for
policy details. Use the cmake_policy command to set the policy and
suppress this warning.
Directory:
".*Tests/RunCMake/include_directories/prefix/BinInInstallPrefix-CMP0052-WARN-build/foo"
in INTERFACE_INCLUDE_DIRECTORIES of target "testTarget" is a subdirectory
of the install directory:
".*Tests/RunCMake/include_directories/prefix"
This warning is for project developers. Use -Wno-dev to suppress it.

View File

@ -1,3 +1,3 @@
cmake_minimum_required(VERSION 2.8.4)
cmake_minimum_required(VERSION 3.0)
project(${RunCMake_TEST} CXX)
include(${RunCMake_TEST}.cmake)

View File

@ -0,0 +1 @@
1

View File

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

View File

@ -0,0 +1 @@
1

View File

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

View File

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

View File

@ -12,3 +12,128 @@ run_cmake(CMP0021)
run_cmake(install_config)
run_cmake(incomplete-genex)
run_cmake(export-NOWARN)
configure_file(
"${RunCMake_SOURCE_DIR}/CMakeLists.txt"
"${RunCMake_BINARY_DIR}/copy/CMakeLists.txt"
COPYONLY
)
configure_file(
"${RunCMake_SOURCE_DIR}/empty.cpp"
"${RunCMake_BINARY_DIR}/copy/empty.cpp"
COPYONLY
)
configure_file(
"${RunCMake_SOURCE_DIR}/SourceDirectoryInInterface.cmake"
"${RunCMake_BINARY_DIR}/copy/SourceDirectoryInInterface.cmake"
COPYONLY
)
set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/copy/SourceDirectoryInInterface/prefix")
set(RunCMake_TEST_FILE "${RunCMake_BINARY_DIR}/copy/SourceDirectoryInInterface")
set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/copy")
run_cmake(InstallInSrcDir)
unset(RunCMake_TEST_SOURCE_DIR)
unset(RunCMake_TEST_FILE)
set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/InstallInBinDir-build/prefix")
set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/InstallInBinDir-build")
set(RunCMake_TEST_FILE "${RunCMake_SOURCE_DIR}/BinaryDirectoryInInterface")
run_cmake(InstallInBinDir)
unset(RunCMake_TEST_BINARY_DIR)
unset(RunCMake_TEST_FILE)
configure_file(
"${RunCMake_SOURCE_DIR}/CMakeLists.txt"
"${RunCMake_BINARY_DIR}/prefix/src/CMakeLists.txt"
COPYONLY
)
configure_file(
"${RunCMake_SOURCE_DIR}/empty.cpp"
"${RunCMake_BINARY_DIR}/prefix/src/empty.cpp"
COPYONLY
)
configure_file(
"${RunCMake_SOURCE_DIR}/SourceDirectoryInInterface.cmake"
"${RunCMake_BINARY_DIR}/prefix/src/SourceDirectoryInInterface.cmake"
COPYONLY
)
foreach(policyStatus "" NEW OLD)
if (NOT "${policyStatus}" STREQUAL "")
set(policyOption -DCMAKE_POLICY_DEFAULT_CMP0052=${policyStatus})
else()
unset(policyOption)
set(policyStatus WARN)
endif()
set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/prefix" ${policyOption})
# Set the RunCMake_TEST_SOURCE_DIR here to the copy too. This is needed to run
# the test suite in-source properly. Otherwise the install directory would be
# a subdirectory or the source directory, which is allowed and tested separately
# below.
set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/prefix/src")
set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/prefix/BinInInstallPrefix-CMP0052-${policyStatus}-build")
set(RunCMake_TEST_FILE "${RunCMake_SOURCE_DIR}/BinaryDirectoryInInterface")
run_cmake(BinInInstallPrefix-CMP0052-${policyStatus})
unset(RunCMake_TEST_BINARY_DIR)
unset(RunCMake_TEST_FILE)
set(RunCMake_TEST_FILE "${RunCMake_BINARY_DIR}/prefix/src/SourceDirectoryInInterface")
run_cmake(SrcInInstallPrefix-CMP0052-${policyStatus})
unset(RunCMake_TEST_SOURCE_DIR)
unset(RunCMake_TEST_FILE)
endforeach()
set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/InstallPrefixInInterface-build/prefix")
run_cmake(InstallPrefixInInterface)
configure_file(
"${RunCMake_SOURCE_DIR}/CMakeLists.txt"
"${RunCMake_BINARY_DIR}/installToSrc/CMakeLists.txt"
COPYONLY
)
configure_file(
"${RunCMake_SOURCE_DIR}/empty.cpp"
"${RunCMake_BINARY_DIR}/installToSrc/empty.cpp"
COPYONLY
)
configure_file(
"${RunCMake_SOURCE_DIR}/InstallPrefixInInterface.cmake"
"${RunCMake_BINARY_DIR}/installToSrc/InstallPrefixInInterface.cmake"
COPYONLY
)
set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/installToSrc/InstallPrefixInInterface/prefix")
set(RunCMake_TEST_FILE "${RunCMake_BINARY_DIR}/installToSrc/InstallPrefixInInterface")
set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/installToSrc")
run_cmake(InstallToPrefixInSrcDirOutOfSource)
unset(RunCMake_TEST_SOURCE_DIR)
unset(RunCMake_TEST_FILE)
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}/installToSrcInSrc")
set(RunCMake_TEST_NO_CLEAN ON)
configure_file(
"${RunCMake_SOURCE_DIR}/CMakeLists.txt"
"${RunCMake_BINARY_DIR}/installToSrcInSrc/CMakeLists.txt"
COPYONLY
)
configure_file(
"${RunCMake_SOURCE_DIR}/empty.cpp"
"${RunCMake_BINARY_DIR}/installToSrcInSrc/empty.cpp"
COPYONLY
)
configure_file(
"${RunCMake_SOURCE_DIR}/InstallPrefixInInterface.cmake"
"${RunCMake_BINARY_DIR}/installToSrcInSrc/InstallPrefixInInterface.cmake"
COPYONLY
)
set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/installToSrcInSrc/InstallPrefixInInterface/prefix")
set(RunCMake_TEST_FILE "${RunCMake_BINARY_DIR}/installToSrcInSrc/InstallPrefixInInterface")
set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/installToSrcInSrc")
set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/installToSrcInSrc")
run_cmake(InstallToPrefixInSrcDirInSource)
unset(RunCMake_TEST_SOURCE_DIR)
unset(RunCMake_TEST_BINARY_DIR)
unset(RunCMake_TEST_FILE)
unset(RunCMake_TEST_NO_CLEAN)

View File

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

View File

@ -0,0 +1,15 @@
CMake Warning \(dev\) in CMakeLists.txt:
Policy CMP0052 is not set: Reject source and build dirs in installed
INTERFACE_INCLUDE_DIRECTORIES. Run "cmake --help-policy CMP0052" for
policy details. Use the cmake_policy command to set the policy and
suppress this warning.
Directory:
".*Tests/RunCMake/include_directories/prefix/src/foo"
in INTERFACE_INCLUDE_DIRECTORIES of target "testTarget" is a subdirectory
of the install directory:
".*Tests/RunCMake/include_directories/prefix"
This warning is for project developers. Use -Wno-dev to suppress it.