comparison third_party/emsdk/bazel/emscripten_toolchain/toolchain.bzl @ 179:8d17f6e6e290

[ThirdParty] Added emsdk bazel rules that can be supported by bazel 9.0.0
author MrJuneJune <me@mrjunejune.com>
date Thu, 22 Jan 2026 21:23:17 -0800
parents
children
comparison
equal deleted inserted replaced
178:94705b5986b3 179:8d17f6e6e290
1 """This module encapsulates logic to create emscripten_cc_toolchain_config rule."""
2
3 load(
4 "@rules_cc//cc:cc_toolchain_config_lib.bzl",
5 "action_config",
6 "env_entry",
7 "env_set",
8 "feature",
9 "feature_set",
10 "flag_group",
11 "tool",
12 "tool_path",
13 "variable_with_value",
14 "with_feature_set",
15 _flag_set = "flag_set",
16 )
17 load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES")
18 load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
19
20 def flag_set(flags = None, features = None, not_features = None, **kwargs):
21 """Extension to flag_set which allows for a "simple" form.
22
23 The simple form allows specifying flags as a simple list instead of a flag_group
24 if enable_if or expand_if semantics are not required.
25
26 Similarly, the simple form allows passing features/not_features if they are a simple
27 list of semantically "and" features.
28 (i.e. "asan" and "dbg", rather than "asan" or "dbg")
29
30 Args:
31 flags: list, set of flags
32 features: list, set of features required to be enabled.
33 not_features: list, set of features required to not be enabled.
34 **kwargs: The rest of the args for flag_set.
35
36 Returns:
37 flag_set
38 """
39 if flags:
40 if kwargs.get("flag_groups"):
41 fail("Cannot set flags and flag_groups")
42 else:
43 kwargs["flag_groups"] = [flag_group(flags = flags)]
44
45 if features or not_features:
46 if kwargs.get("with_features"):
47 fail("Cannot set features/not_feature and with_features")
48 kwargs["with_features"] = [with_feature_set(
49 features = features or [],
50 not_features = not_features or [],
51 )]
52 return _flag_set(**kwargs)
53
54 CROSSTOOL_DEFAULT_WARNINGS = [
55 "-Wall",
56 ]
57
58 def _impl(ctx):
59 target_cpu = ctx.attr.cpu
60 toolchain_identifier = "emscripten-" + target_cpu
61 target_system_name = target_cpu + "-unknown-emscripten"
62
63 host_system_name = "i686-unknown-linux-gnu"
64
65 target_libc = "musl/js"
66
67 abi_version = "emscripten_syscalls"
68
69 compiler = "emscripten"
70 abi_libc_version = "default"
71
72 cc_target_os = "emscripten"
73
74 emscripten_dir = ctx.attr.emscripten_binaries.label.workspace_root
75
76 nodejs_path = ctx.file.nodejs_bin.path
77
78 builtin_sysroot = emscripten_dir + "/emscripten/cache/sysroot"
79
80 emcc_script = "emcc.%s" % ctx.attr.script_extension
81 emcc_link_script = "emcc_link.%s" % ctx.attr.script_extension
82 emar_script = "emar.%s" % ctx.attr.script_extension
83
84 ################################################################
85 # Tools
86 ################################################################
87 clang_tool = tool(path = emcc_script)
88 clif_match_tool = tool(path = "dummy_clif_matcher")
89 link_tool = tool(path = emcc_link_script)
90 archive_tool = tool(path = emar_script)
91 strip_tool = tool(path = "NOT_USED_STRIP_TOOL")
92
93 #### Legacy tool paths (much of this is redundant with action_configs, but
94 #### these are still used for some things)
95 tool_paths = [
96 tool_path(name = "ar", path = emar_script),
97 tool_path(name = "cpp", path = "/bin/false"),
98 tool_path(name = "gcc", path = emcc_script),
99 tool_path(name = "gcov", path = "/bin/false"),
100 tool_path(name = "ld", path = emcc_link_script),
101 tool_path(name = "nm", path = "NOT_USED"),
102 tool_path(name = "objdump", path = "/bin/false"),
103 tool_path(name = "strip", path = "NOT_USED"),
104 ]
105
106 ################################################################
107 # Action Configs
108 ################################################################
109
110 cpp_compile_action = action_config(
111 action_name = ACTION_NAMES.cpp_compile,
112 tools = [clang_tool],
113 )
114
115 cpp_module_compile_action = action_config(
116 action_name = ACTION_NAMES.cpp_module_compile,
117 tools = [clang_tool],
118 )
119
120 cpp_module_codegen_action = action_config(
121 action_name = ACTION_NAMES.cpp_module_codegen,
122 tools = [clang_tool],
123 )
124
125 clif_match_action = action_config(
126 action_name = ACTION_NAMES.clif_match,
127 tools = [clif_match_tool],
128 )
129
130 cpp_link_dynamic_library_action = action_config(
131 action_name = ACTION_NAMES.cpp_link_dynamic_library,
132 tools = [link_tool],
133 )
134
135 strip_action = action_config(
136 action_name = ACTION_NAMES.strip,
137 tools = [strip_tool],
138 )
139
140 preprocess_assemble_action = action_config(
141 action_name = ACTION_NAMES.preprocess_assemble,
142 tools = [clang_tool],
143 )
144
145 cpp_header_parsing_action = action_config(
146 action_name = ACTION_NAMES.cpp_header_parsing,
147 tools = [clang_tool],
148 )
149
150 cpp_link_static_library_action = action_config(
151 action_name = ACTION_NAMES.cpp_link_static_library,
152 enabled = True,
153 flag_sets = [
154 flag_set(
155 flag_groups = [
156 flag_group(
157 flags = ["rcsD", "%{output_execpath}"],
158 expand_if_available = "output_execpath",
159 ),
160 ],
161 ),
162 flag_set(
163 flag_groups = [
164 flag_group(
165 iterate_over = "libraries_to_link",
166 flag_groups = [
167 flag_group(
168 flags = ["%{libraries_to_link.name}"],
169 expand_if_equal = variable_with_value(
170 name = "libraries_to_link.type",
171 value = "object_file",
172 ),
173 ),
174 flag_group(
175 flags = ["%{libraries_to_link.object_files}"],
176 iterate_over = "libraries_to_link.object_files",
177 expand_if_equal = variable_with_value(
178 name = "libraries_to_link.type",
179 value = "object_file_group",
180 ),
181 ),
182 ],
183 expand_if_available = "libraries_to_link",
184 ),
185 ],
186 ),
187 flag_set(
188 flag_groups = [
189 flag_group(
190 flags = ["@%{linker_param_file}"],
191 expand_if_available = "linker_param_file",
192 ),
193 ],
194 ),
195 ],
196 tools = [archive_tool],
197 )
198
199 c_compile_action = action_config(
200 action_name = ACTION_NAMES.c_compile,
201 tools = [clang_tool],
202 )
203
204 linkstamp_compile_action = action_config(
205 action_name = ACTION_NAMES.linkstamp_compile,
206 tools = [clang_tool],
207 )
208
209 assemble_action = action_config(
210 action_name = ACTION_NAMES.assemble,
211 tools = [clang_tool],
212 )
213
214 cpp_link_executable_action = action_config(
215 action_name = ACTION_NAMES.cpp_link_executable,
216 tools = [link_tool],
217 )
218
219 cpp_link_nodeps_dynamic_library_action = action_config(
220 action_name = ACTION_NAMES.cpp_link_nodeps_dynamic_library,
221 tools = [link_tool],
222 )
223
224 action_configs = [
225 strip_action,
226 c_compile_action,
227 cpp_compile_action,
228 linkstamp_compile_action,
229 assemble_action,
230 preprocess_assemble_action,
231 cpp_header_parsing_action,
232 cpp_module_compile_action,
233 cpp_module_codegen_action,
234 cpp_link_executable_action,
235 cpp_link_dynamic_library_action,
236 cpp_link_nodeps_dynamic_library_action,
237 cpp_link_static_library_action,
238 clif_match_action,
239 ]
240
241 all_compile_actions = [
242 ACTION_NAMES.c_compile,
243 ACTION_NAMES.cpp_compile,
244 ACTION_NAMES.linkstamp_compile,
245 ACTION_NAMES.assemble,
246 ACTION_NAMES.preprocess_assemble,
247 ACTION_NAMES.cpp_header_parsing,
248 ACTION_NAMES.cpp_module_compile,
249 ACTION_NAMES.cpp_module_codegen,
250 ACTION_NAMES.clif_match,
251 ACTION_NAMES.lto_backend,
252 ]
253
254 all_cpp_compile_actions = [
255 ACTION_NAMES.cpp_compile,
256 ACTION_NAMES.linkstamp_compile,
257 ACTION_NAMES.cpp_header_parsing,
258 ACTION_NAMES.cpp_module_compile,
259 ACTION_NAMES.cpp_module_codegen,
260 ACTION_NAMES.clif_match,
261 ]
262
263 preprocessor_compile_actions = [
264 ACTION_NAMES.c_compile,
265 ACTION_NAMES.cpp_compile,
266 ACTION_NAMES.linkstamp_compile,
267 ACTION_NAMES.preprocess_assemble,
268 ACTION_NAMES.cpp_header_parsing,
269 ACTION_NAMES.cpp_module_compile,
270 ACTION_NAMES.clif_match,
271 ]
272
273 all_link_actions = [
274 ACTION_NAMES.cpp_link_executable,
275 ACTION_NAMES.cpp_link_dynamic_library,
276 ACTION_NAMES.cpp_link_nodeps_dynamic_library,
277 ]
278
279 ################################################################
280 # Features
281 ################################################################
282
283 features = [
284 # This set of magic "feature"s are important configuration information for blaze.
285 feature(name = "no_legacy_features", enabled = True),
286 feature(
287 name = "has_configured_linker_path",
288 enabled = True,
289 ),
290
291 # Blaze requests this feature by default, but we don't care.
292 feature(name = "dependency_file"),
293
294 # Blaze requests this feature by default, but we don't care.
295 feature(name = "random_seed"),
296
297 # Formerly "needsPic" attribute
298 feature(name = "supports_pic", enabled = False),
299
300 # Blaze requests this feature by default.
301 # Blaze also tests if this feature is supported, before setting the "pic" build-variable.
302 feature(name = "pic"),
303
304 # Blaze requests this feature by default.
305 # Blaze also tests if this feature is supported before setting preprocessor_defines
306 # (...but why?)
307 feature(name = "preprocessor_defines"),
308
309 # Blaze requests this feature by default.
310 # Blaze also tests if this feature is supported before setting includes. (...but why?)
311 feature(name = "include_paths"),
312
313 # Blaze tests if this feature is enabled in order to create implicit
314 # "nodeps" .so outputs from cc_library rules.
315 feature(name = "supports_dynamic_linker", enabled = False),
316
317 # Blaze requests this feature when linking a cc_binary which is
318 # "dynamic" aka linked against nodeps-dynamic-library cc_library
319 # outputs.
320 feature(name = "dynamic_linking_mode"),
321
322 #### Configuration features
323 feature(
324 name = "crosstool_cpu",
325 enabled = True,
326 implies = ["crosstool_cpu_" + target_cpu],
327 ),
328 feature(
329 name = "crosstool_cpu_asmjs",
330 provides = ["variant:crosstool_cpu"],
331 ),
332 feature(
333 name = "crosstool_cpu_wasm",
334 provides = ["variant:crosstool_cpu"],
335 ),
336
337 # These 3 features will be automatically enabled by blaze in the
338 # corresponding build mode.
339 feature(
340 name = "opt",
341 provides = ["variant:crosstool_build_mode"],
342 ),
343 feature(
344 name = "dbg",
345 provides = ["variant:crosstool_build_mode"],
346 ),
347 feature(
348 name = "fastbuild",
349 provides = ["variant:crosstool_build_mode"],
350 ),
351
352 # Feature to prevent 'command line too long' issues
353 feature(
354 name = "archive_param_file",
355 enabled = True,
356 ),
357 feature(
358 name = "compiler_param_file",
359 enabled = True,
360 ),
361
362 #### User-settable features
363
364 # Set if enabling exceptions.
365 feature(name = "exceptions"),
366
367 # Set if enabling wasm_exceptions.
368 feature(name = "wasm_exceptions"),
369
370 # This feature overrides the default optimization to prefer execution speed
371 # over binary size (like clang -O3).
372 feature(
373 name = "optimized_for_speed",
374 provides = ["variant:crosstool_optimization_mode"],
375 ),
376
377 # This feature overrides the default optimization to prefer binary size over
378 # execution speed (like clang -Oz).
379 feature(
380 name = "optimized_for_size",
381 provides = ["variant:crosstool_optimization_mode"],
382 ),
383
384 # Convenience aliases / alt-spellings.
385 feature(
386 name = "optimize_for_speed",
387 implies = ["optimized_for_speed"],
388 ),
389 feature(
390 name = "optimize_for_size",
391 implies = ["optimized_for_size"],
392 ),
393
394 # This feature allows easier use of profiling tools by preserving mangled
395 # C++ names. This does everything profiling_funcs does and more.
396 feature(name = "profiling"),
397
398 # This feature emits only enough debug info for function names to appear
399 # in profiles.
400 feature(name = "profiling_funcs"),
401
402 # This feature allows source maps to be generated.
403 feature(
404 name = "source_maps",
405 implies = ["full_debug_info"],
406 ),
407 feature(
408 name = "dwarf_debug_info",
409 implies = ["profiling"],
410 ),
411
412 # Turns on full debug info (-g3).
413 feature(name = "full_debug_info"),
414
415 # Enables the use of "Emscripten" Pthread implementation.
416 # https://kripken.github.io/emscripten-site/docs/porting/pthreads.html
417 # https://github.com/kripken/emscripten/wiki/Pthreads-with-WebAssembly
418 feature(name = "use_pthreads"),
419
420 # If enabled, the runtime will exit when main() completes.
421 feature(name = "exit_runtime"),
422
423 # Primarily for toolchain maintainers:
424 feature(name = "emcc_debug"),
425 feature(name = "emcc_debug_link"),
426 feature(
427 name = "llvm_backend",
428 requires = [feature_set(features = ["crosstool_cpu_wasm"])],
429 enabled = True,
430 ),
431
432 # Remove once flag is flipped.
433 # See https://github.com/bazelbuild/bazel/issues/7687
434 feature(
435 name = "do_not_split_linking_cmdline",
436 ),
437
438 # Adds simd support, only available with the llvm backend.
439 feature(
440 name = "wasm_simd",
441 requires = [feature_set(features = ["llvm_backend"])],
442 ),
443 # Adds relaxed-simd support, only available with the llvm backend.
444 feature(
445 name = "wasm_relaxed_simd",
446 requires = [feature_set(features = ["llvm_backend"])],
447 ),
448 feature(
449 name = "precise_long_double_printf",
450 enabled = True,
451 ),
452 feature(
453 name = "wasm_warnings_as_errors",
454 enabled = False,
455 ),
456
457 # ASan and UBSan. See also:
458 # https://emscripten.org/docs/debugging/Sanitizers.html
459 feature(name = "wasm_asan"),
460 feature(name = "wasm_ubsan"),
461 feature(
462 name = "output_format_js",
463 enabled = True,
464 ),
465 feature(
466 name = "wasm_standalone",
467 ),
468 ]
469
470 crosstool_default_flag_sets = [
471 # Compile, Link, and CC_FLAGS make variable
472 flag_set(
473 actions = [
474 ACTION_NAMES.c_compile,
475 ACTION_NAMES.cpp_compile,
476 ACTION_NAMES.linkstamp_compile,
477 ACTION_NAMES.assemble,
478 ACTION_NAMES.preprocess_assemble,
479 ACTION_NAMES.cpp_header_parsing,
480 ACTION_NAMES.cpp_module_compile,
481 ACTION_NAMES.cpp_module_codegen,
482 ACTION_NAMES.clif_match,
483 ACTION_NAMES.cpp_link_executable,
484 ACTION_NAMES.cpp_link_dynamic_library,
485 ACTION_NAMES.cpp_link_nodeps_dynamic_library,
486 ],
487 flag_groups = [
488 flag_group(
489 flags = ["--sysroot=%{sysroot}"],
490 expand_if_available = "sysroot",
491 ),
492 ],
493 ),
494 # Compile + Link
495 flag_set(
496 actions = [
497 ACTION_NAMES.c_compile,
498 ACTION_NAMES.cpp_compile,
499 ACTION_NAMES.linkstamp_compile,
500 ACTION_NAMES.assemble,
501 ACTION_NAMES.preprocess_assemble,
502 ACTION_NAMES.cpp_header_parsing,
503 ACTION_NAMES.cpp_module_compile,
504 ACTION_NAMES.cpp_module_codegen,
505 ACTION_NAMES.clif_match,
506 ACTION_NAMES.cpp_link_executable,
507 ACTION_NAMES.cpp_link_dynamic_library,
508 ACTION_NAMES.cpp_link_nodeps_dynamic_library,
509 ],
510 # This forces color diagnostics even on Forge (where we don't have an
511 # attached terminal).
512 flags = [
513 "-fdiagnostics-color",
514 ],
515 ),
516 # C++ compiles (and implicitly link)
517 flag_set(
518 actions = all_cpp_compile_actions,
519 flags = [
520 "-fno-exceptions",
521 ],
522 not_features = ["exceptions", "wasm_exceptions"],
523 ),
524 flag_set(
525 actions = all_cpp_compile_actions,
526 flags = [
527 "-fexceptions",
528 ],
529 features = ["exceptions"],
530 ),
531 flag_set(
532 actions = all_cpp_compile_actions +
533 all_link_actions,
534 flags = [
535 "-fwasm-exceptions",
536 ],
537 features = ["wasm_exceptions"],
538 ),
539 # All compiles (and implicitly link)
540 flag_set(
541 actions = all_compile_actions +
542 all_link_actions,
543 flags = [
544 "-fno-strict-aliasing",
545 "-funsigned-char",
546 "-no-canonical-prefixes",
547 ],
548 ),
549 # Language Features
550 flag_set(
551 actions = all_cpp_compile_actions,
552 flags = ["-std=gnu++17", "-nostdinc", "-nostdinc++"],
553 ),
554
555 # Emscripten-specific settings:
556 flag_set(
557 actions = all_compile_actions + all_link_actions,
558 flags = ["-s", "WASM=0"],
559 features = ["crosstool_cpu_asmjs"],
560 ),
561 flag_set(
562 actions = all_compile_actions +
563 all_link_actions,
564 flags = ["-s", "USE_PTHREADS=1"],
565 features = ["use_pthreads"],
566 ),
567 flag_set(
568 actions = all_link_actions,
569 flags = ["-s", "EXIT_RUNTIME=1"],
570 features = ["exit_runtime"],
571 ),
572 flag_set(
573 actions = all_compile_actions + all_link_actions,
574 flags = ["-pthread"],
575 features = ["llvm_backend", "use_pthreads"],
576 ),
577 flag_set(
578 actions = all_compile_actions + all_link_actions,
579 flags = ["-msimd128"],
580 features = ["wasm_simd"],
581 ),
582 flag_set(
583 actions = all_compile_actions + all_link_actions,
584 flags = ["-msimd128", "-mrelaxed-simd"],
585 features = ["wasm_relaxed_simd"],
586 ),
587 flag_set(
588 actions = all_link_actions,
589 flags = ["-s", "PRINTF_LONG_DOUBLE=1"],
590 features = ["precise_long_double_printf"],
591 ),
592 flag_set(
593 actions = all_link_actions,
594 flags = ["--oformat=js"],
595 features = ["output_format_js"],
596 ),
597
598 # Opt
599 flag_set(
600 actions = preprocessor_compile_actions,
601 flags = ["-DNDEBUG"],
602 features = ["opt"],
603 ),
604 flag_set(
605 actions = all_compile_actions,
606 flags = ["-fomit-frame-pointer"],
607 features = ["opt"],
608 ),
609 flag_set(
610 actions = all_compile_actions +
611 all_link_actions,
612 flags = ["-O2"],
613 features = ["opt"],
614 ),
615
616 # Users can override opt-level with semantic names...
617 flag_set(
618 actions = all_compile_actions +
619 all_link_actions,
620 flags = ["-Oz"],
621 features = ["optimized_for_size", "opt"],
622 ),
623 flag_set(
624 actions = all_compile_actions +
625 all_link_actions,
626 flags = ["-O3"],
627 features = ["optimized_for_speed", "opt"],
628 ),
629
630 # Fastbuild
631 flag_set(
632 actions = all_compile_actions,
633 flags = ["-fomit-frame-pointer"],
634 features = ["fastbuild"],
635 ),
636 flag_set(
637 actions = all_compile_actions +
638 all_link_actions,
639 flags = ["-O0"],
640 features = ["fastbuild"],
641 ),
642
643 # Dbg
644 flag_set(
645 actions = all_compile_actions,
646 flags = ["-fno-omit-frame-pointer"],
647 features = ["dbg"],
648 ),
649 flag_set(
650 actions = all_compile_actions +
651 all_link_actions,
652 flags = ["-g", "-O0"],
653 features = ["dbg"],
654 ),
655 flag_set(
656 actions = all_compile_actions +
657 all_link_actions,
658 flags = [
659 "-g",
660 "-fsanitize=address",
661 "-O1",
662 "-DADDRESS_SANITIZER=1",
663 "-fno-omit-frame-pointer",
664 ],
665 features = ["wasm_asan"],
666 ),
667 flag_set(
668 actions = all_compile_actions +
669 all_link_actions,
670 flags = [
671 "-g3",
672 "-fsanitize=undefined",
673 "-O1",
674 "-DUNDEFINED_BEHAVIOR_SANITIZER=1",
675 "-fno-omit-frame-pointer",
676 "-fno-sanitize=vptr",
677 ],
678 features = ["wasm_ubsan"],
679 ),
680
681 # Profiling provides full debug info and a special --profiling flag
682 # to control name mangling
683 flag_set(
684 actions = all_link_actions,
685 flags = ["--profiling"],
686 features = ["profiling"],
687 ),
688 flag_set(
689 actions = all_link_actions,
690 flags = ["--profiling_funcs"],
691 features = ["profiling_funcs"],
692 ),
693 flag_set(
694 actions = all_compile_actions +
695 all_link_actions,
696 flags = ["-g3"],
697 features = ["full_debug_info"],
698 ),
699 flag_set(
700 actions = all_link_actions,
701 flags = ["-gseparate-dwarf"],
702 features = ["dwarf_debug_info"],
703 ),
704 flag_set(
705 actions = all_compile_actions +
706 all_link_actions,
707 flags = ["-fdebug-compilation-dir=."],
708 features = ["dwarf_debug_info"],
709 ),
710 # Generic warning flag list
711 flag_set(
712 actions = all_compile_actions,
713 flags = CROSSTOOL_DEFAULT_WARNINGS,
714 ),
715
716 # Defines and Includes and Paths and such
717 flag_set(
718 actions = all_compile_actions,
719 flag_groups = [
720 flag_group(flags = ["-fPIC"], expand_if_available = "pic"),
721 ],
722 ),
723 flag_set(
724 actions = preprocessor_compile_actions,
725 flag_groups = [
726 flag_group(
727 flags = ["-D%{preprocessor_defines}"],
728 iterate_over = "preprocessor_defines",
729 ),
730 ],
731 ),
732 flag_set(
733 actions = preprocessor_compile_actions,
734 flag_groups = [
735 flag_group(
736 flags = ["-include", "%{includes}"],
737 iterate_over = "includes",
738 expand_if_available = "includes",
739 ),
740 ],
741 ),
742 flag_set(
743 actions = preprocessor_compile_actions,
744 flag_groups = [
745 flag_group(
746 flags = ["-iquote", "%{quote_include_paths}"],
747 iterate_over = "quote_include_paths",
748 ),
749 flag_group(
750 flags = ["-I%{include_paths}"],
751 iterate_over = "include_paths",
752 ),
753 flag_group(
754 flags = ["-isystem", "%{system_include_paths}"],
755 iterate_over = "system_include_paths",
756 ),
757 ],
758 ),
759
760 ## Linking options (not libs -- those go last)
761
762 # Generic link options
763 flag_set(
764 actions = [
765 ACTION_NAMES.cpp_link_dynamic_library,
766 ACTION_NAMES.cpp_link_nodeps_dynamic_library,
767 ],
768 flags = ["-shared"],
769 ),
770
771 # Linker search paths and objects:
772 flag_set(
773 actions = all_link_actions,
774 flag_groups = [
775 flag_group(
776 iterate_over = "runtime_library_search_directories",
777 flag_groups = [
778 flag_group(
779 flags = [
780 "-Wl,-rpath,$EXEC_ORIGIN/%{runtime_library_search_directories}",
781 ],
782 expand_if_true = "is_cc_test",
783 ),
784 flag_group(
785 flags = [
786 "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}",
787 ],
788 expand_if_false = "is_cc_test",
789 ),
790 ],
791 expand_if_available = "runtime_library_search_directories",
792 ),
793 ],
794 ),
795 flag_set(
796 actions = all_link_actions,
797 flag_groups = [
798 flag_group(
799 flags = ["-L%{library_search_directories}"],
800 iterate_over = "library_search_directories",
801 expand_if_available = "library_search_directories",
802 ),
803 ],
804 ),
805 flag_set(
806 actions = all_link_actions,
807 flag_groups = [
808 flag_group(
809 # This is actually a list of object files from the linkstamp steps
810 flags = ["%{linkstamp_paths}"],
811 iterate_over = "linkstamp_paths",
812 expand_if_available = "linkstamp_paths",
813 ),
814 ],
815 ),
816 flag_set(
817 actions = all_link_actions,
818 flag_groups = [
819 flag_group(
820 flags = ["@%{thinlto_param_file}"],
821 expand_if_available = "libraries_to_link",
822 expand_if_true = "thinlto_param_file",
823 ),
824 flag_group(
825 iterate_over = "libraries_to_link",
826 flag_groups = [
827 flag_group(
828 flags = ["-Wl,--start-lib"],
829 expand_if_equal = variable_with_value(
830 name = "libraries_to_link.type",
831 value = "object_file_group",
832 ),
833 ),
834 flag_group(
835 flags = ["-Wl,-whole-archive"],
836 expand_if_true = "libraries_to_link.is_whole_archive",
837 ),
838 flag_group(
839 flags = ["%{libraries_to_link.object_files}"],
840 iterate_over = "libraries_to_link.object_files",
841 expand_if_equal = variable_with_value(
842 name = "libraries_to_link.type",
843 value = "object_file_group",
844 ),
845 ),
846 flag_group(
847 flags = ["%{libraries_to_link.name}"],
848 expand_if_equal = variable_with_value(
849 name = "libraries_to_link.type",
850 value = "object_file",
851 ),
852 ),
853 flag_group(
854 flags = ["%{libraries_to_link.name}"],
855 expand_if_equal = variable_with_value(
856 name = "libraries_to_link.type",
857 value = "interface_library",
858 ),
859 ),
860 flag_group(
861 flags = ["%{libraries_to_link.name}"],
862 expand_if_equal = variable_with_value(
863 name = "libraries_to_link.type",
864 value = "static_library",
865 ),
866 ),
867 flag_group(
868 flags = ["-l%{libraries_to_link.name}"],
869 expand_if_equal = variable_with_value(
870 name = "libraries_to_link.type",
871 value = "dynamic_library",
872 ),
873 ),
874 flag_group(
875 flags = ["-l:%{libraries_to_link.name}"],
876 expand_if_equal = variable_with_value(
877 name = "libraries_to_link.type",
878 value = "versioned_dynamic_library",
879 ),
880 ),
881 flag_group(
882 flags = ["-Wl,-no-whole-archive"],
883 expand_if_true = "libraries_to_link.is_whole_archive",
884 ),
885 flag_group(
886 flags = ["-Wl,--end-lib"],
887 expand_if_equal = variable_with_value(
888 name = "libraries_to_link.type",
889 value = "object_file_group",
890 ),
891 ),
892 ],
893 expand_if_available = "libraries_to_link",
894 ),
895 ],
896 ),
897
898 # Configure the header parsing and preprocessing.
899 flag_set(
900 actions = [ACTION_NAMES.cpp_header_parsing],
901 flags = ["-xc++-header", "-fsyntax-only"],
902 features = ["parse_headers"],
903 ),
904
905 # Note: user compile flags should be nearly last -- you probably
906 # don't want to put any more features after this!
907 flag_set(
908 actions = [
909 ACTION_NAMES.c_compile,
910 ACTION_NAMES.cpp_compile,
911 ACTION_NAMES.linkstamp_compile,
912 ACTION_NAMES.assemble,
913 ACTION_NAMES.preprocess_assemble,
914 ACTION_NAMES.cpp_header_parsing,
915 ACTION_NAMES.cpp_module_compile,
916 ACTION_NAMES.cpp_module_codegen,
917 ACTION_NAMES.clif_match,
918 ],
919 flag_groups = [
920 flag_group(
921 flags = ["%{user_compile_flags}"],
922 iterate_over = "user_compile_flags",
923 expand_if_available = "user_compile_flags",
924 ),
925 ],
926 ),
927 flag_set(
928 actions = all_link_actions,
929 flag_groups = [
930 flag_group(
931 flags = ["%{user_link_flags}"],
932 iterate_over = "user_link_flags",
933 expand_if_available = "user_link_flags",
934 ),
935 ],
936 ),
937 ## Options which need to go late -- after all the user options -- go here.
938 flag_set(
939 # One might hope that these options would only be needed for C++
940 # compiles. But, sadly, users compile ".c" files with custom
941 # copts=["-x", "c++"], and expect that to be able to find C++ stdlib
942 # headers. It might be worth pondering how blaze could support this sort
943 # of use-case better.
944 actions = preprocessor_compile_actions +
945 [ACTION_NAMES.cc_flags_make_variable],
946 flags = [
947 "-iwithsysroot" + "/include/c++/v1",
948 "-iwithsysroot" + "/include/compat",
949 "-iwithsysroot" + "/include",
950 "-isystem",
951 emscripten_dir + "/lib/clang/22/include",
952 ],
953 ),
954 # Inputs and outputs
955 flag_set(
956 actions = [
957 ACTION_NAMES.c_compile,
958 ACTION_NAMES.cpp_compile,
959 ACTION_NAMES.linkstamp_compile,
960 ACTION_NAMES.assemble,
961 ACTION_NAMES.preprocess_assemble,
962 ACTION_NAMES.cpp_header_parsing,
963 ACTION_NAMES.cpp_module_compile,
964 ACTION_NAMES.cpp_module_codegen,
965 ACTION_NAMES.clif_match,
966 ],
967 flag_groups = [
968 flag_group(
969 flags = ["-MD", "-MF", "%{dependency_file}"],
970 expand_if_available = "dependency_file",
971 ),
972 ],
973 ),
974 flag_set(
975 actions = [
976 ACTION_NAMES.c_compile,
977 ACTION_NAMES.cpp_compile,
978 ACTION_NAMES.linkstamp_compile,
979 ACTION_NAMES.assemble,
980 ACTION_NAMES.preprocess_assemble,
981 ACTION_NAMES.cpp_header_parsing,
982 ACTION_NAMES.cpp_module_compile,
983 ACTION_NAMES.cpp_module_codegen,
984 ACTION_NAMES.clif_match,
985 ],
986 flag_groups = [
987 flag_group(
988 flags = ["-c", "%{source_file}"],
989 expand_if_available = "source_file",
990 ),
991 ],
992 ),
993 flag_set(
994 actions = [
995 ACTION_NAMES.c_compile,
996 ACTION_NAMES.cpp_compile,
997 ACTION_NAMES.linkstamp_compile,
998 ACTION_NAMES.assemble,
999 ACTION_NAMES.preprocess_assemble,
1000 ACTION_NAMES.cpp_header_parsing,
1001 ACTION_NAMES.cpp_module_compile,
1002 ACTION_NAMES.cpp_module_codegen,
1003 ACTION_NAMES.clif_match,
1004 ],
1005 flag_groups = [
1006 flag_group(
1007 flags = ["-S"],
1008 expand_if_available = "output_assembly_file",
1009 ),
1010 flag_group(
1011 flags = ["-E"],
1012 expand_if_available = "output_preprocess_file",
1013 ),
1014 flag_group(
1015 flags = ["-o", "%{output_file}"],
1016 expand_if_available = "output_file",
1017 ),
1018 ],
1019 ),
1020 flag_set(
1021 actions = all_link_actions,
1022 flag_groups = [
1023 flag_group(
1024 flags = ["-o", "%{output_execpath}"],
1025 expand_if_available = "output_execpath",
1026 ),
1027 ],
1028 ),
1029 # And finally, the params file!
1030 flag_set(
1031 actions = all_link_actions,
1032 flag_groups = [
1033 flag_group(
1034 flags = ["@%{linker_param_file}"],
1035 expand_if_available = "linker_param_file",
1036 ),
1037 ],
1038 ),
1039 flag_set(
1040 actions = all_compile_actions,
1041 flags = [
1042 "-Wno-builtin-macro-redefined",
1043 # Genrules may not escape quotes enough for these, so
1044 # don't put them into $(CC_FLAGS):
1045 '-D__DATE__="redacted"',
1046 '-D__TIMESTAMP__="redacted"',
1047 '-D__TIME__="redacted"',
1048 ],
1049 ),
1050 flag_set(
1051 actions = all_compile_actions,
1052 flags = ["-Werror"],
1053 features = ["wasm_warnings_as_errors"],
1054 ),
1055 flag_set(
1056 actions = all_link_actions,
1057 flags = ["-sSTANDALONE_WASM"],
1058 features = ["wasm_standalone"],
1059 ),
1060 ]
1061
1062 crosstool_default_env_sets = [
1063 # Globals
1064 env_set(
1065 actions = all_compile_actions +
1066 all_link_actions +
1067 [ACTION_NAMES.cpp_link_static_library],
1068 env_entries = [
1069 env_entry(
1070 key = "EM_BIN_PATH",
1071 value = emscripten_dir,
1072 ),
1073 env_entry(
1074 key = "EM_CONFIG_PATH",
1075 value = ctx.file.em_config.path,
1076 ),
1077 env_entry(
1078 key = "NODE_JS_PATH",
1079 value = nodejs_path,
1080 ),
1081 ],
1082 ),
1083 # Use llvm backend. Off by default, enabled via --features=llvm_backend
1084 env_set(
1085 actions = all_compile_actions +
1086 all_link_actions +
1087 [ACTION_NAMES.cpp_link_static_library],
1088 env_entries = [env_entry(key = "EMCC_WASM_BACKEND", value = "1")],
1089 with_features = [with_feature_set(features = ["llvm_backend"])],
1090 ),
1091 # Debug compile and link. Off by default, enabled via --features=emcc_debug
1092 env_set(
1093 actions = all_compile_actions,
1094 env_entries = [env_entry(key = "EMCC_DEBUG", value = "1")],
1095 with_features = [with_feature_set(features = ["emcc_debug"])],
1096 ),
1097
1098 # Debug only link step. Off by default, enabled via --features=emcc_debug_link
1099 env_set(
1100 actions = all_link_actions,
1101 env_entries = [env_entry(key = "EMCC_DEBUG", value = "1")],
1102 with_features = [
1103 with_feature_set(features = ["emcc_debug"]),
1104 with_feature_set(features = ["emcc_debug_link"]),
1105 ],
1106 ),
1107 ]
1108
1109 crosstool_default_flags_feature = feature(
1110 name = "crosstool_default_flags",
1111 enabled = True,
1112 flag_sets = crosstool_default_flag_sets,
1113 env_sets = crosstool_default_env_sets,
1114 )
1115
1116 features.append(crosstool_default_flags_feature)
1117
1118 cxx_builtin_include_directories = [
1119 emscripten_dir + "/emscripten/cache/sysroot/include/c++/v1",
1120 emscripten_dir + "/emscripten/cache/sysroot/include/compat",
1121 emscripten_dir + "/emscripten/cache/sysroot/include",
1122 emscripten_dir + "/lib/clang/21/include",
1123 ]
1124
1125 artifact_name_patterns = []
1126
1127 make_variables = []
1128
1129 return cc_common.create_cc_toolchain_config_info(
1130 ctx = ctx,
1131 features = features,
1132 action_configs = action_configs,
1133 artifact_name_patterns = artifact_name_patterns,
1134 cxx_builtin_include_directories = cxx_builtin_include_directories,
1135 toolchain_identifier = toolchain_identifier,
1136 host_system_name = host_system_name,
1137 target_system_name = target_system_name,
1138 target_cpu = target_cpu,
1139 target_libc = target_libc,
1140 compiler = compiler,
1141 abi_version = abi_version,
1142 abi_libc_version = abi_libc_version,
1143 tool_paths = tool_paths,
1144 make_variables = make_variables,
1145 builtin_sysroot = builtin_sysroot,
1146 cc_target_os = cc_target_os,
1147 )
1148
1149 emscripten_cc_toolchain_config_rule = rule(
1150 implementation = _impl,
1151 attrs = {
1152 "cpu": attr.string(mandatory = True, values = ["asmjs", "wasm"]),
1153 "em_config": attr.label(mandatory = True, allow_single_file = True),
1154 "emscripten_binaries": attr.label(mandatory = True, cfg = "exec"),
1155 "nodejs_bin": attr.label(mandatory = True, allow_single_file = True),
1156 "script_extension": attr.string(mandatory = True, values = ["sh", "bat"]),
1157 },
1158 )