blob: 3870a2a8760b9bd7bc1936a8345b99c4d890ea94 [file] [log] [blame]
// Copyright 2024 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "tools/cpp/modules_tools/generate-modmap/generate-modmap.h"
#include <iostream>
#include <queue>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
// This function writes parameters about the required modules.
//
// Format of the modmap file
// Clang: -fmodule-file=<module-name>=<path/to/bmi>
// GCC: <module-name> <path/to/bmi>
// MSVC: /reference <module-name>=<path/to/bmi>
//
// NOTE: For the GCC compiler, additional `$root .` is added
//
// Another special consideration for GCC is that it cannot specify
// the output module name when compiling a Module Interface.
// Therefore, the generated module name and BMI file path is added
//
// see also https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Module-Mapper.html
void write_modmap(std::ostream &modmap_file_stream,
std::ostream &modmap_file_dot_input_stream,
const std::unordered_set<ModmapItem> &modmap,
const std::string &compiler,
const std::optional<ModmapItem> &generated) {
if (compiler == "gcc") {
modmap_file_stream << "$root ." << "\n";
if (generated.has_value()) {
modmap_file_stream << generated.value().name << " "
<< generated.value().path << "\n";
}
}
for (const auto &item : modmap) {
if (compiler == "clang") {
modmap_file_stream << "-fmodule-file=" << item.name << "=" << item.path
<< "\n";
} else if (compiler == "gcc") {
modmap_file_stream << item.name << " " << item.path << "\n";
} else if (compiler == "msvc-cl") {
modmap_file_stream << "/reference " << item.name << "=" << item.path
<< "\n";
} else {
std::cerr << "bad compiler: " << compiler << std::endl;
std::exit(1);
}
modmap_file_dot_input_stream << item.path << "\n";
}
}
std::unordered_set<ModmapItem> process(const ModuleDep &dep,
const Cpp20ModulesInfo &info) {
std::queue<std::string> q;
for (const auto &item : dep.require_list) {
q.push(item);
}
// Get all dependencies
std::unordered_set<std::string> s;
while (!q.empty()) {
std::string name = q.front();
q.pop();
s.insert(name);
auto it = info.usages.find(name);
if (it == info.usages.end()) {
continue;
}
auto deps = it->second;
for (const auto &dep : deps) {
if (s.count(dep)) {
continue;
}
q.push(dep);
}
}
// Construct modmap
std::unordered_set<ModmapItem> modmap;
for (const auto &name : s) {
auto it = info.modules.find(name);
if (it == info.modules.end()) {
std::cerr << "ERROR: Module not found: " << name << std::endl;
std::exit(1);
}
modmap.insert(ModmapItem{name, it->second});
}
return modmap;
}