1
- def _custom_toolchain_impl (ctx ):
2
- toolchain_name_base = ctx .attr .toolchain_name
3
1
4
- # Create a file to store Xcode version
5
- xcode_version_file = ctx .actions .declare_file (toolchain_name_base + "_xcode_version.txt" )
2
+ def _get_xcode_product_version (* , xcode_config ):
3
+ raw_version = str (xcode_config .xcode_version ())
4
+ if not raw_version :
5
+ fail ("""\
6
+ `xcode_config.xcode_version` was not set. This is a bazel bug. Try again.
7
+ """ )
6
8
7
- # Run xcodebuild to get the Xcode version
8
- ctx .actions .run_shell (
9
- outputs = [xcode_version_file ],
10
- command = """
11
- # Get Xcode version and clean it for use in filenames
12
- xcodebuild -version | head -n 1 | sed 's/Xcode //' | tr -d '.' | tr ' ' '_' > {outfile}
13
- """ .format (outfile = xcode_version_file .path ),
14
- mnemonic = "GetXcodeVersion" ,
15
- execution_requirements = {"no-sandbox" : "1" },
16
- )
9
+ version_components = raw_version .split ("." )
10
+ if len (version_components ) < 4 :
11
+ # This will result in analysis cache misses, but it's better than
12
+ # failing
13
+ return raw_version
17
14
18
- # Create a file to store the default toolchain path
19
- default_toolchain_path_file = ctx .actions .declare_file (toolchain_name_base + "_default_toolchain_path.txt" )
15
+ return version_components [3 ]
20
16
21
- # Run xcrun to get the default toolchain path
22
- ctx .actions .run_shell (
23
- outputs = [default_toolchain_path_file ],
24
- command = "xcrun --find clang | sed 's|/usr/bin/clang$||' > {outfile}" .format (
25
- outfile = default_toolchain_path_file .path
26
- ),
27
- mnemonic = "GetDefaultToolchainPath" ,
28
- execution_requirements = {"no-sandbox" : "1" }, # Allow xcrun to access system paths
17
+
18
+ def _custom_toolchain_impl (ctx ):
19
+ xcode_version = _get_xcode_product_version (
20
+ xcode_config = ctx .attr ._xcode_config [apple_common .XcodeVersionConfig ],
29
21
)
30
22
31
- # Declare the output directory for the toolchain
32
- toolchain_dir = ctx .actions .declare_directory (toolchain_name_base + ".xctoolchain" )
23
+ toolchain_name_base = ctx .attr .toolchain_name
24
+ toolchain_dir = ctx .actions .declare_directory (
25
+ toolchain_name_base + ".{}" .format (xcode_version ) + ".xctoolchain"
26
+ )
33
27
34
28
resolved_overrides = {}
35
- override_files = [] # Collect all override files to include in inputs
29
+ override_files = []
36
30
37
31
for tool_target , tool_name in ctx .attr .overrides .items ():
38
- # The key is the target (label), the value is the tool name (string)
39
32
files = tool_target .files .to_list ()
40
33
if not files :
41
34
fail ("ERROR: Override for '{}' does not produce any files!" .format (tool_name ))
@@ -45,15 +38,13 @@ def _custom_toolchain_impl(ctx):
45
38
tool_name , len (files )))
46
39
47
40
override_file = files [0 ]
48
- override_files .append (override_file ) # Add to list of input files
41
+ override_files .append (override_file )
49
42
resolved_overrides [tool_name ] = override_file .path
50
43
51
- # Generate symlink creation commands dynamically, excluding plist files
52
44
overrides_list = " " .join (["{}={}" .format (k , v ) for k , v in resolved_overrides .items ()])
53
45
54
46
script_file = ctx .actions .declare_file (toolchain_name_base + "_setup.sh" )
55
47
56
- # Use expand_template with simplified substitutions
57
48
ctx .actions .expand_template (
58
49
template = ctx .file ._symlink_template ,
59
50
output = script_file ,
@@ -62,39 +53,49 @@ def _custom_toolchain_impl(ctx):
62
53
"%toolchain_name_base%" : toolchain_name_base ,
63
54
"%toolchain_dir%" : toolchain_dir .path ,
64
55
"%overrides_list%" : overrides_list ,
65
- "%default_toolchain_path_file%" : default_toolchain_path_file .path ,
66
- "%xcode_version_file%" : xcode_version_file .path ,
56
+ "%xcode_version%" : xcode_version ,
67
57
},
68
58
)
69
59
70
- # Run the generated shell script
71
60
ctx .actions .run_shell (
72
- outputs = [toolchain_dir ],
73
- inputs = [default_toolchain_path_file , xcode_version_file ] + override_files ,
74
- tools = [script_file ],
75
- mnemonic = "SymlinkDefaultXcodeToolchain" ,
76
- command = script_file .path ,
77
- execution_requirements = {"no-sandbox" : "1" },
61
+ outputs = [toolchain_dir ],
62
+ inputs = override_files ,
63
+ tools = [script_file ],
64
+ mnemonic = "CreateCustomToolchain" ,
65
+ command = script_file .path ,
66
+ execution_requirements = {
67
+ "no-sandbox" : "1" ,
68
+ "no-cache" : "1" ,
69
+ "local" : "1" ,
70
+ "requires-darwin" : "1" ,
71
+ },
72
+ use_default_shell_env = True ,
78
73
)
79
74
80
75
# Create runfiles with the override files and script file
81
- runfiles = ctx .runfiles (files = override_files + [script_file , default_toolchain_path_file , xcode_version_file ])
76
+ runfiles = ctx .runfiles (files = override_files + [script_file ])
82
77
83
78
return [DefaultInfo (
84
- files = depset ([toolchain_dir ]),
85
- runfiles = runfiles ,
79
+ files = depset ([toolchain_dir ]),
80
+ runfiles = runfiles ,
86
81
)]
87
82
88
83
custom_toolchain = rule (
89
- implementation = _custom_toolchain_impl ,
90
- attrs = {
91
- "toolchain_name" : attr .string (mandatory = True ),
84
+ implementation = _custom_toolchain_impl ,
85
+ attrs = {
86
+ "toolchain_name" : attr .string (mandatory = True ),
92
87
"overrides" : attr .label_keyed_string_dict (
93
- allow_files = True , mandatory = False , default = {}
88
+ allow_files = True , mandatory = False , default = {}
94
89
),
95
90
"_symlink_template" : attr .label (
96
- allow_single_file = True ,
97
- default = Label ("//xcodeproj/internal/templates:custom_toolchain_symlink.sh" ),
91
+ allow_single_file = True ,
92
+ default = Label ("//xcodeproj/internal/templates:custom_toolchain_symlink.sh" ),
93
+ ),
94
+ "_xcode_config" : attr .label (
95
+ default = configuration_field (
96
+ name = "xcode_config_label" ,
97
+ fragment = "apple" ,
98
+ ),
98
99
),
99
100
},
100
101
)
0 commit comments