1# Copyright 2019 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#    http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""A Starlark cc_toolchain configuration rule"""
16
17load(
18    "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
19    "action_config",
20    "feature",
21    "feature_set",
22    "flag_group",
23    "flag_set",
24    "tool",
25    "tool_path",
26    "variable_with_value",
27    "with_feature_set",
28)
29load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
30
31def layering_check_features(compiler):
32    if compiler != "clang":
33        return []
34    return [
35        feature(
36            name = "use_module_maps",
37            requires = [feature_set(features = ["module_maps"])],
38            flag_sets = [
39                flag_set(
40                    actions = [
41                        ACTION_NAMES.c_compile,
42                        ACTION_NAMES.cpp_compile,
43                        ACTION_NAMES.cpp_header_parsing,
44                        ACTION_NAMES.cpp_module_compile,
45                    ],
46                    flag_groups = [
47                        flag_group(
48                            flags = [
49                                "-fmodule-name=%{module_name}",
50                                "-fmodule-map-file=%{module_map_file}",
51                            ],
52                        ),
53                    ],
54                ),
55            ],
56        ),
57
58        # Tell blaze we support module maps in general, so they will be generated
59        # for all c/c++ rules.
60        # Note: not all C++ rules support module maps; thus, do not imply this
61        # feature from other features - instead, require it.
62        feature(name = "module_maps", enabled = True),
63        feature(
64            name = "layering_check",
65            implies = ["use_module_maps"],
66            flag_sets = [
67                flag_set(
68                    actions = [
69                        ACTION_NAMES.c_compile,
70                        ACTION_NAMES.cpp_compile,
71                        ACTION_NAMES.cpp_header_parsing,
72                        ACTION_NAMES.cpp_module_compile,
73                    ],
74                    flag_groups = [
75                        flag_group(flags = [
76                            "-fmodules-strict-decluse",
77                            "-Wprivate-header",
78                        ]),
79                        flag_group(
80                            iterate_over = "dependent_module_map_files",
81                            flags = [
82                                "-fmodule-map-file=%{dependent_module_map_files}",
83                            ],
84                        ),
85                    ],
86                ),
87            ],
88        ),
89    ]
90
91all_compile_actions = [
92    ACTION_NAMES.c_compile,
93    ACTION_NAMES.cpp_compile,
94    ACTION_NAMES.linkstamp_compile,
95    ACTION_NAMES.assemble,
96    ACTION_NAMES.preprocess_assemble,
97    ACTION_NAMES.cpp_header_parsing,
98    ACTION_NAMES.cpp_module_compile,
99    ACTION_NAMES.cpp_module_codegen,
100    ACTION_NAMES.clif_match,
101    ACTION_NAMES.lto_backend,
102]
103
104all_cpp_compile_actions = [
105    ACTION_NAMES.cpp_compile,
106    ACTION_NAMES.linkstamp_compile,
107    ACTION_NAMES.cpp_header_parsing,
108    ACTION_NAMES.cpp_module_compile,
109    ACTION_NAMES.cpp_module_codegen,
110    ACTION_NAMES.clif_match,
111]
112
113preprocessor_compile_actions = [
114    ACTION_NAMES.c_compile,
115    ACTION_NAMES.cpp_compile,
116    ACTION_NAMES.linkstamp_compile,
117    ACTION_NAMES.preprocess_assemble,
118    ACTION_NAMES.cpp_header_parsing,
119    ACTION_NAMES.cpp_module_compile,
120    ACTION_NAMES.clif_match,
121]
122
123codegen_compile_actions = [
124    ACTION_NAMES.c_compile,
125    ACTION_NAMES.cpp_compile,
126    ACTION_NAMES.linkstamp_compile,
127    ACTION_NAMES.assemble,
128    ACTION_NAMES.preprocess_assemble,
129    ACTION_NAMES.cpp_module_codegen,
130    ACTION_NAMES.lto_backend,
131]
132
133all_link_actions = [
134    ACTION_NAMES.cpp_link_executable,
135    ACTION_NAMES.cpp_link_dynamic_library,
136    ACTION_NAMES.cpp_link_nodeps_dynamic_library,
137]
138
139lto_index_actions = [
140    ACTION_NAMES.lto_index_for_executable,
141    ACTION_NAMES.lto_index_for_dynamic_library,
142    ACTION_NAMES.lto_index_for_nodeps_dynamic_library,
143]
144
145def _impl(ctx):
146    tool_paths = [
147        tool_path(name = name, path = path)
148        for name, path in ctx.attr.tool_paths.items()
149    ]
150    action_configs = []
151
152    llvm_cov_action = action_config(
153        action_name = ACTION_NAMES.llvm_cov,
154        tools = [
155            tool(
156                path = ctx.attr.tool_paths["llvm-cov"],
157            ),
158        ],
159    )
160
161    action_configs.append(llvm_cov_action)
162
163    supports_pic_feature = feature(
164        name = "supports_pic",
165        enabled = True,
166    )
167    supports_start_end_lib_feature = feature(
168        name = "supports_start_end_lib",
169        enabled = True,
170    )
171
172    default_compile_flags_feature = feature(
173        name = "default_compile_flags",
174        enabled = True,
175        flag_sets = [
176            flag_set(
177                actions = all_compile_actions,
178                flag_groups = [
179                    flag_group(
180                        # Security hardening requires optimization.
181                        # We need to undef it as some distributions now have it enabled by default.
182                        flags = ["-U_FORTIFY_SOURCE"],
183                    ),
184                ],
185                with_features = [
186                    with_feature_set(
187                        not_features = ["thin_lto"],
188                    ),
189                ],
190            ),
191            flag_set(
192                actions = all_compile_actions,
193                flag_groups = ([
194                    flag_group(
195                        flags = ctx.attr.compile_flags,
196                    ),
197                ] if ctx.attr.compile_flags else []),
198            ),
199            flag_set(
200                actions = all_compile_actions,
201                flag_groups = ([
202                    flag_group(
203                        flags = ctx.attr.dbg_compile_flags,
204                    ),
205                ] if ctx.attr.dbg_compile_flags else []),
206                with_features = [with_feature_set(features = ["dbg"])],
207            ),
208            flag_set(
209                actions = all_compile_actions,
210                flag_groups = ([
211                    flag_group(
212                        flags = ctx.attr.opt_compile_flags,
213                    ),
214                ] if ctx.attr.opt_compile_flags else []),
215                with_features = [with_feature_set(features = ["opt"])],
216            ),
217            flag_set(
218                actions = all_cpp_compile_actions + [ACTION_NAMES.lto_backend],
219                flag_groups = ([
220                    flag_group(
221                        flags = ctx.attr.cxx_flags,
222                    ),
223                ] if ctx.attr.cxx_flags else []),
224            ),
225        ],
226    )
227
228    default_link_flags_feature = feature(
229        name = "default_link_flags",
230        enabled = True,
231        flag_sets = [
232            flag_set(
233                actions = all_link_actions + lto_index_actions,
234                flag_groups = ([
235                    flag_group(
236                        flags = ctx.attr.link_flags,
237                    ),
238                ] if ctx.attr.link_flags else []),
239            ),
240            flag_set(
241                actions = all_link_actions + lto_index_actions,
242                flag_groups = ([
243                    flag_group(
244                        flags = ctx.attr.opt_link_flags,
245                    ),
246                ] if ctx.attr.opt_link_flags else []),
247                with_features = [with_feature_set(features = ["opt"])],
248            ),
249        ],
250    )
251
252    dbg_feature = feature(name = "dbg")
253
254    opt_feature = feature(name = "opt")
255
256    sysroot_feature = feature(
257        name = "sysroot",
258        enabled = True,
259        flag_sets = [
260            flag_set(
261                actions = [
262                    ACTION_NAMES.preprocess_assemble,
263                    ACTION_NAMES.linkstamp_compile,
264                    ACTION_NAMES.c_compile,
265                    ACTION_NAMES.cpp_compile,
266                    ACTION_NAMES.cpp_header_parsing,
267                    ACTION_NAMES.cpp_module_compile,
268                    ACTION_NAMES.cpp_module_codegen,
269                    ACTION_NAMES.lto_backend,
270                    ACTION_NAMES.clif_match,
271                ] + all_link_actions + lto_index_actions,
272                flag_groups = [
273                    flag_group(
274                        flags = ["--sysroot=%{sysroot}"],
275                        expand_if_available = "sysroot",
276                    ),
277                ],
278            ),
279        ],
280    )
281
282    fdo_optimize_feature = feature(
283        name = "fdo_optimize",
284        flag_sets = [
285            flag_set(
286                actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile],
287                flag_groups = [
288                    flag_group(
289                        flags = [
290                            "-fprofile-use=%{fdo_profile_path}",
291                            "-fprofile-correction",
292                        ],
293                        expand_if_available = "fdo_profile_path",
294                    ),
295                ],
296            ),
297        ],
298        provides = ["profile"],
299    )
300
301    supports_dynamic_linker_feature = feature(name = "supports_dynamic_linker", enabled = True)
302
303    user_compile_flags_feature = feature(
304        name = "user_compile_flags",
305        enabled = True,
306        flag_sets = [
307            flag_set(
308                actions = all_compile_actions,
309                flag_groups = [
310                    flag_group(
311                        flags = ["%{user_compile_flags}"],
312                        iterate_over = "user_compile_flags",
313                        expand_if_available = "user_compile_flags",
314                    ),
315                ],
316            ),
317        ],
318    )
319
320    unfiltered_compile_flags_feature = feature(
321        name = "unfiltered_compile_flags",
322        enabled = True,
323        flag_sets = [
324            flag_set(
325                actions = all_compile_actions,
326                flag_groups = ([
327                    flag_group(
328                        flags = ctx.attr.unfiltered_compile_flags,
329                    ),
330                ] if ctx.attr.unfiltered_compile_flags else []),
331            ),
332        ],
333    )
334
335    library_search_directories_feature = feature(
336        name = "library_search_directories",
337        flag_sets = [
338            flag_set(
339                actions = all_link_actions + lto_index_actions,
340                flag_groups = [
341                    flag_group(
342                        flags = ["-L%{library_search_directories}"],
343                        iterate_over = "library_search_directories",
344                        expand_if_available = "library_search_directories",
345                    ),
346                ],
347            ),
348        ],
349    )
350
351    static_libgcc_feature = feature(
352        name = "static_libgcc",
353        enabled = True,
354        flag_sets = [
355            flag_set(
356                actions = [
357                    ACTION_NAMES.cpp_link_executable,
358                    ACTION_NAMES.cpp_link_dynamic_library,
359                    ACTION_NAMES.lto_index_for_executable,
360                    ACTION_NAMES.lto_index_for_dynamic_library,
361                ],
362                flag_groups = [flag_group(flags = ["-static-libgcc"])],
363                with_features = [
364                    with_feature_set(features = ["static_link_cpp_runtimes"]),
365                ],
366            ),
367        ],
368    )
369
370    pic_feature = feature(
371        name = "pic",
372        enabled = True,
373        flag_sets = [
374            flag_set(
375                actions = [
376                    ACTION_NAMES.assemble,
377                    ACTION_NAMES.preprocess_assemble,
378                    ACTION_NAMES.linkstamp_compile,
379                    ACTION_NAMES.c_compile,
380                    ACTION_NAMES.cpp_compile,
381                    ACTION_NAMES.cpp_module_codegen,
382                    ACTION_NAMES.cpp_module_compile,
383                ],
384                flag_groups = [
385                    flag_group(flags = ["-fPIC"], expand_if_available = "pic"),
386                ],
387            ),
388        ],
389    )
390
391    per_object_debug_info_feature = feature(
392        name = "per_object_debug_info",
393        flag_sets = [
394            flag_set(
395                actions = [
396                    ACTION_NAMES.assemble,
397                    ACTION_NAMES.preprocess_assemble,
398                    ACTION_NAMES.c_compile,
399                    ACTION_NAMES.cpp_compile,
400                    ACTION_NAMES.cpp_module_codegen,
401                ],
402                flag_groups = [
403                    flag_group(
404                        flags = ["-gsplit-dwarf", "-g"],
405                        expand_if_available = "per_object_debug_info_file",
406                    ),
407                ],
408            ),
409        ],
410    )
411
412    preprocessor_defines_feature = feature(
413        name = "preprocessor_defines",
414        enabled = True,
415        flag_sets = [
416            flag_set(
417                actions = [
418                    ACTION_NAMES.preprocess_assemble,
419                    ACTION_NAMES.linkstamp_compile,
420                    ACTION_NAMES.c_compile,
421                    ACTION_NAMES.cpp_compile,
422                    ACTION_NAMES.cpp_header_parsing,
423                    ACTION_NAMES.cpp_module_compile,
424                    ACTION_NAMES.clif_match,
425                ],
426                flag_groups = [
427                    flag_group(
428                        flags = ["-D%{preprocessor_defines}"],
429                        iterate_over = "preprocessor_defines",
430                    ),
431                ],
432            ),
433        ],
434    )
435
436    cs_fdo_optimize_feature = feature(
437        name = "cs_fdo_optimize",
438        flag_sets = [
439            flag_set(
440                actions = [ACTION_NAMES.lto_backend],
441                flag_groups = [
442                    flag_group(
443                        flags = [
444                            "-fprofile-use=%{fdo_profile_path}",
445                            "-Wno-profile-instr-unprofiled",
446                            "-Wno-profile-instr-out-of-date",
447                            "-fprofile-correction",
448                        ],
449                        expand_if_available = "fdo_profile_path",
450                    ),
451                ],
452            ),
453        ],
454        provides = ["csprofile"],
455    )
456
457    autofdo_feature = feature(
458        name = "autofdo",
459        flag_sets = [
460            flag_set(
461                actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile],
462                flag_groups = [
463                    flag_group(
464                        flags = [
465                            "-fauto-profile=%{fdo_profile_path}",
466                            "-fprofile-correction",
467                        ],
468                        expand_if_available = "fdo_profile_path",
469                    ),
470                ],
471            ),
472        ],
473        provides = ["profile"],
474    )
475
476    runtime_library_search_directories_feature = feature(
477        name = "runtime_library_search_directories",
478        flag_sets = [
479            flag_set(
480                actions = all_link_actions + lto_index_actions,
481                flag_groups = [
482                    flag_group(
483                        iterate_over = "runtime_library_search_directories",
484                        flag_groups = [
485                            flag_group(
486                                flags = [
487                                    "-Wl,-rpath,$EXEC_ORIGIN/%{runtime_library_search_directories}",
488                                ],
489                                expand_if_true = "is_cc_test",
490                            ),
491                            flag_group(
492                                flags = [
493                                    "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}",
494                                ],
495                                expand_if_false = "is_cc_test",
496                            ),
497                        ],
498                        expand_if_available =
499                            "runtime_library_search_directories",
500                    ),
501                ],
502                with_features = [
503                    with_feature_set(features = ["static_link_cpp_runtimes"]),
504                ],
505            ),
506            flag_set(
507                actions = all_link_actions + lto_index_actions,
508                flag_groups = [
509                    flag_group(
510                        iterate_over = "runtime_library_search_directories",
511                        flag_groups = [
512                            flag_group(
513                                flags = [
514                                    "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}",
515                                ],
516                            ),
517                        ],
518                        expand_if_available =
519                            "runtime_library_search_directories",
520                    ),
521                ],
522                with_features = [
523                    with_feature_set(
524                        not_features = ["static_link_cpp_runtimes"],
525                    ),
526                ],
527            ),
528        ],
529    )
530
531    fission_support_feature = feature(
532        name = "fission_support",
533        flag_sets = [
534            flag_set(
535                actions = all_link_actions + lto_index_actions,
536                flag_groups = [
537                    flag_group(
538                        flags = ["-Wl,--gdb-index"],
539                        expand_if_available = "is_using_fission",
540                    ),
541                ],
542            ),
543        ],
544    )
545
546    shared_flag_feature = feature(
547        name = "shared_flag",
548        flag_sets = [
549            flag_set(
550                actions = [
551                    ACTION_NAMES.cpp_link_dynamic_library,
552                    ACTION_NAMES.cpp_link_nodeps_dynamic_library,
553                    ACTION_NAMES.lto_index_for_dynamic_library,
554                    ACTION_NAMES.lto_index_for_nodeps_dynamic_library,
555                ],
556                flag_groups = [flag_group(flags = ["-shared"])],
557            ),
558        ],
559    )
560
561    random_seed_feature = feature(
562        name = "random_seed",
563        enabled = True,
564        flag_sets = [
565            flag_set(
566                actions = [
567                    ACTION_NAMES.c_compile,
568                    ACTION_NAMES.cpp_compile,
569                    ACTION_NAMES.cpp_module_codegen,
570                    ACTION_NAMES.cpp_module_compile,
571                ],
572                flag_groups = [
573                    flag_group(
574                        flags = ["-frandom-seed=%{output_file}"],
575                        expand_if_available = "output_file",
576                    ),
577                ],
578            ),
579        ],
580    )
581
582    includes_feature = feature(
583        name = "includes",
584        enabled = True,
585        flag_sets = [
586            flag_set(
587                actions = [
588                    ACTION_NAMES.preprocess_assemble,
589                    ACTION_NAMES.linkstamp_compile,
590                    ACTION_NAMES.c_compile,
591                    ACTION_NAMES.cpp_compile,
592                    ACTION_NAMES.cpp_header_parsing,
593                    ACTION_NAMES.cpp_module_compile,
594                    ACTION_NAMES.clif_match,
595                    ACTION_NAMES.objc_compile,
596                    ACTION_NAMES.objcpp_compile,
597                ],
598                flag_groups = [
599                    flag_group(
600                        flags = ["-include", "%{includes}"],
601                        iterate_over = "includes",
602                        expand_if_available = "includes",
603                    ),
604                ],
605            ),
606        ],
607    )
608
609    fdo_instrument_feature = feature(
610        name = "fdo_instrument",
611        flag_sets = [
612            flag_set(
613                actions = [
614                    ACTION_NAMES.c_compile,
615                    ACTION_NAMES.cpp_compile,
616                ] + all_link_actions + lto_index_actions,
617                flag_groups = [
618                    flag_group(
619                        flags = [
620                            "-fprofile-generate=%{fdo_instrument_path}",
621                            "-fno-data-sections",
622                        ],
623                        expand_if_available = "fdo_instrument_path",
624                    ),
625                ],
626            ),
627        ],
628        provides = ["profile"],
629    )
630
631    cs_fdo_instrument_feature = feature(
632        name = "cs_fdo_instrument",
633        flag_sets = [
634            flag_set(
635                actions = [
636                    ACTION_NAMES.c_compile,
637                    ACTION_NAMES.cpp_compile,
638                    ACTION_NAMES.lto_backend,
639                ] + all_link_actions + lto_index_actions,
640                flag_groups = [
641                    flag_group(
642                        flags = [
643                            "-fcs-profile-generate=%{cs_fdo_instrument_path}",
644                        ],
645                        expand_if_available = "cs_fdo_instrument_path",
646                    ),
647                ],
648            ),
649        ],
650        provides = ["csprofile"],
651    )
652
653    include_paths_feature = feature(
654        name = "include_paths",
655        enabled = True,
656        flag_sets = [
657            flag_set(
658                actions = [
659                    ACTION_NAMES.preprocess_assemble,
660                    ACTION_NAMES.linkstamp_compile,
661                    ACTION_NAMES.c_compile,
662                    ACTION_NAMES.cpp_compile,
663                    ACTION_NAMES.cpp_header_parsing,
664                    ACTION_NAMES.cpp_module_compile,
665                    ACTION_NAMES.clif_match,
666                    ACTION_NAMES.objc_compile,
667                    ACTION_NAMES.objcpp_compile,
668                ],
669                flag_groups = [
670                    flag_group(
671                        flags = ["-iquote", "%{quote_include_paths}"],
672                        iterate_over = "quote_include_paths",
673                    ),
674                    flag_group(
675                        flags = ["-I%{include_paths}"],
676                        iterate_over = "include_paths",
677                    ),
678                    flag_group(
679                        flags = ["-isystem", "%{system_include_paths}"],
680                        iterate_over = "system_include_paths",
681                    ),
682                ],
683            ),
684        ],
685    )
686
687    external_include_paths_feature = feature(
688        name = "external_include_paths",
689        flag_sets = [
690            flag_set(
691                actions = [
692                    ACTION_NAMES.preprocess_assemble,
693                    ACTION_NAMES.linkstamp_compile,
694                    ACTION_NAMES.c_compile,
695                    ACTION_NAMES.cpp_compile,
696                    ACTION_NAMES.cpp_header_parsing,
697                    ACTION_NAMES.cpp_module_compile,
698                    ACTION_NAMES.clif_match,
699                    ACTION_NAMES.objc_compile,
700                    ACTION_NAMES.objcpp_compile,
701                ],
702                flag_groups = [
703                    flag_group(
704                        flags = ["-isystem", "%{external_include_paths}"],
705                        iterate_over = "external_include_paths",
706                        expand_if_available = "external_include_paths",
707                    ),
708                ],
709            ),
710        ],
711    )
712
713    symbol_counts_feature = feature(
714        name = "symbol_counts",
715        flag_sets = [
716            flag_set(
717                actions = all_link_actions + lto_index_actions,
718                flag_groups = [
719                    flag_group(
720                        flags = [
721                            "-Wl,--print-symbol-counts=%{symbol_counts_output}",
722                        ],
723                        expand_if_available = "symbol_counts_output",
724                    ),
725                ],
726            ),
727        ],
728    )
729
730    llvm_coverage_map_format_feature = feature(
731        name = "llvm_coverage_map_format",
732        flag_sets = [
733            flag_set(
734                actions = [
735                    ACTION_NAMES.preprocess_assemble,
736                    ACTION_NAMES.c_compile,
737                    ACTION_NAMES.cpp_compile,
738                    ACTION_NAMES.cpp_module_compile,
739                    ACTION_NAMES.objc_compile,
740                    ACTION_NAMES.objcpp_compile,
741                ],
742                flag_groups = [
743                    flag_group(
744                        flags = [
745                            "-fprofile-instr-generate",
746                            "-fcoverage-mapping",
747                        ],
748                    ),
749                ],
750            ),
751            flag_set(
752                actions = all_link_actions + lto_index_actions + [
753                    "objc-executable",
754                    "objc++-executable",
755                ],
756                flag_groups = [
757                    flag_group(flags = ["-fprofile-instr-generate"]),
758                ],
759            ),
760        ],
761        requires = [feature_set(features = ["coverage"])],
762        provides = ["profile"],
763    )
764
765    strip_debug_symbols_feature = feature(
766        name = "strip_debug_symbols",
767        flag_sets = [
768            flag_set(
769                actions = all_link_actions + lto_index_actions,
770                flag_groups = [
771                    flag_group(
772                        flags = ["-Wl,-S"],
773                        expand_if_available = "strip_debug_symbols",
774                    ),
775                ],
776            ),
777        ],
778    )
779
780    build_interface_libraries_feature = feature(
781        name = "build_interface_libraries",
782        flag_sets = [
783            flag_set(
784                actions = [
785                    ACTION_NAMES.cpp_link_dynamic_library,
786                    ACTION_NAMES.cpp_link_nodeps_dynamic_library,
787                    ACTION_NAMES.lto_index_for_dynamic_library,
788                    ACTION_NAMES.lto_index_for_nodeps_dynamic_library,
789                ],
790                flag_groups = [
791                    flag_group(
792                        flags = [
793                            "%{generate_interface_library}",
794                            "%{interface_library_builder_path}",
795                            "%{interface_library_input_path}",
796                            "%{interface_library_output_path}",
797                        ],
798                        expand_if_available = "generate_interface_library",
799                    ),
800                ],
801                with_features = [
802                    with_feature_set(
803                        features = ["supports_interface_shared_libraries"],
804                    ),
805                ],
806            ),
807        ],
808    )
809
810    libraries_to_link_feature = feature(
811        name = "libraries_to_link",
812        flag_sets = [
813            flag_set(
814                actions = all_link_actions + lto_index_actions,
815                flag_groups = [
816                    flag_group(
817                        iterate_over = "libraries_to_link",
818                        flag_groups = [
819                            flag_group(
820                                flags = ["-Wl,--start-lib"],
821                                expand_if_equal = variable_with_value(
822                                    name = "libraries_to_link.type",
823                                    value = "object_file_group",
824                                ),
825                            ),
826                            flag_group(
827                                flags = ["-Wl,-whole-archive"],
828                                expand_if_true =
829                                    "libraries_to_link.is_whole_archive",
830                            ),
831                            flag_group(
832                                flags = ["%{libraries_to_link.object_files}"],
833                                iterate_over = "libraries_to_link.object_files",
834                                expand_if_equal = variable_with_value(
835                                    name = "libraries_to_link.type",
836                                    value = "object_file_group",
837                                ),
838                            ),
839                            flag_group(
840                                flags = ["%{libraries_to_link.name}"],
841                                expand_if_equal = variable_with_value(
842                                    name = "libraries_to_link.type",
843                                    value = "object_file",
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 = "interface_library",
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 = "static_library",
858                                ),
859                            ),
860                            flag_group(
861                                flags = ["-l%{libraries_to_link.name}"],
862                                expand_if_equal = variable_with_value(
863                                    name = "libraries_to_link.type",
864                                    value = "dynamic_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 = "versioned_dynamic_library",
872                                ),
873                            ),
874                            flag_group(
875                                flags = ["-Wl,-no-whole-archive"],
876                                expand_if_true = "libraries_to_link.is_whole_archive",
877                            ),
878                            flag_group(
879                                flags = ["-Wl,--end-lib"],
880                                expand_if_equal = variable_with_value(
881                                    name = "libraries_to_link.type",
882                                    value = "object_file_group",
883                                ),
884                            ),
885                        ],
886                        expand_if_available = "libraries_to_link",
887                    ),
888                    flag_group(
889                        flags = ["-Wl,@%{thinlto_param_file}"],
890                        expand_if_true = "thinlto_param_file",
891                    ),
892                ],
893            ),
894        ],
895    )
896
897    user_link_flags_feature = feature(
898        name = "user_link_flags",
899        flag_sets = [
900            flag_set(
901                actions = all_link_actions + lto_index_actions,
902                flag_groups = [
903                    flag_group(
904                        flags = ["%{user_link_flags}"],
905                        iterate_over = "user_link_flags",
906                        expand_if_available = "user_link_flags",
907                    ),
908                ] + ([flag_group(flags = ctx.attr.link_libs)] if ctx.attr.link_libs else []),
909            ),
910        ],
911    )
912
913    fdo_prefetch_hints_feature = feature(
914        name = "fdo_prefetch_hints",
915        flag_sets = [
916            flag_set(
917                actions = [
918                    ACTION_NAMES.c_compile,
919                    ACTION_NAMES.cpp_compile,
920                    ACTION_NAMES.lto_backend,
921                ],
922                flag_groups = [
923                    flag_group(
924                        flags = [
925                            "-mllvm",
926                            "-prefetch-hints-file=%{fdo_prefetch_hints_path}",
927                        ],
928                        expand_if_available = "fdo_prefetch_hints_path",
929                    ),
930                ],
931            ),
932        ],
933    )
934
935    linkstamps_feature = feature(
936        name = "linkstamps",
937        flag_sets = [
938            flag_set(
939                actions = all_link_actions + lto_index_actions,
940                flag_groups = [
941                    flag_group(
942                        flags = ["%{linkstamp_paths}"],
943                        iterate_over = "linkstamp_paths",
944                        expand_if_available = "linkstamp_paths",
945                    ),
946                ],
947            ),
948        ],
949    )
950
951    gcc_coverage_map_format_feature = feature(
952        name = "gcc_coverage_map_format",
953        flag_sets = [
954            flag_set(
955                actions = [
956                    ACTION_NAMES.preprocess_assemble,
957                    ACTION_NAMES.c_compile,
958                    ACTION_NAMES.cpp_compile,
959                    ACTION_NAMES.cpp_module_compile,
960                    ACTION_NAMES.objc_compile,
961                    ACTION_NAMES.objcpp_compile,
962                    "objc-executable",
963                    "objc++-executable",
964                ],
965                flag_groups = [
966                    flag_group(
967                        flags = ["-fprofile-arcs", "-ftest-coverage"],
968                        expand_if_available = "gcov_gcno_file",
969                    ),
970                ],
971            ),
972            flag_set(
973                actions = all_link_actions + lto_index_actions,
974                flag_groups = [flag_group(flags = ["--coverage"])],
975            ),
976        ],
977        requires = [feature_set(features = ["coverage"])],
978        provides = ["profile"],
979    )
980
981    archiver_flags_feature = feature(
982        name = "archiver_flags",
983        flag_sets = [
984            flag_set(
985                actions = [ACTION_NAMES.cpp_link_static_library],
986                flag_groups = [
987                    flag_group(flags = ["rcsD"]),
988                    flag_group(
989                        flags = ["%{output_execpath}"],
990                        expand_if_available = "output_execpath",
991                    ),
992                ],
993            ),
994            flag_set(
995                actions = [ACTION_NAMES.cpp_link_static_library],
996                flag_groups = [
997                    flag_group(
998                        iterate_over = "libraries_to_link",
999                        flag_groups = [
1000                            flag_group(
1001                                flags = ["%{libraries_to_link.name}"],
1002                                expand_if_equal = variable_with_value(
1003                                    name = "libraries_to_link.type",
1004                                    value = "object_file",
1005                                ),
1006                            ),
1007                            flag_group(
1008                                flags = ["%{libraries_to_link.object_files}"],
1009                                iterate_over = "libraries_to_link.object_files",
1010                                expand_if_equal = variable_with_value(
1011                                    name = "libraries_to_link.type",
1012                                    value = "object_file_group",
1013                                ),
1014                            ),
1015                        ],
1016                        expand_if_available = "libraries_to_link",
1017                    ),
1018                ],
1019            ),
1020        ],
1021    )
1022
1023    force_pic_flags_feature = feature(
1024        name = "force_pic_flags",
1025        flag_sets = [
1026            flag_set(
1027                actions = [
1028                    ACTION_NAMES.cpp_link_executable,
1029                    ACTION_NAMES.lto_index_for_executable,
1030                ],
1031                flag_groups = [
1032                    flag_group(
1033                        flags = ["-pie"],
1034                        expand_if_available = "force_pic",
1035                    ),
1036                ],
1037            ),
1038        ],
1039    )
1040
1041    dependency_file_feature = feature(
1042        name = "dependency_file",
1043        enabled = True,
1044        flag_sets = [
1045            flag_set(
1046                actions = [
1047                    ACTION_NAMES.assemble,
1048                    ACTION_NAMES.preprocess_assemble,
1049                    ACTION_NAMES.c_compile,
1050                    ACTION_NAMES.cpp_compile,
1051                    ACTION_NAMES.cpp_module_compile,
1052                    ACTION_NAMES.objc_compile,
1053                    ACTION_NAMES.objcpp_compile,
1054                    ACTION_NAMES.cpp_header_parsing,
1055                    ACTION_NAMES.clif_match,
1056                ],
1057                flag_groups = [
1058                    flag_group(
1059                        flags = ["-MD", "-MF", "%{dependency_file}"],
1060                        expand_if_available = "dependency_file",
1061                    ),
1062                ],
1063            ),
1064        ],
1065    )
1066
1067    serialized_diagnostics_file_feature = feature(
1068        name = "serialized_diagnostics_file",
1069        flag_sets = [
1070            flag_set(
1071                actions = [
1072                    ACTION_NAMES.assemble,
1073                    ACTION_NAMES.preprocess_assemble,
1074                    ACTION_NAMES.c_compile,
1075                    ACTION_NAMES.cpp_compile,
1076                    ACTION_NAMES.cpp_module_compile,
1077                    ACTION_NAMES.objc_compile,
1078                    ACTION_NAMES.objcpp_compile,
1079                    ACTION_NAMES.cpp_header_parsing,
1080                    ACTION_NAMES.clif_match,
1081                ],
1082                flag_groups = [
1083                    flag_group(
1084                        flags = ["--serialize-diagnostics", "%{serialized_diagnostics_file}"],
1085                        expand_if_available = "serialized_diagnostics_file",
1086                    ),
1087                ],
1088            ),
1089        ],
1090    )
1091
1092    dynamic_library_linker_tool_path = tool_paths
1093    dynamic_library_linker_tool_feature = feature(
1094        name = "dynamic_library_linker_tool",
1095        flag_sets = [
1096            flag_set(
1097                actions = [
1098                    ACTION_NAMES.cpp_link_dynamic_library,
1099                    ACTION_NAMES.cpp_link_nodeps_dynamic_library,
1100                    ACTION_NAMES.lto_index_for_dynamic_library,
1101                    ACTION_NAMES.lto_index_for_nodeps_dynamic_library,
1102                ],
1103                flag_groups = [
1104                    flag_group(
1105                        flags = [" + cppLinkDynamicLibraryToolPath + "],
1106                        expand_if_available = "generate_interface_library",
1107                    ),
1108                ],
1109                with_features = [
1110                    with_feature_set(
1111                        features = ["supports_interface_shared_libraries"],
1112                    ),
1113                ],
1114            ),
1115        ],
1116    )
1117
1118    output_execpath_flags_feature = feature(
1119        name = "output_execpath_flags",
1120        flag_sets = [
1121            flag_set(
1122                actions = all_link_actions + lto_index_actions,
1123                flag_groups = [
1124                    flag_group(
1125                        flags = ["-o", "%{output_execpath}"],
1126                        expand_if_available = "output_execpath",
1127                    ),
1128                ],
1129            ),
1130        ],
1131    )
1132
1133    # Note that we also set --coverage for c++-link-nodeps-dynamic-library. The
1134    # generated code contains references to gcov symbols, and the dynamic linker
1135    # can't resolve them unless the library is linked against gcov.
1136    coverage_feature = feature(
1137        name = "coverage",
1138        provides = ["profile"],
1139        flag_sets = [
1140            flag_set(
1141                actions = [
1142                    ACTION_NAMES.preprocess_assemble,
1143                    ACTION_NAMES.c_compile,
1144                    ACTION_NAMES.cpp_compile,
1145                    ACTION_NAMES.cpp_header_parsing,
1146                    ACTION_NAMES.cpp_module_compile,
1147                ],
1148                flag_groups = ([
1149                    flag_group(flags = ctx.attr.coverage_compile_flags),
1150                ] if ctx.attr.coverage_compile_flags else []),
1151            ),
1152            flag_set(
1153                actions = all_link_actions + lto_index_actions,
1154                flag_groups = ([
1155                    flag_group(flags = ctx.attr.coverage_link_flags),
1156                ] if ctx.attr.coverage_link_flags else []),
1157            ),
1158        ],
1159    )
1160
1161    thinlto_feature = feature(
1162        name = "thin_lto",
1163        flag_sets = [
1164            flag_set(
1165                actions = [
1166                    ACTION_NAMES.c_compile,
1167                    ACTION_NAMES.cpp_compile,
1168                ] + all_link_actions + lto_index_actions,
1169                flag_groups = [
1170                    flag_group(flags = ["-flto=thin"]),
1171                    flag_group(
1172                        expand_if_available = "lto_indexing_bitcode_file",
1173                        flags = [
1174                            "-Xclang",
1175                            "-fthin-link-bitcode=%{lto_indexing_bitcode_file}",
1176                        ],
1177                    ),
1178                ],
1179            ),
1180            flag_set(
1181                actions = [ACTION_NAMES.linkstamp_compile],
1182                flag_groups = [flag_group(flags = ["-DBUILD_LTO_TYPE=thin"])],
1183            ),
1184            flag_set(
1185                actions = lto_index_actions,
1186                flag_groups = [
1187                    flag_group(flags = [
1188                        "-flto=thin",
1189                        "-Wl,-plugin-opt,thinlto-index-only%{thinlto_optional_params_file}",
1190                        "-Wl,-plugin-opt,thinlto-emit-imports-files",
1191                        "-Wl,-plugin-opt,thinlto-prefix-replace=%{thinlto_prefix_replace}",
1192                    ]),
1193                    flag_group(
1194                        expand_if_available = "thinlto_object_suffix_replace",
1195                        flags = [
1196                            "-Wl,-plugin-opt,thinlto-object-suffix-replace=%{thinlto_object_suffix_replace}",
1197                        ],
1198                    ),
1199                    flag_group(
1200                        expand_if_available = "thinlto_merged_object_file",
1201                        flags = [
1202                            "-Wl,-plugin-opt,obj-path=%{thinlto_merged_object_file}",
1203                        ],
1204                    ),
1205                ],
1206            ),
1207            flag_set(
1208                actions = [ACTION_NAMES.lto_backend],
1209                flag_groups = [
1210                    flag_group(flags = [
1211                        "-c",
1212                        "-fthinlto-index=%{thinlto_index}",
1213                        "-o",
1214                        "%{thinlto_output_object_file}",
1215                        "-x",
1216                        "ir",
1217                        "%{thinlto_input_bitcode_file}",
1218                    ]),
1219                ],
1220            ),
1221        ],
1222    )
1223
1224    is_linux = ctx.attr.target_libc != "macosx"
1225
1226    # TODO(#8303): Mac crosstool should also declare every feature.
1227    if is_linux:
1228        features = [
1229            dependency_file_feature,
1230            serialized_diagnostics_file_feature,
1231            random_seed_feature,
1232            pic_feature,
1233            per_object_debug_info_feature,
1234            preprocessor_defines_feature,
1235            includes_feature,
1236            include_paths_feature,
1237            external_include_paths_feature,
1238            fdo_instrument_feature,
1239            cs_fdo_instrument_feature,
1240            cs_fdo_optimize_feature,
1241            thinlto_feature,
1242            fdo_prefetch_hints_feature,
1243            autofdo_feature,
1244            build_interface_libraries_feature,
1245            dynamic_library_linker_tool_feature,
1246            symbol_counts_feature,
1247            shared_flag_feature,
1248            linkstamps_feature,
1249            output_execpath_flags_feature,
1250            runtime_library_search_directories_feature,
1251            library_search_directories_feature,
1252            archiver_flags_feature,
1253            force_pic_flags_feature,
1254            fission_support_feature,
1255            strip_debug_symbols_feature,
1256            coverage_feature,
1257            supports_pic_feature,
1258        ] + (
1259            [
1260                supports_start_end_lib_feature,
1261            ] if ctx.attr.supports_start_end_lib else []
1262        ) + [
1263            default_compile_flags_feature,
1264            default_link_flags_feature,
1265            libraries_to_link_feature,
1266            user_link_flags_feature,
1267            static_libgcc_feature,
1268            fdo_optimize_feature,
1269            supports_dynamic_linker_feature,
1270            dbg_feature,
1271            opt_feature,
1272            user_compile_flags_feature,
1273            sysroot_feature,
1274            unfiltered_compile_flags_feature,
1275        ] + layering_check_features(ctx.attr.compiler)
1276    else:
1277        features = [
1278            supports_pic_feature,
1279        ] + (
1280            [
1281                supports_start_end_lib_feature,
1282            ] if ctx.attr.supports_start_end_lib else []
1283        ) + [
1284            coverage_feature,
1285            default_compile_flags_feature,
1286            default_link_flags_feature,
1287            user_link_flags_feature,
1288            fdo_optimize_feature,
1289            supports_dynamic_linker_feature,
1290            dbg_feature,
1291            opt_feature,
1292            user_compile_flags_feature,
1293            sysroot_feature,
1294            unfiltered_compile_flags_feature,
1295        ] + layering_check_features(ctx.attr.compiler)
1296
1297    return cc_common.create_cc_toolchain_config_info(
1298        ctx = ctx,
1299        features = features,
1300        action_configs = action_configs,
1301        cxx_builtin_include_directories = ctx.attr.cxx_builtin_include_directories,
1302        toolchain_identifier = ctx.attr.toolchain_identifier,
1303        host_system_name = ctx.attr.host_system_name,
1304        target_system_name = ctx.attr.target_system_name,
1305        target_cpu = ctx.attr.cpu,
1306        target_libc = ctx.attr.target_libc,
1307        compiler = ctx.attr.compiler,
1308        abi_version = ctx.attr.abi_version,
1309        abi_libc_version = ctx.attr.abi_libc_version,
1310        tool_paths = tool_paths,
1311        builtin_sysroot = ctx.attr.builtin_sysroot,
1312    )
1313
1314cc_toolchain_config = rule(
1315    implementation = _impl,
1316    attrs = {
1317        "cpu": attr.string(mandatory = True),
1318        "compiler": attr.string(mandatory = True),
1319        "toolchain_identifier": attr.string(mandatory = True),
1320        "host_system_name": attr.string(mandatory = True),
1321        "target_system_name": attr.string(mandatory = True),
1322        "target_libc": attr.string(mandatory = True),
1323        "abi_version": attr.string(mandatory = True),
1324        "abi_libc_version": attr.string(mandatory = True),
1325        "cxx_builtin_include_directories": attr.string_list(),
1326        "tool_paths": attr.string_dict(),
1327        "compile_flags": attr.string_list(),
1328        "dbg_compile_flags": attr.string_list(),
1329        "opt_compile_flags": attr.string_list(),
1330        "cxx_flags": attr.string_list(),
1331        "link_flags": attr.string_list(),
1332        "link_libs": attr.string_list(),
1333        "opt_link_flags": attr.string_list(),
1334        "unfiltered_compile_flags": attr.string_list(),
1335        "coverage_compile_flags": attr.string_list(),
1336        "coverage_link_flags": attr.string_list(),
1337        "supports_start_end_lib": attr.bool(),
1338        "builtin_sysroot": attr.string(),
1339    },
1340    provides = [CcToolchainConfigInfo],
1341)
1342