| // 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; | |
| } |