diff --git a/toolchains/cxx.bzl b/toolchains/cxx.bzl index 437547d01..4d9f69b0f 100644 --- a/toolchains/cxx.bzl +++ b/toolchains/cxx.bzl @@ -22,52 +22,74 @@ load("@prelude//cxx:headers.bzl", "HeaderMode") load("@prelude//cxx:linker.bzl", "is_pdb_generated") load("@prelude//linking:link_info.bzl", "LinkOrdering", "LinkStyle") load("@prelude//linking:lto.bzl", "LtoMode") -load("@prelude//toolchains/msvc:tools.bzl", "VisualStudio") -load("@prelude//utils:cmd_script.bzl", "ScriptOs", "cmd_script") +load("@prelude//os_lookup:defs.bzl", "OsLookup") +load("@prelude//decls/common.bzl", "buck") + +CxxToolsInfo = provider( + fields = { + "archiver": provider_field(typing.Any, default = None), + "archiver_type": provider_field(typing.Any, default = None), + "asm_compiler": provider_field(typing.Any, default = None), + "asm_compiler_type": provider_field(typing.Any, default = None), + "compiler": provider_field(typing.Any, default = None), + "compiler_type": provider_field(typing.Any, default = None), + "cvtres_compiler": provider_field(typing.Any, default = None), + "cxx_compiler": provider_field(typing.Any, default = None), + "linker": provider_field(typing.Any, default = None), + "linker_type": provider_field(typing.Any, default = None), + "rc_compiler": provider_field(typing.Any, default = None), + }, +) + +def _legacy_equivalent_cxx_tools_info_windows(ctx: AnalysisContext, default_toolchain: CxxToolsInfo) -> CxxToolsInfo: + return CxxToolsInfo( + compiler = default_toolchain.compiler if ctx.attrs.compiler == None or ctx.attrs.compiler == "cl.exe" else ctx.attrs.compiler, + compiler_type = default_toolchain.compiler_type if ctx.attrs.compiler_type == None else ctx.attrs.compiler_type, + cxx_compiler = default_toolchain.cxx_compiler if ctx.attrs.compiler == None or ctx.attrs.compiler == "cl.exe" else ctx.attrs.compiler, + asm_compiler = default_toolchain.asm_compiler, + asm_compiler_type = default_toolchain.asm_compiler_type, + rc_compiler = default_toolchain.rc_compiler if ctx.attrs.rc_compiler == None or ctx.attrs.rc_compiler == "rc.exe" else ctx.attrs.rc_compiler, + cvtres_compiler = default_toolchain.cvtres_compiler if ctx.attrs.cvtres_compiler == None or ctx.attrs.cvtres_compiler == "cvtres.exe" else ctx.attrs.cvtres_compiler, + archiver = default_toolchain.archiver, + archiver_type = default_toolchain.archiver_type, + linker = default_toolchain.linker if ctx.attrs.linker == None or ctx.attrs.linker == "link.exe" else ctx.attrs.linker, + linker_type = default_toolchain.linker_type, + ) + +def _legacy_equivalent_cxx_tools_info_non_windows(ctx: AnalysisContext, default_toolchain: CxxToolsInfo) -> CxxToolsInfo: + return CxxToolsInfo( + compiler = default_toolchain.compiler if ctx.attrs.compiler == None else ctx.attrs.compiler, + compiler_type = default_toolchain.compiler_type if ctx.attrs.compiler_type == None else ctx.attrs.compiler_type, + cxx_compiler = default_toolchain.cxx_compiler if ctx.attrs.cxx_compiler == None else ctx.attrs.cxx_compiler, + asm_compiler = default_toolchain.asm_compiler if ctx.attrs.compiler == None else ctx.attrs.compiler, + asm_compiler_type = default_toolchain.asm_compiler_type if ctx.attrs.compiler_type == None else ctx.attrs.compiler_type, + rc_compiler = default_toolchain.rc_compiler if ctx.attrs.rc_compiler == None else ctx.attrs.rc_compiler, + cvtres_compiler = default_toolchain.cvtres_compiler if ctx.attrs.cvtres_compiler == None else ctx.attrs.cvtres_compiler, + archiver = default_toolchain.archiver, + archiver_type = default_toolchain.archiver_type, + linker = default_toolchain.linker if ctx.attrs.linker == None else ctx.attrs.linker, + linker_type = default_toolchain.linker_type, + ) def _system_cxx_toolchain_impl(ctx: AnalysisContext): """ A very simple toolchain that is hardcoded to the current environment. """ - archiver_args = ["ar"] - archiver_type = "gnu" - archiver_supports_argfiles = True - asm_compiler = ctx.attrs.compiler - asm_compiler_type = ctx.attrs.compiler_type - compiler = ctx.attrs.compiler - cxx_compiler = ctx.attrs.cxx_compiler - cvtres_compiler = ctx.attrs.cvtres_compiler - rc_compiler = ctx.attrs.rc_compiler - linker = ctx.attrs.linker - linker_type = "gnu" - pic_behavior = PicBehavior("supported") - binary_extension = "" - object_file_extension = "o" - static_library_extension = "a" - shared_library_name_default_prefix = "lib" - shared_library_name_format = "{}.so" - shared_library_versioned_name_format = "{}.so.{}" - additional_linker_flags = [] - if host_info().os.is_macos: - archiver_supports_argfiles = False - linker_type = "darwin" - pic_behavior = PicBehavior("always_enabled") - elif host_info().os.is_windows: - msvc_tools = ctx.attrs.msvc_tools[VisualStudio] - archiver_args = [msvc_tools.lib_exe] - archiver_type = "windows" - asm_compiler = msvc_tools.ml64_exe - asm_compiler_type = "windows_ml64" - if compiler == "cl.exe": - compiler = msvc_tools.cl_exe - cxx_compiler = compiler - if cvtres_compiler == "cvtres.exe": - cvtres_compiler = msvc_tools.cvtres_exe - if rc_compiler == "rc.exe": - rc_compiler = msvc_tools.rc_exe - if linker == "link.exe": - linker = msvc_tools.link_exe - linker = _windows_linker_wrapper(ctx, linker) + + os = ctx.attrs._target_os_type[OsLookup].platform + cxx_tools_info = ctx.attrs._cxx_tools_info[CxxToolsInfo] + cxx_tools_info = _legacy_equivalent_cxx_tools_info_windows(ctx, cxx_tools_info) if os == "windows" else _legacy_equivalent_cxx_tools_info_non_windows(ctx, cxx_tools_info) + return _cxx_toolchain_from_cxx_tools_info(ctx, cxx_tools_info) + +def _cxx_tools_info_toolchain_impl(ctx: AnalysisContext): + return _cxx_toolchain_from_cxx_tools_info(ctx, ctx.attrs.cxx_tools_info[CxxToolsInfo]) + +def _cxx_toolchain_from_cxx_tools_info(ctx: AnalysisContext, cxx_tools_info: CxxToolsInfo): + os = ctx.attrs._target_os_type[OsLookup].platform + archiver_supports_argfiles = os != "macos" + additional_linker_flags = ["-fuse-ld=lld"] if os == "linux" and cxx_tools_info.linker != "g++" and cxx_tools_info.cxx_compiler != "g++" else [] + + if os == "windows": linker_type = "windows" binary_extension = "exe" object_file_extension = "obj" @@ -76,12 +98,22 @@ def _system_cxx_toolchain_impl(ctx: AnalysisContext): shared_library_name_format = "{}.dll" shared_library_versioned_name_format = "{}.dll" pic_behavior = PicBehavior("not_supported") - elif ctx.attrs.linker == "g++" or ctx.attrs.cxx_compiler == "g++": - pass else: - additional_linker_flags = ["-fuse-ld=lld"] + binary_extension = "" + object_file_extension = "o" + static_library_extension = "a" + shared_library_name_default_prefix = "lib" + shared_library_name_format = "{}.so" + shared_library_versioned_name_format = "{}.so.{}" + + if os == "macos": + linker_type = "darwin" + pic_behavior = PicBehavior("always_enabled") + else: + linker_type = "gnu" + pic_behavior = PicBehavior("supported") - if ctx.attrs.compiler_type == "clang": + if cxx_tools_info.compiler_type == "clang": llvm_link = RunInfo(args = ["llvm-link"]) else: llvm_link = None @@ -91,16 +123,17 @@ def _system_cxx_toolchain_impl(ctx: AnalysisContext): CxxToolchainInfo( mk_comp_db = ctx.attrs.make_comp_db, linker_info = LinkerInfo( - linker = RunInfo(args = linker), + linker = _run_info(cxx_tools_info.linker), linker_flags = additional_linker_flags + ctx.attrs.link_flags, post_linker_flags = ctx.attrs.post_link_flags, - archiver = RunInfo(args = archiver_args), - archiver_type = archiver_type, + archiver = _run_info(cxx_tools_info.archiver), + archiver_type = cxx_tools_info.archiver_type, archiver_supports_argfiles = archiver_supports_argfiles, generate_linker_maps = False, lto_mode = LtoMode("none"), type = linker_type, link_binaries_locally = True, + link_libraries_locally = True, archive_objects_locally = True, use_archiver_flags = True, static_dep_runtime_ld_flags = [], @@ -131,36 +164,36 @@ def _system_cxx_toolchain_impl(ctx: AnalysisContext): bolt_msdk = None, ), cxx_compiler_info = CxxCompilerInfo( - compiler = RunInfo(args = [cxx_compiler]), + compiler = _run_info(cxx_tools_info.cxx_compiler), preprocessor_flags = [], compiler_flags = ctx.attrs.cxx_flags, - compiler_type = ctx.attrs.compiler_type, + compiler_type = cxx_tools_info.compiler_type, ), c_compiler_info = CCompilerInfo( - compiler = RunInfo(args = [compiler]), + compiler = _run_info(cxx_tools_info.compiler), preprocessor_flags = [], compiler_flags = ctx.attrs.c_flags, - compiler_type = ctx.attrs.compiler_type, + compiler_type = cxx_tools_info.compiler_type, ), as_compiler_info = CCompilerInfo( - compiler = RunInfo(args = [compiler]), - compiler_type = ctx.attrs.compiler_type, + compiler = _run_info(cxx_tools_info.compiler), + compiler_type = cxx_tools_info.compiler_type, ), asm_compiler_info = CCompilerInfo( - compiler = RunInfo(args = [asm_compiler]), - compiler_type = asm_compiler_type, + compiler = _run_info(cxx_tools_info.asm_compiler), + compiler_type = cxx_tools_info.asm_compiler_type, ), cvtres_compiler_info = CvtresCompilerInfo( - compiler = RunInfo(args = [cvtres_compiler]), + compiler = _run_info(cxx_tools_info.cvtres_compiler), preprocessor_flags = [], compiler_flags = ctx.attrs.cvtres_flags, - compiler_type = ctx.attrs.compiler_type, + compiler_type = cxx_tools_info.compiler_type, ), rc_compiler_info = RcCompilerInfo( - compiler = RunInfo(args = [rc_compiler]), + compiler = _run_info(cxx_tools_info.rc_compiler), preprocessor_flags = [], compiler_flags = ctx.attrs.rc_flags, - compiler_type = ctx.attrs.compiler_type, + compiler_type = cxx_tools_info.compiler_type, ), header_mode = HeaderMode("symlink_tree_only"), cpp_dep_tracking_mode = ctx.attrs.cpp_dep_tracking_mode, @@ -170,50 +203,52 @@ def _system_cxx_toolchain_impl(ctx: AnalysisContext): CxxPlatformInfo(name = "x86_64"), ] -def _windows_linker_wrapper(ctx: AnalysisContext, linker: cmd_args) -> cmd_args: - # Linkers pretty much all support @file.txt argument syntax to insert - # arguments from the given text file, usually formatted one argument per - # line. - # - # - GNU ld: https://gcc.gnu.org/onlinedocs/gcc/Overall-Options.html - # - lld is command line compatible with GNU ld - # - MSVC link.exe: https://learn.microsoft.com/en-us/cpp/build/reference/linking?view=msvc-170#link-command-files - # - # However, there is inconsistency in whether they support nesting of @file - # arguments inside of another @file. - # - # We wrap the linker to flatten @file arguments down to 1 level of nesting. - return cmd_script( - ctx = ctx, - name = "windows_linker", - cmd = cmd_args( - ctx.attrs.linker_wrapper[RunInfo], - linker, - ), - os = ScriptOs("windows"), - ) +def _run_info(args): + return None if args == None else RunInfo(args = [args]) system_cxx_toolchain = rule( impl = _system_cxx_toolchain_impl, attrs = { "c_flags": attrs.list(attrs.string(), default = []), - "compiler": attrs.string(default = "cl.exe" if host_info().os.is_windows else "clang"), - "compiler_type": attrs.string(default = "windows" if host_info().os.is_windows else "clang"), # one of CxxToolProviderType + "compiler": attrs.option(attrs.string(), default = None), + "compiler_type": attrs.option(attrs.string(), default = None), # one of CxxToolProviderType + "cpp_dep_tracking_mode": attrs.string(default = "makefile"), + "cvtres_compiler": attrs.option(attrs.string(), default = None), + "cvtres_flags": attrs.list(attrs.string(), default = []), + "cxx_compiler": attrs.option(attrs.string(), default = None), + "cxx_flags": attrs.list(attrs.string(), default = []), + "link_flags": attrs.list(attrs.string(), default = []), + "link_ordering": attrs.option(attrs.enum(LinkOrdering.values()), default = None), + "link_style": attrs.string(default = "shared"), + "linker": attrs.option(attrs.string(), default = None), + "make_comp_db": attrs.default_only(attrs.exec_dep(providers = [RunInfo], default = "prelude//cxx/tools:make_comp_db")), + "post_link_flags": attrs.list(attrs.string(), default = []), + "rc_compiler": attrs.option(attrs.string(), default = None), + "rc_flags": attrs.list(attrs.string(), default = []), + "_cxx_tools_info": attrs.exec_dep(providers = [CxxToolsInfo], default = "prelude//toolchains/msvc:msvc_tools" if host_info().os.is_windows else "prelude//toolchains/cxx/clang:path_clang_tools"), + "_target_os_type": buck.target_os_type_arg(), + }, + is_toolchain_rule = True, +) + +cxx_tools_info_toolchain = rule( + impl = _cxx_tools_info_toolchain_impl, + attrs = { + "c_flags": attrs.list(attrs.string(), default = []), "cpp_dep_tracking_mode": attrs.string(default = "makefile"), - "cvtres_compiler": attrs.string(default = "cvtres.exe"), "cvtres_flags": attrs.list(attrs.string(), default = []), - "cxx_compiler": attrs.string(default = "cl.exe" if host_info().os.is_windows else "clang++"), "cxx_flags": attrs.list(attrs.string(), default = []), + "cxx_tools_info": attrs.exec_dep(providers = [CxxToolsInfo], default = select({ + "DEFAULT": "prelude//toolchains/cxx/clang:path_clang_tools", + "config//os:windows": "prelude//toolchains/msvc:msvc_tools", + })), "link_flags": attrs.list(attrs.string(), default = []), "link_ordering": attrs.option(attrs.enum(LinkOrdering.values()), default = None), "link_style": attrs.string(default = "shared"), - "linker": attrs.string(default = "link.exe" if host_info().os.is_windows else "clang++"), - "linker_wrapper": attrs.default_only(attrs.exec_dep(providers = [RunInfo], default = "prelude//cxx/tools:linker_wrapper")), "make_comp_db": attrs.default_only(attrs.exec_dep(providers = [RunInfo], default = "prelude//cxx/tools:make_comp_db")), - "msvc_tools": attrs.default_only(attrs.exec_dep(providers = [VisualStudio], default = "prelude//toolchains/msvc:msvc_tools")), "post_link_flags": attrs.list(attrs.string(), default = []), - "rc_compiler": attrs.string(default = "rc.exe"), "rc_flags": attrs.list(attrs.string(), default = []), + "_target_os_type": buck.target_os_type_arg(), }, is_toolchain_rule = True, ) diff --git a/toolchains/cxx/clang/BUCK b/toolchains/cxx/clang/BUCK new file mode 100644 index 000000000..9a1337a44 --- /dev/null +++ b/toolchains/cxx/clang/BUCK @@ -0,0 +1,11 @@ +load("@prelude//utils:source_listing.bzl", "source_listing") +load(":tools.bzl", "path_clang_tools") + +oncall("build_infra") + +source_listing() + +path_clang_tools( + name = "path_clang_tools", + visibility = ["PUBLIC"], +) diff --git a/toolchains/cxx/clang/tools.bzl b/toolchains/cxx/clang/tools.bzl new file mode 100644 index 000000000..ac85a344b --- /dev/null +++ b/toolchains/cxx/clang/tools.bzl @@ -0,0 +1,31 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under both the MIT license found in the +# LICENSE-MIT file in the root directory of this source tree and the Apache +# License, Version 2.0 found in the LICENSE-APACHE file in the root directory +# of this source tree. + +load("@prelude//toolchains:cxx.bzl", "CxxToolsInfo") + +def _path_clang_tools_impl(_ctx) -> list[Provider]: + return [ + DefaultInfo(), + CxxToolsInfo( + compiler = "clang", + compiler_type = "clang", + cxx_compiler = "clang++", + asm_compiler = "clang", + asm_compiler_type = "clang", + rc_compiler = None, + cvtres_compiler = None, + archiver = "ar", + archiver_type = "gnu", + linker = "clang++", + linker_type = "gnu", + ), + ] + +path_clang_tools = rule( + impl = _path_clang_tools_impl, + attrs = {}, +) diff --git a/toolchains/msvc/BUCK.v2 b/toolchains/msvc/BUCK.v2 index beea9a306..42d4db537 100644 --- a/toolchains/msvc/BUCK.v2 +++ b/toolchains/msvc/BUCK.v2 @@ -8,16 +8,17 @@ source_listing() python_bootstrap_binary( name = "vswhere", main = "vswhere.py", - visibility = [], + visibility = ["PUBLIC"], ) python_bootstrap_binary( name = "run_msvc_tool", main = "run_msvc_tool.py", - visibility = [], + visibility = ["PUBLIC"], ) find_msvc_tools( name = "msvc_tools", + target_compatible_with = ["config//os:windows"], visibility = ["PUBLIC"], ) diff --git a/toolchains/msvc/tools.bzl b/toolchains/msvc/tools.bzl index 199065fb9..e5b058194 100644 --- a/toolchains/msvc/tools.bzl +++ b/toolchains/msvc/tools.bzl @@ -5,26 +5,9 @@ # License, Version 2.0 found in the LICENSE-APACHE file in the root directory # of this source tree. +load("@prelude//toolchains:cxx.bzl", "CxxToolsInfo") load("@prelude//utils:cmd_script.bzl", "ScriptOs", "cmd_script") -VisualStudio = provider( - # @unsorted-dict-items - fields = { - # cl.exe - "cl_exe": provider_field(typing.Any, default = None), - # cvtres.exe - "cvtres_exe": provider_field(typing.Any, default = None), - # lib.exe - "lib_exe": provider_field(typing.Any, default = None), - # ml64.exe - "ml64_exe": provider_field(typing.Any, default = None), - # link.exe - "link_exe": provider_field(typing.Any, default = None), - # rc.exe - "rc_exe": provider_field(typing.Any, default = None), - }, -) - def _find_msvc_tools_impl(ctx: AnalysisContext) -> list[Provider]: cl_exe_json = ctx.actions.declare_output("cl.exe.json") cvtres_exe_json = ctx.actions.declare_output("cvtres.exe.json") @@ -50,42 +33,53 @@ def _find_msvc_tools_impl(ctx: AnalysisContext) -> list[Provider]: ) run_msvc_tool = ctx.attrs.run_msvc_tool[RunInfo] - cl_exe_script = cmd_script( - ctx = ctx, - name = "cl", - cmd = cmd_args(run_msvc_tool, cl_exe_json), - os = ScriptOs("windows"), - ) - cvtres_exe_script = cmd_script( - ctx = ctx, - name = "cvtres", - cmd = cmd_args(run_msvc_tool, cvtres_exe_json), - os = ScriptOs("windows"), - ) - lib_exe_script = cmd_script( - ctx = ctx, - name = "lib", - cmd = cmd_args(run_msvc_tool, lib_exe_json), - os = ScriptOs("windows"), - ) - ml64_exe_script = cmd_script( - ctx = ctx, - name = "ml64", - cmd = cmd_args(run_msvc_tool, ml64_exe_json), - os = ScriptOs("windows"), - ) - link_exe_script = cmd_script( - ctx = ctx, - name = "link", - cmd = cmd_args(run_msvc_tool, link_exe_json), - os = ScriptOs("windows"), - ) - rc_exe_script = cmd_script( - ctx = ctx, - name = "rc", - cmd = cmd_args(run_msvc_tool, rc_exe_json), - os = ScriptOs("windows"), - ) + if ctx.attrs.use_path_compilers: + cl_exe_script = "cl.exe" + ml64_exe_script = "ml64.exe" + rc_exe_script = "rc.exe" + cvtres_exe_script = "cvtres.exe" + else: + cl_exe_script = cmd_script( + ctx = ctx, + name = "cl", + cmd = cmd_args(run_msvc_tool, cl_exe_json), + os = ScriptOs("windows"), + ) + cvtres_exe_script = cmd_script( + ctx = ctx, + name = "cvtres", + cmd = cmd_args(run_msvc_tool, cvtres_exe_json), + os = ScriptOs("windows"), + ) + ml64_exe_script = cmd_script( + ctx = ctx, + name = "ml64", + cmd = cmd_args(run_msvc_tool, ml64_exe_json), + os = ScriptOs("windows"), + ) + rc_exe_script = cmd_script( + ctx = ctx, + name = "rc", + cmd = cmd_args(run_msvc_tool, rc_exe_json), + os = ScriptOs("windows"), + ) + + if ctx.attrs.use_path_linkers: + lib_exe_script = "lib.exe" + link_exe_script = "link.exe" + else: + lib_exe_script = cmd_script( + ctx = ctx, + name = "lib", + cmd = cmd_args(run_msvc_tool, lib_exe_json), + os = ScriptOs("windows"), + ) + link_exe_script = cmd_script( + ctx = ctx, + name = "link", + cmd = cmd_args(run_msvc_tool, link_exe_json), + os = ScriptOs("windows"), + ) return [ # Supports `buck2 run prelude//toolchains/msvc:msvc_tools[cl.exe]` @@ -128,20 +122,51 @@ def _find_msvc_tools_impl(ctx: AnalysisContext) -> list[Provider]: }), ], }), - VisualStudio( - cl_exe = cl_exe_script, - cvtres_exe = cvtres_exe_script, - lib_exe = lib_exe_script, - ml64_exe = ml64_exe_script, - link_exe = link_exe_script, - rc_exe = rc_exe_script, + CxxToolsInfo( + compiler = cl_exe_script, + compiler_type = "windows", + cxx_compiler = cl_exe_script, + asm_compiler = ml64_exe_script, + asm_compiler_type = "windows_ml64", + rc_compiler = rc_exe_script, + cvtres_compiler = cvtres_exe_script, + archiver = lib_exe_script, + archiver_type = "windows", + linker = _windows_linker_wrapper(ctx, link_exe_script), + linker_type = "windows", ), ] +def _windows_linker_wrapper(ctx: AnalysisContext, linker: [cmd_args, str]) -> cmd_args: + # Linkers pretty much all support @file.txt argument syntax to insert + # arguments from the given text file, usually formatted one argument per + # line. + # + # - GNU ld: https://gcc.gnu.org/onlinedocs/gcc/Overall-Options.html + # - lld is command line compatible with GNU ld + # - MSVC link.exe: https://learn.microsoft.com/en-us/cpp/build/reference/linking?view=msvc-170#link-command-files + # + # However, there is inconsistency in whether they support nesting of @file + # arguments inside of another @file. + # + # We wrap the linker to flatten @file arguments down to 1 level of nesting. + return cmd_script( + ctx = ctx, + name = "windows_linker", + cmd = cmd_args( + ctx.attrs.linker_wrapper[RunInfo], + linker, + ), + os = ScriptOs("windows"), + ) + find_msvc_tools = rule( impl = _find_msvc_tools_impl, attrs = { + "linker_wrapper": attrs.default_only(attrs.exec_dep(providers = [RunInfo], default = "prelude//cxx/tools:linker_wrapper")), "run_msvc_tool": attrs.default_only(attrs.dep(providers = [RunInfo], default = "prelude//toolchains/msvc:run_msvc_tool")), + "use_path_compilers": attrs.bool(default = False), + "use_path_linkers": attrs.bool(default = False), "vswhere": attrs.default_only(attrs.dep(providers = [RunInfo], default = "prelude//toolchains/msvc:vswhere")), }, )