blob: 5190d4a7a31d4adab89e9fc6d12417695f072583 [file]
// Copyright 2025 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gn/ninja_module_writer_util.h"
#include <algorithm>
#include <set>
#include <utility>
#include "base/strings/stringprintf.h"
#include "gn/resolved_target_data.h"
#include "gn/substitution_writer.h"
#include "gn/target.h"
ClangModuleDep::ClangModuleDep(const SourceFile* modulemap,
const std::string& module_name,
std::optional<OutputFile> pcm,
bool is_self)
: modulemap(modulemap),
module_name(module_name),
pcm(std::move(pcm)),
is_self(is_self) {}
std::strong_ordering ClangModuleDep::operator<=>(
const ClangModuleDep& other) const {
// Sort by (module name, modulemap path, module file path)
if (auto cmp = module_name <=> other.module_name; cmp != 0)
return cmp;
if (modulemap && other.modulemap) {
if (auto cmp = *modulemap <=> *other.modulemap; cmp != 0)
return cmp;
} else {
if (auto cmp = modulemap <=> other.modulemap; cmp != 0)
return cmp;
}
// std::optional doesn't support <=> on older versions of mac.
if (pcm.has_value() && other.pcm.has_value()) {
return *pcm <=> *other.pcm;
} else {
return pcm.has_value() <=> other.pcm.has_value();
}
}
std::set<ClangModuleDep> GetModuleDepsInformation(
const Target* target,
const ResolvedTargetData& resolved) {
std::set<ClangModuleDep> ret;
auto add_if_new = [&ret](const Target* t, bool is_self,
bool has_generated_modulemap) {
if (!t->module_type().test(Target::HAS_MODULEMAP))
return;
std::optional<OutputFile> pcm = std::nullopt;
auto modulemap = t->modulemap_file();
CHECK(modulemap != nullptr);
if (!t->module_type().test(Target::MODULEMAP_IS_TEXTUAL)) {
const char* tool_type;
std::vector<OutputFile> modulemap_outputs;
CHECK(t->GetOutputFilesForSource(*modulemap, &tool_type,
&modulemap_outputs));
CHECK(modulemap_outputs.size() == 1u);
pcm = std::move(modulemap_outputs[0]);
}
ret.emplace(
// If we have a generated modulemap, the modulemap should contain
// "extern module" declarations, so we don't need to declare
// -fmodule-map-file for the dependencies.
has_generated_modulemap ? nullptr : modulemap, t->module_name(), pcm,
is_self);
};
// Generated modulemaps always generate private modulemaps as well.
bool has_generated_modulemap =
target->module_type().test(Target::MODULEMAP_IS_GENERATED);
if (has_generated_modulemap) {
// Add the private modulemap as a dependency.
ret.emplace(target->private_modulemap_file(),
base::StringPrintf("%s_Private", target->module_name().c_str()),
std::nullopt, true);
} else {
add_if_new(target, true, has_generated_modulemap);
}
for (const auto& pair : resolved.GetModuleDepsInformation(target))
add_if_new(pair.target(), false, has_generated_modulemap);
return ret;
}
void ClangModuleDep::Write(std::ostream& out,
const PathOutput& path_output,
bool include_self) const {
if (modulemap) {
out << " -fmodule-map-file=";
path_output.WriteFile(out, *modulemap);
}
if (pcm && (include_self || !is_self)) {
out << " -fmodule-file=" << module_name << "=";
path_output.WriteFile(out, *pcm);
}
}