Skip to content

Commit 16ac29c

Browse files
committed
Sync swift_runner code with upstream
1 parent 58820dd commit 16ac29c

19 files changed

+2221
-969
lines changed

MODULE.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ bazel_dep(name = "rules_shell", version = "0.3.0")
1616
bazel_dep(name = "platforms", version = "0.0.9")
1717
bazel_dep(name = "protobuf", version = "27.0", repo_name = "com_google_protobuf")
1818
bazel_dep(name = "nlohmann_json", version = "3.6.1", repo_name = "com_github_nlohmann_json")
19+
bazel_dep(name = "abseil-cpp", version = "20250127.0")
20+
bazel_dep(name = "re2", version = "2024-07-02")
1921
bazel_dep(
2022
name = "swift_argument_parser",
2123
version = "1.3.1.2",

tools/common/BUILD

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ cc_library(
3939
"-std=c++17",
4040
],
4141
}),
42+
deps = [
43+
":temp_file",
44+
"@abseil-cpp//absl/container:flat_hash_map",
45+
"@abseil-cpp//absl/status:statusor",
46+
],
4247
)
4348

4449
cc_library(
@@ -52,6 +57,94 @@ cc_library(
5257
"-std=c++17",
5358
],
5459
}),
60+
deps = [
61+
"@abseil-cpp//absl/strings",
62+
],
63+
)
64+
65+
cc_library(
66+
name = "color",
67+
hdrs = ["color.h"],
68+
copts = selects.with_or({
69+
("//tools:clang-cl", "//tools:msvc"): [
70+
"/std:c++17",
71+
],
72+
"//conditions:default": [
73+
"-std=c++17",
74+
],
75+
}),
76+
)
77+
78+
cc_library(
79+
name = "file_system",
80+
srcs = ["file_system.cc"],
81+
hdrs = ["file_system.h"],
82+
copts = selects.with_or({
83+
("//tools:clang-cl", "//tools:msvc"): [
84+
"/std:c++17",
85+
],
86+
"//conditions:default": [
87+
"-std=c++17",
88+
],
89+
}),
90+
deps = [
91+
":path_utils",
92+
":status",
93+
"@abseil-cpp//absl/cleanup",
94+
"@abseil-cpp//absl/status:statusor",
95+
"@abseil-cpp//absl/strings",
96+
],
97+
)
98+
99+
cc_library(
100+
name = "path_utils",
101+
srcs = ["path_utils.cc"],
102+
hdrs = ["path_utils.h"],
103+
copts = selects.with_or({
104+
("//tools:clang-cl", "//tools:msvc"): [
105+
"/std:c++17",
106+
],
107+
"//conditions:default": [
108+
"-std=c++17",
109+
],
110+
}),
111+
deps = [
112+
"@abseil-cpp//absl/strings",
113+
],
114+
)
115+
116+
cc_library(
117+
name = "status",
118+
srcs = ["status.cc"],
119+
hdrs = ["status.h"],
120+
copts = selects.with_or({
121+
("//tools:clang-cl", "//tools:msvc"): [
122+
"/std:c++17",
123+
],
124+
"//conditions:default": [
125+
"-std=c++17",
126+
],
127+
}),
128+
deps = [
129+
"@abseil-cpp//absl/status",
130+
"@abseil-cpp//absl/strings",
131+
],
132+
)
133+
134+
cc_library(
135+
name = "target_triple",
136+
hdrs = ["target_triple.h"],
137+
copts = selects.with_or({
138+
("//tools:clang-cl", "//tools:msvc"): [
139+
"/std:c++17",
140+
],
141+
"//conditions:default": [
142+
"-std=c++17",
143+
],
144+
}),
145+
deps = [
146+
"@abseil-cpp//absl/strings",
147+
],
55148
)
56149

57150
# Consumed by Bazel integration tests.

tools/common/bazel_substitutions.cc

Lines changed: 25 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -15,133 +15,53 @@
1515
#include "tools/common/bazel_substitutions.h"
1616

1717
#include <cstdlib>
18-
#include <filesystem>
1918
#include <iostream>
20-
#include <map>
21-
#include <sstream>
2219
#include <string>
2320

24-
#include "tools/common/process.h"
21+
#include "absl/container/flat_hash_map.h"
22+
#include "absl/strings/str_replace.h"
23+
#include "absl/strings/string_view.h"
2524

2625
namespace bazel_rules_swift {
2726
namespace {
2827

29-
// The placeholder string used by Bazel that should be replaced by
30-
// `DEVELOPER_DIR` at runtime.
31-
static const char kBazelXcodeDeveloperDir[] = "__BAZEL_XCODE_DEVELOPER_DIR__";
32-
33-
// The placeholder string used by Bazel that should be replaced by `SDKROOT`
34-
// at runtime.
35-
static const char kBazelXcodeSdkRoot[] = "__BAZEL_XCODE_SDKROOT__";
36-
37-
// The placeholder string used by the Apple and Swift rules to be replaced with
38-
// the absolute path to the custom toolchain being used
39-
static const char kBazelToolchainPath[] =
40-
"__BAZEL_CUSTOM_XCODE_TOOLCHAIN_PATH__";
41-
4228
// Returns the value of the given environment variable, or the empty string if
4329
// it wasn't set.
44-
std::string GetAppleEnvironmentVariable(const char *name) {
45-
#if !defined(__APPLE__)
46-
return "";
47-
#endif
48-
49-
char *env_value = getenv(name);
30+
std::string GetEnvironmentVariable(absl::string_view name) {
31+
std::string null_terminated_name(name.data(), name.length());
32+
char *env_value = getenv(null_terminated_name.c_str());
5033
if (env_value == nullptr) {
51-
std::cerr << "error: required Apple environment variable '" << name << "' was not set. Please file an issue on bazelbuild/rules_swift.\n";
52-
exit(EXIT_FAILURE);
53-
}
54-
return env_value;
55-
}
56-
57-
std::string GetToolchainPath() {
58-
#if !defined(__APPLE__)
59-
return "";
60-
#endif
61-
62-
char *toolchain_id = getenv("TOOLCHAINS");
63-
if (toolchain_id == nullptr) {
6434
return "";
6535
}
66-
67-
std::ostringstream output_stream;
68-
int exit_code =
69-
RunSubProcess({"/usr/bin/xcrun", "--find", "clang", "--toolchain", toolchain_id},
70-
/*env=*/nullptr, &output_stream, /*stdout_to_stderr=*/true);
71-
if (exit_code != 0) {
72-
std::cerr << output_stream.str() << "Error: TOOLCHAINS was set to '"
73-
<< toolchain_id << "' but xcrun failed when searching for that ID"
74-
<< std::endl;
75-
exit(EXIT_FAILURE);
76-
}
77-
78-
if (output_stream.str().empty()) {
79-
std::cerr << "Error: TOOLCHAINS was set to '" << toolchain_id
80-
<< "' but no toolchain with that ID was found" << std::endl;
81-
exit(EXIT_FAILURE);
82-
} else if (output_stream.str().find("XcodeDefault.xctoolchain") !=
83-
std::string::npos) {
84-
// NOTE: Ideally xcrun would fail if the toolchain we asked for didn't exist
85-
// but it falls back to the DEVELOPER_DIR instead, so we have to check the
86-
// output ourselves.
87-
std::cerr << "Error: TOOLCHAINS was set to '" << toolchain_id
88-
<< "' but the default toolchain was found, that likely means a "
89-
"matching "
90-
<< "toolchain isn't installed" << std::endl;
91-
exit(EXIT_FAILURE);
92-
}
93-
94-
std::filesystem::path toolchain_path(output_stream.str());
95-
// Remove usr/bin/clang components to get the root of the custom toolchain
96-
return toolchain_path.parent_path().parent_path().parent_path().string();
36+
return env_value;
9737
}
9838

9939
} // namespace
10040

10141
BazelPlaceholderSubstitutions::BazelPlaceholderSubstitutions() {
10242
// When targeting Apple platforms, replace the magic Bazel placeholders with
103-
// the path in the corresponding environment variable. These should be set by
104-
// the build rules; only attempt to retrieve them if they're actually seen in
105-
// the argument list.
106-
placeholder_resolvers_ = {
107-
{kBazelXcodeDeveloperDir, PlaceholderResolver([]() {
108-
return GetAppleEnvironmentVariable("DEVELOPER_DIR");
109-
})},
110-
{kBazelXcodeSdkRoot, PlaceholderResolver([]() {
111-
return GetAppleEnvironmentVariable("SDKROOT");
112-
})},
113-
{kBazelToolchainPath,
114-
PlaceholderResolver([]() { return GetToolchainPath(); })},
115-
};
116-
}
117-
118-
bool BazelPlaceholderSubstitutions::Apply(std::string &arg) {
119-
bool changed = false;
120-
121-
// Replace placeholders in the string with their actual values.
122-
for (auto &pair : placeholder_resolvers_) {
123-
changed |= FindAndReplace(pair.first, pair.second, arg);
43+
// the path in the corresponding environment variable, which should be set by
44+
// the build rules. If the variable isn't set, we don't store a substitution;
45+
// if it was needed then the eventual replacement will be a no-op and the
46+
// command will presumably fail later.
47+
if (std::string developer_dir = GetEnvironmentVariable("DEVELOPER_DIR");
48+
!developer_dir.empty()) {
49+
substitutions_[kBazelXcodeDeveloperDir] = developer_dir;
50+
}
51+
if (std::string sdk_root = GetEnvironmentVariable("SDKROOT");
52+
!sdk_root.empty()) {
53+
substitutions_[kBazelXcodeSdkRoot] = sdk_root;
12454
}
55+
}
12556

126-
return changed;
57+
BazelPlaceholderSubstitutions::BazelPlaceholderSubstitutions(
58+
absl::string_view developer_dir, absl::string_view sdk_root) {
59+
substitutions_[kBazelXcodeDeveloperDir] = std::string(developer_dir);
60+
substitutions_[kBazelXcodeSdkRoot] = std::string(sdk_root);
12761
}
12862

129-
bool BazelPlaceholderSubstitutions::FindAndReplace(
130-
const std::string &placeholder,
131-
BazelPlaceholderSubstitutions::PlaceholderResolver &resolver,
132-
std::string &str) {
133-
int start = 0;
134-
bool changed = false;
135-
while ((start = str.find(placeholder, start)) != std::string::npos) {
136-
std::string resolved_value = resolver.get();
137-
if (resolved_value.empty()) {
138-
return false;
139-
}
140-
changed = true;
141-
str.replace(start, placeholder.length(), resolved_value);
142-
start += resolved_value.length();
143-
}
144-
return changed;
63+
bool BazelPlaceholderSubstitutions::Apply(std::string &arg) {
64+
return absl::StrReplaceAll(substitutions_, &arg) > 0;
14565
}
14666

14767
} // namespace bazel_rules_swift

tools/common/bazel_substitutions.h

Lines changed: 18 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
#ifndef BUILD_BAZEL_RULES_SWIFT_TOOLS_COMMON_BAZEL_SUBSTITUTIONS_H_
1616
#define BUILD_BAZEL_RULES_SWIFT_TOOLS_COMMON_BAZEL_SUBSTITUTIONS_H_
1717

18-
#include <functional>
19-
#include <map>
2018
#include <string>
2119

20+
#include "absl/container/flat_hash_map.h"
21+
#include "absl/strings/string_view.h"
22+
2223
namespace bazel_rules_swift {
2324

2425
// Manages the substitution of special Bazel placeholder strings in command line
@@ -27,57 +28,32 @@ namespace bazel_rules_swift {
2728
class BazelPlaceholderSubstitutions {
2829
public:
2930
// Initializes the substitutions by looking them up in the process's
30-
// environment when they are first requested.
31+
// environment.
3132
BazelPlaceholderSubstitutions();
3233

3334
// Initializes the substitutions with the given fixed strings. Intended to be
3435
// used for testing.
35-
BazelPlaceholderSubstitutions(const std::string &developer_dir,
36-
const std::string &sdk_root);
36+
BazelPlaceholderSubstitutions(absl::string_view developer_dir,
37+
absl::string_view sdk_root);
3738

3839
// Applies any necessary substitutions to `arg` and returns true if this
3940
// caused the string to change.
4041
bool Apply(std::string &arg);
4142

42-
private:
43-
// A resolver for a Bazel placeholder string that retrieves and caches the
44-
// value the first time it is requested.
45-
class PlaceholderResolver {
46-
public:
47-
explicit PlaceholderResolver(std::function<std::string()> fn)
48-
: function_(fn), initialized_(false) {}
49-
50-
// Returns the requested placeholder value, caching it for future
51-
// retrievals.
52-
std::string get() {
53-
if (!initialized_) {
54-
value_ = function_();
55-
initialized_ = true;
56-
}
57-
return value_;
58-
}
59-
60-
private:
61-
// The function that returns the value of the placeholder, or the empty
62-
// string if the placeholder should not be replaced.
63-
std::function<std::string()> function_;
43+
// The placeholder string used by Bazel that should be replaced by
44+
// `DEVELOPER_DIR` at runtime.
45+
inline static constexpr absl::string_view kBazelXcodeDeveloperDir =
46+
"__BAZEL_XCODE_DEVELOPER_DIR__";
6447

65-
// Indicates whether the value of the placeholder has been requested yet and
66-
// and is therefore initialized.
67-
bool initialized_;
48+
// The placeholder string used by Bazel that should be replaced by `SDKROOT`
49+
// at runtime.
50+
inline static constexpr absl::string_view kBazelXcodeSdkRoot =
51+
"__BAZEL_XCODE_SDKROOT__";
6852

69-
// The cached value of the placeholder if `initialized_` is true.
70-
std::string value_;
71-
};
72-
73-
// Finds and replaces all instances of `placeholder` with the value provided
74-
// by `resolver`, in-place on `str`. Returns true if the string was changed.
75-
bool FindAndReplace(const std::string &placeholder,
76-
PlaceholderResolver &resolver, std::string &str);
77-
78-
// A mapping from Bazel placeholder strings to resolvers that provide their
79-
// values.
80-
std::map<std::string, PlaceholderResolver> placeholder_resolvers_;
53+
private:
54+
// A mapping from Bazel placeholder strings to the values that should be
55+
// substituted for them.
56+
absl::flat_hash_map<std::string, std::string> substitutions_;
8157
};
8258

8359
} // namespace bazel_rules_swift

0 commit comments

Comments
 (0)