Merge topic 'subdir_target_sources'

316815e1f4 target_sources: Interpret relative paths as relative to the calling directory

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !2128
This commit is contained in:
Craig Scott
2018-06-19 12:23:44 +00:00
committed by Kitware Robot
46 changed files with 447 additions and 4 deletions

View File

@@ -9,7 +9,9 @@ Add sources to a target.
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
Specify sources to use when compiling a given target. The
Specify sources to use when compiling a given target. Relative
source file paths are interpreted as being relative to the current
source directory (i.e. :variable:`CMAKE_CURRENT_SOURCE_DIR`). The
named ``<target>`` must have been created by a command such as
:command:`add_executable` or :command:`add_library` and must not be an
:ref:`ALIAS target <Alias Targets>`.
@@ -27,3 +29,6 @@ Arguments to ``target_sources`` may use "generator expressions"
with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
manual for available expressions. See the :manual:`cmake-buildsystem(7)`
manual for more on defining buildsystem properties.
See also the :policy:`CMP0076` policy for older behavior related to the
handling of relative source file paths.

View File

@@ -51,6 +51,14 @@ The :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` variable may also be used
to determine whether to report an error on use of deprecated macros or
functions.
Policies Introduced by CMake 3.13
=================================
.. toctree::
:maxdepth: 1
CMP0076: target_sources() command converts relative paths to absolute. </policy/CMP0076>
Policies Introduced by CMake 3.12
=================================

26
Help/policy/CMP0076.rst Normal file
View File

@@ -0,0 +1,26 @@
CMP0076
-------
The :command:`target_sources` command converts relative paths to absolute.
In CMake 3.13 and above, the :command:`target_sources` command now converts
relative source file paths to absolute paths in the following cases:
* Source files are added to the target's :prop_tgt:`INTERFACE_SOURCES`
property.
* The target's :prop_tgt:`SOURCE_DIR` property differs from
:variable:`CMAKE_CURRENT_SOURCE_DIR`.
A path that begins with a generator expression is always left unmodified.
This policy provides compatibility with projects that have not been updated
to expect this behavior. The ``OLD`` behavior for this policy is to leave
all relative source file paths unmodified. The ``NEW`` behavior of this
policy is to convert relative paths to absolute according to above rules.
This policy was introduced in CMake version 3.13. 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.
.. include:: DEPRECATED.txt

View File

@@ -0,0 +1,8 @@
subdirectory-sources
--------------------
* The :command:`target_sources` command now interprets relative source file
paths as relative to the current source directory. This simplifies
incrementally building up a target's sources from subdirectories. The
:policy:`CMP0076` policy was added to provide backward compatibility with
the old behavior where required.

View File

@@ -223,7 +223,10 @@ class cmMakefile;
12, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0075, \
"Include file check macros honor CMAKE_REQUIRED_LIBRARIES.", 3, 12, \
0, cmPolicies::WARN)
0, cmPolicies::WARN) \
SELECT(POLICY, CMP0076, \
"target_sources() command converts relative paths to absolute.", 3, \
13, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
@@ -248,7 +251,8 @@ class cmMakefile;
F(CMP0065) \
F(CMP0068) \
F(CMP0069) \
F(CMP0073)
F(CMP0073) \
F(CMP0076)
/** \class cmPolicies
* \brief Handles changes in CMake behavior and policies

View File

@@ -2,10 +2,14 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmTargetSourcesCommand.h"
#include <cstring>
#include <sstream>
#include "cmAlgorithms.h"
#include "cmGeneratorExpression.h"
#include "cmMakefile.h"
#include "cmPolicies.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmake.h"
@@ -17,6 +21,14 @@ bool cmTargetSourcesCommand::InitialPass(std::vector<std::string> const& args,
return this->HandleArguments(args, "SOURCES");
}
void cmTargetSourcesCommand::HandleInterfaceContent(
cmTarget* tgt, const std::vector<std::string>& content, bool prepend,
bool system)
{
cmTargetPropCommandBase::HandleInterfaceContent(
tgt, ConvertToAbsoluteContent(tgt, content, true), prepend, system);
}
void cmTargetSourcesCommand::HandleMissingTarget(const std::string& name)
{
std::ostringstream e;
@@ -35,6 +47,79 @@ std::string cmTargetSourcesCommand::Join(
bool cmTargetSourcesCommand::HandleDirectContent(
cmTarget* tgt, const std::vector<std::string>& content, bool, bool)
{
tgt->AppendProperty("SOURCES", this->Join(content).c_str());
tgt->AppendProperty(
"SOURCES",
this->Join(ConvertToAbsoluteContent(tgt, content, false)).c_str());
return true; // Successfully handled.
}
std::vector<std::string> cmTargetSourcesCommand::ConvertToAbsoluteContent(
cmTarget* tgt, const std::vector<std::string>& content,
bool isInterfaceContent)
{
// Skip conversion in case old behavior has been explictly requested
if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0076) ==
cmPolicies::OLD) {
return content;
}
bool changedPath = false;
std::vector<std::string> absoluteContent;
absoluteContent.reserve(content.size());
for (std::string const& src : content) {
std::string absoluteSrc;
if (cmSystemTools::FileIsFullPath(src) ||
cmGeneratorExpression::Find(src) == 0 ||
(!isInterfaceContent &&
strcmp(this->Makefile->GetCurrentSourceDirectory(),
tgt->GetMakefile()->GetCurrentSourceDirectory()) == 0)) {
absoluteSrc = src;
} else {
changedPath = true;
absoluteSrc = this->Makefile->GetCurrentSourceDirectory();
absoluteSrc += "/";
absoluteSrc += src;
}
absoluteContent.push_back(absoluteSrc);
}
if (!changedPath) {
return content;
}
bool issueMessage = true;
bool useAbsoluteContent = false;
std::ostringstream e;
switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0076)) {
case cmPolicies::WARN:
e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0076) << "\n";
break;
case cmPolicies::OLD:
issueMessage = false;
break;
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::REQUIRED_IF_USED:
this->Makefile->IssueMessage(
cmake::FATAL_ERROR,
cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0076));
break;
case cmPolicies::NEW: {
issueMessage = false;
useAbsoluteContent = true;
break;
}
}
if (issueMessage) {
if (isInterfaceContent) {
e << "An interface source of target \"" << tgt->GetName()
<< "\" has a relative path.";
} else {
e << "A private source from a directory other than that of target \""
<< tgt->GetName() << "\" has a relative path.";
}
this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, e.str());
}
return useAbsoluteContent ? absoluteContent : content;
}

View File

@@ -29,6 +29,11 @@ public:
bool InitialPass(std::vector<std::string> const& args,
cmExecutionStatus& status) override;
protected:
void HandleInterfaceContent(cmTarget* tgt,
const std::vector<std::string>& content,
bool prepend, bool system) override;
private:
void HandleMissingTarget(const std::string& name) override;
@@ -37,6 +42,10 @@ private:
bool prepend, bool system) override;
std::string Join(const std::vector<std::string>& content) override;
std::vector<std::string> ConvertToAbsoluteContent(
cmTarget* tgt, const std::vector<std::string>& content,
bool isInterfaceContent);
};
#endif

View File

@@ -0,0 +1,36 @@
cmake_minimum_required(VERSION 3.12)
cmake_policy(SET CMP0076 NEW)
project(target_sources)
add_library(target_sources_lib)
target_compile_definitions(target_sources_lib PRIVATE "-DIS_LIB")
add_subdirectory(subdir)
set(subdir_fullpath "${CMAKE_CURRENT_LIST_DIR}/subdir")
get_property(target_sources_lib_property TARGET target_sources_lib PROPERTY SOURCES)
if (NOT "$<1:${subdir_fullpath}/subdir_empty_1.cpp>" IN_LIST target_sources_lib_property)
message(SEND_ERROR "target_sources_lib: Generator expression to absolute sub directory file not found")
endif()
if (NOT "$<1:${subdir_fullpath}/../empty_1.cpp>" IN_LIST target_sources_lib_property)
message(SEND_ERROR "target_sources_lib: Generator expression to absolute main directory file not found")
endif()
if (NOT "${subdir_fullpath}/subdir_empty_2.cpp" IN_LIST target_sources_lib_property)
message(SEND_ERROR "target_sources_lib: Relative sub directory file not converted to absolute")
endif()
if (NOT "$<1:empty_2.cpp>" IN_LIST target_sources_lib_property)
message(SEND_ERROR "target_sources_lib: Generator expression to relative main directory file not found")
endif()
if (NOT "${subdir_fullpath}/../empty_3.cpp" IN_LIST target_sources_lib_property)
message(SEND_ERROR "target_sources_lib: Relative main directory file not converted to absolute")
endif()
add_executable(target_sources main.cpp)
target_link_libraries(target_sources target_sources_lib)
get_property(target_sources_property TARGET target_sources PROPERTY SOURCES)
if (NOT "main.cpp" IN_LIST target_sources_property)
message(SEND_ERROR "target_sources: Relative main directory file converted to absolute")
endif()

View File

@@ -0,0 +1,21 @@
#ifdef IS_LIB
# ifdef _WIN32
__declspec(dllexport)
# endif
int internal_empty_1()
{
return 0;
}
#else
# ifdef _WIN32
__declspec(dllexport)
# endif
int empty_1()
{
return 0;
}
#endif

View File

@@ -0,0 +1,7 @@
#ifdef _WIN32
__declspec(dllexport)
#endif
int empty_2()
{
return 0;
}

View File

@@ -0,0 +1,7 @@
#ifdef _WIN32
__declspec(dllexport)
#endif
int empty_3()
{
return 0;
}

View File

@@ -0,0 +1,16 @@
#include <iostream>
int empty_1();
int subdir_empty_1();
int subdir_empty_2();
int main()
{
int e1 = empty_1();
int se1 = subdir_empty_1();
int se2 = subdir_empty_2();
std::cout << e1 << " " << se1 << " " << se2 << std::endl;
return 0;
}

View File

@@ -0,0 +1,6 @@
target_sources(target_sources_lib PUBLIC $<1:${CMAKE_CURRENT_LIST_DIR}/subdir_empty_1.cpp>
$<1:${CMAKE_CURRENT_LIST_DIR}/../empty_1.cpp>
subdir_empty_2.cpp
PRIVATE $<1:empty_2.cpp>
../empty_3.cpp)

View File

@@ -0,0 +1,21 @@
#ifdef IS_LIB
# ifdef _WIN32
__declspec(dllexport)
# endif
int internal_subdir_empty_1()
{
return 0;
}
#else
# ifdef _WIN32
__declspec(dllexport)
# endif
int subdir_empty_1()
{
return 0;
}
#endif

View File

@@ -0,0 +1,21 @@
#ifdef IS_LIB
# ifdef _WIN32
__declspec(dllexport)
# endif
int internal_subdir_empty_2()
{
return 0;
}
#else
# ifdef _WIN32
__declspec(dllexport)
# endif
int subdir_empty_2()
{
return 0;
}
#endif

View File

@@ -2839,6 +2839,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
ADD_TEST_MACRO(CMakeCommands.target_include_directories target_include_directories)
ADD_TEST_MACRO(CMakeCommands.target_compile_definitions target_compile_definitions)
ADD_TEST_MACRO(CMakeCommands.target_compile_options target_compile_options)
ADD_TEST_MACRO(CMakeCommands.target_sources target_sources)
ADD_TEST_MACRO(CMakeCommands.add_link_options)
ADD_TEST_MACRO(CMakeCommands.target_link_options)

View File

@@ -24,6 +24,7 @@
\* CMP0068
\* CMP0069
\* CMP0073
\* CMP0076
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@@ -0,0 +1,10 @@
cmake_policy(SET CMP0076 OLD)
add_library(iface INTERFACE)
target_sources(iface INTERFACE empty_1.cpp)
get_property(iface_sources TARGET iface PROPERTY INTERFACE_SOURCES)
message(STATUS "iface: ${iface_sources}")
add_executable(main main.cpp)
target_link_libraries(main iface)

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,21 @@
CMake Warning \(dev\) at CMP0076-WARN/CMakeLists.txt:2 \(target_sources\):
Policy CMP0076 is not set: target_sources\(\) command converts relative paths
to absolute. Run "cmake --help-policy CMP0076" for policy details. Use
the cmake_policy command to set the policy and suppress this warning.
An interface source of target "publiclib" has a relative path.
This warning is for project developers. Use -Wno-dev to suppress it.
CMake Warning \(dev\) at CMP0076-WARN/CMakeLists.txt:2 \(target_sources\):
Policy CMP0076 is not set: target_sources\(\) command converts relative paths
to absolute. Run "cmake --help-policy CMP0076" for policy details. Use
the cmake_policy command to set the policy and suppress this warning.
A private source from a directory other than that of target "publiclib" has
a relative path.
This warning is for project developers. Use -Wno-dev to suppress it.
CMake Error in CMakeLists.txt:
Target "publiclib" contains relative path in its INTERFACE_SOURCES:
"CMP0076-WARN/subdir_empty_1.cpp"

View File

@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.12)
add_library(publiclib)
add_subdirectory(CMP0076-WARN)
add_executable(main main.cpp)
target_link_libraries(main publiclib)

View File

@@ -0,0 +1,3 @@
target_sources(publiclib INTERFACE CMP0076-WARN/subdir_empty_1.cpp
PRIVATE empty_1.cpp)

View File

@@ -0,0 +1,7 @@
#ifdef _WIN32
__declspec(dllexport)
#endif
int empty()
{
return 0;
}

View File

@@ -0,0 +1 @@
-- iface: .*Tests/RunCMake/TargetSources/empty_1.cpp

View File

@@ -1,6 +1,10 @@
cmake_policy(SET CMP0076 NEW)
add_library(iface INTERFACE)
target_sources(iface INTERFACE empty_1.cpp)
get_property(iface_sources TARGET iface PROPERTY INTERFACE_SOURCES)
message(STATUS "iface: ${iface_sources}")
add_executable(main main.cpp)
target_link_libraries(main iface)

View File

@@ -0,0 +1 @@
-- genexlib: \$<1:.*Tests/RunCMake/TargetSources/RelativePathInSubdirGenEx/subdir_empty_1.cpp>;\$<1:.*Tests/RunCMake/TargetSources/RelativePathInSubdirGenEx/../empty_1.cpp>;\$<1:empty_2.cpp>

View File

@@ -0,0 +1,10 @@
cmake_policy(SET CMP0076 NEW)
add_library(genexlib)
add_subdirectory(RelativePathInSubdirGenEx)
get_property(genexlib_sources TARGET genexlib PROPERTY SOURCES)
message(STATUS "genexlib: ${genexlib_sources}")
add_executable(genexmain main.cpp)
target_link_libraries(genexmain genexlib)

View File

@@ -0,0 +1,4 @@
target_sources(genexlib PUBLIC $<1:${CMAKE_CURRENT_LIST_DIR}/subdir_empty_1.cpp>
$<1:${CMAKE_CURRENT_LIST_DIR}/../empty_1.cpp>
PRIVATE $<1:empty_2.cpp>)

View File

@@ -0,0 +1,7 @@
#ifdef _WIN32
__declspec(dllexport)
#endif
int empty()
{
return 0;
}

View File

@@ -0,0 +1 @@
-- privatelib: .*Tests/RunCMake/TargetSources/RelativePathInSubdirInclude/subdir_empty_1.cpp;empty_1.cpp

View File

@@ -0,0 +1,8 @@
cmake_policy(SET CMP0076 NEW)
add_library(privatelib)
include("RelativePathInSubdirInclude/CMakeLists.txt")
get_property(privatelib_sources TARGET privatelib PROPERTY SOURCES)
message(STATUS "privatelib: ${privatelib_sources}")

View File

@@ -0,0 +1,3 @@
target_sources(privatelib PRIVATE "${CMAKE_CURRENT_LIST_DIR}/subdir_empty_1.cpp"
empty_1.cpp)

View File

@@ -0,0 +1,7 @@
#ifdef _WIN32
__declspec(dllexport)
#endif
int empty()
{
return 0;
}

View File

@@ -0,0 +1 @@
-- iface: .*Tests/RunCMake/TargetSources/RelativePathInSubdirInterface/subdir_empty_1.cpp;.*Tests/RunCMake/TargetSources/RelativePathInSubdirInterface/subdir_empty_2.cpp;.*Tests/RunCMake/TargetSources/RelativePathInSubdirInterface/../empty_1.cpp;.*Tests/RunCMake/TargetSources/RelativePathInSubdirInterface/../empty_2.cpp

View File

@@ -0,0 +1,11 @@
cmake_policy(SET CMP0076 NEW)
add_library(iface INTERFACE)
add_subdirectory(RelativePathInSubdirInterface)
get_property(iface_sources TARGET iface PROPERTY INTERFACE_SOURCES)
message(STATUS "iface: ${iface_sources}")
add_executable(main main.cpp)
target_link_libraries(main iface)

View File

@@ -0,0 +1,5 @@
target_sources(iface INTERFACE subdir_empty_1.cpp
"${CMAKE_CURRENT_LIST_DIR}/subdir_empty_2.cpp"
../empty_1.cpp
"${CMAKE_CURRENT_LIST_DIR}/../empty_2.cpp")

View File

@@ -0,0 +1,7 @@
#ifdef _WIN32
__declspec(dllexport)
#endif
int empty()
{
return 0;
}

View File

@@ -0,0 +1,7 @@
#ifdef _WIN32
__declspec(dllexport)
#endif
int empty()
{
return 0;
}

View File

@@ -0,0 +1 @@
-- privatelib: .*Tests/RunCMake/TargetSources/RelativePathInSubdirPrivate/subdir_empty_1.cpp;.*Tests/RunCMake/TargetSources/RelativePathInSubdirPrivate/subdir_empty_2.cpp;.*Tests/RunCMake/TargetSources/RelativePathInSubdirPrivate/../empty_1.cpp;.*Tests/RunCMake/TargetSources/RelativePathInSubdirPrivate/../empty_2.cpp

View File

@@ -0,0 +1,8 @@
cmake_policy(SET CMP0076 NEW)
add_library(privatelib)
add_subdirectory(RelativePathInSubdirPrivate)
get_property(privatelib_sources TARGET privatelib PROPERTY SOURCES)
message(STATUS "privatelib: ${privatelib_sources}")

View File

@@ -0,0 +1,5 @@
target_sources(privatelib PRIVATE subdir_empty_1.cpp
"${CMAKE_CURRENT_LIST_DIR}/subdir_empty_2.cpp"
../empty_1.cpp
"${CMAKE_CURRENT_LIST_DIR}/../empty_2.cpp")

View File

@@ -0,0 +1,7 @@
#ifdef _WIN32
__declspec(dllexport)
#endif
int empty()
{
return 0;
}

View File

@@ -0,0 +1,7 @@
#ifdef _WIN32
__declspec(dllexport)
#endif
int empty()
{
return 0;
}

View File

@@ -6,5 +6,11 @@ endif()
run_cmake(OriginDebug)
run_cmake(CMP0026-LOCATION)
run_cmake(CMP0076-OLD)
run_cmake(CMP0076-WARN)
run_cmake(RelativePathInInterface)
run_cmake(RelativePathInSubdirGenEx)
run_cmake(RelativePathInSubdirInterface)
run_cmake(RelativePathInSubdirPrivate)
run_cmake(RelativePathInSubdirInclude)
run_cmake(ExportBuild)