CMake/Source/cmTargetSourcesCommand.cxx
Patrick Stotko 316815e1f4 target_sources: Interpret relative paths as relative to the calling directory
Previously the command considered non-absolute source file paths relative to
the associated target on the LHS. This causes problems in incremental builds
where files are added from subdirectories and forces users to workaround by
manually converting to absolute paths. Change this to enable more intuitive
usage by projects.

Fixes #17981
2018-06-18 21:01:57 +02:00

126 lines
3.7 KiB
C++

/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
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"
class cmExecutionStatus;
bool cmTargetSourcesCommand::InitialPass(std::vector<std::string> const& args,
cmExecutionStatus&)
{
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;
e << "Cannot specify sources for target \"" << name
<< "\" "
"which is not built by this project.";
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
}
std::string cmTargetSourcesCommand::Join(
const std::vector<std::string>& content)
{
return cmJoin(content, ";");
}
bool cmTargetSourcesCommand::HandleDirectContent(
cmTarget* tgt, const std::vector<std::string>& content, bool, bool)
{
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;
}