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