-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathdetect.cppm
More file actions
133 lines (109 loc) · 5.19 KB
/
Copy pathdetect.cppm
File metadata and controls
133 lines (109 loc) · 5.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// mcpp.toolchain.detect - compiler discovery facade.
export module mcpp.toolchain.detect;
export import mcpp.toolchain.model;
export import mcpp.toolchain.probe;
import std;
import mcpp.toolchain.clang;
import mcpp.toolchain.gcc;
import mcpp.toolchain.msvc;
import mcpp.platform.xlings;
export namespace mcpp::toolchain {
// Detect toolchain. If explicit_compiler is given, use that binary path
// directly. Otherwise fall back to $CXX, then PATH g++.
std::expected<Toolchain, DetectError>
detect(const std::filesystem::path& explicit_compiler = {},
std::string_view runtimeBinding = {},
std::string_view runtimeContractHash = {});
// Compatibility helper for older call sites/tests: GCC std module lookup now
// lives in the GCC provider.
std::optional<std::filesystem::path> find_std_module_source(
const std::filesystem::path& cxx_binary, std::string_view version);
} // namespace mcpp::toolchain
namespace mcpp::toolchain {
std::optional<std::filesystem::path> find_std_module_source(
const std::filesystem::path& cxx_binary, std::string_view version) {
return mcpp::toolchain::gcc::find_std_module_source(cxx_binary, version);
}
std::expected<Toolchain, DetectError>
detect(const std::filesystem::path& explicit_compiler,
std::string_view runtimeBinding,
std::string_view runtimeContractHash) {
auto bin_r = probe_compiler_binary(explicit_compiler);
if (!bin_r) return std::unexpected(bin_r.error());
Toolchain tc;
tc.binaryPath = *bin_r;
// Set before provider-specific early returns (notably native MSVC), so
// every platform carries the same RuntimeBinding cache identity.
tc.runtimeBinding = std::string(runtimeBinding);
tc.runtimeContractHash = std::string(runtimeContractHash);
// MSVC cl.exe has no --version / -dumpmachine / -print-sysroot; classify
// it by filename and take a dedicated enrich path (banner → version,
// arch → triple, std.ixx lookup). No runtime dirs / sysroot / payloads —
// those concepts are GCC/Clang-shaped.
if (auto stem = lower_copy(tc.binaryPath.stem().string()); stem == "cl") {
if (auto r = mcpp::toolchain::msvc::enrich_toolchain_from_cl(tc); !r)
return std::unexpected(r.error());
return tc;
}
tc.compilerRuntimeDirs = discover_compiler_runtime_dirs(tc.binaryPath);
auto envPrefix = compiler_env_prefix(tc);
auto ver_r = run_capture(std::format("{}{} --version 2>&1",
envPrefix,
mcpp::xlings::shq(tc.binaryPath.string())));
if (!ver_r) return std::unexpected(ver_r.error());
const auto& vstr = *ver_r;
tc.driverIdent = normalize_driver_output(vstr);
auto head = first_line_of(vstr);
auto headLower = lower_copy(head);
auto fullLower = lower_copy(vstr);
if (mcpp::toolchain::clang::matches_version_output(headLower, fullLower)) {
tc.compiler = CompilerId::Clang;
tc.version = extract_version(head.empty()
? std::string_view(vstr)
: std::string_view(head));
} else if (mcpp::toolchain::gcc::matches_version_output(headLower)) {
tc.compiler = CompilerId::GCC;
tc.version = mcpp::toolchain::gcc::parse_version(head);
} else {
return std::unexpected(DetectError{
std::format("unrecognized compiler output:\n{}", vstr)});
}
if (auto triple = probe_target_triple(tc.binaryPath, envPrefix)) {
tc.targetTriple = *triple;
}
#if defined(_WIN32)
// On Windows, Clang targeting MSVC auto-detects the MSVC version at
// compile time and bakes it into the module AST. The -dumpmachine triple
// doesn't include this version, so fingerprints don't change when MSVC
// patches (e.g. 19.44.35226 → 35227), causing stale BMI cache hits.
// Query the effective triple which includes the actual MSVC version.
if (tc.compiler == CompilerId::Clang
&& is_msvc_target(tc)) {
auto vr = run_capture(std::format(
"{}{} -print-effective-triple 2>NUL",
envPrefix,
mcpp::xlings::shq(tc.binaryPath.string())));
if (vr) {
auto effective = trim_line(*vr);
if (!effective.empty() && effective != tc.targetTriple)
tc.driverIdent += "\neffective-triple: " + effective;
}
}
#endif
if (tc.compiler == CompilerId::GCC) {
mcpp::toolchain::gcc::enrich_toolchain(tc);
} else if (tc.compiler == CompilerId::Clang) {
mcpp::toolchain::clang::enrich_toolchain(tc, envPrefix);
}
tc.sysroot = probe_sysroot(tc.binaryPath, envPrefix);
// Probe fine-grained payload paths from sibling xpkgs (glibc, linux-headers).
// When available, flags are assembled from these paths instead of --sysroot.
tc.payloadPaths = probe_payload_paths(tc.binaryPath, tc.runtimeBinding);
// For GCC: ensure the probed sysroot has complete headers by symlinking
// missing content (linux kernel headers, glibc) from payload xpkgs.
// This makes mcpp self-sufficient — not dependent on xlings subos init.
if (tc.payloadPaths && !tc.sysroot.empty())
ensure_sysroot_complete(tc.sysroot, *tc.payloadPaths);
return tc;
}
} // namespace mcpp::toolchain