#include "CppModuleConfiguration.h"
#include "ClangHost.h"
#include "lldb/Host/FileSystem.h"
#include "llvm/TargetParser/Triple.h"
#include <optional>
using namespace lldb_private;
bool CppModuleConfiguration::SetOncePath::TrySet(llvm::StringRef path) {
if (m_first) {
m_path = path.str();
m_valid = true;
m_first = false;
return true;
}
if (m_path == path)
return true;
m_valid = false;
return false;
}
static llvm::SmallVector<std::string, 2>
getTargetIncludePaths(const llvm::Triple &triple) {
llvm::SmallVector<std::string, 2> paths;
if (!triple.str().empty()) {
paths.push_back("/usr/include/" + triple.str());
if (!triple.getArchName().empty() ||
triple.getOSAndEnvironmentName().empty())
paths.push_back(("/usr/include/" + triple.getArchName() + "-" +
triple.getOSAndEnvironmentName())
.str());
}
return paths;
}
static std::optional<llvm::StringRef>
guessIncludePath(llvm::StringRef path_to_file, llvm::StringRef pattern) {
if (pattern.empty())
return std::nullopt;
size_t pos = path_to_file.find(pattern);
if (pos == llvm::StringRef::npos)
return std::nullopt;
return path_to_file.substr(0, pos + pattern.size());
}
bool CppModuleConfiguration::analyzeFile(const FileSpec &f,
const llvm::Triple &triple) {
using namespace llvm::sys::path;
std::string dir_buffer = convert_to_slash(f.GetDirectory().GetStringRef());
llvm::StringRef posix_dir(dir_buffer);
static llvm::Regex libcpp_regex(R"regex(/c[+][+]/v[0-9]/)regex");
if (libcpp_regex.match(convert_to_slash(f.GetPath())) &&
parent_path(posix_dir, Style::posix).ends_with("c++")) {
if (!m_std_inc.TrySet(posix_dir))
return false;
if (triple.str().empty())
return true;
posix_dir.consume_back("c++/v1");
return m_std_target_inc.TrySet(
(posix_dir + triple.str() + "/c++/v1").str());
}
std::optional<llvm::StringRef> inc_path;
for (auto &path : getTargetIncludePaths(triple)) {
if ((inc_path = guessIncludePath(posix_dir, path)))
return m_c_target_inc.TrySet(*inc_path);
}
if ((inc_path = guessIncludePath(posix_dir, "/usr/include")))
return m_c_inc.TrySet(*inc_path);
return true;
}
static std::string MakePath(llvm::StringRef lhs, llvm::StringRef rhs) {
llvm::SmallString<256> result(lhs);
llvm::sys::path::append(result, rhs);
return std::string(result);
}
bool CppModuleConfiguration::hasValidConfig() {
if (!m_c_inc.Valid() || !m_std_inc.Valid())
return false;
const std::vector<std::string> files_to_check = {
MakePath(m_c_inc.Get(), "stdio.h"),
MakePath(m_std_inc.Get(), "module.modulemap"),
MakePath(m_std_inc.Get(), "vector"),
};
for (llvm::StringRef file_to_check : files_to_check) {
if (!FileSystem::Instance().Exists(file_to_check))
return false;
}
return true;
}
CppModuleConfiguration::CppModuleConfiguration(
const FileSpecList &support_files, const llvm::Triple &triple) {
bool error = !llvm::all_of(support_files, [&](auto &file) {
return CppModuleConfiguration::analyzeFile(file, triple);
});
if (!error && hasValidConfig()) {
llvm::SmallString<256> resource_dir;
llvm::sys::path::append(resource_dir, GetClangResourceDir().GetPath(),
"include");
m_resource_inc = std::string(resource_dir.str());
m_include_dirs = {m_std_inc.Get().str(), m_resource_inc,
m_c_inc.Get().str()};
if (m_c_target_inc.Valid())
m_include_dirs.push_back(m_c_target_inc.Get().str());
if (m_std_target_inc.Valid())
m_include_dirs.push_back(m_std_target_inc.Get().str());
m_imported_modules = {"std"};
}
}