Files
CMake/Source/cmFileSet.cxx
Ben Boeckel 80d6544398 cxxmodules: generate synthetic targets as an initial pass
We need to be able to construct BMIs that will be usable from the client
modules for the target importing the module, so create BMI-only
compilation rules for `IMPORTED` targets to create these BMIs.
2023-08-17 14:42:53 -04:00

234 lines
6.6 KiB
C++

/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmFileSet.h"
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include <cmext/algorithm>
#include <cmext/string_view>
#include "cmsys/RegularExpression.hxx"
#include "cmGeneratorExpression.h"
#include "cmList.h"
#include "cmListFileCache.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmake.h"
cm::static_string_view cmFileSetVisibilityToName(cmFileSetVisibility vis)
{
switch (vis) {
case cmFileSetVisibility::Interface:
return "INTERFACE"_s;
case cmFileSetVisibility::Public:
return "PUBLIC"_s;
case cmFileSetVisibility::Private:
return "PRIVATE"_s;
}
return ""_s;
}
cmFileSetVisibility cmFileSetVisibilityFromName(cm::string_view name,
cmMakefile* mf)
{
if (name == "INTERFACE"_s) {
return cmFileSetVisibility::Interface;
}
if (name == "PUBLIC"_s) {
return cmFileSetVisibility::Public;
}
if (name == "PRIVATE"_s) {
return cmFileSetVisibility::Private;
}
auto msg = cmStrCat("File set visibility \"", name, "\" is not valid.");
if (mf) {
mf->IssueMessage(MessageType::FATAL_ERROR, msg);
} else {
cmSystemTools::Error(msg);
}
return cmFileSetVisibility::Private;
}
bool cmFileSetVisibilityIsForSelf(cmFileSetVisibility vis)
{
switch (vis) {
case cmFileSetVisibility::Interface:
return false;
case cmFileSetVisibility::Public:
case cmFileSetVisibility::Private:
return true;
}
return false;
}
bool cmFileSetVisibilityIsForInterface(cmFileSetVisibility vis)
{
switch (vis) {
case cmFileSetVisibility::Interface:
case cmFileSetVisibility::Public:
return true;
case cmFileSetVisibility::Private:
return false;
}
return false;
}
cmFileSet::cmFileSet(cmake& cmakeInstance, std::string name, std::string type,
cmFileSetVisibility visibility)
: CMakeInstance(cmakeInstance)
, Name(std::move(name))
, Type(std::move(type))
, Visibility(visibility)
{
}
void cmFileSet::CopyEntries(cmFileSet const* fs)
{
cm::append(this->DirectoryEntries, fs->DirectoryEntries);
cm::append(this->FileEntries, fs->FileEntries);
}
void cmFileSet::ClearDirectoryEntries()
{
this->DirectoryEntries.clear();
}
void cmFileSet::AddDirectoryEntry(BT<std::string> directories)
{
this->DirectoryEntries.push_back(std::move(directories));
}
void cmFileSet::ClearFileEntries()
{
this->FileEntries.clear();
}
void cmFileSet::AddFileEntry(BT<std::string> files)
{
this->FileEntries.push_back(std::move(files));
}
std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>
cmFileSet::CompileFileEntries() const
{
std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> result;
for (auto const& entry : this->FileEntries) {
for (auto const& ex : cmList{ entry.Value }) {
cmGeneratorExpression ge(this->CMakeInstance, entry.Backtrace);
auto cge = ge.Parse(ex);
result.push_back(std::move(cge));
}
}
return result;
}
std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>
cmFileSet::CompileDirectoryEntries() const
{
std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> result;
for (auto const& entry : this->DirectoryEntries) {
for (auto const& ex : cmList{ entry.Value }) {
cmGeneratorExpression ge(this->CMakeInstance, entry.Backtrace);
auto cge = ge.Parse(ex);
result.push_back(std::move(cge));
}
}
return result;
}
std::vector<std::string> cmFileSet::EvaluateDirectoryEntries(
const std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>& cges,
cmLocalGenerator* lg, const std::string& config,
const cmGeneratorTarget* target,
cmGeneratorExpressionDAGChecker* dagChecker) const
{
std::vector<std::string> result;
for (auto const& cge : cges) {
auto entry = cge->Evaluate(lg, config, target, dagChecker);
cmList dirs{ entry };
for (std::string dir : dirs) {
if (!cmSystemTools::FileIsFullPath(dir)) {
dir = cmStrCat(lg->GetCurrentSourceDirectory(), '/', dir);
}
auto collapsedDir = cmSystemTools::CollapseFullPath(dir);
for (auto const& priorDir : result) {
auto collapsedPriorDir = cmSystemTools::CollapseFullPath(priorDir);
if (!cmSystemTools::SameFile(collapsedDir, collapsedPriorDir) &&
(cmSystemTools::IsSubDirectory(collapsedDir, collapsedPriorDir) ||
cmSystemTools::IsSubDirectory(collapsedPriorDir, collapsedDir))) {
lg->GetCMakeInstance()->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat(
"Base directories in file set cannot be subdirectories of each "
"other:\n ",
priorDir, "\n ", dir),
cge->GetBacktrace());
return {};
}
}
result.push_back(dir);
}
}
return result;
}
void cmFileSet::EvaluateFileEntry(
const std::vector<std::string>& dirs,
std::map<std::string, std::vector<std::string>>& filesPerDir,
const std::unique_ptr<cmCompiledGeneratorExpression>& cge,
cmLocalGenerator* lg, const std::string& config,
const cmGeneratorTarget* target,
cmGeneratorExpressionDAGChecker* dagChecker) const
{
auto files = cge->Evaluate(lg, config, target, dagChecker);
for (std::string file : cmList{ files }) {
if (!cmSystemTools::FileIsFullPath(file)) {
file = cmStrCat(lg->GetCurrentSourceDirectory(), '/', file);
}
auto collapsedFile = cmSystemTools::CollapseFullPath(file);
bool found = false;
std::string relDir;
for (auto const& dir : dirs) {
auto collapsedDir = cmSystemTools::CollapseFullPath(dir);
if (cmSystemTools::IsSubDirectory(collapsedFile, collapsedDir)) {
found = true;
relDir = cmSystemTools::GetParentDirectory(
cmSystemTools::RelativePath(collapsedDir, collapsedFile));
break;
}
}
if (!found) {
std::ostringstream e;
e << "File:\n " << file
<< "\nmust be in one of the file set's base directories:";
for (auto const& dir : dirs) {
e << "\n " << dir;
}
lg->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(),
cge->GetBacktrace());
return;
}
filesPerDir[relDir].push_back(file);
}
}
bool cmFileSet::IsValidName(const std::string& name)
{
static const cmsys::RegularExpression regex("^[a-z0-9][a-zA-Z0-9_]*$");
cmsys::RegularExpressionMatch match;
return regex.find(name.c_str(), match);
}