From ffbdbbe9e8fe5baf3f223d977df689d91a3abebc Mon Sep 17 00:00:00 2001 From: Gavin Zhao Date: Tue, 21 Feb 2023 21:13:09 -0500 Subject: [PATCH 01/92] Initial working toolchain setup Signed-off-by: Gavin Zhao --- WORKSPACE | 16 ++++ d/BUILD | 68 +++++--------- d/DMD.bzl | 40 ++++++++ d/d.bzl | 238 +++++++++++++++++++++--------------------------- d/toolchain.bzl | 34 +++++++ 5 files changed, 216 insertions(+), 180 deletions(-) create mode 100644 d/DMD.bzl create mode 100644 d/toolchain.bzl diff --git a/WORKSPACE b/WORKSPACE index 733a0f4..caf84ef 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,4 +1,20 @@ workspace(name = "io_bazel_rules_d") +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +http_archive( + name = "bazel_skylib", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz", + ], + sha256 = "74d544d96f4a5bb630d465ca8bbcfe231e3594e5aae57e1edbf17a6eb3ca2506", +) +load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") +bazel_skylib_workspace() + load("@io_bazel_rules_d//d:d.bzl", "d_repositories") d_repositories() + +register_toolchains( + "//d:dmd_linux_x86_64_toolchain", +) diff --git a/d/BUILD b/d/BUILD index 11b67c9..3e652e5 100644 --- a/d/BUILD +++ b/d/BUILD @@ -1,57 +1,33 @@ package(default_visibility = ["//visibility:public"]) -filegroup( - name = "srcs", - srcs = glob(["**"]), -) +load("//d:toolchain.bzl", "D_TOOLCHAIN", "d_toolchain") -config_setting( - name = "darwin", - values = {"host_cpu": "darwin"}, -) - -config_setting( - name = "k8", - values = {"host_cpu": "k8"}, -) - -config_setting( - name = "x64_windows", - values = {"host_cpu": "x64_windows"}, -) +toolchain_type(name = "toolchain_type") filegroup( - name = "dmd", - srcs = select({ - ":darwin": ["@dmd_darwin_x86_64//:dmd"], - ":k8": ["@dmd_linux_x86_64//:dmd"], - ":x64_windows": ["@dmd_windows_x86_64//:dmd"], - }), + name = "srcs", + srcs = glob(["**"]), ) -filegroup( - name = "libphobos2", - srcs = select({ - ":darwin": ["@dmd_darwin_x86_64//:libphobos2"], - ":k8": ["@dmd_linux_x86_64//:libphobos2"], - ":x64_windows": ["@dmd_windows_x86_64//:libphobos2"], - }), +d_toolchain( + name = "dmd_linux_x86_64", + d_compiler = "@dmd_linux_x86_64//:dmd", + libphobos = "@dmd_linux_x86_64//:libphobos2", + libphobos_src = "@dmd_linux_x86_64//:phobos_src", + druntime_src = "@dmd_linux_x86_64//:druntime_src", ) -filegroup( - name = "phobos-src", - srcs = select({ - ":darwin": ["@dmd_darwin_x86_64//:phobos-src"], - ":k8": ["@dmd_linux_x86_64//:phobos-src"], - ":x64_windows": ["@dmd_windows_x86_64//:phobos-src"], - }), +toolchain( + name = "dmd_linux_x86_64_toolchain", + exec_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + target_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + toolchain = ":dmd_linux_x86_64", + toolchain_type = D_TOOLCHAIN, ) -filegroup( - name = "druntime-import-src", - srcs = select({ - ":darwin": ["@dmd_darwin_x86_64//:druntime-import-src"], - ":k8": ["@dmd_linux_x86_64//:druntime-import-src"], - ":x64_windows": ["@dmd_windows_x86_64//:druntime-import-src"], - }), -) diff --git a/d/DMD.bzl b/d/DMD.bzl new file mode 100644 index 0000000..c3510dc --- /dev/null +++ b/d/DMD.bzl @@ -0,0 +1,40 @@ +load("@bazel_skylib//rules:native_binary.bzl", "native_binary") + +package(default_visibility = ["//visibility:public"]) + +native_binary( + name = "dmd", + out = "dmdcopy.exe", + src = select({ + "@bazel_tools//src/conditions:darwin": "osx/bin/dmd", + "@bazel_tools//src/conditions:linux_x86_64": "linux/bin64/dmd", + "@bazel_tools//src/conditions:windows_x64": "windows/bin64/dmd.exe", + }), +) + +cc_import( + name = "libphobos2", + shared_library = select({ + "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", + "@bazel_tools//src/conditions:linux_x86_64": "linux/lib64/libphobos2.so", + "@bazel_tools//src/conditions:windows_x64": "windows/lib64/dmd.exe", + }), + static_library = select({ + "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", + "@bazel_tools//src/conditions:linux_x86_64": "linux/lib64/libphobos2.a", + "@bazel_tools//src/conditions:windows_x64": "windows/lib64/dmd.exe", + }) +) + +filegroup( + name = "phobos_src", + srcs = glob(["src/phobos/**/*.*"]), +) + +filegroup( + name = "druntime_src", + srcs = glob([ + "src/druntime/import/*.*", + "src/druntime/import/**/*.*", + ]), +) diff --git a/d/d.bzl b/d/d.bzl index 57c5f42..f41cd01 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -15,6 +15,7 @@ """D rules for Bazel.""" load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("//d:toolchain.bzl", "D_TOOLCHAIN") def _is_windows(ctx): return ctx.configuration.host_path_separator == ";" @@ -35,30 +36,30 @@ def _files_directory(files): dir = f.dirname return dir -def _d_toolchain(ctx): - """Returns a struct containing info about the D toolchain. - - Args: - ctx: The ctx object. - - Return: - Struct containing the following fields: - d_compiler_path: The path to the D compiler. - link_flags: Linker (-L) flags for adding the standard library to the - library search paths. - import_flags: import (-I) flags for adding the standard library sources - to the import paths. - """ - - d_compiler_path = ctx.file._d_compiler.path - return struct( - d_compiler_path = d_compiler_path, - link_flags = [("-L/LIBPATH:" if _is_windows(ctx) else "-L-L") + ctx.files._d_stdlib[0].dirname], - import_flags = [ - "-I" + _files_directory(ctx.files._d_stdlib_src), - "-I" + _files_directory(ctx.files._d_runtime_import_src), - ], - ) +# def _d_toolchain(ctx): +# """Returns a struct containing info about the D toolchain. +# +# Args: +# ctx: The ctx object. +# +# Return: +# Struct containing the following fields: +# d_compiler_path: The path to the D compiler. +# link_flags: Linker (-L) flags for adding the standard library to the +# library search paths. +# import_flags: import (-I) flags for adding the standard library sources +# to the import paths. +# """ +# +# d_compiler_path = ctx.file._d_compiler.path +# return struct( +# d_compiler_path = d_compiler_path, +# link_flags = [("-L/LIBPATH:" if _is_windows(ctx) else "-L-L") + ctx.files._d_stdlib[0].dirname], +# import_flags = [ +# "-I" + _files_directory(ctx.files._d_stdlib_src), +# "-I" + _files_directory(ctx.files._d_runtime_import_src), +# ], +# ) COMPILATION_MODE_FLAGS_POSIX = { "fastbuild": ["-g"], @@ -96,7 +97,7 @@ def _build_import(label, im): def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): """Returns a list of strings constituting the D compile command arguments.""" - toolchain = _d_toolchain(ctx) + toolchain = ctx.toolchains[D_TOOLCHAIN] return ( _compilation_mode_flags(ctx) + extra_flags + [ @@ -106,7 +107,7 @@ def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): ] + ["-I%s" % _build_import(ctx.label, im) for im in ctx.attr.imports] + ["-I%s" % im for im in depinfo.imports] + - toolchain.import_flags + + # toolchain.import_flags + ["-version=Have_%s" % _format_version(ctx.label.name)] + ["-version=%s" % v for v in ctx.attr.versions] + ["-version=%s" % v for v in depinfo.versions] @@ -114,11 +115,9 @@ def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): def _build_link_arglist(ctx, objs, out, depinfo): """Returns a list of strings constituting the D link command arguments.""" - toolchain = _d_toolchain(ctx) return ( _compilation_mode_flags(ctx) + ["-of" + out.path] + - toolchain.link_flags + [f.path for f in depset(transitive = [depinfo.libs, depinfo.transitive_libs]).to_list()] + depinfo.link_flags + objs @@ -197,9 +196,11 @@ def _setup_deps(ctx, deps, name, working_dir): def _d_library_impl(ctx): """Implementation of the d_library rule.""" + toolchain = ctx.toolchains[D_TOOLCHAIN] d_lib = ctx.actions.declare_file((ctx.label.name + ".lib") if _is_windows(ctx) else ("lib" + ctx.label.name + ".a")) # Dependencies + deps = ctx.attr.deps + [toolchain.libphobos] depinfo = _setup_deps(ctx, ctx.attr.deps, ctx.label.name, d_lib.dirname) # Build compile command. @@ -217,25 +218,28 @@ def _d_library_impl(ctx): args.add_all(compile_args) args.add_all(ctx.files.srcs) + # TODO: Should they be in transitive? compile_inputs = depset( ctx.files.srcs + - depinfo.d_srcs + - ctx.files._d_stdlib + - ctx.files._d_stdlib_src + - ctx.files._d_runtime_import_src, + depinfo.d_srcs, transitive = [ depinfo.transitive_d_srcs, depinfo.libs, depinfo.transitive_libs, + toolchain.libphobos.files, + toolchain.libphobos_src.files, + toolchain.druntime_src.files, ], ) + d_compiler = toolchain.d_compiler.files.to_list()[0] + ctx.actions.run( inputs = compile_inputs, - tools = [ctx.file._d_compiler], + tools = [d_compiler], outputs = [d_lib], mnemonic = "Dcompile", - executable = ctx.file._d_compiler.path, + executable = d_compiler, arguments = [args], use_default_shell_env = True, progress_message = "Compiling D library " + ctx.label.name, @@ -254,9 +258,13 @@ def _d_library_impl(ctx): def _d_binary_impl_common(ctx, extra_flags = []): """Common implementation for rules that build a D binary.""" + toolchain = ctx.toolchains[D_TOOLCHAIN] d_bin = ctx.actions.declare_file(ctx.label.name + ".exe" if _is_windows(ctx) else ctx.label.name) d_obj = ctx.actions.declare_file(ctx.label.name + (".obj" if _is_windows(ctx) else ".o")) - depinfo = _setup_deps(ctx, ctx.attr.deps, ctx.label.name, d_bin.dirname) + + # Dependencies + deps = ctx.attr.deps + [toolchain.libphobos] + depinfo = _setup_deps(ctx, deps, ctx.label.name, d_bin.dirname) # Build compile command compile_args = _build_compile_arglist( @@ -273,22 +281,24 @@ def _d_binary_impl_common(ctx, extra_flags = []): args.add_all(compile_args) args.add_all(ctx.files.srcs) - toolchain_files = ( - ctx.files._d_stdlib + - ctx.files._d_stdlib_src + - ctx.files._d_runtime_import_src - ) + toolchain_files = [ + toolchain.libphobos.files, + toolchain.libphobos_src.files, + toolchain.druntime_src.files, + ] + + d_compiler = toolchain.d_compiler.files.to_list()[0] compile_inputs = depset( - ctx.files.srcs + depinfo.d_srcs + toolchain_files, - transitive = [depinfo.transitive_d_srcs], + ctx.files.srcs + depinfo.d_srcs, + transitive = [depinfo.transitive_d_srcs] + toolchain_files, ) ctx.actions.run( inputs = compile_inputs, - tools = [ctx.file._d_compiler], + tools = [d_compiler], outputs = [d_obj], mnemonic = "Dcompile", - executable = ctx.file._d_compiler.path, + executable = d_compiler, arguments = [args], use_default_shell_env = True, progress_message = "Compiling D binary " + ctx.label.name, @@ -303,16 +313,16 @@ def _d_binary_impl_common(ctx, extra_flags = []): ) link_inputs = depset( - [d_obj] + toolchain_files, - transitive = [depinfo.libs, depinfo.transitive_libs], + [d_obj], + transitive = [depinfo.libs, depinfo.transitive_libs] + toolchain_files, ) ctx.actions.run( inputs = link_inputs, - tools = [ctx.file._d_compiler], + tools = [d_compiler], outputs = [d_bin], mnemonic = "Dlink", - executable = ctx.file._d_compiler.path, + executable = d_compiler, arguments = link_args, use_default_shell_env = True, progress_message = "Linking D binary " + ctx.label.name, @@ -411,14 +421,16 @@ def _d_docs_impl(ctx): imports = ctx.attr.dep.imports, ) + toolchain = ctx.toolchains[D_TOOLCHAIN] + d_compiler = toolchain.d_compiler.files.to_list()[0] + # Build D docs command - toolchain = _d_toolchain(ctx) doc_cmd = ( [ "set -e;", "rm -rf %s; mkdir -p %s;" % (docs_dir, docs_dir), "rm -rf %s; mkdir -p %s;" % (objs_dir, objs_dir), - toolchain.d_compiler_path, + d_compiler.path, "-c", "-D", "-Dd%s" % docs_dir, @@ -426,7 +438,7 @@ def _d_docs_impl(ctx): "-I.", ] + ["-I%s" % _build_import(ctx.label, im) for im in target.imports] + - toolchain.import_flags + + # toolchain.import_flags + [src.path for src in target.srcs] + [ "&&", @@ -439,15 +451,16 @@ def _d_docs_impl(ctx): ] ) - toolchain_files = ( - ctx.files._d_stdlib + - ctx.files._d_stdlib_src + - ctx.files._d_runtime_import_src - ) - ddoc_inputs = depset(target.srcs + toolchain_files, transitive = [target.transitive_srcs]) + toolchain_files = [ + toolchain.libphobos, + toolchain.libphobos_src, + toolchain.druntime_src, + ] + + ddoc_inputs = depset(target.srcs, transitive = [target.transitive_srcs] + toolchain_files) ctx.actions.run_shell( inputs = ddoc_inputs, - tools = [ctx.file._d_compiler], + tools = [d_compiler], outputs = [d_docs_zip], mnemonic = "Ddoc", command = " ".join(doc_cmd), @@ -463,45 +476,49 @@ _d_common_attrs = { "deps": attr.label_list(), } -_d_compile_attrs = { - "_d_compiler": attr.label( - default = Label("//d:dmd"), - executable = True, - allow_single_file = True, - cfg = "host", - ), - "_d_runtime_import_src": attr.label( - default = Label("//d:druntime-import-src"), - ), - "_d_stdlib": attr.label( - default = Label("//d:libphobos2"), - ), - "_d_stdlib_src": attr.label( - default = Label("//d:phobos-src"), - ), -} +# _d_compile_attrs = { +# "_d_compiler": attr.label( +# default = Label("//d:dmd"), +# executable = True, +# allow_single_file = True, +# cfg = "host", +# ), +# "_d_runtime_import_src": attr.label( +# default = Label("//d:druntime-import-src"), +# ), +# "_d_stdlib": attr.label( +# default = Label("//d:libphobos2"), +# ), +# "_d_stdlib_src": attr.label( +# default = Label("//d:phobos-src"), +# ), +# } d_library = rule( _d_library_impl, - attrs = dict(_d_common_attrs.items() + _d_compile_attrs.items()), + attrs = dict(_d_common_attrs.items()), + toolchains = [D_TOOLCHAIN], ) d_source_library = rule( _d_source_library_impl, attrs = _d_common_attrs, + toolchains = [D_TOOLCHAIN], ) d_binary = rule( _d_binary_impl, - attrs = dict(_d_common_attrs.items() + _d_compile_attrs.items()), + attrs = dict(_d_common_attrs.items()), executable = True, + toolchains = [D_TOOLCHAIN], ) d_test = rule( _d_test_impl, - attrs = dict(_d_common_attrs.items() + _d_compile_attrs.items()), + attrs = dict(_d_common_attrs.items()), executable = True, test = True, + toolchains = [D_TOOLCHAIN], ) _d_docs_attrs = { @@ -510,64 +527,14 @@ _d_docs_attrs = { d_docs = rule( _d_docs_impl, - attrs = dict(_d_docs_attrs.items() + _d_compile_attrs.items()), + attrs = dict(_d_docs_attrs.items()), outputs = { "d_docs": "%{name}-docs.zip", }, + toolchains = [D_TOOLCHAIN], ) -DMD_BUILD_FILE = """ -package(default_visibility = ["//visibility:public"]) - -config_setting( - name = "darwin", - values = {"host_cpu": "darwin"}, -) - -config_setting( - name = "k8", - values = {"host_cpu": "k8"}, -) - -config_setting( - name = "x64_windows", - values = {"host_cpu": "x64_windows"}, -) - -filegroup( - name = "dmd", - srcs = select({ - ":darwin": ["dmd2/osx/bin/dmd"], - ":k8": ["dmd2/linux/bin64/dmd"], - ":x64_windows": ["dmd2/windows/bin64/dmd.exe"], - }), -) - -filegroup( - name = "libphobos2", - srcs = select({ - ":darwin": ["dmd2/osx/lib/libphobos2.a"], - ":k8": [ - "dmd2/linux/lib64/libphobos2.a", - "dmd2/linux/lib64/libphobos2.so", - ], - ":x64_windows": ["dmd2/windows/lib64/phobos64.lib"], - }), -) - -filegroup( - name = "phobos-src", - srcs = glob(["dmd2/src/phobos/**/*.*"]), -) - -filegroup( - name = "druntime-import-src", - srcs = glob([ - "dmd2/src/druntime/import/*.*", - "dmd2/src/druntime/import/**/*.*", - ]), -) -""" +DMD_BUILD_FILE = "//d:DMD.bzl" def d_repositories(): http_archive( @@ -576,7 +543,8 @@ def d_repositories(): "http://downloads.dlang.org/releases/2021/dmd.2.097.1.linux.tar.xz", ], sha256 = "030fd1bc3b7308dadcf08edc1529d4a2e46496d97ee92ed532b246a0f55745e6", - build_file_content = DMD_BUILD_FILE, + strip_prefix = "dmd2", + build_file = DMD_BUILD_FILE, ) http_archive( @@ -585,7 +553,8 @@ def d_repositories(): "http://downloads.dlang.org/releases/2021/dmd.2.097.1.osx.tar.xz", ], sha256 = "383a5524266417bcdd3126da947be7caebd4730f789021e9ec26d869c8448f6a", - build_file_content = DMD_BUILD_FILE, + strip_prefix = "dmd2", + build_file = DMD_BUILD_FILE, ) http_archive( @@ -594,5 +563,6 @@ def d_repositories(): "http://downloads.dlang.org/releases/2021/dmd.2.097.1.windows.zip", ], sha256 = "63a00e624bf23ab676c543890a93b5325d6ef6b336dee2a2f739f2bbcef7ef1f", - build_file_content = DMD_BUILD_FILE, + strip_prefix = "dmd2", + build_file = DMD_BUILD_FILE, ) diff --git a/d/toolchain.bzl b/d/toolchain.bzl new file mode 100644 index 0000000..06a37b7 --- /dev/null +++ b/d/toolchain.bzl @@ -0,0 +1,34 @@ +D_TOOLCHAIN = "@//d:toolchain_type" + +def _d_toolchain_impl(ctx): + toolchain_info = platform_common.ToolchainInfo( + name = ctx.label.name, + d_compiler = ctx.attr.d_compiler, + link_flags = ctx.attr.link_flags, + import_flags = ctx.attr.import_flags, + libphobos = ctx.attr.libphobos, + libphobos_src = ctx.attr.libphobos_src, + druntime = ctx.attr.druntime, + druntime_src = ctx.attr.druntime_src, + ) + return [toolchain_info] + +d_toolchain = rule( + _d_toolchain_impl, + attrs = { + "d_compiler": attr.label( + executable = True, + # allow_files = True, + cfg = "host", + ), + "link_flags": attr.string_list( + default = [], + ), + "import_flags": attr.string_list(), + "libphobos": attr.label(), + "libphobos_src": attr.label(), + "druntime": attr.label(), + "druntime_src": attr.label(), + } +) + From 6cbb76d7252d1b8889a4e6a864d6b382cbc10883 Mon Sep 17 00:00:00 2001 From: Gavin Zhao Date: Wed, 22 Feb 2023 17:19:03 -0500 Subject: [PATCH 02/92] Add LDC support Signed-off-by: Gavin Zhao --- README.md | 5 ++- WORKSPACE | 8 +--- d/BUILD | 24 ++++++++++++ d/DMD.bzl | 2 +- d/LDC.bzl | 61 +++++++++++++++++++++++++++++ d/d.bzl | 46 ++++------------------ d/repositories.bzl | 98 ++++++++++++++++++++++++++++++++++++++++++++++ d/toolchain.bzl | 5 +++ extensions.bzl | 0 9 files changed, 202 insertions(+), 47 deletions(-) create mode 100644 d/LDC.bzl create mode 100644 d/repositories.bzl create mode 100644 extensions.bzl diff --git a/README.md b/README.md index 3c94072..8d16a41 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,9 @@ http_archive( strip_prefix = "rules_d-bcf137e3c9381545ce54715632bc1d31c51ee4da", ) -load("@io_bazel_rules_d//d:d.bzl", "d_repositories") -d_repositories() +load("@io_bazel_rules_d//d:repositories.bzl", "rules_d_toolchains") +rules_d_toolchains() +# rules_d_toolchains(ctype = "ldc") # If you want to use LDC instead of DMD ``` ## Roadmap diff --git a/WORKSPACE b/WORKSPACE index caf84ef..3124b1e 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -12,9 +12,5 @@ http_archive( load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") bazel_skylib_workspace() -load("@io_bazel_rules_d//d:d.bzl", "d_repositories") -d_repositories() - -register_toolchains( - "//d:dmd_linux_x86_64_toolchain", -) +load("@io_bazel_rules_d//d:repositories.bzl", "rules_d_toolchains") +rules_d_toolchains() diff --git a/d/BUILD b/d/BUILD index 3e652e5..5d263b7 100644 --- a/d/BUILD +++ b/d/BUILD @@ -17,6 +17,16 @@ d_toolchain( druntime_src = "@dmd_linux_x86_64//:druntime_src", ) +d_toolchain( + name = "ldc_linux_x86_64", + d_compiler = "@ldc_linux_x86_64//:ldc2", + libphobos = "@ldc_linux_x86_64//:libphobos2", + libphobos_src = "@ldc_linux_x86_64//:phobos_src", + druntime = "@ldc_linux_x86_64//:druntime", + druntime_src = "@ldc_linux_x86_64//:druntime_src", + ctype = "ldc", +) + toolchain( name = "dmd_linux_x86_64_toolchain", exec_compatible_with = [ @@ -31,3 +41,17 @@ toolchain( toolchain_type = D_TOOLCHAIN, ) +toolchain( + name = "ldc_linux_x86_64_toolchain", + exec_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + target_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + toolchain = ":ldc_linux_x86_64", + toolchain_type = D_TOOLCHAIN, +) + diff --git a/d/DMD.bzl b/d/DMD.bzl index c3510dc..854a1c5 100644 --- a/d/DMD.bzl +++ b/d/DMD.bzl @@ -23,7 +23,7 @@ cc_import( "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", "@bazel_tools//src/conditions:linux_x86_64": "linux/lib64/libphobos2.a", "@bazel_tools//src/conditions:windows_x64": "windows/lib64/dmd.exe", - }) + }), ) filegroup( diff --git a/d/LDC.bzl b/d/LDC.bzl new file mode 100644 index 0000000..b6bee32 --- /dev/null +++ b/d/LDC.bzl @@ -0,0 +1,61 @@ +load("@bazel_skylib//rules:native_binary.bzl", "native_binary") + +package(default_visibility = ["//visibility:public"]) + +native_binary( + name = "ldc2", + out = "ldc2copy.exe", + src = select({ + "@bazel_tools//src/conditions:darwin": "bin/ldc2", + "@bazel_tools//src/conditions:linux_x86_64": "bin/ldc2", + "@bazel_tools//src/conditions:windows_x64": "bin/ldc2.exe", + }), +) + +cc_import( + name = "libphobos2", + shared_library = select({ + "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", + "@bazel_tools//src/conditions:linux_x86_64": "lib/libphobos2-ldc-shared.so", + "@bazel_tools//src/conditions:windows_x64": "lib/phobos2-ldc-shared.lib", + }), + static_library = select({ + "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", + "@bazel_tools//src/conditions:linux_x86_64": "lib/libphobos2-ldc.a", + "@bazel_tools//src/conditions:windows_x64": "lib/phobos2-ldc.lib", + }), +) + +cc_import( + name = "druntime", + shared_library = select({ + "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", + "@bazel_tools//src/conditions:linux_x86_64": "lib/libdruntime-ldc-shared.so", + "@bazel_tools//src/conditions:windows_x64": "lib/druntime-ldc-shared.lib", + }), + static_library = select({ + "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", + "@bazel_tools//src/conditions:linux_x86_64": "lib/libdruntime-ldc.a", + "@bazel_tools//src/conditions:windows_x64": "lib/druntime-ldc.lib", + }), +) + +filegroup( + name = "phobos_src", + srcs = glob([ + "import/std/**/*.*", + "import/std/*.*", + "import/etc/**/*.*", + "import/etc/*.*", + ]), +) + +filegroup( + name = "druntime_src", + srcs = glob([ + "import/core/**/*.*", + "import/core/*.*", + "import/ldc/**/*.*", + "import/ldc/*.*", + ]), +) diff --git a/d/d.bzl b/d/d.bzl index f41cd01..b53b3e8 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -14,7 +14,6 @@ """D rules for Bazel.""" -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("//d:toolchain.bzl", "D_TOOLCHAIN") def _is_windows(ctx): @@ -98,6 +97,9 @@ def _build_import(label, im): def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): """Returns a list of strings constituting the D compile command arguments.""" toolchain = ctx.toolchains[D_TOOLCHAIN] + isDMD = toolchain.ctype == "dmd" + version_flag = "-version" if isDMD else "-d-version" + return ( _compilation_mode_flags(ctx) + extra_flags + [ @@ -108,9 +110,9 @@ def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): ["-I%s" % _build_import(ctx.label, im) for im in ctx.attr.imports] + ["-I%s" % im for im in depinfo.imports] + # toolchain.import_flags + - ["-version=Have_%s" % _format_version(ctx.label.name)] + - ["-version=%s" % v for v in ctx.attr.versions] + - ["-version=%s" % v for v in depinfo.versions] + [version_flag + "=Have_%s" % _format_version(ctx.label.name)] + + [version_flag + "=%s" % v for v in ctx.attr.versions] + + [version_flag + "=%s" % v for v in depinfo.versions] ) def _build_link_arglist(ctx, objs, out, depinfo): @@ -200,7 +202,7 @@ def _d_library_impl(ctx): d_lib = ctx.actions.declare_file((ctx.label.name + ".lib") if _is_windows(ctx) else ("lib" + ctx.label.name + ".a")) # Dependencies - deps = ctx.attr.deps + [toolchain.libphobos] + deps = ctx.attr.deps + [toolchain.libphobos] + ([toolchain.druntime] if toolchain.druntime != None else []) depinfo = _setup_deps(ctx, ctx.attr.deps, ctx.label.name, d_lib.dirname) # Build compile command. @@ -263,7 +265,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): d_obj = ctx.actions.declare_file(ctx.label.name + (".obj" if _is_windows(ctx) else ".o")) # Dependencies - deps = ctx.attr.deps + [toolchain.libphobos] + deps = ctx.attr.deps + [toolchain.libphobos] + ([toolchain.druntime] if toolchain.druntime != None else []) depinfo = _setup_deps(ctx, deps, ctx.label.name, d_bin.dirname) # Build compile command @@ -534,35 +536,3 @@ d_docs = rule( toolchains = [D_TOOLCHAIN], ) -DMD_BUILD_FILE = "//d:DMD.bzl" - -def d_repositories(): - http_archive( - name = "dmd_linux_x86_64", - urls = [ - "http://downloads.dlang.org/releases/2021/dmd.2.097.1.linux.tar.xz", - ], - sha256 = "030fd1bc3b7308dadcf08edc1529d4a2e46496d97ee92ed532b246a0f55745e6", - strip_prefix = "dmd2", - build_file = DMD_BUILD_FILE, - ) - - http_archive( - name = "dmd_darwin_x86_64", - urls = [ - "http://downloads.dlang.org/releases/2021/dmd.2.097.1.osx.tar.xz", - ], - sha256 = "383a5524266417bcdd3126da947be7caebd4730f789021e9ec26d869c8448f6a", - strip_prefix = "dmd2", - build_file = DMD_BUILD_FILE, - ) - - http_archive( - name = "dmd_windows_x86_64", - urls = [ - "http://downloads.dlang.org/releases/2021/dmd.2.097.1.windows.zip", - ], - sha256 = "63a00e624bf23ab676c543890a93b5325d6ef6b336dee2a2f739f2bbcef7ef1f", - strip_prefix = "dmd2", - build_file = DMD_BUILD_FILE, - ) diff --git a/d/repositories.bzl b/d/repositories.bzl new file mode 100644 index 0000000..e19d089 --- /dev/null +++ b/d/repositories.bzl @@ -0,0 +1,98 @@ +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_skylib//lib:versions.bzl", "versions") + +DMD_BUILD_FILE = "//d:DMD.bzl" +LDC_BUILD_FILE = "//d:LDC.bzl" +DMD_STRIP_PREFIX = "dmd2" + +def fetch_and_register_dmd(version = None): + if version == None: + http_archive( + name = "dmd_linux_x86_64", + urls = [ + "https://downloads.dlang.org/releases/2.x/2.102.1/dmd.2.102.1.linux.tar.xz", + ], + sha256 = "f3f62fd7357d9c0c0349c7b96721d6734fe8285c0f32a37649d378c8abb0e9eb", + strip_prefix = DMD_STRIP_PREFIX, + build_file = DMD_BUILD_FILE, + ) + + http_archive( + name = "dmd_darwin_x86_64", + urls = [ + "https://downloads.dlang.org/releases/2.x/2.102.1/dmd.2.102.1.osx.tar.xz", + ], + sha256 = "300d309a2b71e95404f58e14a23daf342f47cc8608476a0b6414d356485df2bc", + strip_prefix = DMD_STRIP_PREFIX, + build_file = DMD_BUILD_FILE, + ) + + http_archive( + name = "dmd_windows_x86_64", + urls = [ + "https://downloads.dlang.org/releases/2.x/2.102.1/dmd.2.102.1.windows.zip", + ], + sha256 = "a263ffbf6232288fa093c71a43a5cc1cd09ef5a75e7eca385ece16606c245090", + strip_prefix = DMD_STRIP_PREFIX, + build_file = DMD_BUILD_FILE, + ) + + native.register_toolchains( + "//d:dmd_linux_x86_64_toolchain", + ) + elif versions.is_at_least("2.0.0", version): + http_archive( + name = "dmd_linux_x86_64", + urls = [ + "https://downloads.dlang.org/releases/2.x/{version}/dmd.{version}.linux.tar.xz".format(version = version), + ], + strip_prefix = DMD_STRIP_PREFIX, + build_file = DMD_BUILD_FILE, + ) + + http_archive( + name = "dmd_darwin_x86_64", + urls = [ + "https://downloads.dlang.org/releases/2.x/{version}/dmd.{version}.osx.tar.xz".format(version = version), + ], + strip_prefix = DMD_STRIP_PREFIX, + build_file = DMD_BUILD_FILE, + ) + + http_archive( + name = "dmd_windows_x86_64", + urls = [ + "https://downloads.dlang.org/releases/2.x/{version}/dmd.{version}.windows.zip".format(version = version), + ], + strip_prefix = DMD_STRIP_PREFIX, + build_file = DMD_BUILD_FILE, + ) + + native.register_toolchains( + "//d:dmd_linux_x86_64_toolchain", + ) + else: + fail("Sorry, only DMD 2 is supported, but got %s. Maybe consider switching to D2?" % version) + +def fetch_and_register_ldc(): + http_archive( + name = "ldc_linux_x86_64", + urls = [ + "https://github.com/ldc-developers/ldc/releases/download/v1.31.0/ldc2-1.31.0-linux-x86_64.tar.xz", + ], + sha256 = "7dbd44786c0772ec41890a8c03e22b0985d6ef547c40943dd56bc6be21cf4d98", + strip_prefix = "ldc2-1.31.0-linux-x86_64", + build_file = LDC_BUILD_FILE, + ) + + native.register_toolchains( + "//d:ldc_linux_x86_64_toolchain", + ) + +def rules_d_toolchains(ctype = "dmd", version = None): + if ctype == "dmd": + fetch_and_register_dmd(version = version) + elif ctype == "ldc": + fetch_and_register_ldc() + else: + fail("Only \"dmd\" and \"ldc\" compilers are supported at this moment.") diff --git a/d/toolchain.bzl b/d/toolchain.bzl index 06a37b7..a6db6a9 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -10,6 +10,7 @@ def _d_toolchain_impl(ctx): libphobos_src = ctx.attr.libphobos_src, druntime = ctx.attr.druntime, druntime_src = ctx.attr.druntime_src, + ctype = ctx.attr.ctype, ) return [toolchain_info] @@ -29,6 +30,10 @@ d_toolchain = rule( "libphobos_src": attr.label(), "druntime": attr.label(), "druntime_src": attr.label(), + "ctype": attr.string( + default = "dmd", + values = ["dmd", "ldc"] + ), } ) diff --git a/extensions.bzl b/extensions.bzl new file mode 100644 index 0000000..e69de29 From 09d2249343aac0a624622a6b62df020063181c59 Mon Sep 17 00:00:00 2001 From: Gavin Zhao Date: Sat, 25 Feb 2023 09:51:31 -0500 Subject: [PATCH 03/92] Fill in correct files for Windows and MacOS Signed-off-by: Gavin Zhao --- d/BUILD | 69 +++++++++++++++++++++++++----------- d/DMD.bzl | 24 +++++++++---- d/LDC.bzl | 1 + d/constraints/compiler/BUILD | 1 + d/d.bzl | 41 ++++++--------------- d/repositories.bzl | 29 ++++++++------- d/toolchain.bzl | 29 +++++++++++++-- 7 files changed, 120 insertions(+), 74 deletions(-) create mode 100644 d/constraints/compiler/BUILD diff --git a/d/BUILD b/d/BUILD index 5d263b7..c9c4775 100644 --- a/d/BUILD +++ b/d/BUILD @@ -9,23 +9,13 @@ filegroup( srcs = glob(["**"]), ) -d_toolchain( - name = "dmd_linux_x86_64", - d_compiler = "@dmd_linux_x86_64//:dmd", - libphobos = "@dmd_linux_x86_64//:libphobos2", - libphobos_src = "@dmd_linux_x86_64//:phobos_src", - druntime_src = "@dmd_linux_x86_64//:druntime_src", -) - -d_toolchain( - name = "ldc_linux_x86_64", - d_compiler = "@ldc_linux_x86_64//:ldc2", - libphobos = "@ldc_linux_x86_64//:libphobos2", - libphobos_src = "@ldc_linux_x86_64//:phobos_src", - druntime = "@ldc_linux_x86_64//:druntime", - druntime_src = "@ldc_linux_x86_64//:druntime_src", - ctype = "ldc", -) +[d_toolchain( + name = "dmd_" + os + "_x86_64", + d_compiler = "@dmd_" + os + "_x86_64//:dmd", + druntime_src = "@dmd_" + os + "_x86_64//:druntime_src", + libphobos = "@dmd_" + os + "_x86_64//:libphobos2", + libphobos_src = "@dmd_" + os + "_x86_64//:phobos_src", +) for os in ["linux", "darwin", "windows"]] toolchain( name = "dmd_linux_x86_64_toolchain", @@ -42,16 +32,53 @@ toolchain( ) toolchain( - name = "ldc_linux_x86_64_toolchain", + name = "dmd_darwin_x86_64_toolchain", exec_compatible_with = [ - "@platforms//os:linux", + "@platforms//os:macos", "@platforms//cpu:x86_64", ], target_compatible_with = [ - "@platforms//os:linux", + "@platforms//os:macos", + "@platforms//cpu:x86_64", + ], + toolchain = ":dmd_darwin_x86_64", + toolchain_type = D_TOOLCHAIN, +) + +toolchain( + name = "dmd_windows_x86_64_toolchain", + exec_compatible_with = [ + "@platforms//os:windows", + "@platforms//cpu:x86_64", + ], + target_compatible_with = [ + "@platforms//os:windows", "@platforms//cpu:x86_64", ], - toolchain = ":ldc_linux_x86_64", + toolchain = ":dmd_windows_x86_64", toolchain_type = D_TOOLCHAIN, ) +# d_toolchain( +# name = "ldc_linux_x86_64", +# ctype = "ldc", +# d_compiler = "@ldc_linux_x86_64//:ldc2", +# druntime = "@ldc_linux_x86_64//:druntime", +# druntime_src = "@ldc_linux_x86_64//:druntime_src", +# libphobos = "@ldc_linux_x86_64//:libphobos2", +# libphobos_src = "@ldc_linux_x86_64//:phobos_src", +# ) +# +# toolchain( +# name = "ldc_linux_x86_64_toolchain", +# exec_compatible_with = [ +# "@platforms//os:linux", +# "@platforms//cpu:x86_64", +# ], +# target_compatible_with = [ +# "@platforms//os:linux", +# "@platforms//cpu:x86_64", +# ], +# toolchain = ":ldc_linux_x86_64", +# toolchain_type = D_TOOLCHAIN, +# ) diff --git a/d/DMD.bzl b/d/DMD.bzl index 854a1c5..fc50853 100644 --- a/d/DMD.bzl +++ b/d/DMD.bzl @@ -10,19 +10,29 @@ native_binary( "@bazel_tools//src/conditions:linux_x86_64": "linux/bin64/dmd", "@bazel_tools//src/conditions:windows_x64": "windows/bin64/dmd.exe", }), + data = select({ + "@bazel_tools//src/conditions:darwin": ["osx/bin/dmd.conf"], + "@bazel_tools//src/conditions:linux_x86_64": ["linux/bin64/dmd.conf"], + "@bazel_tools//src/conditions:windows_x64": glob(["windows/lib64/mingw/**"]) + [ + "windows/bin64/sc.ini", + "windows/bin64/lld-link.exe", + "windows/bin64/libcurl.dll", + "windows/bin64/msvcr120.dll", + "windows/lib64/curl.lib", + ], + }), ) cc_import( name = "libphobos2", - shared_library = select({ - "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", - "@bazel_tools//src/conditions:linux_x86_64": "linux/lib64/libphobos2.so", - "@bazel_tools//src/conditions:windows_x64": "windows/lib64/dmd.exe", - }), + # shared_library = select({ + # "@bazel_tools//src/conditions:linux_x86_64": "linux/lib64/libphobos2.so", + # "//conditions:default": None, + # }), static_library = select({ - "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", + "@bazel_tools//src/conditions:darwin": "osx/lib/libphobos2.a", "@bazel_tools//src/conditions:linux_x86_64": "linux/lib64/libphobos2.a", - "@bazel_tools//src/conditions:windows_x64": "windows/lib64/dmd.exe", + "@bazel_tools//src/conditions:windows_x64": "windows/lib64/phobos64.lib", }), ) diff --git a/d/LDC.bzl b/d/LDC.bzl index b6bee32..dfe4bfc 100644 --- a/d/LDC.bzl +++ b/d/LDC.bzl @@ -10,6 +10,7 @@ native_binary( "@bazel_tools//src/conditions:linux_x86_64": "bin/ldc2", "@bazel_tools//src/conditions:windows_x64": "bin/ldc2.exe", }), + # TODO: add the conf files to `data` field. ) cc_import( diff --git a/d/constraints/compiler/BUILD b/d/constraints/compiler/BUILD new file mode 100644 index 0000000..ffd0fb0 --- /dev/null +++ b/d/constraints/compiler/BUILD @@ -0,0 +1 @@ +package(default_visibility = ["//visibility:public"]) diff --git a/d/d.bzl b/d/d.bzl index b53b3e8..c89df3e 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -35,31 +35,6 @@ def _files_directory(files): dir = f.dirname return dir -# def _d_toolchain(ctx): -# """Returns a struct containing info about the D toolchain. -# -# Args: -# ctx: The ctx object. -# -# Return: -# Struct containing the following fields: -# d_compiler_path: The path to the D compiler. -# link_flags: Linker (-L) flags for adding the standard library to the -# library search paths. -# import_flags: import (-I) flags for adding the standard library sources -# to the import paths. -# """ -# -# d_compiler_path = ctx.file._d_compiler.path -# return struct( -# d_compiler_path = d_compiler_path, -# link_flags = [("-L/LIBPATH:" if _is_windows(ctx) else "-L-L") + ctx.files._d_stdlib[0].dirname], -# import_flags = [ -# "-I" + _files_directory(ctx.files._d_stdlib_src), -# "-I" + _files_directory(ctx.files._d_runtime_import_src), -# ], -# ) - COMPILATION_MODE_FLAGS_POSIX = { "fastbuild": ["-g"], "dbg": ["-debug", "-g"], @@ -69,8 +44,13 @@ COMPILATION_MODE_FLAGS_POSIX = { COMPILATION_MODE_FLAGS_WINDOWS = { "fastbuild": ["-g", "-m64", "-mscrtlib=msvcrt"], "dbg": ["-debug", "-g", "-m64", "-mscrtlib=msvcrtd"], - "opt": ["-checkaction=halt", "-boundscheck=safeonly", "-O", - "-m64", "-mscrtlib=msvcrt"], + "opt": [ + "-checkaction=halt", + "-boundscheck=safeonly", + "-O", + "-m64", + "-mscrtlib=msvcrt", + ], } def _compilation_mode_flags(ctx): @@ -454,9 +434,9 @@ def _d_docs_impl(ctx): ) toolchain_files = [ - toolchain.libphobos, - toolchain.libphobos_src, - toolchain.druntime_src, + toolchain.libphobos.files, + toolchain.libphobos_src.files, + toolchain.druntime_src.files, ] ddoc_inputs = depset(target.srcs, transitive = [target.transitive_srcs] + toolchain_files) @@ -535,4 +515,3 @@ d_docs = rule( }, toolchains = [D_TOOLCHAIN], ) - diff --git a/d/repositories.bzl b/d/repositories.bzl index e19d089..3765969 100644 --- a/d/repositories.bzl +++ b/d/repositories.bzl @@ -5,7 +5,7 @@ DMD_BUILD_FILE = "//d:DMD.bzl" LDC_BUILD_FILE = "//d:LDC.bzl" DMD_STRIP_PREFIX = "dmd2" -def fetch_and_register_dmd(version = None): +def fetch_dmd(version = None): if version == None: http_archive( name = "dmd_linux_x86_64", @@ -33,7 +33,7 @@ def fetch_and_register_dmd(version = None): "https://downloads.dlang.org/releases/2.x/2.102.1/dmd.2.102.1.windows.zip", ], sha256 = "a263ffbf6232288fa093c71a43a5cc1cd09ef5a75e7eca385ece16606c245090", - strip_prefix = DMD_STRIP_PREFIX, + # strip_prefix = DMD_STRIP_PREFIX, build_file = DMD_BUILD_FILE, ) @@ -68,13 +68,10 @@ def fetch_and_register_dmd(version = None): build_file = DMD_BUILD_FILE, ) - native.register_toolchains( - "//d:dmd_linux_x86_64_toolchain", - ) else: fail("Sorry, only DMD 2 is supported, but got %s. Maybe consider switching to D2?" % version) -def fetch_and_register_ldc(): +def fetch_ldc(version = None): http_archive( name = "ldc_linux_x86_64", urls = [ @@ -85,14 +82,22 @@ def fetch_and_register_ldc(): build_file = LDC_BUILD_FILE, ) - native.register_toolchains( - "//d:ldc_linux_x86_64_toolchain", - ) - def rules_d_toolchains(ctype = "dmd", version = None): if ctype == "dmd": - fetch_and_register_dmd(version = version) + fetch_dmd(version = version) + fetch_ldc() + + native.register_toolchains( + "//d:dmd_linux_x86_64_toolchain", + "//d:dmd_darwin_x86_64_toolchain", + "//d:dmd_windows_x86_64_toolchain", + ) elif ctype == "ldc": - fetch_and_register_ldc() + fetch_dmd() + fetch_ldc(version = version) + + native.register_toolchains( + "//d:ldc_linux_x86_64_toolchain", + ) else: fail("Only \"dmd\" and \"ldc\" compilers are supported at this moment.") diff --git a/d/toolchain.bzl b/d/toolchain.bzl index a6db6a9..230ba95 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -1,5 +1,29 @@ +load("@bazel_skylib//rules:common_settings.bzl", "string_setting") + D_TOOLCHAIN = "@//d:toolchain_type" +# string_setting( +# name = "compiler_type", +# values = [ +# "dmd", +# "ldc", +# ], +# ) +# +# config_setting( +# name = "dmd", +# flag_values = { +# ":compiler_type": "dmd", +# }, +# ) +# +# config_setting( +# name = "ldc", +# flag_values = { +# ":compiler_type": "ldc", +# }, +# ) + def _d_toolchain_impl(ctx): toolchain_info = platform_common.ToolchainInfo( name = ctx.label.name, @@ -32,8 +56,7 @@ d_toolchain = rule( "druntime_src": attr.label(), "ctype": attr.string( default = "dmd", - values = ["dmd", "ldc"] + values = ["dmd", "ldc"], ), - } + }, ) - From 26a5a6fc0158fd384a3f4d28ecdc5c58bd82a4bd Mon Sep 17 00:00:00 2001 From: Gavin Zhao Date: Sat, 25 Feb 2023 11:00:07 -0500 Subject: [PATCH 04/92] Use windows paths Signed-off-by: Gavin Zhao --- d/repositories.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/d/repositories.bzl b/d/repositories.bzl index 3765969..65fa3fa 100644 --- a/d/repositories.bzl +++ b/d/repositories.bzl @@ -33,7 +33,7 @@ def fetch_dmd(version = None): "https://downloads.dlang.org/releases/2.x/2.102.1/dmd.2.102.1.windows.zip", ], sha256 = "a263ffbf6232288fa093c71a43a5cc1cd09ef5a75e7eca385ece16606c245090", - # strip_prefix = DMD_STRIP_PREFIX, + strip_prefix = DMD_STRIP_PREFIX, build_file = DMD_BUILD_FILE, ) From 2e74016adf637bfbd1d40fcc280d4690f4d6e80f Mon Sep 17 00:00:00 2001 From: Gavin Zhao Date: Fri, 30 Jun 2023 10:41:44 -0400 Subject: [PATCH 05/92] Use platforms to specify DMD or LDC Signed-off-by: Gavin Zhao --- d/BUILD | 51 ++++++++++++++++++++---------------- d/constraints/compiler/BUILD | 16 +++++++++++ d/d.bzl | 3 +-- d/platforms/BUILD | 18 +++++++++++++ d/repositories.bzl | 1 + d/toolchain.bzl | 7 ++--- 6 files changed, 66 insertions(+), 30 deletions(-) create mode 100644 d/platforms/BUILD diff --git a/d/BUILD b/d/BUILD index c9c4775..80557e6 100644 --- a/d/BUILD +++ b/d/BUILD @@ -15,6 +15,7 @@ filegroup( druntime_src = "@dmd_" + os + "_x86_64//:druntime_src", libphobos = "@dmd_" + os + "_x86_64//:libphobos2", libphobos_src = "@dmd_" + os + "_x86_64//:phobos_src", + version_flag = "-version", ) for os in ["linux", "darwin", "windows"]] toolchain( @@ -22,6 +23,7 @@ toolchain( exec_compatible_with = [ "@platforms//os:linux", "@platforms//cpu:x86_64", + "@//d/constraints/compiler:dmd", ], target_compatible_with = [ "@platforms//os:linux", @@ -36,6 +38,7 @@ toolchain( exec_compatible_with = [ "@platforms//os:macos", "@platforms//cpu:x86_64", + "@//d/constraints/compiler:dmd", ], target_compatible_with = [ "@platforms//os:macos", @@ -50,6 +53,7 @@ toolchain( exec_compatible_with = [ "@platforms//os:windows", "@platforms//cpu:x86_64", + "@//d/constraints/compiler:dmd", ], target_compatible_with = [ "@platforms//os:windows", @@ -59,26 +63,27 @@ toolchain( toolchain_type = D_TOOLCHAIN, ) -# d_toolchain( -# name = "ldc_linux_x86_64", -# ctype = "ldc", -# d_compiler = "@ldc_linux_x86_64//:ldc2", -# druntime = "@ldc_linux_x86_64//:druntime", -# druntime_src = "@ldc_linux_x86_64//:druntime_src", -# libphobos = "@ldc_linux_x86_64//:libphobos2", -# libphobos_src = "@ldc_linux_x86_64//:phobos_src", -# ) -# -# toolchain( -# name = "ldc_linux_x86_64_toolchain", -# exec_compatible_with = [ -# "@platforms//os:linux", -# "@platforms//cpu:x86_64", -# ], -# target_compatible_with = [ -# "@platforms//os:linux", -# "@platforms//cpu:x86_64", -# ], -# toolchain = ":ldc_linux_x86_64", -# toolchain_type = D_TOOLCHAIN, -# ) +d_toolchain( + name = "ldc_linux_x86_64", + d_compiler = "@ldc_linux_x86_64//:ldc2", + druntime = "@ldc_linux_x86_64//:druntime", + druntime_src = "@ldc_linux_x86_64//:druntime_src", + libphobos = "@ldc_linux_x86_64//:libphobos2", + libphobos_src = "@ldc_linux_x86_64//:phobos_src", + version_flag = "--d-version", +) + +toolchain( + name = "ldc_linux_x86_64_toolchain", + exec_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + "@//d/constraints/compiler:ldc", + ], + target_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + toolchain = ":ldc_linux_x86_64", + toolchain_type = D_TOOLCHAIN, +) diff --git a/d/constraints/compiler/BUILD b/d/constraints/compiler/BUILD index ffd0fb0..140cfca 100644 --- a/d/constraints/compiler/BUILD +++ b/d/constraints/compiler/BUILD @@ -1 +1,17 @@ package(default_visibility = ["//visibility:public"]) + +constraint_setting( + name = "d_compiler", + default_constraint_value = ":dmd", +) + +constraint_value( + name = "dmd", + constraint_setting = ":d_compiler", +) + +constraint_value( + name = "ldc", + constraint_setting = ":d_compiler", +) + diff --git a/d/d.bzl b/d/d.bzl index c89df3e..30bca30 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -77,8 +77,7 @@ def _build_import(label, im): def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): """Returns a list of strings constituting the D compile command arguments.""" toolchain = ctx.toolchains[D_TOOLCHAIN] - isDMD = toolchain.ctype == "dmd" - version_flag = "-version" if isDMD else "-d-version" + version_flag = toolchain.version_flag return ( _compilation_mode_flags(ctx) + diff --git a/d/platforms/BUILD b/d/platforms/BUILD new file mode 100644 index 0000000..0644ef2 --- /dev/null +++ b/d/platforms/BUILD @@ -0,0 +1,18 @@ +package(default_visibility = ["//visibility:public"]) + +platform( + name = "dmd", + parents = ["@local_config_platform//:host"], + constraint_values = [ + "@//d/constraints/compiler:dmd", + ], +) + +platform( + name = "ldc", + parents = ["@local_config_platform//:host"], + constraint_values = [ + "@//d/constraints/compiler:ldc", + ], +) + diff --git a/d/repositories.bzl b/d/repositories.bzl index 65fa3fa..9c985fe 100644 --- a/d/repositories.bzl +++ b/d/repositories.bzl @@ -91,6 +91,7 @@ def rules_d_toolchains(ctype = "dmd", version = None): "//d:dmd_linux_x86_64_toolchain", "//d:dmd_darwin_x86_64_toolchain", "//d:dmd_windows_x86_64_toolchain", + "//d:ldc_linux_x86_64_toolchain", ) elif ctype == "ldc": fetch_dmd() diff --git a/d/toolchain.bzl b/d/toolchain.bzl index 230ba95..16383ff 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -34,7 +34,7 @@ def _d_toolchain_impl(ctx): libphobos_src = ctx.attr.libphobos_src, druntime = ctx.attr.druntime, druntime_src = ctx.attr.druntime_src, - ctype = ctx.attr.ctype, + version_flag = ctx.attr.version_flag, ) return [toolchain_info] @@ -54,9 +54,6 @@ d_toolchain = rule( "libphobos_src": attr.label(), "druntime": attr.label(), "druntime_src": attr.label(), - "ctype": attr.string( - default = "dmd", - values = ["dmd", "ldc"], - ), + "version_flag": attr.string(), }, ) From 278459e4e5bafb4e0e17baef9192d95c368ff45a Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Tue, 1 Apr 2025 10:08:15 -0400 Subject: [PATCH 06/92] Remove d_repositories from d.bzl Seems to be a bad merge, these things are in a separate file now --- d/d.bzl | 81 --------------------------------------------------------- 1 file changed, 81 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index ddef99e..30bca30 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -514,84 +514,3 @@ d_docs = rule( }, toolchains = [D_TOOLCHAIN], ) - -DMD_BUILD_FILE = """ -package(default_visibility = ["//visibility:public"]) - -config_setting( - name = "darwin", - values = {"host_cpu": "darwin"}, -) - -config_setting( - name = "k8", - values = {"host_cpu": "k8"}, -) - -config_setting( - name = "x64_windows", - values = {"host_cpu": "x64_windows"}, -) - -filegroup( - name = "dmd", - srcs = select({ - ":darwin": ["dmd2/osx/bin/dmd"], - ":k8": ["dmd2/linux/bin64/dmd"], - ":x64_windows": ["dmd2/windows/bin64/dmd.exe"], - }), -) - -filegroup( - name = "libphobos2", - srcs = select({ - ":darwin": ["dmd2/osx/lib/libphobos2.a"], - ":k8": [ - "dmd2/linux/lib64/libphobos2.a", - "dmd2/linux/lib64/libphobos2.so", - ], - ":x64_windows": ["dmd2/windows/lib64/phobos64.lib"], - }), -) - -filegroup( - name = "phobos-src", - srcs = glob(["dmd2/src/phobos/**/*.*"]), -) - -filegroup( - name = "druntime-import-src", - srcs = glob([ - "dmd2/src/druntime/import/*.*", - "dmd2/src/druntime/import/**/*.*", - ]), -) -""" - -def d_repositories(): - http_archive( - name = "dmd_linux_x86_64", - urls = [ - "https://downloads.dlang.org/releases/2.x/2.101.2/dmd.2.101.2.linux.tar.xz", - ], - sha256 = "95d96731853805a8a026324240f8ea7bd871927f6a405d14268408685bbbdc5c", - build_file_content = DMD_BUILD_FILE, - ) - - http_archive( - name = "dmd_darwin_x86_64", - urls = [ - "https://downloads.dlang.org/releases/2.x/2.101.2/dmd.2.101.2.osx.tar.xz", - ], - sha256 = "45bbe0d0e500faee5c84aaa5b124553671f1cec06a711860647cfaa7016aeb56", - build_file_content = DMD_BUILD_FILE, - ) - - http_archive( - name = "dmd_windows_x86_64", - urls = [ - "https://downloads.dlang.org/releases/2.x/2.101.2/dmd.2.101.2.windows.zip", - ], - sha256 = "8065df7316e4d2d9e1f322998ec16b4b52c5c966dc3e7220159ba4029d5b97ba", - build_file_content = DMD_BUILD_FILE, - ) From 66f2bac88b4b23f62cafc3796972234ae60b89c5 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Tue, 1 Apr 2025 10:17:09 -0400 Subject: [PATCH 07/92] Comment out windows stuff Doesn't work for me --- d/BUILD | 30 +++++++++++++++--------------- d/DMD.bzl | 18 +++++++++--------- d/LDC.bzl | 12 ++++++------ d/repositories.bzl | 20 ++++++++++---------- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/d/BUILD b/d/BUILD index 80557e6..af1bf56 100644 --- a/d/BUILD +++ b/d/BUILD @@ -16,7 +16,7 @@ filegroup( libphobos = "@dmd_" + os + "_x86_64//:libphobos2", libphobos_src = "@dmd_" + os + "_x86_64//:phobos_src", version_flag = "-version", -) for os in ["linux", "darwin", "windows"]] +) for os in ["linux", "darwin"]] # , "windows"]] toolchain( name = "dmd_linux_x86_64_toolchain", @@ -48,20 +48,20 @@ toolchain( toolchain_type = D_TOOLCHAIN, ) -toolchain( - name = "dmd_windows_x86_64_toolchain", - exec_compatible_with = [ - "@platforms//os:windows", - "@platforms//cpu:x86_64", - "@//d/constraints/compiler:dmd", - ], - target_compatible_with = [ - "@platforms//os:windows", - "@platforms//cpu:x86_64", - ], - toolchain = ":dmd_windows_x86_64", - toolchain_type = D_TOOLCHAIN, -) +# toolchain( +# name = "dmd_windows_x86_64_toolchain", +# exec_compatible_with = [ +# "@platforms//os:windows", +# "@platforms//cpu:x86_64", +# "@//d/constraints/compiler:dmd", +# ], +# target_compatible_with = [ +# "@platforms//os:windows", +# "@platforms//cpu:x86_64", +# ], +# toolchain = ":dmd_windows_x86_64", +# toolchain_type = D_TOOLCHAIN, +# ) d_toolchain( name = "ldc_linux_x86_64", diff --git a/d/DMD.bzl b/d/DMD.bzl index fc50853..3645d34 100644 --- a/d/DMD.bzl +++ b/d/DMD.bzl @@ -8,18 +8,18 @@ native_binary( src = select({ "@bazel_tools//src/conditions:darwin": "osx/bin/dmd", "@bazel_tools//src/conditions:linux_x86_64": "linux/bin64/dmd", - "@bazel_tools//src/conditions:windows_x64": "windows/bin64/dmd.exe", + # "@bazel_tools//src/conditions:windows_x64": "windows/bin64/dmd.exe", }), data = select({ "@bazel_tools//src/conditions:darwin": ["osx/bin/dmd.conf"], "@bazel_tools//src/conditions:linux_x86_64": ["linux/bin64/dmd.conf"], - "@bazel_tools//src/conditions:windows_x64": glob(["windows/lib64/mingw/**"]) + [ - "windows/bin64/sc.ini", - "windows/bin64/lld-link.exe", - "windows/bin64/libcurl.dll", - "windows/bin64/msvcr120.dll", - "windows/lib64/curl.lib", - ], + # "@bazel_tools//src/conditions:windows_x64": glob(["windows/lib64/mingw/**"]) + [ + # "windows/bin64/sc.ini", + # "windows/bin64/lld-link.exe", + # "windows/bin64/libcurl.dll", + # "windows/bin64/msvcr120.dll", + # "windows/lib64/curl.lib", + # ], }), ) @@ -32,7 +32,7 @@ cc_import( static_library = select({ "@bazel_tools//src/conditions:darwin": "osx/lib/libphobos2.a", "@bazel_tools//src/conditions:linux_x86_64": "linux/lib64/libphobos2.a", - "@bazel_tools//src/conditions:windows_x64": "windows/lib64/phobos64.lib", + # "@bazel_tools//src/conditions:windows_x64": "windows/lib64/phobos64.lib", }), ) diff --git a/d/LDC.bzl b/d/LDC.bzl index dfe4bfc..b89e096 100644 --- a/d/LDC.bzl +++ b/d/LDC.bzl @@ -8,7 +8,7 @@ native_binary( src = select({ "@bazel_tools//src/conditions:darwin": "bin/ldc2", "@bazel_tools//src/conditions:linux_x86_64": "bin/ldc2", - "@bazel_tools//src/conditions:windows_x64": "bin/ldc2.exe", + # "@bazel_tools//src/conditions:windows_x64": "bin/ldc2.exe", }), # TODO: add the conf files to `data` field. ) @@ -18,12 +18,12 @@ cc_import( shared_library = select({ "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", "@bazel_tools//src/conditions:linux_x86_64": "lib/libphobos2-ldc-shared.so", - "@bazel_tools//src/conditions:windows_x64": "lib/phobos2-ldc-shared.lib", + # "@bazel_tools//src/conditions:windows_x64": "lib/phobos2-ldc-shared.lib", }), static_library = select({ "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", "@bazel_tools//src/conditions:linux_x86_64": "lib/libphobos2-ldc.a", - "@bazel_tools//src/conditions:windows_x64": "lib/phobos2-ldc.lib", + # "@bazel_tools//src/conditions:windows_x64": "lib/phobos2-ldc.lib", }), ) @@ -32,12 +32,12 @@ cc_import( shared_library = select({ "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", "@bazel_tools//src/conditions:linux_x86_64": "lib/libdruntime-ldc-shared.so", - "@bazel_tools//src/conditions:windows_x64": "lib/druntime-ldc-shared.lib", + # "@bazel_tools//src/conditions:windows_x64": "lib/druntime-ldc-shared.lib", }), static_library = select({ "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", "@bazel_tools//src/conditions:linux_x86_64": "lib/libdruntime-ldc.a", - "@bazel_tools//src/conditions:windows_x64": "lib/druntime-ldc.lib", + # "@bazel_tools//src/conditions:windows_x64": "lib/druntime-ldc.lib", }), ) @@ -47,7 +47,7 @@ filegroup( "import/std/**/*.*", "import/std/*.*", "import/etc/**/*.*", - "import/etc/*.*", + # "import/etc/*.*", ]), ) diff --git a/d/repositories.bzl b/d/repositories.bzl index 9c985fe..7525163 100644 --- a/d/repositories.bzl +++ b/d/repositories.bzl @@ -27,15 +27,15 @@ def fetch_dmd(version = None): build_file = DMD_BUILD_FILE, ) - http_archive( - name = "dmd_windows_x86_64", - urls = [ - "https://downloads.dlang.org/releases/2.x/2.102.1/dmd.2.102.1.windows.zip", - ], - sha256 = "a263ffbf6232288fa093c71a43a5cc1cd09ef5a75e7eca385ece16606c245090", - strip_prefix = DMD_STRIP_PREFIX, - build_file = DMD_BUILD_FILE, - ) + # http_archive( + # name = "dmd_windows_x86_64", + # urls = [ + # "https://downloads.dlang.org/releases/2.x/2.102.1/dmd.2.102.1.windows.zip", + # ], + # sha256 = "a263ffbf6232288fa093c71a43a5cc1cd09ef5a75e7eca385ece16606c245090", + # strip_prefix = DMD_STRIP_PREFIX, + # build_file = DMD_BUILD_FILE, + # ) native.register_toolchains( "//d:dmd_linux_x86_64_toolchain", @@ -90,7 +90,7 @@ def rules_d_toolchains(ctype = "dmd", version = None): native.register_toolchains( "//d:dmd_linux_x86_64_toolchain", "//d:dmd_darwin_x86_64_toolchain", - "//d:dmd_windows_x86_64_toolchain", + # "//d:dmd_windows_x86_64_toolchain", "//d:ldc_linux_x86_64_toolchain", ) elif ctype == "ldc": From 77e6794458e9363824cb419e638b8ea103861431 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Tue, 1 Apr 2025 17:32:53 -0400 Subject: [PATCH 08/92] Switch to use DInfo provider instead of struct --- d/d.bzl | 111 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 62 insertions(+), 49 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 30bca30..0e0b8dd 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -27,6 +27,8 @@ D_FILETYPE = [".d", ".di"] ZIP_PATH = "/usr/bin/zip" +DInfo = provider() + def _files_directory(files): """Returns the shortest parent directory of a list of files.""" dir = files[0].dirname @@ -136,24 +138,26 @@ def _setup_deps(ctx, deps, name, working_dir): imports = [] link_flags = [] for dep in deps: - if hasattr(dep, "d_lib"): + if DInfo in dep and hasattr(dep[DInfo], "d_lib"): # The dependency is a d_library. - libs.append(dep.d_lib) - transitive_libs.append(dep.transitive_libs) - d_srcs += dep.d_srcs - transitive_d_srcs.append(dep.transitive_d_srcs) - versions += dep.versions + ["Have_%s" % _format_version(dep.label.name)] - link_flags.extend(dep.link_flags) - imports += [_build_import(dep.label, im) for im in dep.imports] - - elif hasattr(dep, "d_srcs"): + ddep = dep[DInfo] + libs.append(ddep.d_lib) + transitive_libs.append(ddep.transitive_libs) + d_srcs += ddep.d_srcs + transitive_d_srcs.append(ddep.transitive_d_srcs) + versions += ddep.versions + ["Have_%s" % _format_version(dep.label.name)] + link_flags.extend(ddep.link_flags) + imports += [_build_import(ddep.label, im) for im in ddep.imports] + + elif DInfo in dep and hasattr(dep[DInfo], "d_srcs"): # The dependency is a d_source_library. - d_srcs += dep.d_srcs - transitive_d_srcs.append(dep.transitive_d_srcs) - transitive_libs.append(dep.transitive_libs) - link_flags += ["-L%s" % linkopt for linkopt in dep.linkopts] - imports += [_build_import(dep.label, im) for im in dep.imports] - versions += dep.versions + ddep = dep[DInfo] + d_srcs += ddep.d_srcs + transitive_d_srcs.append(ddep.transitive_d_srcs) + transitive_libs.append(ddep.transitive_libs) + link_flags += ["-L%s" % linkopt for linkopt in ddep.linkopts] + imports += [_build_import(ddep.label, im) for im in ddep.imports] + versions += ddep.versions elif CcInfo in dep: # The dependency is a cc_library @@ -226,16 +230,18 @@ def _d_library_impl(ctx): progress_message = "Compiling D library " + ctx.label.name, ) - return struct( - files = depset([d_lib]), - d_srcs = ctx.files.srcs, - transitive_d_srcs = depset(depinfo.d_srcs), - transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), - link_flags = depinfo.link_flags, - versions = ctx.attr.versions, - imports = ctx.attr.imports, - d_lib = d_lib, - ) + return [ + DInfo( + files = depset([d_lib]), + d_srcs = ctx.files.srcs, + transitive_d_srcs = depset(depinfo.d_srcs), + transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), + link_flags = depinfo.link_flags, + versions = ctx.attr.versions, + imports = ctx.attr.imports, + d_lib = d_lib, + ), + ] def _d_binary_impl_common(ctx, extra_flags = []): """Common implementation for rules that build a D binary.""" @@ -309,12 +315,16 @@ def _d_binary_impl_common(ctx, extra_flags = []): progress_message = "Linking D binary " + ctx.label.name, ) - return struct( - d_srcs = ctx.files.srcs, - transitive_d_srcs = depset(depinfo.d_srcs), - imports = ctx.attr.imports, - executable = d_bin, - ) + return [ + DInfo( + d_srcs = ctx.files.srcs, + transitive_d_srcs = depset(depinfo.d_srcs), + imports = ctx.attr.imports, + ), + DefaultInfo( + executable = d_bin, + ), + ] def _d_binary_impl(ctx): """Implementation of the d_binary rule.""" @@ -355,13 +365,14 @@ def _d_source_library_impl(ctx): transitive_linkopts = depset() transitive_versions = depset() for dep in ctx.attr.deps: - if hasattr(dep, "d_srcs"): + if DInfo in dep and hasattr(dep[DInfo], "d_srcs"): # Dependency is another d_source_library target. - transitive_d_srcs.append(dep.d_srcs) - transitive_imports = depset(dep.imports, transitive = [transitive_imports]) - transitive_linkopts = depset(dep.linkopts, transitive = [transitive_linkopts]) - transitive_versions = depset(dep.versions, transitive = [transitive_versions]) - transitive_transitive_libs.append(dep.transitive_libs) + ddep = dep[DInfo] + transitive_d_srcs.append(ddep.d_srcs) + transitive_imports = depset(ddep.imports, transitive = [transitive_imports]) + transitive_linkopts = depset(ddep.linkopts, transitive = [transitive_linkopts]) + transitive_versions = depset(ddep.versions, transitive = [transitive_versions]) + transitive_transitive_libs.append(ddep.transitive_libs) elif CcInfo in dep: # Dependency is a cc_library target. @@ -372,14 +383,16 @@ def _d_source_library_impl(ctx): fail("d_source_library can only depend on other " + "d_source_library or cc_library targets.", "deps") - return struct( - d_srcs = ctx.files.srcs, - transitive_d_srcs = depset(transitive = transitive_d_srcs, order = "postorder"), - transitive_libs = depset(transitive_libs, transitive = transitive_transitive_libs), - imports = ctx.attr.imports + transitive_imports.to_list(), - linkopts = ctx.attr.linkopts + transitive_linkopts.to_list(), - versions = ctx.attr.versions + transitive_versions.to_list(), - ) + return [ + DInfo( + d_srcs = ctx.files.srcs, + transitive_d_srcs = depset(transitive = transitive_d_srcs, order = "postorder"), + transitive_libs = depset(transitive_libs, transitive = transitive_transitive_libs), + imports = ctx.attr.imports + transitive_imports.to_list(), + linkopts = ctx.attr.linkopts + transitive_linkopts.to_list(), + versions = ctx.attr.versions + transitive_versions.to_list(), + ), + ] # TODO(dzc): Use ddox for generating HTML documentation. def _d_docs_impl(ctx): @@ -397,9 +410,9 @@ def _d_docs_impl(ctx): target = struct( name = ctx.attr.dep.label.name, - srcs = ctx.attr.dep.d_srcs, - transitive_srcs = ctx.attr.dep.transitive_d_srcs, - imports = ctx.attr.dep.imports, + srcs = ctx.attr.dep[DInfo].d_srcs, + transitive_srcs = ctx.attr.dep[DInfo].transitive_d_srcs, + imports = ctx.attr.dep[DInfo].imports, ) toolchain = ctx.toolchains[D_TOOLCHAIN] From c015c266749d88558df9e95b2c1c134358bdda2d Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Thu, 3 Apr 2025 04:02:50 -0400 Subject: [PATCH 09/92] Make it work with bazel modules --- MODULE.bazel | 15 +++++++++++++++ WORKSPACE | 18 ++---------------- d/extensions.bzl | 6 ++++++ d/repositories.bzl | 12 ------------ extensions.bzl | 0 5 files changed, 23 insertions(+), 28 deletions(-) create mode 100644 MODULE.bazel create mode 100644 d/extensions.bzl delete mode 100644 extensions.bzl diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000..dc55cae --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,15 @@ +module( + name = "rules_d", + repo_name = "io_bazel_rules_d", +) + +bazel_dep( + name = "bazel_skylib", + version = "1.7.1", +) + +bazel_dep(name="platforms", version="0.0.11") + +non_module_dependencies = use_extension("//d:extensions.bzl", "non_module_dependencies") +use_repo(non_module_dependencies, "ldc_linux_x86_64", "dmd_linux_x86_64", "dmd_darwin_x86_64") +register_toolchains("//d:ldc_linux_x86_64_toolchain", "//d:dmd_linux_x86_64_toolchain", "//d:dmd_darwin_x86_64_toolchain") \ No newline at end of file diff --git a/WORKSPACE b/WORKSPACE index 3124b1e..9aceb46 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,16 +1,2 @@ -workspace(name = "io_bazel_rules_d") - -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -http_archive( - name = "bazel_skylib", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz", - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz", - ], - sha256 = "74d544d96f4a5bb630d465ca8bbcfe231e3594e5aae57e1edbf17a6eb3ca2506", -) -load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") -bazel_skylib_workspace() - -load("@io_bazel_rules_d//d:repositories.bzl", "rules_d_toolchains") -rules_d_toolchains() +## This is just a root of workspace marked +## Dependencies are moved to MODULE.bazel diff --git a/d/extensions.bzl b/d/extensions.bzl new file mode 100644 index 0000000..fdde34e --- /dev/null +++ b/d/extensions.bzl @@ -0,0 +1,6 @@ +load("//d:repositories.bzl", "rules_d_toolchains") + +def _non_module_dependencies_impl(_ctx): + rules_d_toolchains() + +non_module_dependencies = module_extension(implementation = _non_module_dependencies_impl) diff --git a/d/repositories.bzl b/d/repositories.bzl index 7525163..d3af200 100644 --- a/d/repositories.bzl +++ b/d/repositories.bzl @@ -37,9 +37,6 @@ def fetch_dmd(version = None): # build_file = DMD_BUILD_FILE, # ) - native.register_toolchains( - "//d:dmd_linux_x86_64_toolchain", - ) elif versions.is_at_least("2.0.0", version): http_archive( name = "dmd_linux_x86_64", @@ -87,18 +84,9 @@ def rules_d_toolchains(ctype = "dmd", version = None): fetch_dmd(version = version) fetch_ldc() - native.register_toolchains( - "//d:dmd_linux_x86_64_toolchain", - "//d:dmd_darwin_x86_64_toolchain", - # "//d:dmd_windows_x86_64_toolchain", - "//d:ldc_linux_x86_64_toolchain", - ) elif ctype == "ldc": fetch_dmd() fetch_ldc(version = version) - native.register_toolchains( - "//d:ldc_linux_x86_64_toolchain", - ) else: fail("Only \"dmd\" and \"ldc\" compilers are supported at this moment.") diff --git a/extensions.bzl b/extensions.bzl deleted file mode 100644 index e69de29..0000000 From c573d1060722e31b4ab6207d900cf049d6273119 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Thu, 3 Apr 2025 04:22:18 -0400 Subject: [PATCH 10/92] Remove ocasional `@`s. They are not compatible with bazel mods --- d/BUILD | 8 ++++---- d/platforms/BUILD | 4 ++-- d/toolchain.bzl | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/d/BUILD b/d/BUILD index af1bf56..b869f96 100644 --- a/d/BUILD +++ b/d/BUILD @@ -23,7 +23,7 @@ toolchain( exec_compatible_with = [ "@platforms//os:linux", "@platforms//cpu:x86_64", - "@//d/constraints/compiler:dmd", + "//d/constraints/compiler:dmd", ], target_compatible_with = [ "@platforms//os:linux", @@ -38,7 +38,7 @@ toolchain( exec_compatible_with = [ "@platforms//os:macos", "@platforms//cpu:x86_64", - "@//d/constraints/compiler:dmd", + "//d/constraints/compiler:dmd", ], target_compatible_with = [ "@platforms//os:macos", @@ -53,7 +53,7 @@ toolchain( # exec_compatible_with = [ # "@platforms//os:windows", # "@platforms//cpu:x86_64", -# "@//d/constraints/compiler:dmd", +# "//d/constraints/compiler:dmd", # ], # target_compatible_with = [ # "@platforms//os:windows", @@ -78,7 +78,7 @@ toolchain( exec_compatible_with = [ "@platforms//os:linux", "@platforms//cpu:x86_64", - "@//d/constraints/compiler:ldc", + "//d/constraints/compiler:ldc", ], target_compatible_with = [ "@platforms//os:linux", diff --git a/d/platforms/BUILD b/d/platforms/BUILD index 0644ef2..4d4df0f 100644 --- a/d/platforms/BUILD +++ b/d/platforms/BUILD @@ -4,7 +4,7 @@ platform( name = "dmd", parents = ["@local_config_platform//:host"], constraint_values = [ - "@//d/constraints/compiler:dmd", + "//d/constraints/compiler:dmd", ], ) @@ -12,7 +12,7 @@ platform( name = "ldc", parents = ["@local_config_platform//:host"], constraint_values = [ - "@//d/constraints/compiler:ldc", + "//d/constraints/compiler:ldc", ], ) diff --git a/d/toolchain.bzl b/d/toolchain.bzl index 16383ff..9d57248 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -1,6 +1,6 @@ load("@bazel_skylib//rules:common_settings.bzl", "string_setting") -D_TOOLCHAIN = "@//d:toolchain_type" +D_TOOLCHAIN = "//d:toolchain_type" # string_setting( # name = "compiler_type", From 160f5794a24a0b26455da953fb40f521c2617879 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Thu, 3 Apr 2025 05:11:04 -0400 Subject: [PATCH 11/92] `files` must be in `DefaultInfo` to create a library file --- d/d.bzl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/d/d.bzl b/d/d.bzl index 0e0b8dd..864fc07 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -231,8 +231,10 @@ def _d_library_impl(ctx): ) return [ - DInfo( + DefaultInfo( files = depset([d_lib]), + ), + DInfo( d_srcs = ctx.files.srcs, transitive_d_srcs = depset(depinfo.d_srcs), transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), From 5c34eb7cc380797cc6d8bf7257959bd07648ef73 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Thu, 3 Apr 2025 06:02:21 -0400 Subject: [PATCH 12/92] Add weka-ldc toolchain --- MODULE.bazel | 4 ++-- d/BUILD | 25 +++++++++++++++++++++++++ d/constraints/compiler/BUILD | 4 ++++ d/platforms/BUILD | 7 +++++++ d/repositories.bzl | 21 ++++++++++++++++++++- 5 files changed, 58 insertions(+), 3 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index dc55cae..d3c112d 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -11,5 +11,5 @@ bazel_dep( bazel_dep(name="platforms", version="0.0.11") non_module_dependencies = use_extension("//d:extensions.bzl", "non_module_dependencies") -use_repo(non_module_dependencies, "ldc_linux_x86_64", "dmd_linux_x86_64", "dmd_darwin_x86_64") -register_toolchains("//d:ldc_linux_x86_64_toolchain", "//d:dmd_linux_x86_64_toolchain", "//d:dmd_darwin_x86_64_toolchain") \ No newline at end of file +use_repo(non_module_dependencies, "ldc_linux_x86_64", "dmd_linux_x86_64", "dmd_darwin_x86_64", "weka_ldc_linux_x86_64") +register_toolchains("//d:ldc_linux_x86_64_toolchain", "//d:dmd_linux_x86_64_toolchain", "//d:dmd_darwin_x86_64_toolchain", "//d:weka_ldc_linux_x86_64_toolchain") \ No newline at end of file diff --git a/d/BUILD b/d/BUILD index b869f96..8ec3f7e 100644 --- a/d/BUILD +++ b/d/BUILD @@ -87,3 +87,28 @@ toolchain( toolchain = ":ldc_linux_x86_64", toolchain_type = D_TOOLCHAIN, ) + +d_toolchain( + name = "weka_ldc_linux_x86_64", + d_compiler = "@weka_ldc_linux_x86_64//:ldc2", + druntime = "@weka_ldc_linux_x86_64//:druntime", + druntime_src = "@weka_ldc_linux_x86_64//:druntime_src", + libphobos = "@weka_ldc_linux_x86_64//:libphobos2", + libphobos_src = "@weka_ldc_linux_x86_64//:phobos_src", + version_flag = "--d-version", +) + +toolchain( + name = "weka_ldc_linux_x86_64_toolchain", + exec_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + "//d/constraints/compiler:weka-ldc", + ], + target_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + toolchain = ":weka_ldc_linux_x86_64", + toolchain_type = D_TOOLCHAIN, +) diff --git a/d/constraints/compiler/BUILD b/d/constraints/compiler/BUILD index 140cfca..53d2e18 100644 --- a/d/constraints/compiler/BUILD +++ b/d/constraints/compiler/BUILD @@ -15,3 +15,7 @@ constraint_value( constraint_setting = ":d_compiler", ) +constraint_value( + name = "weka-ldc", + constraint_setting = ":d_compiler", +) diff --git a/d/platforms/BUILD b/d/platforms/BUILD index 4d4df0f..51ee5d6 100644 --- a/d/platforms/BUILD +++ b/d/platforms/BUILD @@ -16,3 +16,10 @@ platform( ], ) +platform( + name = "weka-ldc", + parents = ["@local_config_platform//:host"], + constraint_values = [ + "//d/constraints/compiler:weka-ldc", + ], +) \ No newline at end of file diff --git a/d/repositories.bzl b/d/repositories.bzl index d3af200..c77406f 100644 --- a/d/repositories.bzl +++ b/d/repositories.bzl @@ -79,14 +79,33 @@ def fetch_ldc(version = None): build_file = LDC_BUILD_FILE, ) +def fetch_weka_ldc(version = "1.30-weka17-ctfe-attr"): + http_archive( + name = "weka_ldc_linux_x86_64", + urls = [ + "https://github.com/yanok/ldc/releases/download/v{version}/ldc2-{version}-linux-x86_64.tar.xz".format(version = version), + ], + sha256 = "30fcca329dcaa7a15e2dfa7828c07e462b438a106b706aa5a20e2a8ea1570e0c", + strip_prefix = "ldc2-{version}-linux-x86_64".format(version = version), + build_file = LDC_BUILD_FILE, + ) + def rules_d_toolchains(ctype = "dmd", version = None): if ctype == "dmd": fetch_dmd(version = version) fetch_ldc() + fetch_weka_ldc() elif ctype == "ldc": fetch_dmd() fetch_ldc(version = version) + fetch_weka_ldc() + + elif ctype == "weka-ldc": + # Special case for Weka LDC, which is a fork of LDC + fetch_weka_ldc(version = version) + fetch_dmd() + fetch_ldc() else: - fail("Only \"dmd\" and \"ldc\" compilers are supported at this moment.") + fail("Only \"dmd\", \"ldc\" and \"weka-ldc\" compilers are supported at this moment.") From f93ec3eb1240942ea1c37daf71578f9214ab70fc Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Thu, 3 Apr 2025 10:59:15 -0400 Subject: [PATCH 13/92] Fix error introduced by migration to providers `label` is an attribute of `dep`, not `ddep`. --- d/d.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 864fc07..1cba548 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -147,7 +147,7 @@ def _setup_deps(ctx, deps, name, working_dir): transitive_d_srcs.append(ddep.transitive_d_srcs) versions += ddep.versions + ["Have_%s" % _format_version(dep.label.name)] link_flags.extend(ddep.link_flags) - imports += [_build_import(ddep.label, im) for im in ddep.imports] + imports += [_build_import(dep.label, im) for im in ddep.imports] elif DInfo in dep and hasattr(dep[DInfo], "d_srcs"): # The dependency is a d_source_library. @@ -156,7 +156,7 @@ def _setup_deps(ctx, deps, name, working_dir): transitive_d_srcs.append(ddep.transitive_d_srcs) transitive_libs.append(ddep.transitive_libs) link_flags += ["-L%s" % linkopt for linkopt in ddep.linkopts] - imports += [_build_import(ddep.label, im) for im in ddep.imports] + imports += [_build_import(dep.label, im) for im in ddep.imports] versions += ddep.versions elif CcInfo in dep: From f7521f7bb39e0a58555a37cbf22d0390cddda697 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Thu, 3 Apr 2025 11:00:03 -0400 Subject: [PATCH 14/92] d_library: use `-oq` flag to avoid filename collision --- d/d.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/d/d.bzl b/d/d.bzl index 1cba548..c6a9b52 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -193,7 +193,7 @@ def _d_library_impl(ctx): ctx = ctx, out = d_lib, depinfo = depinfo, - extra_flags = ["-lib"], + extra_flags = ["-lib", "-oq"], ) # Convert sources to args From caaa8106f0206069c076fa8ae0af353e4da93935 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Fri, 4 Apr 2025 10:40:08 -0400 Subject: [PATCH 15/92] Fix enforcement of no d_library in d_source_library deps --- d/d.bzl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/d/d.bzl b/d/d.bzl index c6a9b52..91ef5f9 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -367,8 +367,9 @@ def _d_source_library_impl(ctx): transitive_linkopts = depset() transitive_versions = depset() for dep in ctx.attr.deps: - if DInfo in dep and hasattr(dep[DInfo], "d_srcs"): + if DInfo in dep and hasattr(dep[DInfo], "d_srcs") and not hasattr(dep[DInfo], "d_lib"): # Dependency is another d_source_library target. + # TODO: Could we also support d_library here? ddep = dep[DInfo] transitive_d_srcs.append(ddep.d_srcs) transitive_imports = depset(ddep.imports, transitive = [transitive_imports]) From ede793ffadc8147b1f0c60c3bffdac2433620e3e Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Mon, 7 Apr 2025 11:13:47 -0400 Subject: [PATCH 16/92] d_source_library: transitive_d_srcs should contain depsets --- d/d.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/d/d.bzl b/d/d.bzl index 91ef5f9..de1891b 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -371,7 +371,7 @@ def _d_source_library_impl(ctx): # Dependency is another d_source_library target. # TODO: Could we also support d_library here? ddep = dep[DInfo] - transitive_d_srcs.append(ddep.d_srcs) + transitive_d_srcs.append(depset(ddep.d_srcs)) transitive_imports = depset(ddep.imports, transitive = [transitive_imports]) transitive_linkopts = depset(ddep.linkopts, transitive = [transitive_linkopts]) transitive_versions = depset(ddep.versions, transitive = [transitive_versions]) From a8767767b93f71cb917a72fbc0f71c878be407b3 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Mon, 7 Apr 2025 11:34:25 -0400 Subject: [PATCH 17/92] dmd doesn't support -oq So make it part of d_toolchain.lib_flags and set for LDC only --- d/BUILD | 6 ++++++ d/d.bzl | 2 +- d/toolchain.bzl | 4 ++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/d/BUILD b/d/BUILD index 8ec3f7e..1b82071 100644 --- a/d/BUILD +++ b/d/BUILD @@ -71,6 +71,9 @@ d_toolchain( libphobos = "@ldc_linux_x86_64//:libphobos2", libphobos_src = "@ldc_linux_x86_64//:phobos_src", version_flag = "--d-version", + lib_flags = [ + "-lib", "-oq", + ], ) toolchain( @@ -96,6 +99,9 @@ d_toolchain( libphobos = "@weka_ldc_linux_x86_64//:libphobos2", libphobos_src = "@weka_ldc_linux_x86_64//:phobos_src", version_flag = "--d-version", + lib_flags = [ + "-lib", "-oq", + ], ) toolchain( diff --git a/d/d.bzl b/d/d.bzl index de1891b..4a49005 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -193,7 +193,7 @@ def _d_library_impl(ctx): ctx = ctx, out = d_lib, depinfo = depinfo, - extra_flags = ["-lib", "-oq"], + extra_flags = toolchain.lib_flags, ) # Convert sources to args diff --git a/d/toolchain.bzl b/d/toolchain.bzl index 9d57248..1dde527 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -28,6 +28,7 @@ def _d_toolchain_impl(ctx): toolchain_info = platform_common.ToolchainInfo( name = ctx.label.name, d_compiler = ctx.attr.d_compiler, + lib_flags = ctx.attr.lib_flags, link_flags = ctx.attr.link_flags, import_flags = ctx.attr.import_flags, libphobos = ctx.attr.libphobos, @@ -46,6 +47,9 @@ d_toolchain = rule( # allow_files = True, cfg = "host", ), + "lib_flags": attr.string_list( + default = ["-lib"], + ), "link_flags": attr.string_list( default = [], ), From 3ea814cc533ec52c723115789b7b66b4126e72d1 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Mon, 7 Apr 2025 11:56:30 -0400 Subject: [PATCH 18/92] d_test_library: yet another rule for D library When we build a library for a test, we need to set `version(unittest)`, since ocasionally the code has some hacks for tests. We can't set this version directly, so need to pass `-unittest` flag. This has an unfortunate side effect that the tests inside the library are also included. --- d/d.bzl | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 4a49005..6be28a5 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -179,7 +179,7 @@ def _setup_deps(ctx, deps, name, working_dir): link_flags = depset(link_flags).to_list(), ) -def _d_library_impl(ctx): +def _d_library_impl_common(ctx, extra_flags = []): """Implementation of the d_library rule.""" toolchain = ctx.toolchains[D_TOOLCHAIN] d_lib = ctx.actions.declare_file((ctx.label.name + ".lib") if _is_windows(ctx) else ("lib" + ctx.label.name + ".a")) @@ -193,7 +193,7 @@ def _d_library_impl(ctx): ctx = ctx, out = d_lib, depinfo = depinfo, - extra_flags = toolchain.lib_flags, + extra_flags = toolchain.lib_flags + extra_flags, ) # Convert sources to args @@ -328,6 +328,15 @@ def _d_binary_impl_common(ctx, extra_flags = []): ), ] +def _d_library_impl(ctx): + """Implementation of the d_library rule.""" + return _d_library_impl_common(ctx) + +def _d_test_library_impl(ctx): + """Implementation of the d_test_library rule.""" + # A test library is just a d_library with testonly=True + return _d_library_impl_common(ctx, extra_flags=["-unittest"]) + def _d_binary_impl(ctx): """Implementation of the d_binary rule.""" return _d_binary_impl_common(ctx) @@ -497,6 +506,12 @@ d_library = rule( toolchains = [D_TOOLCHAIN], ) +d_test_library = rule( + _d_test_library_impl, + attrs = dict(_d_common_attrs.items()), + toolchains = [D_TOOLCHAIN], +) + d_source_library = rule( _d_source_library_impl, attrs = _d_common_attrs, From c2fd66920f6c847af61268233e04c6595066ec4e Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 9 Apr 2025 06:25:46 -0400 Subject: [PATCH 19/92] d_{library, binary}: add include_workspace_root attribute To allow suppressing imports from workspace directly. This is needed for instrumented code: we create a copy of directory structure with instrumented files in `bazel-out` and we need to make sure we never import non-instrumented version. --- d/d.bzl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/d/d.bzl b/d/d.bzl index 6be28a5..87668d7 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -85,9 +85,9 @@ def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): _compilation_mode_flags(ctx) + extra_flags + [ "-of" + out.path, - "-I.", "-w", ] + + (["-I."] if ctx.attr.include_workspace_root else []) + ["-I%s" % _build_import(ctx.label, im) for im in ctx.attr.imports] + ["-I%s" % im for im in depinfo.imports] + # toolchain.import_flags + @@ -479,6 +479,7 @@ _d_common_attrs = { "imports": attr.string_list(), "linkopts": attr.string_list(), "versions": attr.string_list(), + "include_workspace_root": attr.bool(default = True), "deps": attr.label_list(), } From 9e850cbaaf000e4319cc23f437e3e4201055f2bb Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 9 Apr 2025 07:29:44 -0400 Subject: [PATCH 20/92] Support string imports --- d/d.bzl | 40 ++++++++++++++++++++++-- examples/string_imports/BUILD | 16 ++++++++++ examples/string_imports/imports/test.txt | 1 + examples/string_imports/lib.d | 8 +++++ examples/string_imports/main.d | 8 +++++ 5 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 examples/string_imports/BUILD create mode 100644 examples/string_imports/imports/test.txt create mode 100644 examples/string_imports/lib.d create mode 100644 examples/string_imports/main.d diff --git a/d/d.bzl b/d/d.bzl index 87668d7..9366f19 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -90,6 +90,8 @@ def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): (["-I."] if ctx.attr.include_workspace_root else []) + ["-I%s" % _build_import(ctx.label, im) for im in ctx.attr.imports] + ["-I%s" % im for im in depinfo.imports] + + ["-J%s" % _build_import(ctx.label, im) for im in ctx.attr.string_imports] + + ["-J%s" % im for im in depinfo.string_imports] + # toolchain.import_flags + [version_flag + "=Have_%s" % _format_version(ctx.label.name)] + [version_flag + "=%s" % v for v in ctx.attr.versions] + @@ -127,15 +129,20 @@ def _setup_deps(ctx, deps, name, working_dir): versions: List of D versions to be used for compiling the target. imports: List of Strings containing input paths that will be passed to the D compiler via -I flags. + string_imports: List of strings containing input paths that will be + passed to the D compiler via -J flags. link_flags: List of linker flags. """ libs = [] transitive_libs = [] d_srcs = [] + extra_files = [] transitive_d_srcs = [] + transitive_extra_files = [] versions = [] imports = [] + string_imports = [] link_flags = [] for dep in deps: if DInfo in dep and hasattr(dep[DInfo], "d_lib"): @@ -145,18 +152,24 @@ def _setup_deps(ctx, deps, name, working_dir): transitive_libs.append(ddep.transitive_libs) d_srcs += ddep.d_srcs transitive_d_srcs.append(ddep.transitive_d_srcs) + extra_files += ddep.extra_files + transitive_extra_files.append(ddep.transitive_extra_files) versions += ddep.versions + ["Have_%s" % _format_version(dep.label.name)] link_flags.extend(ddep.link_flags) imports += [_build_import(dep.label, im) for im in ddep.imports] + string_imports += [_build_import(dep.label, im) for im in ddep.string_imports] elif DInfo in dep and hasattr(dep[DInfo], "d_srcs"): # The dependency is a d_source_library. ddep = dep[DInfo] d_srcs += ddep.d_srcs transitive_d_srcs.append(ddep.transitive_d_srcs) + extra_files += ddep.extra_files + transitive_extra_files.append(ddep.transitive_extra_files) transitive_libs.append(ddep.transitive_libs) link_flags += ["-L%s" % linkopt for linkopt in ddep.linkopts] imports += [_build_import(dep.label, im) for im in ddep.imports] + string_imports += [_build_import(dep.label, im) for im in ddep.string_imports] versions += ddep.versions elif CcInfo in dep: @@ -174,8 +187,11 @@ def _setup_deps(ctx, deps, name, working_dir): transitive_libs = depset(transitive = transitive_libs), d_srcs = depset(d_srcs).to_list(), transitive_d_srcs = depset(transitive = transitive_d_srcs), + extra_files = depset(extra_files).to_list(), + transitive_extra_files = depset(transitive = transitive_extra_files), versions = versions, imports = depset(imports).to_list(), + string_imports = depset(string_imports).to_list(), link_flags = depset(link_flags).to_list(), ) @@ -206,9 +222,12 @@ def _d_library_impl_common(ctx, extra_flags = []): # TODO: Should they be in transitive? compile_inputs = depset( ctx.files.srcs + - depinfo.d_srcs, + depinfo.d_srcs + + ctx.files.extra_files + + depinfo.extra_files, transitive = [ depinfo.transitive_d_srcs, + depinfo.transitive_extra_files, depinfo.libs, depinfo.transitive_libs, toolchain.libphobos.files, @@ -237,10 +256,13 @@ def _d_library_impl_common(ctx, extra_flags = []): DInfo( d_srcs = ctx.files.srcs, transitive_d_srcs = depset(depinfo.d_srcs), + extra_files = ctx.files.extra_files, + transitive_extra_files = depset(depinfo.extra_files), transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), link_flags = depinfo.link_flags, versions = ctx.attr.versions, imports = ctx.attr.imports, + string_imports = ctx.attr.string_imports, d_lib = d_lib, ), ] @@ -279,8 +301,8 @@ def _d_binary_impl_common(ctx, extra_flags = []): d_compiler = toolchain.d_compiler.files.to_list()[0] compile_inputs = depset( - ctx.files.srcs + depinfo.d_srcs, - transitive = [depinfo.transitive_d_srcs] + toolchain_files, + ctx.files.srcs + depinfo.d_srcs + ctx.files.extra_files + depinfo.extra_files, + transitive = [depinfo.transitive_d_srcs, depinfo.transitive_extra_files] + toolchain_files, ) ctx.actions.run( inputs = compile_inputs, @@ -321,7 +343,10 @@ def _d_binary_impl_common(ctx, extra_flags = []): DInfo( d_srcs = ctx.files.srcs, transitive_d_srcs = depset(depinfo.d_srcs), + extra_files = ctx.files.extra_files, + transitive_extra_files = depset(depinfo.extra_files), imports = ctx.attr.imports, + string_imports = ctx.attr.string_imports, ), DefaultInfo( executable = d_bin, @@ -370,9 +395,11 @@ def _get_libs_for_static_executable(dep): def _d_source_library_impl(ctx): """Implementation of the d_source_library rule.""" transitive_d_srcs = [] + transitive_extra_files = [] transitive_libs = [] transitive_transitive_libs = [] transitive_imports = depset() + transitive_string_imports = depset() transitive_linkopts = depset() transitive_versions = depset() for dep in ctx.attr.deps: @@ -381,7 +408,9 @@ def _d_source_library_impl(ctx): # TODO: Could we also support d_library here? ddep = dep[DInfo] transitive_d_srcs.append(depset(ddep.d_srcs)) + transitive_extra_files.append(depset(ddep.extra_files)) transitive_imports = depset(ddep.imports, transitive = [transitive_imports]) + transitive_string_imports = depset(ddep.string_imports, transitive = [transitive_string_imports]) transitive_linkopts = depset(ddep.linkopts, transitive = [transitive_linkopts]) transitive_versions = depset(ddep.versions, transitive = [transitive_versions]) transitive_transitive_libs.append(ddep.transitive_libs) @@ -398,9 +427,12 @@ def _d_source_library_impl(ctx): return [ DInfo( d_srcs = ctx.files.srcs, + extra_files = ctx.files.extra_files, transitive_d_srcs = depset(transitive = transitive_d_srcs, order = "postorder"), + transitive_extra_files = depset(transitive = transitive_extra_files, order = "postorder"), transitive_libs = depset(transitive_libs, transitive = transitive_transitive_libs), imports = ctx.attr.imports + transitive_imports.to_list(), + string_imports = ctx.attr.string_imports + transitive_string_imports.to_list(), linkopts = ctx.attr.linkopts + transitive_linkopts.to_list(), versions = ctx.attr.versions + transitive_versions.to_list(), ), @@ -477,6 +509,8 @@ def _d_docs_impl(ctx): _d_common_attrs = { "srcs": attr.label_list(allow_files = D_FILETYPE), "imports": attr.string_list(), + "string_imports": attr.string_list(), + "extra_files": attr.label_list(allow_files = True), "linkopts": attr.string_list(), "versions": attr.string_list(), "include_workspace_root": attr.bool(default = True), diff --git a/examples/string_imports/BUILD b/examples/string_imports/BUILD new file mode 100644 index 0000000..51d164a --- /dev/null +++ b/examples/string_imports/BUILD @@ -0,0 +1,16 @@ +load("//d:d.bzl", "d_binary", "d_library") + +d_library( + name = "lib", + srcs = ["lib.d"], + extra_files = ["imports/test.txt"], + string_imports = ["imports"], +) + +d_binary( + name = "main", + srcs = ["main.d"], + deps = [ + ":lib", + ] +) \ No newline at end of file diff --git a/examples/string_imports/imports/test.txt b/examples/string_imports/imports/test.txt new file mode 100644 index 0000000..f2ba8f8 --- /dev/null +++ b/examples/string_imports/imports/test.txt @@ -0,0 +1 @@ +abc \ No newline at end of file diff --git a/examples/string_imports/lib.d b/examples/string_imports/lib.d new file mode 100644 index 0000000..4bd7df0 --- /dev/null +++ b/examples/string_imports/lib.d @@ -0,0 +1,8 @@ + +string testTemplate()() { + return import("test.txt"); +} + +string test() { + return import("test.txt"); +} \ No newline at end of file diff --git a/examples/string_imports/main.d b/examples/string_imports/main.d new file mode 100644 index 0000000..544abaf --- /dev/null +++ b/examples/string_imports/main.d @@ -0,0 +1,8 @@ +import examples.string_imports.lib; + +import std.stdio; + +void main() { + writeln(test); + writeln(testTemplate); +} \ No newline at end of file From 65854413498c50b9492ce44cb798297761948772 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 13 Apr 2025 06:32:13 -0400 Subject: [PATCH 21/92] d: support for generated sources Currently only for d_library and d_source_library. When we generated sources, we need to patch imports flags, so the generated files are found by the compiler. In theory, string imports also need this. But currently I don't generate files I want to import as strings (though I will). Currently there is an issue with `d_library`: it doesn't accumulate transitive imports, so we if A imports from B and B imports from C and C requires non-standard import location, this won't work. This works with d_source_library though. --- d/d.bzl | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 9366f19..4d5a684 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -66,29 +66,36 @@ def _format_version(name): """Formats the string name to be used in a --version flag.""" return name.replace("-", "_") -def _build_import(label, im): +def _build_import(label, im, gen_dir = None): """Builds the import path under a specific label""" import_path = "" if label.workspace_root: import_path += label.workspace_root + "/" if label.package: import_path += label.package + "/" - import_path += im + if im == ".": + import_path = import_path[0:len(import_path) - 1] + else: + import_path += im + if gen_dir: + import_path = gen_dir + "/" + import_path return import_path def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): """Returns a list of strings constituting the D compile command arguments.""" toolchain = ctx.toolchains[D_TOOLCHAIN] version_flag = toolchain.version_flag + gen_dir = ctx.genfiles_dir.path if ctx.attr.is_generated else None + ws_root = gen_dir if ctx.attr.is_generated else "." return ( _compilation_mode_flags(ctx) + extra_flags + [ "-of" + out.path, "-w", ] + - (["-I."] if ctx.attr.include_workspace_root else []) + - ["-I%s" % _build_import(ctx.label, im) for im in ctx.attr.imports] + + (["-I%s" % ws_root] if ctx.attr.include_workspace_root else []) + + ["-I%s" % _build_import(ctx.label, im, gen_dir) for im in ctx.attr.imports] + ["-I%s" % im for im in depinfo.imports] + ["-J%s" % _build_import(ctx.label, im) for im in ctx.attr.string_imports] + ["-J%s" % im for im in depinfo.string_imports] + @@ -134,6 +141,7 @@ def _setup_deps(ctx, deps, name, working_dir): link_flags: List of linker flags. """ + gen_dir = ctx.genfiles_dir.path libs = [] transitive_libs = [] d_srcs = [] @@ -156,7 +164,9 @@ def _setup_deps(ctx, deps, name, working_dir): transitive_extra_files.append(ddep.transitive_extra_files) versions += ddep.versions + ["Have_%s" % _format_version(dep.label.name)] link_flags.extend(ddep.link_flags) - imports += [_build_import(dep.label, im) for im in ddep.imports] + imports += [_build_import(dep.label, im, gen_dir if ddep.is_generated else None) for im in ddep.imports] + if ddep.is_generated: + imports.append(gen_dir) string_imports += [_build_import(dep.label, im) for im in ddep.string_imports] elif DInfo in dep and hasattr(dep[DInfo], "d_srcs"): @@ -168,7 +178,9 @@ def _setup_deps(ctx, deps, name, working_dir): transitive_extra_files.append(ddep.transitive_extra_files) transitive_libs.append(ddep.transitive_libs) link_flags += ["-L%s" % linkopt for linkopt in ddep.linkopts] - imports += [_build_import(dep.label, im) for im in ddep.imports] + imports += ddep.imports + if ddep.is_generated: + imports.append(gen_dir) string_imports += [_build_import(dep.label, im) for im in ddep.string_imports] versions += ddep.versions @@ -264,6 +276,7 @@ def _d_library_impl_common(ctx, extra_flags = []): imports = ctx.attr.imports, string_imports = ctx.attr.string_imports, d_lib = d_lib, + is_generated = ctx.attr.is_generated, ), ] @@ -424,6 +437,8 @@ def _d_source_library_impl(ctx): fail("d_source_library can only depend on other " + "d_source_library or cc_library targets.", "deps") + gen_dir = ctx.genfiles_dir.path if ctx.attr.is_generated else None + return [ DInfo( d_srcs = ctx.files.srcs, @@ -431,10 +446,11 @@ def _d_source_library_impl(ctx): transitive_d_srcs = depset(transitive = transitive_d_srcs, order = "postorder"), transitive_extra_files = depset(transitive = transitive_extra_files, order = "postorder"), transitive_libs = depset(transitive_libs, transitive = transitive_transitive_libs), - imports = ctx.attr.imports + transitive_imports.to_list(), + imports = [_build_import(ctx.label, im, gen_dir) for im in ctx.attr.imports] + transitive_imports.to_list(), string_imports = ctx.attr.string_imports + transitive_string_imports.to_list(), linkopts = ctx.attr.linkopts + transitive_linkopts.to_list(), versions = ctx.attr.versions + transitive_versions.to_list(), + is_generated = ctx.attr.is_generated, ), ] @@ -514,6 +530,7 @@ _d_common_attrs = { "linkopts": attr.string_list(), "versions": attr.string_list(), "include_workspace_root": attr.bool(default = True), + "is_generated": attr.bool(default = False), "deps": attr.label_list(), } From 3b5b427da1817f4b1c7dd7287e82c2a5cb59d833 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 13 Apr 2025 06:45:06 -0400 Subject: [PATCH 22/92] d: also support generated string imports --- d/d.bzl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 4d5a684..2dc7a76 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -167,7 +167,7 @@ def _setup_deps(ctx, deps, name, working_dir): imports += [_build_import(dep.label, im, gen_dir if ddep.is_generated else None) for im in ddep.imports] if ddep.is_generated: imports.append(gen_dir) - string_imports += [_build_import(dep.label, im) for im in ddep.string_imports] + string_imports += [_build_import(dep.label, im, gen_dir if ddep.is_generated else None) for im in ddep.string_imports] elif DInfo in dep and hasattr(dep[DInfo], "d_srcs"): # The dependency is a d_source_library. @@ -181,7 +181,7 @@ def _setup_deps(ctx, deps, name, working_dir): imports += ddep.imports if ddep.is_generated: imports.append(gen_dir) - string_imports += [_build_import(dep.label, im) for im in ddep.string_imports] + string_imports += ddep.string_imports versions += ddep.versions elif CcInfo in dep: @@ -447,7 +447,7 @@ def _d_source_library_impl(ctx): transitive_extra_files = depset(transitive = transitive_extra_files, order = "postorder"), transitive_libs = depset(transitive_libs, transitive = transitive_transitive_libs), imports = [_build_import(ctx.label, im, gen_dir) for im in ctx.attr.imports] + transitive_imports.to_list(), - string_imports = ctx.attr.string_imports + transitive_string_imports.to_list(), + string_imports = [_build_import(ctx.label, im, gen_dir) for im in ctx.attr.string_imports] + transitive_string_imports.to_list(), linkopts = ctx.attr.linkopts + transitive_linkopts.to_list(), versions = ctx.attr.versions + transitive_versions.to_list(), is_generated = ctx.attr.is_generated, From c95c71956e6d8fab44e74c8f5690213d8508edd6 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 13 Apr 2025 10:08:57 -0400 Subject: [PATCH 23/92] d_source_library: make transitive_d_srcs actualy transitive TODO: Do we need that also for d_library? --- d/d.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/d/d.bzl b/d/d.bzl index 2dc7a76..1f58a09 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -420,7 +420,7 @@ def _d_source_library_impl(ctx): # Dependency is another d_source_library target. # TODO: Could we also support d_library here? ddep = dep[DInfo] - transitive_d_srcs.append(depset(ddep.d_srcs)) + transitive_d_srcs.append(depset(ddep.d_srcs, transitive = [ddep.transitive_d_srcs])) transitive_extra_files.append(depset(ddep.extra_files)) transitive_imports = depset(ddep.imports, transitive = [transitive_imports]) transitive_string_imports = depset(ddep.string_imports, transitive = [transitive_string_imports]) From 40bc1598adc1527600a3604ba7d202a418180bab Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 13 Apr 2025 10:24:32 -0400 Subject: [PATCH 24/92] Allow setting extra switches for D toolchains --- d/d.bzl | 1 + d/toolchain.bzl | 2 ++ 2 files changed, 3 insertions(+) diff --git a/d/d.bzl b/d/d.bzl index 1f58a09..e9e5be7 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -90,6 +90,7 @@ def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): ws_root = gen_dir if ctx.attr.is_generated else "." return ( _compilation_mode_flags(ctx) + + toolchain.extra_switches + extra_flags + [ "-of" + out.path, "-w", diff --git a/d/toolchain.bzl b/d/toolchain.bzl index 1dde527..17ccc2a 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -36,6 +36,7 @@ def _d_toolchain_impl(ctx): druntime = ctx.attr.druntime, druntime_src = ctx.attr.druntime_src, version_flag = ctx.attr.version_flag, + extra_switches = ctx.attr.extra_switches, ) return [toolchain_info] @@ -59,5 +60,6 @@ d_toolchain = rule( "druntime": attr.label(), "druntime_src": attr.label(), "version_flag": attr.string(), + "extra_switches": attr.string_list(), }, ) From cdd2e2437519f9c54baf9052bee61afc2cab3fe8 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 13 Apr 2025 10:24:56 -0400 Subject: [PATCH 25/92] weka-ldc-x86_64: set (some of?) required switches --- d/BUILD | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/d/BUILD b/d/BUILD index 1b82071..a6bb8b6 100644 --- a/d/BUILD +++ b/d/BUILD @@ -102,6 +102,12 @@ d_toolchain( lib_flags = [ "-lib", "-oq", ], + extra_switches = [ + "-mtriple=x86_64-pc-linux-gnu", + "-march=x86-64", + "-mcpu=x86-64-v3", + "-mattr=", + ], ) toolchain( From 254efaef5e4c42481a4f8ee1f6f2f86cf22a4feb Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Thu, 17 Apr 2025 10:46:33 -0400 Subject: [PATCH 26/92] d: show the actual problemmatic dep --- d/d.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/d/d.bzl b/d/d.bzl index e9e5be7..07bee75 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -193,7 +193,7 @@ def _setup_deps(ctx, deps, name, working_dir): else: fail("D targets can only depend on d_library, d_source_library, or " + - "cc_library targets.", "deps") + "cc_library targets.", dep) return struct( libs = depset(libs), From f409c868087f572283ec790f548b8fdd3e882003 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Thu, 17 Apr 2025 10:47:07 -0400 Subject: [PATCH 27/92] d/toolchain: support unset phobos/druntime This is useful for remote toolchains --- d/d.bzl | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 07bee75..224a31d 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -214,7 +214,7 @@ def _d_library_impl_common(ctx, extra_flags = []): d_lib = ctx.actions.declare_file((ctx.label.name + ".lib") if _is_windows(ctx) else ("lib" + ctx.label.name + ".a")) # Dependencies - deps = ctx.attr.deps + [toolchain.libphobos] + ([toolchain.druntime] if toolchain.druntime != None else []) + deps = ctx.attr.deps + ([toolchain.libphobos] if toolchain.libphobos != None else []) + ([toolchain.druntime] if toolchain.druntime != None else []) depinfo = _setup_deps(ctx, ctx.attr.deps, ctx.label.name, d_lib.dirname) # Build compile command. @@ -232,6 +232,9 @@ def _d_library_impl_common(ctx, extra_flags = []): args.add_all(compile_args) args.add_all(ctx.files.srcs) + phobos_files = toolchain.libphobos.files if toolchain.libphobos != None else depset() + phobos_src_files = toolchain.libphobos_src.files if toolchain.libphobos_src != None else depset() + druntime_src_files = toolchain.druntime_src.files if toolchain.druntime_src != None else depset() # TODO: Should they be in transitive? compile_inputs = depset( ctx.files.srcs + @@ -243,9 +246,9 @@ def _d_library_impl_common(ctx, extra_flags = []): depinfo.transitive_extra_files, depinfo.libs, depinfo.transitive_libs, - toolchain.libphobos.files, - toolchain.libphobos_src.files, - toolchain.druntime_src.files, + phobos_files, + phobos_src_files, + druntime_src_files, ], ) @@ -288,7 +291,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): d_obj = ctx.actions.declare_file(ctx.label.name + (".obj" if _is_windows(ctx) else ".o")) # Dependencies - deps = ctx.attr.deps + [toolchain.libphobos] + ([toolchain.druntime] if toolchain.druntime != None else []) + deps = ctx.attr.deps + ([toolchain.libphobos] if toolchain.libphobos != None else []) + ([toolchain.druntime] if toolchain.druntime != None else []) depinfo = _setup_deps(ctx, deps, ctx.label.name, d_bin.dirname) # Build compile command @@ -307,9 +310,9 @@ def _d_binary_impl_common(ctx, extra_flags = []): args.add_all(ctx.files.srcs) toolchain_files = [ - toolchain.libphobos.files, - toolchain.libphobos_src.files, - toolchain.druntime_src.files, + toolchain.libphobos.files if toolchain.libphobos != None else depset(), + toolchain.libphobos_src.files if toolchain.libphobos_src != None else depset(), + toolchain.druntime_src.files if toolchain.druntime_src != None else depset(), ] d_compiler = toolchain.d_compiler.files.to_list()[0] @@ -507,9 +510,9 @@ def _d_docs_impl(ctx): ) toolchain_files = [ - toolchain.libphobos.files, - toolchain.libphobos_src.files, - toolchain.druntime_src.files, + toolchain.libphobos.files if toolchain.libphobos != None else depset(), + toolchain.libphobos_src.files if toolchain.libphobos_src != None else depset(), + toolchain.druntime_src.files if toolchain.druntime_src != None else depset(), ] ddoc_inputs = depset(target.srcs, transitive = [target.transitive_srcs] + toolchain_files) From 7755b632df2f04d8633694a4a04edcfd76b2d323 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Fri, 18 Apr 2025 09:38:21 -0400 Subject: [PATCH 28/92] copt: hack to use ldc options TODO: move it to toolchain declaration --- d/d.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/d/d.bzl b/d/d.bzl index 224a31d..3854f8c 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -39,7 +39,7 @@ def _files_directory(files): COMPILATION_MODE_FLAGS_POSIX = { "fastbuild": ["-g"], - "dbg": ["-debug", "-g"], + "dbg": ["-d-debug", "-d-version=debug_assert", "-g"], "opt": ["-checkaction=halt", "-boundscheck=safeonly", "-O"], } From 3712d03da351ae4d9c1a3e424ef04e356aab435f Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Fri, 18 Apr 2025 11:00:45 -0400 Subject: [PATCH 29/92] d_library: build .o instead of .a not sure this is needed --- d/d.bzl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 3854f8c..2eea018 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -211,7 +211,8 @@ def _setup_deps(ctx, deps, name, working_dir): def _d_library_impl_common(ctx, extra_flags = []): """Implementation of the d_library rule.""" toolchain = ctx.toolchains[D_TOOLCHAIN] - d_lib = ctx.actions.declare_file((ctx.label.name + ".lib") if _is_windows(ctx) else ("lib" + ctx.label.name + ".a")) + #d_lib = ctx.actions.declare_file((ctx.label.name + ".lib") if _is_windows(ctx) else ("lib" + ctx.label.name + ".a")) + d_lib = ctx.actions.declare_file(ctx.label.name + ".o") # Dependencies deps = ctx.attr.deps + ([toolchain.libphobos] if toolchain.libphobos != None else []) + ([toolchain.druntime] if toolchain.druntime != None else []) @@ -222,7 +223,7 @@ def _d_library_impl_common(ctx, extra_flags = []): ctx = ctx, out = d_lib, depinfo = depinfo, - extra_flags = toolchain.lib_flags + extra_flags, + extra_flags = ["-c"] + extra_flags, ) # Convert sources to args From e60ce34f350e7386b4b4c208efc2ebd3b1bb4304 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 20 Apr 2025 06:49:06 -0400 Subject: [PATCH 30/92] toolchain: add flags per build type instead of extra switches --- d/BUILD | 16 ++++++++++------ d/d.bzl | 25 +++++++++++++++++++------ d/toolchain.bzl | 8 ++++++-- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/d/BUILD b/d/BUILD index a6bb8b6..fd7f9b2 100644 --- a/d/BUILD +++ b/d/BUILD @@ -91,6 +91,13 @@ toolchain( toolchain_type = D_TOOLCHAIN, ) +WEKA_LDC_X86_COMMON_OPTS = [ + "-mtriple=x86_64-pc-linux-gnu", + "-march=x86-64", + "-mcpu=x86-64-v3", + "-mattr=", +] + d_toolchain( name = "weka_ldc_linux_x86_64", d_compiler = "@weka_ldc_linux_x86_64//:ldc2", @@ -102,12 +109,9 @@ d_toolchain( lib_flags = [ "-lib", "-oq", ], - extra_switches = [ - "-mtriple=x86_64-pc-linux-gnu", - "-march=x86-64", - "-mcpu=x86-64-v3", - "-mattr=", - ], + fastbuild_flags = ["-g"] + WEKA_LDC_X86_COMMON_OPTS, + dbg_flags = [ "-d-debug", "-d-version=debug_assert", "-g" ] + WEKA_LDC_X86_COMMON_OPTS, + opt_flags = ["-checkaction=halt", "-boundscheck=safeonly", "-O"] + WEKA_LDC_X86_COMMON_OPTS, ) toolchain( diff --git a/d/d.bzl b/d/d.bzl index 2eea018..bc91ce5 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -37,13 +37,13 @@ def _files_directory(files): dir = f.dirname return dir -COMPILATION_MODE_FLAGS_POSIX = { +DEFAULT_COMPILATION_MODE_FLAGS_POSIX = { "fastbuild": ["-g"], "dbg": ["-d-debug", "-d-version=debug_assert", "-g"], "opt": ["-checkaction=halt", "-boundscheck=safeonly", "-O"], } -COMPILATION_MODE_FLAGS_WINDOWS = { +DEFAULT_COMPILATION_MODE_FLAGS_WINDOWS = { "fastbuild": ["-g", "-m64", "-mscrtlib=msvcrt"], "dbg": ["-debug", "-g", "-m64", "-mscrtlib=msvcrtd"], "opt": [ @@ -55,12 +55,26 @@ COMPILATION_MODE_FLAGS_WINDOWS = { ], } +def _default_compilation_mode_flags(ctx): + """Returns the default compilation mode flags.""" + if _is_windows(ctx): + return DEFAULT_COMPILATION_MODE_FLAGS_WINDOWS[ctx.var["COMPILATION_MODE"]] + else: + return DEFAULT_COMPILATION_MODE_FLAGS_POSIX[ctx.var["COMPILATION_MODE"]] + def _compilation_mode_flags(ctx): """Returns a list of flags based on the compilation_mode.""" - if _is_windows(ctx): - return COMPILATION_MODE_FLAGS_WINDOWS[ctx.var["COMPILATION_MODE"]] + toolchain = ctx.toolchains[D_TOOLCHAIN] + compilation_mode = ctx.var["COMPILATION_MODE"] + default_flags = _default_compilation_mode_flags(ctx) + if compilation_mode == "dbg": + return toolchain.dbg_flags or default_flags + elif compilation_mode == "opt": + return toolchain.opt_flags or default_flags + elif compilation_mode == "fastbuild": + return toolchain.fastbuild_flags or default_flags else: - return COMPILATION_MODE_FLAGS_POSIX[ctx.var["COMPILATION_MODE"]] + fail("Invalid compilation mode: %s" % compilation_mode) def _format_version(name): """Formats the string name to be used in a --version flag.""" @@ -90,7 +104,6 @@ def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): ws_root = gen_dir if ctx.attr.is_generated else "." return ( _compilation_mode_flags(ctx) + - toolchain.extra_switches + extra_flags + [ "-of" + out.path, "-w", diff --git a/d/toolchain.bzl b/d/toolchain.bzl index 17ccc2a..bcd0645 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -36,7 +36,9 @@ def _d_toolchain_impl(ctx): druntime = ctx.attr.druntime, druntime_src = ctx.attr.druntime_src, version_flag = ctx.attr.version_flag, - extra_switches = ctx.attr.extra_switches, + fastbuild_flags = ctx.attr.fastbuild_flags, + dbg_flags = ctx.attr.dbg_flags, + opt_flags = ctx.attr.opt_flags, ) return [toolchain_info] @@ -60,6 +62,8 @@ d_toolchain = rule( "druntime": attr.label(), "druntime_src": attr.label(), "version_flag": attr.string(), - "extra_switches": attr.string_list(), + "fastbuild_flags": attr.string_list(), + "dbg_flags": attr.string_list(), + "opt_flags": attr.string_list(), }, ) From ae88bf96619f0fa2abca375cc811c26b943a19b7 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 20 Apr 2025 09:20:44 -0400 Subject: [PATCH 31/92] Remove weka-specific bits --- MODULE.bazel | 4 ++-- d/BUILD | 38 -------------------------------------- 2 files changed, 2 insertions(+), 40 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index d3c112d..dc55cae 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -11,5 +11,5 @@ bazel_dep( bazel_dep(name="platforms", version="0.0.11") non_module_dependencies = use_extension("//d:extensions.bzl", "non_module_dependencies") -use_repo(non_module_dependencies, "ldc_linux_x86_64", "dmd_linux_x86_64", "dmd_darwin_x86_64", "weka_ldc_linux_x86_64") -register_toolchains("//d:ldc_linux_x86_64_toolchain", "//d:dmd_linux_x86_64_toolchain", "//d:dmd_darwin_x86_64_toolchain", "//d:weka_ldc_linux_x86_64_toolchain") \ No newline at end of file +use_repo(non_module_dependencies, "ldc_linux_x86_64", "dmd_linux_x86_64", "dmd_darwin_x86_64") +register_toolchains("//d:ldc_linux_x86_64_toolchain", "//d:dmd_linux_x86_64_toolchain", "//d:dmd_darwin_x86_64_toolchain") \ No newline at end of file diff --git a/d/BUILD b/d/BUILD index fd7f9b2..4676a32 100644 --- a/d/BUILD +++ b/d/BUILD @@ -90,41 +90,3 @@ toolchain( toolchain = ":ldc_linux_x86_64", toolchain_type = D_TOOLCHAIN, ) - -WEKA_LDC_X86_COMMON_OPTS = [ - "-mtriple=x86_64-pc-linux-gnu", - "-march=x86-64", - "-mcpu=x86-64-v3", - "-mattr=", -] - -d_toolchain( - name = "weka_ldc_linux_x86_64", - d_compiler = "@weka_ldc_linux_x86_64//:ldc2", - druntime = "@weka_ldc_linux_x86_64//:druntime", - druntime_src = "@weka_ldc_linux_x86_64//:druntime_src", - libphobos = "@weka_ldc_linux_x86_64//:libphobos2", - libphobos_src = "@weka_ldc_linux_x86_64//:phobos_src", - version_flag = "--d-version", - lib_flags = [ - "-lib", "-oq", - ], - fastbuild_flags = ["-g"] + WEKA_LDC_X86_COMMON_OPTS, - dbg_flags = [ "-d-debug", "-d-version=debug_assert", "-g" ] + WEKA_LDC_X86_COMMON_OPTS, - opt_flags = ["-checkaction=halt", "-boundscheck=safeonly", "-O"] + WEKA_LDC_X86_COMMON_OPTS, -) - -toolchain( - name = "weka_ldc_linux_x86_64_toolchain", - exec_compatible_with = [ - "@platforms//os:linux", - "@platforms//cpu:x86_64", - "//d/constraints/compiler:weka-ldc", - ], - target_compatible_with = [ - "@platforms//os:linux", - "@platforms//cpu:x86_64", - ], - toolchain = ":weka_ldc_linux_x86_64", - toolchain_type = D_TOOLCHAIN, -) From ff975c204e034b73ab52f57561f0e37905c5b991 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 20 Apr 2025 10:14:58 -0400 Subject: [PATCH 32/92] Support passing c compiler for linking --- d/d.bzl | 6 ++++-- d/toolchain.bzl | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index bc91ce5..a8f85f8 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -119,10 +119,11 @@ def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): [version_flag + "=%s" % v for v in depinfo.versions] ) -def _build_link_arglist(ctx, objs, out, depinfo): +def _build_link_arglist(ctx, objs, out, depinfo, c_compiler): """Returns a list of strings constituting the D link command arguments.""" return ( _compilation_mode_flags(ctx) + + (["-gcc=%s" % c_compiler.files.to_list()[0].path] if c_compiler else []) + ["-of" + out.path] + [f.path for f in depset(transitive = [depinfo.libs, depinfo.transitive_libs]).to_list()] + depinfo.link_flags + @@ -352,6 +353,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): objs = [d_obj.path], depinfo = depinfo, out = d_bin, + c_compiler = toolchain.c_compiler, ) link_inputs = depset( @@ -361,7 +363,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): ctx.actions.run( inputs = link_inputs, - tools = [d_compiler], + tools = [d_compiler] + (toolchain.c_compiler.files.to_list() if toolchain.c_compiler else []), outputs = [d_bin], mnemonic = "Dlink", executable = d_compiler, diff --git a/d/toolchain.bzl b/d/toolchain.bzl index bcd0645..16b3b2e 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -28,6 +28,7 @@ def _d_toolchain_impl(ctx): toolchain_info = platform_common.ToolchainInfo( name = ctx.label.name, d_compiler = ctx.attr.d_compiler, + c_compiler = ctx.attr.c_compiler, lib_flags = ctx.attr.lib_flags, link_flags = ctx.attr.link_flags, import_flags = ctx.attr.import_flags, @@ -50,6 +51,11 @@ d_toolchain = rule( # allow_files = True, cfg = "host", ), + "c_compiler": attr.label( + executable = True, + allow_files = True, + cfg = "exec", + ), "lib_flags": attr.string_list( default = ["-lib"], ), From e0d65614e500b51dbcb4790c17b87e7834edba4b Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 20 Apr 2025 10:21:13 -0400 Subject: [PATCH 33/92] Respect link_flags from d_toolchain --- d/d.bzl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/d/d.bzl b/d/d.bzl index a8f85f8..5618f25 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -119,11 +119,12 @@ def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): [version_flag + "=%s" % v for v in depinfo.versions] ) -def _build_link_arglist(ctx, objs, out, depinfo, c_compiler): +def _build_link_arglist(ctx, objs, out, depinfo, c_compiler, link_flags): """Returns a list of strings constituting the D link command arguments.""" return ( _compilation_mode_flags(ctx) + (["-gcc=%s" % c_compiler.files.to_list()[0].path] if c_compiler else []) + + (link_flags or []) + ["-of" + out.path] + [f.path for f in depset(transitive = [depinfo.libs, depinfo.transitive_libs]).to_list()] + depinfo.link_flags + @@ -354,6 +355,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): depinfo = depinfo, out = d_bin, c_compiler = toolchain.c_compiler, + link_flags = toolchain.link_flags, ) link_inputs = depset( From 2ef2c9a96e7b8fbc491178d059c819cc789f379a Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 20 Apr 2025 12:07:47 -0400 Subject: [PATCH 34/92] Support linkopts for d_library too TODO: think how this should work in general --- d/d.bzl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/d/d.bzl b/d/d.bzl index 5618f25..7bb40f4 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -180,6 +180,7 @@ def _setup_deps(ctx, deps, name, working_dir): transitive_extra_files.append(ddep.transitive_extra_files) versions += ddep.versions + ["Have_%s" % _format_version(dep.label.name)] link_flags.extend(ddep.link_flags) + link_flags += ["-L%s" % linkopt for linkopt in ddep.linkopts] imports += [_build_import(dep.label, im, gen_dir if ddep.is_generated else None) for im in ddep.imports] if ddep.is_generated: imports.append(gen_dir) @@ -292,6 +293,7 @@ def _d_library_impl_common(ctx, extra_flags = []): transitive_extra_files = depset(depinfo.extra_files), transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), link_flags = depinfo.link_flags, + linkopts = ctx.attr.linkopts, versions = ctx.attr.versions, imports = ctx.attr.imports, string_imports = ctx.attr.string_imports, From f8aac5f4ab698957f018cad4c5db0173f37e7dfb Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Mon, 28 Apr 2025 06:46:39 -0400 Subject: [PATCH 35/92] d_library/d_source_library: support transitive imports That's not entrirely clear if it's good or bad, but let's support accumulating imports/string imports for all transitive deps. In most languages, if you need source-level access to a library, it must be listed in deps explicitly. But in D you can use a template in libA (which is your direct dep), which in turn uses a template from libB (which is a direct dep of libA). So you should either add libB to be a direct dependency, or rely on the build system to collect transitive sources and imports. Before this change we do collect sources, but not imports, this is a weird situation half-way through. So let's also collect transitive imports. It also simplifies the code a bit. On the bad side, this breaks the invariant that you can only use APIs from your direct dependencies: now you can also use APIs from indirect deps. Which is bad, but that was also true before this change: since we were collecting transitive sources anyway, we could already use indirect deps, but only the ones that don't require `-I` flag. --- d/d.bzl | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 7bb40f4..0086783 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -109,9 +109,7 @@ def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): "-w", ] + (["-I%s" % ws_root] if ctx.attr.include_workspace_root else []) + - ["-I%s" % _build_import(ctx.label, im, gen_dir) for im in ctx.attr.imports] + ["-I%s" % im for im in depinfo.imports] + - ["-J%s" % _build_import(ctx.label, im) for im in ctx.attr.string_imports] + ["-J%s" % im for im in depinfo.string_imports] + # toolchain.import_flags + [version_flag + "=Have_%s" % _format_version(ctx.label.name)] + @@ -165,8 +163,9 @@ def _setup_deps(ctx, deps, name, working_dir): transitive_d_srcs = [] transitive_extra_files = [] versions = [] - imports = [] - string_imports = [] + gen_dir_for_imports = gen_dir if ctx.attr.is_generated else None + imports = [_build_import(ctx.label, im, gen_dir_for_imports) for im in ctx.attr.imports] + string_imports = [_build_import(ctx.label, im, gen_dir_for_imports) for im in ctx.attr.string_imports] link_flags = [] for dep in deps: if DInfo in dep and hasattr(dep[DInfo], "d_lib"): @@ -181,10 +180,10 @@ def _setup_deps(ctx, deps, name, working_dir): versions += ddep.versions + ["Have_%s" % _format_version(dep.label.name)] link_flags.extend(ddep.link_flags) link_flags += ["-L%s" % linkopt for linkopt in ddep.linkopts] - imports += [_build_import(dep.label, im, gen_dir if ddep.is_generated else None) for im in ddep.imports] + imports += ddep.imports if ddep.is_generated: imports.append(gen_dir) - string_imports += [_build_import(dep.label, im, gen_dir if ddep.is_generated else None) for im in ddep.string_imports] + string_imports += ddep.string_imports elif DInfo in dep and hasattr(dep[DInfo], "d_srcs"): # The dependency is a d_source_library. @@ -295,8 +294,8 @@ def _d_library_impl_common(ctx, extra_flags = []): link_flags = depinfo.link_flags, linkopts = ctx.attr.linkopts, versions = ctx.attr.versions, - imports = ctx.attr.imports, - string_imports = ctx.attr.string_imports, + imports = depinfo.imports, + string_imports = depinfo.string_imports, d_lib = d_lib, is_generated = ctx.attr.is_generated, ), From 4ac46cf7be477c2388a524aa9a95d35cac145c06 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 30 Apr 2025 08:41:55 -0400 Subject: [PATCH 36/92] _setup_deps: working_dir arg is unused --- d/d.bzl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 0086783..2106845 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -129,7 +129,7 @@ def _build_link_arglist(ctx, objs, out, depinfo, c_compiler, link_flags): objs ) -def _setup_deps(ctx, deps, name, working_dir): +def _setup_deps(ctx, deps, name): """Sets up dependencies. Walks through dependencies and constructs the commands and flags needed @@ -138,7 +138,6 @@ def _setup_deps(ctx, deps, name, working_dir): Args: deps: List of deps labels from ctx.attr.deps. name: Name of the current target. - working_dir: The output directory of the current target's output. Returns: Returns a struct containing the following fields: @@ -231,7 +230,7 @@ def _d_library_impl_common(ctx, extra_flags = []): # Dependencies deps = ctx.attr.deps + ([toolchain.libphobos] if toolchain.libphobos != None else []) + ([toolchain.druntime] if toolchain.druntime != None else []) - depinfo = _setup_deps(ctx, ctx.attr.deps, ctx.label.name, d_lib.dirname) + depinfo = _setup_deps(ctx, ctx.attr.deps, ctx.label.name) # Build compile command. compile_args = _build_compile_arglist( @@ -309,7 +308,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): # Dependencies deps = ctx.attr.deps + ([toolchain.libphobos] if toolchain.libphobos != None else []) + ([toolchain.druntime] if toolchain.druntime != None else []) - depinfo = _setup_deps(ctx, deps, ctx.label.name, d_bin.dirname) + depinfo = _setup_deps(ctx, deps, ctx.label.name) # Build compile command compile_args = _build_compile_arglist( From d1882a6dba53d3529bcb862b79ff6105a4f1468d Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 30 Apr 2025 08:43:19 -0400 Subject: [PATCH 37/92] _setup_deps: fix docstring --- d/d.bzl | 1 + 1 file changed, 1 insertion(+) diff --git a/d/d.bzl b/d/d.bzl index 2106845..4812fb2 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -136,6 +136,7 @@ def _setup_deps(ctx, deps, name): for linking the necessary dependencies. Args: + ctx: The context of the current target. deps: List of deps labels from ctx.attr.deps. name: Name of the current target. From 192b10b40c753bbe53fa642af2b2bd5eab413bc8 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 30 Apr 2025 09:50:30 -0400 Subject: [PATCH 38/92] collect transitive versions for d_library's For the same reason we have to collect sources and imports: a template from direct dependency using another template from indirect dependency. --- d/d.bzl | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 4812fb2..23a9057 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -112,9 +112,7 @@ def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): ["-I%s" % im for im in depinfo.imports] + ["-J%s" % im for im in depinfo.string_imports] + # toolchain.import_flags + - [version_flag + "=Have_%s" % _format_version(ctx.label.name)] + - [version_flag + "=%s" % v for v in ctx.attr.versions] + - [version_flag + "=%s" % v for v in depinfo.versions] + [version_flag + "=%s" % v for v in depinfo.versions.to_list()] ) def _build_link_arglist(ctx, objs, out, depinfo, c_compiler, link_flags): @@ -162,7 +160,8 @@ def _setup_deps(ctx, deps, name): extra_files = [] transitive_d_srcs = [] transitive_extra_files = [] - versions = [] + versions = ctx.attr.versions + ["Have_%s" % _format_version(name)] + transitive_versions = [] gen_dir_for_imports = gen_dir if ctx.attr.is_generated else None imports = [_build_import(ctx.label, im, gen_dir_for_imports) for im in ctx.attr.imports] string_imports = [_build_import(ctx.label, im, gen_dir_for_imports) for im in ctx.attr.string_imports] @@ -177,7 +176,7 @@ def _setup_deps(ctx, deps, name): transitive_d_srcs.append(ddep.transitive_d_srcs) extra_files += ddep.extra_files transitive_extra_files.append(ddep.transitive_extra_files) - versions += ddep.versions + ["Have_%s" % _format_version(dep.label.name)] + transitive_versions.append(ddep.versions) link_flags.extend(ddep.link_flags) link_flags += ["-L%s" % linkopt for linkopt in ddep.linkopts] imports += ddep.imports @@ -198,7 +197,7 @@ def _setup_deps(ctx, deps, name): if ddep.is_generated: imports.append(gen_dir) string_imports += ddep.string_imports - versions += ddep.versions + transitive_versions.append(ddep.versions) elif CcInfo in dep: # The dependency is a cc_library @@ -217,7 +216,7 @@ def _setup_deps(ctx, deps, name): transitive_d_srcs = depset(transitive = transitive_d_srcs), extra_files = depset(extra_files).to_list(), transitive_extra_files = depset(transitive = transitive_extra_files), - versions = versions, + versions = depset(versions, transitive = transitive_versions), imports = depset(imports).to_list(), string_imports = depset(string_imports).to_list(), link_flags = depset(link_flags).to_list(), @@ -293,7 +292,7 @@ def _d_library_impl_common(ctx, extra_flags = []): transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), link_flags = depinfo.link_flags, linkopts = ctx.attr.linkopts, - versions = ctx.attr.versions, + versions = depinfo.versions, imports = depinfo.imports, string_imports = depinfo.string_imports, d_lib = d_lib, @@ -448,7 +447,7 @@ def _d_source_library_impl(ctx): transitive_imports = depset(ddep.imports, transitive = [transitive_imports]) transitive_string_imports = depset(ddep.string_imports, transitive = [transitive_string_imports]) transitive_linkopts = depset(ddep.linkopts, transitive = [transitive_linkopts]) - transitive_versions = depset(ddep.versions, transitive = [transitive_versions]) + transitive_versions = depset(transitive = [ddep.versions, transitive_versions]) transitive_transitive_libs.append(ddep.transitive_libs) elif CcInfo in dep: @@ -472,7 +471,7 @@ def _d_source_library_impl(ctx): imports = [_build_import(ctx.label, im, gen_dir) for im in ctx.attr.imports] + transitive_imports.to_list(), string_imports = [_build_import(ctx.label, im, gen_dir) for im in ctx.attr.string_imports] + transitive_string_imports.to_list(), linkopts = ctx.attr.linkopts + transitive_linkopts.to_list(), - versions = ctx.attr.versions + transitive_versions.to_list(), + versions = depset(ctx.attr.versions, transitive = [transitive_versions]), is_generated = ctx.attr.is_generated, ), ] From dc1e035e257e1d875123a7ecc1b0936babf6071a Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Fri, 23 May 2025 10:22:17 -0400 Subject: [PATCH 39/92] add support for handling generated source files D relies on paths to find modules. So, if you generate a source file, it will be under the output directory and D compiler won't automatically find it. This is solved currently using the `is_generated` attribute, that forces adding the `-Ioutdir` flag to the compiler. This works, but not in all cases. Problems start if you need to support the same module name for both unprocessed and instrumented source. And then add an extra layer of generation, like generating the header files. You can have both `liba/moda.d` and `outdir/liba/moda.d`, but generated header would have to be `outdir/liba/moda.di` in both cases. And that's not allowed by Bazel. So, the new `generated_srcs` attribute is added to `d_library` and `d_binary` rules, allowing to map the generated source files to the expected source location. We collect this mapping information from all the dependencies and wrap the compiler invocation with a script that creates symlinks from the expected location to the actual location. This way, we can generate files with modified names, and still have the compiler find them. Passing that dictionary is a bit cumbersome, but the idea is it will be mostly used by the bazel macros and not by the users directly. We can probably remove the `is_generated` attribute now. --- d/d.bzl | 57 +++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 23a9057..3c817ca 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -166,6 +166,8 @@ def _setup_deps(ctx, deps, name): imports = [_build_import(ctx.label, im, gen_dir_for_imports) for im in ctx.attr.imports] string_imports = [_build_import(ctx.label, im, gen_dir_for_imports) for im in ctx.attr.string_imports] link_flags = [] + generated_srcs = { + src.files.to_list()[0]: src.label.package + "/" + loc for src, loc in ctx.attr.generated_srcs.items()} for dep in deps: if DInfo in dep and hasattr(dep[DInfo], "d_lib"): # The dependency is a d_library. @@ -183,6 +185,7 @@ def _setup_deps(ctx, deps, name): if ddep.is_generated: imports.append(gen_dir) string_imports += ddep.string_imports + generated_srcs = generated_srcs | ddep.generated_srcs elif DInfo in dep and hasattr(dep[DInfo], "d_srcs"): # The dependency is a d_source_library. @@ -198,6 +201,7 @@ def _setup_deps(ctx, deps, name): imports.append(gen_dir) string_imports += ddep.string_imports transitive_versions.append(ddep.versions) + generated_srcs = generated_srcs | ddep.generated_srcs elif CcInfo in dep: # The dependency is a cc_library @@ -220,13 +224,40 @@ def _setup_deps(ctx, deps, name): imports = depset(imports).to_list(), string_imports = depset(string_imports).to_list(), link_flags = depset(link_flags).to_list(), + generated_srcs = generated_srcs, ) +def _handle_generated_srcs(ctx, generated_srcs, d_compiler): + """Handles the generated source files.""" + if not generated_srcs: + return (ctx.files.srcs, None) + mapped_srcs = [src if src not in generated_srcs else generated_srcs[src] for src in ctx.files.srcs] + + generated_srcs_file = ctx.actions.declare_file(ctx.label.name + "_generated_srcs_wrapper.sh") + ctx.actions.write( + output = generated_srcs_file, + content = "\n".join( + [ + "#!/bin/sh", + "set -e", + ] + + [ + "mkdir -p $(dirname %s)\n" % loc + + "ln -s $PWD/%s %s" % (src.path, loc) for src, loc in generated_srcs.items() + ] + [ + "%s $*" % d_compiler.path, + ]), + is_executable = True, + ) + + return (mapped_srcs, generated_srcs_file) + def _d_library_impl_common(ctx, extra_flags = []): """Implementation of the d_library rule.""" toolchain = ctx.toolchains[D_TOOLCHAIN] #d_lib = ctx.actions.declare_file((ctx.label.name + ".lib") if _is_windows(ctx) else ("lib" + ctx.label.name + ".a")) d_lib = ctx.actions.declare_file(ctx.label.name + ".o") + d_compiler = toolchain.d_compiler.files.to_list()[0] # Dependencies deps = ctx.attr.deps + ([toolchain.libphobos] if toolchain.libphobos != None else []) + ([toolchain.druntime] if toolchain.druntime != None else []) @@ -245,7 +276,10 @@ def _d_library_impl_common(ctx, extra_flags = []): # args will auto-expand this to the contained files args = ctx.actions.args() args.add_all(compile_args) - args.add_all(ctx.files.srcs) + + mapped_srcs, generated_srcs_wrapper = _handle_generated_srcs(ctx, depinfo.generated_srcs, d_compiler) + + args.add_all(mapped_srcs) phobos_files = toolchain.libphobos.files if toolchain.libphobos != None else depset() phobos_src_files = toolchain.libphobos_src.files if toolchain.libphobos_src != None else depset() @@ -267,14 +301,12 @@ def _d_library_impl_common(ctx, extra_flags = []): ], ) - d_compiler = toolchain.d_compiler.files.to_list()[0] - ctx.actions.run( inputs = compile_inputs, - tools = [d_compiler], + tools = [d_compiler, generated_srcs_wrapper] if generated_srcs_wrapper else [d_compiler], outputs = [d_lib], mnemonic = "Dcompile", - executable = d_compiler, + executable = generated_srcs_wrapper if generated_srcs_wrapper else d_compiler, arguments = [args], use_default_shell_env = True, progress_message = "Compiling D library " + ctx.label.name, @@ -297,6 +329,7 @@ def _d_library_impl_common(ctx, extra_flags = []): string_imports = depinfo.string_imports, d_lib = d_lib, is_generated = ctx.attr.is_generated, + generated_srcs = depinfo.generated_srcs, ), ] @@ -305,6 +338,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): toolchain = ctx.toolchains[D_TOOLCHAIN] d_bin = ctx.actions.declare_file(ctx.label.name + ".exe" if _is_windows(ctx) else ctx.label.name) d_obj = ctx.actions.declare_file(ctx.label.name + (".obj" if _is_windows(ctx) else ".o")) + d_compiler = toolchain.d_compiler.files.to_list()[0] # Dependencies deps = ctx.attr.deps + ([toolchain.libphobos] if toolchain.libphobos != None else []) + ([toolchain.druntime] if toolchain.druntime != None else []) @@ -323,7 +357,10 @@ def _d_binary_impl_common(ctx, extra_flags = []): # args will auto-expand this to the contained files args = ctx.actions.args() args.add_all(compile_args) - args.add_all(ctx.files.srcs) + + mapped_srcs, generated_srcs_wrapper = _handle_generated_srcs(ctx, depinfo.generated_srcs, d_compiler) + + args.add_all(mapped_srcs) toolchain_files = [ toolchain.libphobos.files if toolchain.libphobos != None else depset(), @@ -331,18 +368,16 @@ def _d_binary_impl_common(ctx, extra_flags = []): toolchain.druntime_src.files if toolchain.druntime_src != None else depset(), ] - d_compiler = toolchain.d_compiler.files.to_list()[0] - compile_inputs = depset( ctx.files.srcs + depinfo.d_srcs + ctx.files.extra_files + depinfo.extra_files, transitive = [depinfo.transitive_d_srcs, depinfo.transitive_extra_files] + toolchain_files, ) ctx.actions.run( inputs = compile_inputs, - tools = [d_compiler], + tools = [d_compiler, generated_srcs_wrapper] if generated_srcs_wrapper else [d_compiler], outputs = [d_obj], mnemonic = "Dcompile", - executable = d_compiler, + executable = generated_srcs_wrapper if generated_srcs_wrapper else d_compiler, arguments = [args], use_default_shell_env = True, progress_message = "Compiling D binary " + ctx.label.name, @@ -473,6 +508,7 @@ def _d_source_library_impl(ctx): linkopts = ctx.attr.linkopts + transitive_linkopts.to_list(), versions = depset(ctx.attr.versions, transitive = [transitive_versions]), is_generated = ctx.attr.is_generated, + generated_srcs = ctx.attr.generated_srcs, ), ] @@ -553,6 +589,7 @@ _d_common_attrs = { "versions": attr.string_list(), "include_workspace_root": attr.bool(default = True), "is_generated": attr.bool(default = False), + "generated_srcs": attr.label_keyed_string_dict(), "deps": attr.label_list(), } From 6a96c6516be9e69c56381d6abeac1a2da468cf5f Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Fri, 23 May 2025 10:50:53 -0400 Subject: [PATCH 40/92] add tests for mixing source and generated code --- tests/mix_sources_and_generated/BUILD | 39 ++++++++++++++++++++++++++ tests/mix_sources_and_generated/a.d | 7 +++++ tests/mix_sources_and_generated/b.d | 5 ++++ tests/mix_sources_and_generated/main.d | 9 ++++++ 4 files changed, 60 insertions(+) create mode 100644 tests/mix_sources_and_generated/BUILD create mode 100644 tests/mix_sources_and_generated/a.d create mode 100644 tests/mix_sources_and_generated/b.d create mode 100644 tests/mix_sources_and_generated/main.d diff --git a/tests/mix_sources_and_generated/BUILD b/tests/mix_sources_and_generated/BUILD new file mode 100644 index 0000000..1c84eca --- /dev/null +++ b/tests/mix_sources_and_generated/BUILD @@ -0,0 +1,39 @@ +load("//d:d.bzl", "d_binary", "d_library") + +genrule( + name = "generate_b", + srcs = ["b.d"], + outs = ["b_generated.d"], + cmd = "cat $< > $@", +) + +d_library( + name = "lib", + srcs = ["a.d", ":generate_b"], + generated_srcs = { + ":generate_b": "b.d", + }, +) + +d_library( + name = "lib_no_map", + srcs = ["a.d", ":generate_b"], +) + +d_binary( + name = "bin", + srcs = ["main.d"], + deps = [ + ":lib", + ], +) + +# This is expected to fail because the generated source file is not mapped +d_binary( + name = "bin_no_map", + srcs = ["main.d"], + deps = [ + ":lib_no_map", + ], + tags = ["manual"], +) \ No newline at end of file diff --git a/tests/mix_sources_and_generated/a.d b/tests/mix_sources_and_generated/a.d new file mode 100644 index 0000000..e7c4379 --- /dev/null +++ b/tests/mix_sources_and_generated/a.d @@ -0,0 +1,7 @@ +module tests.mix_sources_and_generated.a; + +import tests.mix_sources_and_generated.b; + +int a() { + return bfun(); +} diff --git a/tests/mix_sources_and_generated/b.d b/tests/mix_sources_and_generated/b.d new file mode 100644 index 0000000..ce8b226 --- /dev/null +++ b/tests/mix_sources_and_generated/b.d @@ -0,0 +1,5 @@ +module tests.mix_sources_and_generated.b; + +int bfun() { + return 42; +} diff --git a/tests/mix_sources_and_generated/main.d b/tests/mix_sources_and_generated/main.d new file mode 100644 index 0000000..9bdd5e6 --- /dev/null +++ b/tests/mix_sources_and_generated/main.d @@ -0,0 +1,9 @@ +import tests.mix_sources_and_generated.b; + +void main() { + // This is a test to check if the mix of sources and generated code works + // The generated code is in the `generated` directory + // The source code is in the `src` directory + // The test should pass if the mix works + assert(bfun() == 42); +} From e8a4186cfe5aeb7396681991cde4d97eb40f5e82 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Fri, 23 May 2025 11:10:55 -0400 Subject: [PATCH 41/92] Update the doc comment for _setup_deps --- d/d.bzl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/d/d.bzl b/d/d.bzl index 3c817ca..0b2ebaa 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -151,6 +151,10 @@ def _setup_deps(ctx, deps, name): string_imports: List of strings containing input paths that will be passed to the D compiler via -J flags. link_flags: List of linker flags. + generated_srcs: A dictionary mapping generated files to their + desired locations. + extra_files: List of Files containing extra (non-source) files that will + be used as inputs for this target. """ gen_dir = ctx.genfiles_dir.path From 6cef27c9d79bf75bffadedd01a264d3bd04bc8a8 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Fri, 30 May 2025 08:46:17 -0400 Subject: [PATCH 42/92] d_lib: add hdrs and exports The idea is to limit the transitive dependencies: instead of making all srcs visibile, all expose headers + exports. Why we differentiate? The plan is to use header generation for exports, while headers are hand-written. Headers and exports should be closed under imports: if an export A imports module B, B **must** be in exports as well, otherwise compilation will be broken. For now, exports are kinda useless: unless the library interdependency graph is not connected, because of that closure requirement, the whole library will end up in exports. This is going to improve with header generation, since it can truncate some imports. If neither hdrs nor exports is set, the whole srcs are exported. As a results, d_source_library is the same as making d_library only with headers. --- d/d.bzl | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 0b2ebaa..a34da79 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -23,7 +23,7 @@ def a_filetype(ctx, files): lib_suffix = ".lib" if _is_windows(ctx) else ".a" return [f for f in files if f.basename.endswith(lib_suffix)] -D_FILETYPE = [".d", ".di"] +D_FILETYPE = [".d", ".di", ".h"] # TODO: restrict support of .di and .h files to source libraries ZIP_PATH = "/usr/bin/zip" @@ -178,7 +178,7 @@ def _setup_deps(ctx, deps, name): ddep = dep[DInfo] libs.append(ddep.d_lib) transitive_libs.append(ddep.transitive_libs) - d_srcs += ddep.d_srcs + d_srcs += ddep.d_exports transitive_d_srcs.append(ddep.transitive_d_srcs) extra_files += ddep.extra_files transitive_extra_files.append(ddep.transitive_extra_files) @@ -220,8 +220,7 @@ def _setup_deps(ctx, deps, name): return struct( libs = depset(libs), transitive_libs = depset(transitive = transitive_libs), - d_srcs = depset(d_srcs).to_list(), - transitive_d_srcs = depset(transitive = transitive_d_srcs), + transitive_d_srcs = depset(d_srcs, transitive = transitive_d_srcs), extra_files = depset(extra_files).to_list(), transitive_extra_files = depset(transitive = transitive_extra_files), versions = depset(versions, transitive = transitive_versions), @@ -291,7 +290,8 @@ def _d_library_impl_common(ctx, extra_flags = []): # TODO: Should they be in transitive? compile_inputs = depset( ctx.files.srcs + - depinfo.d_srcs + + ctx.files.hdrs + + ctx.files.exports + ctx.files.extra_files + depinfo.extra_files, transitive = [ @@ -316,13 +316,18 @@ def _d_library_impl_common(ctx, extra_flags = []): progress_message = "Compiling D library " + ctx.label.name, ) + public_srcs = ctx.files.hdrs + ctx.files.exports + if not public_srcs: + public_srcs = ctx.files.srcs + return [ DefaultInfo( files = depset([d_lib]), ), DInfo( d_srcs = ctx.files.srcs, - transitive_d_srcs = depset(depinfo.d_srcs), + d_exports = public_srcs, + transitive_d_srcs = depinfo.transitive_d_srcs, extra_files = ctx.files.extra_files, transitive_extra_files = depset(depinfo.extra_files), transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), @@ -373,7 +378,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): ] compile_inputs = depset( - ctx.files.srcs + depinfo.d_srcs + ctx.files.extra_files + depinfo.extra_files, + ctx.files.srcs + ctx.files.extra_files + depinfo.extra_files, transitive = [depinfo.transitive_d_srcs, depinfo.transitive_extra_files] + toolchain_files, ) ctx.actions.run( @@ -416,7 +421,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): return [ DInfo( d_srcs = ctx.files.srcs, - transitive_d_srcs = depset(depinfo.d_srcs), + transitive_d_srcs = depinfo.transitive_d_srcs, extra_files = ctx.files.extra_files, transitive_extra_files = depset(depinfo.extra_files), imports = ctx.attr.imports, @@ -597,6 +602,11 @@ _d_common_attrs = { "deps": attr.label_list(), } +_d_library_attrs = { + "hdrs": attr.label_list(allow_files = D_FILETYPE, allow_empty = True), + "exports": attr.label_list(allow_files = D_FILETYPE), +} + # _d_compile_attrs = { # "_d_compiler": attr.label( # default = Label("//d:dmd"), @@ -617,13 +627,13 @@ _d_common_attrs = { d_library = rule( _d_library_impl, - attrs = dict(_d_common_attrs.items()), + attrs = dict(_d_common_attrs.items() + _d_library_attrs.items()), toolchains = [D_TOOLCHAIN], ) d_test_library = rule( _d_test_library_impl, - attrs = dict(_d_common_attrs.items()), + attrs = dict(_d_common_attrs.items() + _d_library_attrs.items()), toolchains = [D_TOOLCHAIN], ) From f63cf494b8c584f967513bc73dcdac82dc182174 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 1 Jun 2025 09:07:51 -0400 Subject: [PATCH 43/92] weka-ldc: use 1.30-weka19-pre version --- d/repositories.bzl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/d/repositories.bzl b/d/repositories.bzl index c77406f..b2233b9 100644 --- a/d/repositories.bzl +++ b/d/repositories.bzl @@ -79,13 +79,13 @@ def fetch_ldc(version = None): build_file = LDC_BUILD_FILE, ) -def fetch_weka_ldc(version = "1.30-weka17-ctfe-attr"): +def fetch_weka_ldc(version = "1.30.0-weka19-pre"): http_archive( name = "weka_ldc_linux_x86_64", urls = [ - "https://github.com/yanok/ldc/releases/download/v{version}/ldc2-{version}-linux-x86_64.tar.xz".format(version = version), + "https://github.com/weka/ldc/releases/download/v{version}/ldc2-{version}-linux-x86_64.tar.xz".format(version = version), ], - sha256 = "30fcca329dcaa7a15e2dfa7828c07e462b438a106b706aa5a20e2a8ea1570e0c", + sha256 = "ce716c73dc2689da7bff9b7b5d414fae5b90b77bca5ab533e830dfffc9929199", strip_prefix = "ldc2-{version}-linux-x86_64".format(version = version), build_file = LDC_BUILD_FILE, ) From 88be20da35ec62b2c53fbf772d2b294527aba578 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 1 Jun 2025 09:10:43 -0400 Subject: [PATCH 44/92] Register weka-ldc toolchain as well --- MODULE.bazel | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index dc55cae..893a1a7 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -11,5 +11,10 @@ bazel_dep( bazel_dep(name="platforms", version="0.0.11") non_module_dependencies = use_extension("//d:extensions.bzl", "non_module_dependencies") -use_repo(non_module_dependencies, "ldc_linux_x86_64", "dmd_linux_x86_64", "dmd_darwin_x86_64") -register_toolchains("//d:ldc_linux_x86_64_toolchain", "//d:dmd_linux_x86_64_toolchain", "//d:dmd_darwin_x86_64_toolchain") \ No newline at end of file +use_repo(non_module_dependencies, "ldc_linux_x86_64", "dmd_linux_x86_64", "dmd_darwin_x86_64", "weka_ldc_linux_x86_64") +register_toolchains( + "//d:ldc_linux_x86_64_toolchain", + "//d:dmd_linux_x86_64_toolchain", + "//d:dmd_darwin_x86_64_toolchain", + "//d:weka_ldc_linux_x86_64_toolchain", + ) From bd9e67615f91a4c374580f31edb7733277cff599 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 1 Jun 2025 09:14:42 -0400 Subject: [PATCH 45/92] d_header_generator: add rule to generate di files This requires a modified compiler unfortunately --- d/BUILD | 31 ++++++++++++++++++++++++++ d/d.bzl | 47 +++++++++++++++++++++++++++++++++++++++ d/toolchain.bzl | 2 ++ tests/d_lib_headers/BUILD | 6 +++++ tests/d_lib_headers/lib.d | 6 +++++ 5 files changed, 92 insertions(+) create mode 100644 tests/d_lib_headers/BUILD create mode 100644 tests/d_lib_headers/lib.d diff --git a/d/BUILD b/d/BUILD index 4676a32..e4f6fab 100644 --- a/d/BUILD +++ b/d/BUILD @@ -90,3 +90,34 @@ toolchain( toolchain = ":ldc_linux_x86_64", toolchain_type = D_TOOLCHAIN, ) + +d_toolchain( + name = "weka_ldc_linux_x86_64", + d_compiler = "@weka_ldc_linux_x86_64//:ldc2", + druntime = "@weka_ldc_linux_x86_64//:druntime", + druntime_src = "@weka_ldc_linux_x86_64//:druntime_src", + libphobos = "@weka_ldc_linux_x86_64//:libphobos2", + libphobos_src = "@weka_ldc_linux_x86_64//:phobos_src", + version_flag = "--d-version", + lib_flags = [ + "-lib", "-oq", + ], + hdrgen_flags = [ + "-Honly", + ], +) + +toolchain( + name = "weka_ldc_linux_x86_64_toolchain", + exec_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + "//d/constraints/compiler:weka-ldc", + ], + target_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + toolchain = ":weka_ldc_linux_x86_64", + toolchain_type = D_TOOLCHAIN, +) diff --git a/d/d.bzl b/d/d.bzl index a34da79..4f96ec2 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -589,6 +589,42 @@ def _d_docs_impl(ctx): progress_message = "Generating D docs for " + ctx.label.name, ) +def _d_header_generator_impl(ctx): + """Implementation of the d_header_generator rule.""" + toolchain = ctx.toolchains[D_TOOLCHAIN] + if not toolchain.hdrgen_flags: + fail("d_header_generator requires a toolchain with hdrgen_flags set.") + + d_compiler = toolchain.d_compiler.files.to_list()[0] + + infile = ctx.file.src + if not infile: + fail("d_header_generator requires a single source file.") + + if not infile.path.endswith(".d"): + fail("d_header_generator only supports .d files, got: %s" % infile.path) + + header = ctx.actions.declare_file(ctx.label.name + ".di") + + ctx.actions.run( + inputs = [ctx.file.src], + tools = [d_compiler], + outputs = [header], + mnemonic = "Dhdrgen", + executable = d_compiler, + arguments = toolchain.hdrgen_flags + [infile.path, "--Hf", header.path], + use_default_shell_env = True, + progress_message = "Generating D header for " + ctx.label.name, + ) + return [ + DefaultInfo( + files = depset([header]), + ), + DInfo( + d_exports = [header] + ), + ] + _d_common_attrs = { "srcs": attr.label_list(allow_files = D_FILETYPE), "imports": attr.string_list(), @@ -637,6 +673,17 @@ d_test_library = rule( toolchains = [D_TOOLCHAIN], ) +d_header_generator = rule( + _d_header_generator_impl, + attrs = { + "src": attr.label( + mandatory = True, + allow_single_file = [".d"], + ), + }, + toolchains = [D_TOOLCHAIN], +) + d_source_library = rule( _d_source_library_impl, attrs = _d_common_attrs, diff --git a/d/toolchain.bzl b/d/toolchain.bzl index 16b3b2e..bce2810 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -40,6 +40,7 @@ def _d_toolchain_impl(ctx): fastbuild_flags = ctx.attr.fastbuild_flags, dbg_flags = ctx.attr.dbg_flags, opt_flags = ctx.attr.opt_flags, + hdrgen_flags = ctx.attr.hdrgen_flags, ) return [toolchain_info] @@ -71,5 +72,6 @@ d_toolchain = rule( "fastbuild_flags": attr.string_list(), "dbg_flags": attr.string_list(), "opt_flags": attr.string_list(), + "hdrgen_flags": attr.string_list(), }, ) diff --git a/tests/d_lib_headers/BUILD b/tests/d_lib_headers/BUILD new file mode 100644 index 0000000..3e1c74a --- /dev/null +++ b/tests/d_lib_headers/BUILD @@ -0,0 +1,6 @@ +load("//d:d.bzl", "d_header_generator") + +d_header_generator( + name = "d_lib_headers", + src = "lib.d", +) \ No newline at end of file diff --git a/tests/d_lib_headers/lib.d b/tests/d_lib_headers/lib.d new file mode 100644 index 0000000..6e95086 --- /dev/null +++ b/tests/d_lib_headers/lib.d @@ -0,0 +1,6 @@ +module tests.d_lib_headers.lib; + +int plusOne(int x) +{ + return x + 1; +} \ No newline at end of file From 877daed1ae395db334b0488b4ed116486cd76f56 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 1 Jun 2025 11:40:35 -0400 Subject: [PATCH 46/92] d_library: libs shouldn't be in inputs we only care about headers/exports of our dependencies, not the compiled libraries. This allows to skip recompilation if implementation is changed, but not the API. --- d/d.bzl | 2 -- 1 file changed, 2 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 4f96ec2..72d9af4 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -297,8 +297,6 @@ def _d_library_impl_common(ctx, extra_flags = []): transitive = [ depinfo.transitive_d_srcs, depinfo.transitive_extra_files, - depinfo.libs, - depinfo.transitive_libs, phobos_files, phobos_src_files, druntime_src_files, From 11670cd413e2ef2f9085606dd8c64b7f5db24bca Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 1 Jun 2025 11:48:18 -0400 Subject: [PATCH 47/92] d_lib: macro around d_library that hdrgen exports Why this is useful? 1. hdrgen is super cheap. 2. it can help shrinking lib's exports: - exports must include not only files that are directly imported from other libs, but also imports from exports themselves, effectively making it the whole library. - but not with hdrgen: imports from the non-templated function bodies will be dropped, shrinking the export surface. 3. it allows for fewer recompilations of dependents: - if an exported source is changed, - but in a way that doesn't affect hdrgen result dependents don't need to be recompiled, thanks to bazel's content based dependency tracking. --- d/d.bzl | 71 ++++++++++++++++++++++++++++++++++++++++++++++ tests/d_lib/BUILD | 20 +++++++++++++ tests/d_lib/lib.d | 6 ++++ tests/d_lib/lib2.d | 8 ++++++ tests/d_lib/main.d | 11 +++++++ 5 files changed, 116 insertions(+) create mode 100644 tests/d_lib/BUILD create mode 100644 tests/d_lib/lib.d create mode 100644 tests/d_lib/lib2.d create mode 100644 tests/d_lib/main.d diff --git a/d/d.bzl b/d/d.bzl index 72d9af4..98f0a36 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -715,3 +715,74 @@ d_docs = rule( }, toolchains = [D_TOOLCHAIN], ) + +def d_lib( + name, + srcs = [], + imports = [], + string_imports = [], + extra_files = [], + linkopts = [], + versions = [], + hdrs = [], + exports = [], + exports_no_hdrs = [], + deps = [], + include_workspace_root = True, + is_generated = False, + generated_srcs = {}, +): + """d_lib is a macro that can generate header files for a D library. + + It wraps the d_library rule and automatically generates header files + for the exported D source files. It takes mostly the same arguments + as d_library, plus an additional `exports_no_hdrs` argument that + specifies the exported D source files that should be exported without + generating headers for them (this might be useful if they contain + non-templated functions that need to be called during CTFE). + Args: + name: The name of the target. + srcs: List of D source files to compile. + imports: List of import paths to include in the compilation. + string_imports: List of string import paths to include in the compilation. + extra_files: List of extra files to include in the compilation. + linkopts: List of linker options to pass to the linker. + versions: List of D versions to define during compilation. + hdrs: List of header files to include in the library. + exports: List of D source files to export, which will have headers generated for them. + exports_no_hdrs: List of D source files to export without generating headers. + deps: List of dependencies for this library. + include_workspace_root: Whether to include the workspace root in import paths. + is_generated: Whether this library is generated (used for generated sources). + generated_srcs: A dictionary mapping generated source files to their desired locations. + """ + exports_hdrs = [] + new_generated_srcs = {} + new_generated_srcs |= generated_srcs + for exp in exports: + if not exp.endswith(".d"): + fail("Exported files must be D source files, got: %s" % exp) + d_header_generator( + name = exp + "_hdrgen", + src = exp, + ) + hdr = exp + "_hdrgen" + exports_hdrs.append(hdr) + di_name = exp[:-2] + ".di" # Replace .d with .di + new_generated_srcs[hdr] = di_name + + d_library( + name = name, + srcs = srcs, + imports = imports, + string_imports = string_imports, + extra_files = extra_files, + linkopts = linkopts, + versions = versions, + hdrs = hdrs + exports_hdrs, + exports = exports_no_hdrs, + deps = deps, + include_workspace_root = include_workspace_root, + is_generated = is_generated, + generated_srcs = new_generated_srcs, + ) diff --git a/tests/d_lib/BUILD b/tests/d_lib/BUILD new file mode 100644 index 0000000..7548ea3 --- /dev/null +++ b/tests/d_lib/BUILD @@ -0,0 +1,20 @@ +load("//d:d.bzl", "d_binary", "d_lib") + +d_lib( + name = "d_lib", + srcs = ["lib.d"], + exports = ["lib.d"], +) + +d_lib( + name = "d_lib2", + srcs = ["lib2.d"], + exports = ["lib2.d"], + deps = [":d_lib"], +) + +d_binary( + name = "main", + srcs = ["main.d"], + deps = [":d_lib2"], +) \ No newline at end of file diff --git a/tests/d_lib/lib.d b/tests/d_lib/lib.d new file mode 100644 index 0000000..d248f29 --- /dev/null +++ b/tests/d_lib/lib.d @@ -0,0 +1,6 @@ +module tests.d_lib.lib; + +int plusOne(int x) +{ + return x + 1; +} \ No newline at end of file diff --git a/tests/d_lib/lib2.d b/tests/d_lib/lib2.d new file mode 100644 index 0000000..3651497 --- /dev/null +++ b/tests/d_lib/lib2.d @@ -0,0 +1,8 @@ +module tests.d_lib.lib2; + +import tests.d_lib.lib; + +int plusOneTwice(int x) +{ + return plusOne(plusOne(x)); +} \ No newline at end of file diff --git a/tests/d_lib/main.d b/tests/d_lib/main.d new file mode 100644 index 0000000..1409cd5 --- /dev/null +++ b/tests/d_lib/main.d @@ -0,0 +1,11 @@ +module tests.d_lib.main; + +import tests.d_lib.lib2; + +void main() +{ + int x = 5; + int result = plusOneTwice(x); + import std.stdio; + writeln("The result of plusOne(", x, ") is: ", result); +} \ No newline at end of file From b2c33d03ccd82d7b47be86378b5d47f559b27301 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Mon, 2 Jun 2025 06:01:20 -0400 Subject: [PATCH 48/92] d_lib: support creating d_test_library --- d/d.bzl | 49 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 98f0a36..16d2dde 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -731,6 +731,7 @@ def d_lib( include_workspace_root = True, is_generated = False, generated_srcs = {}, + test = False, ): """d_lib is a macro that can generate header files for a D library. @@ -755,6 +756,7 @@ def d_lib( include_workspace_root: Whether to include the workspace root in import paths. is_generated: Whether this library is generated (used for generated sources). generated_srcs: A dictionary mapping generated source files to their desired locations. + test: Whether this library is a test library (compiled with -unittest flag). """ exports_hdrs = [] new_generated_srcs = {} @@ -771,18 +773,35 @@ def d_lib( di_name = exp[:-2] + ".di" # Replace .d with .di new_generated_srcs[hdr] = di_name - d_library( - name = name, - srcs = srcs, - imports = imports, - string_imports = string_imports, - extra_files = extra_files, - linkopts = linkopts, - versions = versions, - hdrs = hdrs + exports_hdrs, - exports = exports_no_hdrs, - deps = deps, - include_workspace_root = include_workspace_root, - is_generated = is_generated, - generated_srcs = new_generated_srcs, - ) + if not test: + d_library( + name = name, + srcs = srcs, + imports = imports, + string_imports = string_imports, + extra_files = extra_files, + linkopts = linkopts, + versions = versions, + hdrs = hdrs + exports_hdrs, + exports = exports_no_hdrs, + deps = deps, + include_workspace_root = include_workspace_root, + is_generated = is_generated, + generated_srcs = new_generated_srcs, + ) + else: + d_test_library( + name = name, + srcs = srcs, + imports = imports, + string_imports = string_imports, + extra_files = extra_files, + linkopts = linkopts, + versions = versions, + hdrs = hdrs + exports_hdrs, + exports = exports_no_hdrs, + deps = deps, + include_workspace_root = include_workspace_root, + is_generated = is_generated, + generated_srcs = new_generated_srcs, + ) From 25c9936c4a71cc0fb1e9d8d65c712bf8df5c6763 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 4 Jun 2025 06:52:08 -0400 Subject: [PATCH 49/92] d_source_library: add processing of generated sources to match what is done in `d_library`. TODO: consider supporting "headers-only" `d_library` and dropping `d_source_library`. --- d/d.bzl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/d/d.bzl b/d/d.bzl index 16d2dde..f3f523f 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -479,6 +479,8 @@ def _d_source_library_impl(ctx): transitive_string_imports = depset() transitive_linkopts = depset() transitive_versions = depset() + generated_srcs = { + src.files.to_list()[0]: src.label.package + "/" + loc for src, loc in ctx.attr.generated_srcs.items()} for dep in ctx.attr.deps: if DInfo in dep and hasattr(dep[DInfo], "d_srcs") and not hasattr(dep[DInfo], "d_lib"): # Dependency is another d_source_library target. @@ -491,6 +493,7 @@ def _d_source_library_impl(ctx): transitive_linkopts = depset(ddep.linkopts, transitive = [transitive_linkopts]) transitive_versions = depset(transitive = [ddep.versions, transitive_versions]) transitive_transitive_libs.append(ddep.transitive_libs) + generated_srcs = generated_srcs | ddep.generated_srcs elif CcInfo in dep: # Dependency is a cc_library target. @@ -515,7 +518,7 @@ def _d_source_library_impl(ctx): linkopts = ctx.attr.linkopts + transitive_linkopts.to_list(), versions = depset(ctx.attr.versions, transitive = [transitive_versions]), is_generated = ctx.attr.is_generated, - generated_srcs = ctx.attr.generated_srcs, + generated_srcs = generated_srcs, ), ] From 96bdd2080c16fb473fdfa13546f21fe995d15316 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 4 Jun 2025 06:53:44 -0400 Subject: [PATCH 50/92] d_lib: add `exports_lib` argument It allows to create a `d_source_library` containing only headers and exports. This should be enough to break a circular dependency. --- d/d.bzl | 19 +++++++++++++++++++ tests/circular_deps/BUILD | 21 +++++++++++++++++++++ tests/circular_deps/lib_a.d | 11 +++++++++++ tests/circular_deps/lib_b.d | 7 +++++++ 4 files changed, 58 insertions(+) create mode 100644 tests/circular_deps/BUILD create mode 100644 tests/circular_deps/lib_a.d create mode 100644 tests/circular_deps/lib_b.d diff --git a/d/d.bzl b/d/d.bzl index f3f523f..214d44b 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -735,6 +735,7 @@ def d_lib( is_generated = False, generated_srcs = {}, test = False, + exports_lib = None, ): """d_lib is a macro that can generate header files for a D library. @@ -760,6 +761,9 @@ def d_lib( is_generated: Whether this library is generated (used for generated sources). generated_srcs: A dictionary mapping generated source files to their desired locations. test: Whether this library is a test library (compiled with -unittest flag). + exports_lib: Optional label of a d_library target that contains the exported files. + If provided, will create an extra `d_source_library` with headers+exports. + This could be used to break a circular dependency. """ exports_hdrs = [] new_generated_srcs = {} @@ -808,3 +812,18 @@ def d_lib( is_generated = is_generated, generated_srcs = new_generated_srcs, ) + + if exports_lib: + # Create a d_source_library with the exported files. + d_source_library( + name = exports_lib, + srcs = hdrs + exports_hdrs + exports_no_hdrs, + imports = imports, + string_imports = string_imports, + extra_files = extra_files, + linkopts = linkopts, + versions = versions, + include_workspace_root = include_workspace_root, + is_generated = is_generated, + generated_srcs = new_generated_srcs, + ) diff --git a/tests/circular_deps/BUILD b/tests/circular_deps/BUILD new file mode 100644 index 0000000..886b595 --- /dev/null +++ b/tests/circular_deps/BUILD @@ -0,0 +1,21 @@ + +load("//d:d.bzl", "d_lib") + +d_lib( + name = "lib_a", + srcs = ["lib_a.d"], + exports = ["lib_a.d"], + exports_lib = "lib_a_exports", + deps = [ + ":lib_b", + ], +) + +d_lib( + name = "lib_b", + srcs = ["lib_b.d"], + exports = ["lib_b.d"], + deps = [ + ":lib_a_exports", + ], +) \ No newline at end of file diff --git a/tests/circular_deps/lib_a.d b/tests/circular_deps/lib_a.d new file mode 100644 index 0000000..2c77335 --- /dev/null +++ b/tests/circular_deps/lib_a.d @@ -0,0 +1,11 @@ +module tests.circular_deps.lib_a; + +import tests.circular_deps.lib_b; + +int f(int x) { + return x + g(x); +} + +int h(int x) { + return x + 1; +} \ No newline at end of file diff --git a/tests/circular_deps/lib_b.d b/tests/circular_deps/lib_b.d new file mode 100644 index 0000000..e0db626 --- /dev/null +++ b/tests/circular_deps/lib_b.d @@ -0,0 +1,7 @@ +module tests.circular_deps.lib_b; + +import tests.circular_deps.lib_a; + +int g(int x) { + return x + h(x); +} From 2a8e93b81be08d9ef5289e1acb8124d55d93ba50 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Thu, 5 Jun 2025 11:20:42 -0400 Subject: [PATCH 51/92] d_library: support "no srcs" libraries There are two usages for those: 1. Template/"header only" libraries, these should eventually replace `d_source_library`s. 2. Logical library grouping, no srcs and no headers, only deps. In both cases there is nothing to compile (yet). --- d/d.bzl | 39 +++++++++++++++---- tests/deps_only_library/BUILD | 16 ++++++++ tests/deps_only_library/test.d | 15 +++++++ tests/header_only_library/BUILD | 17 ++++++++ .../header_only_library_test.d | 9 +++++ tests/header_only_library/lib.di | 5 +++ 6 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 tests/deps_only_library/BUILD create mode 100644 tests/deps_only_library/test.d create mode 100644 tests/header_only_library/BUILD create mode 100644 tests/header_only_library/header_only_library_test.d create mode 100644 tests/header_only_library/lib.di diff --git a/d/d.bzl b/d/d.bzl index 214d44b..c54e299 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -176,7 +176,8 @@ def _setup_deps(ctx, deps, name): if DInfo in dep and hasattr(dep[DInfo], "d_lib"): # The dependency is a d_library. ddep = dep[DInfo] - libs.append(ddep.d_lib) + if ddep.d_lib: + libs.append(ddep.d_lib) transitive_libs.append(ddep.transitive_libs) d_srcs += ddep.d_exports transitive_d_srcs.append(ddep.transitive_d_srcs) @@ -258,14 +259,42 @@ def _handle_generated_srcs(ctx, generated_srcs, d_compiler): def _d_library_impl_common(ctx, extra_flags = []): """Implementation of the d_library rule.""" toolchain = ctx.toolchains[D_TOOLCHAIN] - #d_lib = ctx.actions.declare_file((ctx.label.name + ".lib") if _is_windows(ctx) else ("lib" + ctx.label.name + ".a")) - d_lib = ctx.actions.declare_file(ctx.label.name + ".o") d_compiler = toolchain.d_compiler.files.to_list()[0] # Dependencies deps = ctx.attr.deps + ([toolchain.libphobos] if toolchain.libphobos != None else []) + ([toolchain.druntime] if toolchain.druntime != None else []) depinfo = _setup_deps(ctx, ctx.attr.deps, ctx.label.name) + public_srcs = ctx.files.hdrs + ctx.files.exports + if not public_srcs: + public_srcs = ctx.files.srcs + + if not ctx.files.srcs: + return [ + DefaultInfo( + files = depset(), + ), + DInfo( + d_srcs = ctx.files.srcs, + d_exports = public_srcs, + transitive_d_srcs = depinfo.transitive_d_srcs, + extra_files = ctx.files.extra_files, + transitive_extra_files = depset(depinfo.extra_files), + transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), + link_flags = depinfo.link_flags, + linkopts = ctx.attr.linkopts, + versions = depinfo.versions, + imports = depinfo.imports, + string_imports = depinfo.string_imports, + d_lib = "", # TODO: we only need it to distinguish from d_source_library. Either drop d_source_library or make another provider for it. + is_generated = ctx.attr.is_generated, + generated_srcs = depinfo.generated_srcs, + ), + ] + + #d_lib = ctx.actions.declare_file((ctx.label.name + ".lib") if _is_windows(ctx) else ("lib" + ctx.label.name + ".a")) + d_lib = ctx.actions.declare_file(ctx.label.name + ".o") + # Build compile command. compile_args = _build_compile_arglist( ctx = ctx, @@ -314,10 +343,6 @@ def _d_library_impl_common(ctx, extra_flags = []): progress_message = "Compiling D library " + ctx.label.name, ) - public_srcs = ctx.files.hdrs + ctx.files.exports - if not public_srcs: - public_srcs = ctx.files.srcs - return [ DefaultInfo( files = depset([d_lib]), diff --git a/tests/deps_only_library/BUILD b/tests/deps_only_library/BUILD new file mode 100644 index 0000000..1e6b97c --- /dev/null +++ b/tests/deps_only_library/BUILD @@ -0,0 +1,16 @@ +load("//d:d.bzl", "d_library", "d_test") + +d_library( + name = "deps_only_library", + srcs = [], + deps = [ + "//tests/header_only_library:header_only_library", + "//tests/simple_d_library:simple_d_library", + ], +) + +d_test( + name = "deps_only_library_test", + srcs = ["test.d"], + deps = [":deps_only_library"], +) \ No newline at end of file diff --git a/tests/deps_only_library/test.d b/tests/deps_only_library/test.d new file mode 100644 index 0000000..6cec4d0 --- /dev/null +++ b/tests/deps_only_library/test.d @@ -0,0 +1,15 @@ +module tests.deps_only_library.test; + +void main() { + import tests.header_only_library.lib; + + int result = add(2, 3); + + assert(result == 5); + + import tests.simple_d_library.simple_library; + + int result2 = plusOne(4); + + assert(result2 == 5); +} \ No newline at end of file diff --git a/tests/header_only_library/BUILD b/tests/header_only_library/BUILD new file mode 100644 index 0000000..d84eae3 --- /dev/null +++ b/tests/header_only_library/BUILD @@ -0,0 +1,17 @@ +load("//d:d.bzl", "d_library", "d_test") + +package( + default_visibility = ["//visibility:public"], +) + +d_library( + name = "header_only_library", + srcs = [], + hdrs = ["lib.di"], +) + +d_test( + name = "header_only_library_test", + srcs = ["header_only_library_test.d"], + deps = [":header_only_library"], +) \ No newline at end of file diff --git a/tests/header_only_library/header_only_library_test.d b/tests/header_only_library/header_only_library_test.d new file mode 100644 index 0000000..d4ec9aa --- /dev/null +++ b/tests/header_only_library/header_only_library_test.d @@ -0,0 +1,9 @@ +module tests.header_only_library.header_only_library_test; + +void main() { + import tests.header_only_library.lib; + + int result = add(2, 3); + + assert(result == 5); +} \ No newline at end of file diff --git a/tests/header_only_library/lib.di b/tests/header_only_library/lib.di new file mode 100644 index 0000000..c763937 --- /dev/null +++ b/tests/header_only_library/lib.di @@ -0,0 +1,5 @@ +module tests.header_only_library.lib; + +int add(T)(T a, T b) { + return a + b; +} From 6889a28bf9934dd8b63350b997e0d9a31257c15d Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 11 Jun 2025 08:04:22 -0400 Subject: [PATCH 52/92] d_binary/d_test: allow empty sources to be on part with d_library. Sometimes we just want to link libs into a binary, without compiling anything. --- d/d.bzl | 72 +++++++++++++++--------------- tests/d_binary_no_source/BUILD | 20 +++++++++ tests/d_binary_no_source/main.d | 2 + tests/d_binary_no_source/testlib.d | 13 ++++++ 4 files changed, 72 insertions(+), 35 deletions(-) create mode 100644 tests/d_binary_no_source/BUILD create mode 100644 tests/d_binary_no_source/main.d create mode 100644 tests/d_binary_no_source/testlib.d diff --git a/d/d.bzl b/d/d.bzl index c54e299..b19e5c3 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -369,56 +369,58 @@ def _d_binary_impl_common(ctx, extra_flags = []): """Common implementation for rules that build a D binary.""" toolchain = ctx.toolchains[D_TOOLCHAIN] d_bin = ctx.actions.declare_file(ctx.label.name + ".exe" if _is_windows(ctx) else ctx.label.name) - d_obj = ctx.actions.declare_file(ctx.label.name + (".obj" if _is_windows(ctx) else ".o")) d_compiler = toolchain.d_compiler.files.to_list()[0] # Dependencies deps = ctx.attr.deps + ([toolchain.libphobos] if toolchain.libphobos != None else []) + ([toolchain.druntime] if toolchain.druntime != None else []) depinfo = _setup_deps(ctx, deps, ctx.label.name) - # Build compile command - compile_args = _build_compile_arglist( - ctx = ctx, - depinfo = depinfo, - out = d_obj, - extra_flags = ["-c"] + extra_flags, - ) - - # Convert sources to args - # This is done to support receiving a File that is a directory, as - # args will auto-expand this to the contained files - args = ctx.actions.args() - args.add_all(compile_args) - - mapped_srcs, generated_srcs_wrapper = _handle_generated_srcs(ctx, depinfo.generated_srcs, d_compiler) - - args.add_all(mapped_srcs) - + d_obj = None toolchain_files = [ toolchain.libphobos.files if toolchain.libphobos != None else depset(), toolchain.libphobos_src.files if toolchain.libphobos_src != None else depset(), toolchain.druntime_src.files if toolchain.druntime_src != None else depset(), ] - compile_inputs = depset( - ctx.files.srcs + ctx.files.extra_files + depinfo.extra_files, - transitive = [depinfo.transitive_d_srcs, depinfo.transitive_extra_files] + toolchain_files, - ) - ctx.actions.run( - inputs = compile_inputs, - tools = [d_compiler, generated_srcs_wrapper] if generated_srcs_wrapper else [d_compiler], - outputs = [d_obj], - mnemonic = "Dcompile", - executable = generated_srcs_wrapper if generated_srcs_wrapper else d_compiler, - arguments = [args], - use_default_shell_env = True, - progress_message = "Compiling D binary " + ctx.label.name, - ) + if ctx.files.srcs: + d_obj = ctx.actions.declare_file(ctx.label.name + (".obj" if _is_windows(ctx) else ".o")) + # Build compile command + compile_args = _build_compile_arglist( + ctx = ctx, + depinfo = depinfo, + out = d_obj, + extra_flags = ["-c"] + extra_flags, + ) + + # Convert sources to args + # This is done to support receiving a File that is a directory, as + # args will auto-expand this to the contained files + args = ctx.actions.args() + args.add_all(compile_args) + + mapped_srcs, generated_srcs_wrapper = _handle_generated_srcs(ctx, depinfo.generated_srcs, d_compiler) + + args.add_all(mapped_srcs) + + compile_inputs = depset( + ctx.files.srcs + ctx.files.extra_files + depinfo.extra_files, + transitive = [depinfo.transitive_d_srcs, depinfo.transitive_extra_files] + toolchain_files, + ) + ctx.actions.run( + inputs = compile_inputs, + tools = [d_compiler, generated_srcs_wrapper] if generated_srcs_wrapper else [d_compiler], + outputs = [d_obj], + mnemonic = "Dcompile", + executable = generated_srcs_wrapper if generated_srcs_wrapper else d_compiler, + arguments = [args], + use_default_shell_env = True, + progress_message = "Compiling D binary " + ctx.label.name, + ) # Build link command link_args = _build_link_arglist( ctx = ctx, - objs = [d_obj.path], + objs = [d_obj.path] if d_obj else [], depinfo = depinfo, out = d_bin, c_compiler = toolchain.c_compiler, @@ -426,7 +428,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): ) link_inputs = depset( - [d_obj], + [d_obj] if d_obj else [], transitive = [depinfo.libs, depinfo.transitive_libs] + toolchain_files, ) diff --git a/tests/d_binary_no_source/BUILD b/tests/d_binary_no_source/BUILD new file mode 100644 index 0000000..27ac54c --- /dev/null +++ b/tests/d_binary_no_source/BUILD @@ -0,0 +1,20 @@ +load("//d:d.bzl", "d_library", "d_test_library", "d_test") + +d_test_library( + name = "testlib", + srcs = ["testlib.d"], +) + +d_library( + name = "main", + srcs = ["main.d"], +) + +d_test( + name = "test", + srcs = [], + deps = [ + ":main", + ":testlib", + ], +) \ No newline at end of file diff --git a/tests/d_binary_no_source/main.d b/tests/d_binary_no_source/main.d new file mode 100644 index 0000000..34f46e2 --- /dev/null +++ b/tests/d_binary_no_source/main.d @@ -0,0 +1,2 @@ +void main() { +} diff --git a/tests/d_binary_no_source/testlib.d b/tests/d_binary_no_source/testlib.d new file mode 100644 index 0000000..f1027fa --- /dev/null +++ b/tests/d_binary_no_source/testlib.d @@ -0,0 +1,13 @@ + +int f(int x) { + return x * 2; +} + +unittest +{ + assert(f(2) == 4); + assert(f(3) == 6); + assert(f(0) == 0); + assert(f(-1) == -2); + assert(f(-5) == -10); +} \ No newline at end of file From 500068947e15feba7c89508a721b376ec85b214b Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 11 Jun 2025 08:09:02 -0400 Subject: [PATCH 53/92] rules_d: rename `extra_files` to `data` `data` is the standard Bazel attribute to specify non-source inputs. --- d/d.bzl | 60 +++++++++++++++++------------------ examples/string_imports/BUILD | 2 +- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index b19e5c3..aaa2ae3 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -153,7 +153,7 @@ def _setup_deps(ctx, deps, name): link_flags: List of linker flags. generated_srcs: A dictionary mapping generated files to their desired locations. - extra_files: List of Files containing extra (non-source) files that will + data: List of Files containing extra (non-source) files that will be used as inputs for this target. """ @@ -161,9 +161,9 @@ def _setup_deps(ctx, deps, name): libs = [] transitive_libs = [] d_srcs = [] - extra_files = [] + data = [] transitive_d_srcs = [] - transitive_extra_files = [] + transitive_data = [] versions = ctx.attr.versions + ["Have_%s" % _format_version(name)] transitive_versions = [] gen_dir_for_imports = gen_dir if ctx.attr.is_generated else None @@ -181,8 +181,8 @@ def _setup_deps(ctx, deps, name): transitive_libs.append(ddep.transitive_libs) d_srcs += ddep.d_exports transitive_d_srcs.append(ddep.transitive_d_srcs) - extra_files += ddep.extra_files - transitive_extra_files.append(ddep.transitive_extra_files) + data += ddep.data + transitive_data.append(ddep.transitive_data) transitive_versions.append(ddep.versions) link_flags.extend(ddep.link_flags) link_flags += ["-L%s" % linkopt for linkopt in ddep.linkopts] @@ -197,8 +197,8 @@ def _setup_deps(ctx, deps, name): ddep = dep[DInfo] d_srcs += ddep.d_srcs transitive_d_srcs.append(ddep.transitive_d_srcs) - extra_files += ddep.extra_files - transitive_extra_files.append(ddep.transitive_extra_files) + data += ddep.data + transitive_data.append(ddep.transitive_data) transitive_libs.append(ddep.transitive_libs) link_flags += ["-L%s" % linkopt for linkopt in ddep.linkopts] imports += ddep.imports @@ -222,8 +222,8 @@ def _setup_deps(ctx, deps, name): libs = depset(libs), transitive_libs = depset(transitive = transitive_libs), transitive_d_srcs = depset(d_srcs, transitive = transitive_d_srcs), - extra_files = depset(extra_files).to_list(), - transitive_extra_files = depset(transitive = transitive_extra_files), + data = depset(data).to_list(), + transitive_data = depset(transitive = transitive_data), versions = depset(versions, transitive = transitive_versions), imports = depset(imports).to_list(), string_imports = depset(string_imports).to_list(), @@ -278,8 +278,8 @@ def _d_library_impl_common(ctx, extra_flags = []): d_srcs = ctx.files.srcs, d_exports = public_srcs, transitive_d_srcs = depinfo.transitive_d_srcs, - extra_files = ctx.files.extra_files, - transitive_extra_files = depset(depinfo.extra_files), + data = ctx.files.data, + transitive_data = depset(depinfo.data), transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), link_flags = depinfo.link_flags, linkopts = ctx.attr.linkopts, @@ -321,11 +321,11 @@ def _d_library_impl_common(ctx, extra_flags = []): ctx.files.srcs + ctx.files.hdrs + ctx.files.exports + - ctx.files.extra_files + - depinfo.extra_files, + ctx.files.data + + depinfo.data, transitive = [ depinfo.transitive_d_srcs, - depinfo.transitive_extra_files, + depinfo.transitive_data, phobos_files, phobos_src_files, druntime_src_files, @@ -351,8 +351,8 @@ def _d_library_impl_common(ctx, extra_flags = []): d_srcs = ctx.files.srcs, d_exports = public_srcs, transitive_d_srcs = depinfo.transitive_d_srcs, - extra_files = ctx.files.extra_files, - transitive_extra_files = depset(depinfo.extra_files), + data = ctx.files.data, + transitive_data = depset(depinfo.data), transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), link_flags = depinfo.link_flags, linkopts = ctx.attr.linkopts, @@ -403,8 +403,8 @@ def _d_binary_impl_common(ctx, extra_flags = []): args.add_all(mapped_srcs) compile_inputs = depset( - ctx.files.srcs + ctx.files.extra_files + depinfo.extra_files, - transitive = [depinfo.transitive_d_srcs, depinfo.transitive_extra_files] + toolchain_files, + ctx.files.srcs + ctx.files.data + depinfo.data, + transitive = [depinfo.transitive_d_srcs, depinfo.transitive_data] + toolchain_files, ) ctx.actions.run( inputs = compile_inputs, @@ -447,8 +447,8 @@ def _d_binary_impl_common(ctx, extra_flags = []): DInfo( d_srcs = ctx.files.srcs, transitive_d_srcs = depinfo.transitive_d_srcs, - extra_files = ctx.files.extra_files, - transitive_extra_files = depset(depinfo.extra_files), + data = ctx.files.data, + transitive_data = depset(depinfo.data), imports = ctx.attr.imports, string_imports = ctx.attr.string_imports, ), @@ -499,7 +499,7 @@ def _get_libs_for_static_executable(dep): def _d_source_library_impl(ctx): """Implementation of the d_source_library rule.""" transitive_d_srcs = [] - transitive_extra_files = [] + transitive_data = [] transitive_libs = [] transitive_transitive_libs = [] transitive_imports = depset() @@ -514,7 +514,7 @@ def _d_source_library_impl(ctx): # TODO: Could we also support d_library here? ddep = dep[DInfo] transitive_d_srcs.append(depset(ddep.d_srcs, transitive = [ddep.transitive_d_srcs])) - transitive_extra_files.append(depset(ddep.extra_files)) + transitive_data.append(depset(ddep.data)) transitive_imports = depset(ddep.imports, transitive = [transitive_imports]) transitive_string_imports = depset(ddep.string_imports, transitive = [transitive_string_imports]) transitive_linkopts = depset(ddep.linkopts, transitive = [transitive_linkopts]) @@ -536,9 +536,9 @@ def _d_source_library_impl(ctx): return [ DInfo( d_srcs = ctx.files.srcs, - extra_files = ctx.files.extra_files, + data = ctx.files.data, transitive_d_srcs = depset(transitive = transitive_d_srcs, order = "postorder"), - transitive_extra_files = depset(transitive = transitive_extra_files, order = "postorder"), + transitive_data = depset(transitive = transitive_data, order = "postorder"), transitive_libs = depset(transitive_libs, transitive = transitive_transitive_libs), imports = [_build_import(ctx.label, im, gen_dir) for im in ctx.attr.imports] + transitive_imports.to_list(), string_imports = [_build_import(ctx.label, im, gen_dir) for im in ctx.attr.string_imports] + transitive_string_imports.to_list(), @@ -657,7 +657,7 @@ _d_common_attrs = { "srcs": attr.label_list(allow_files = D_FILETYPE), "imports": attr.string_list(), "string_imports": attr.string_list(), - "extra_files": attr.label_list(allow_files = True), + "data": attr.label_list(allow_files = True), "linkopts": attr.string_list(), "versions": attr.string_list(), "include_workspace_root": attr.bool(default = True), @@ -751,7 +751,7 @@ def d_lib( srcs = [], imports = [], string_imports = [], - extra_files = [], + data = [], linkopts = [], versions = [], hdrs = [], @@ -777,7 +777,7 @@ def d_lib( srcs: List of D source files to compile. imports: List of import paths to include in the compilation. string_imports: List of string import paths to include in the compilation. - extra_files: List of extra files to include in the compilation. + data: List of extra files to include in the compilation. linkopts: List of linker options to pass to the linker. versions: List of D versions to define during compilation. hdrs: List of header files to include in the library. @@ -813,7 +813,7 @@ def d_lib( srcs = srcs, imports = imports, string_imports = string_imports, - extra_files = extra_files, + data = data, linkopts = linkopts, versions = versions, hdrs = hdrs + exports_hdrs, @@ -829,7 +829,7 @@ def d_lib( srcs = srcs, imports = imports, string_imports = string_imports, - extra_files = extra_files, + data = data, linkopts = linkopts, versions = versions, hdrs = hdrs + exports_hdrs, @@ -847,7 +847,7 @@ def d_lib( srcs = hdrs + exports_hdrs + exports_no_hdrs, imports = imports, string_imports = string_imports, - extra_files = extra_files, + data = data, linkopts = linkopts, versions = versions, include_workspace_root = include_workspace_root, diff --git a/examples/string_imports/BUILD b/examples/string_imports/BUILD index 51d164a..f876803 100644 --- a/examples/string_imports/BUILD +++ b/examples/string_imports/BUILD @@ -3,7 +3,7 @@ load("//d:d.bzl", "d_binary", "d_library") d_library( name = "lib", srcs = ["lib.d"], - extra_files = ["imports/test.txt"], + data = ["imports/test.txt"], string_imports = ["imports"], ) From 37c77d1e12e645d339bb36f4d9e809c1a7306abe Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Tue, 17 Jun 2025 04:23:09 -0400 Subject: [PATCH 54/92] d_lib: add kwargs --- d/d.bzl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/d/d.bzl b/d/d.bzl index aaa2ae3..f63ae6d 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -763,6 +763,7 @@ def d_lib( generated_srcs = {}, test = False, exports_lib = None, + **kwargs, ): """d_lib is a macro that can generate header files for a D library. @@ -791,6 +792,7 @@ def d_lib( exports_lib: Optional label of a d_library target that contains the exported files. If provided, will create an extra `d_source_library` with headers+exports. This could be used to break a circular dependency. + **kwargs: Additional attributes for the d_library rule. """ exports_hdrs = [] new_generated_srcs = {} @@ -822,6 +824,7 @@ def d_lib( include_workspace_root = include_workspace_root, is_generated = is_generated, generated_srcs = new_generated_srcs, + **kwargs, ) else: d_test_library( @@ -838,6 +841,7 @@ def d_lib( include_workspace_root = include_workspace_root, is_generated = is_generated, generated_srcs = new_generated_srcs, + **kwargs, ) if exports_lib: @@ -853,4 +857,5 @@ def d_lib( include_workspace_root = include_workspace_root, is_generated = is_generated, generated_srcs = new_generated_srcs, + **kwargs, ) From 75952800c169d9849f026348b7a0968f0f4fa31f Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 18 Jun 2025 06:06:11 -0400 Subject: [PATCH 55/92] d_lib: prefix generated headers' targets with `name` Otherwise we can get target clashes. --- d/d.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index f63ae6d..d97151f 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -800,11 +800,11 @@ def d_lib( for exp in exports: if not exp.endswith(".d"): fail("Exported files must be D source files, got: %s" % exp) + hdr = name + "_" + exp + "_hdrgen" d_header_generator( - name = exp + "_hdrgen", + name = hdr, src = exp, ) - hdr = exp + "_hdrgen" exports_hdrs.append(hdr) di_name = exp[:-2] + ".di" # Replace .d with .di new_generated_srcs[hdr] = di_name From 9938ab6b7c7eb401c013b8daf207b4f2c1af5412 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 18 Jun 2025 06:07:13 -0400 Subject: [PATCH 56/92] d_lib: handle header generation for generated source If we have a generated source `s` in exports that has to be put into the location `path/file.d` before compiling, make sure to extend the generated_srcs map such that the generated header ends up in `path/file.di`. --- d/d.bzl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/d/d.bzl b/d/d.bzl index d97151f..1f5a5d7 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -805,8 +805,13 @@ def d_lib( name = hdr, src = exp, ) + if exp in generated_srcs: + # If the file is already in generated_srcs, let's put di file next to the target d file. + target = generated_srcs[exp] + else: + target = exp exports_hdrs.append(hdr) - di_name = exp[:-2] + ".di" # Replace .d with .di + di_name = target[:-2] + ".di" # Replace .d with .di new_generated_srcs[hdr] = di_name if not test: From b21697ac500b18a031bc1951666a1840460e8f30 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 18 Jun 2025 09:49:09 -0400 Subject: [PATCH 57/92] d_lib: put generated headers into a subdirectory --- d/d.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/d/d.bzl b/d/d.bzl index 1f5a5d7..ccdbe62 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -800,7 +800,7 @@ def d_lib( for exp in exports: if not exp.endswith(".d"): fail("Exported files must be D source files, got: %s" % exp) - hdr = name + "_" + exp + "_hdrgen" + hdr = name + ".hdrgen/" + exp + "_hdrgen" d_header_generator( name = hdr, src = exp, From 68bf5386c0b0468c34f3765a3458591118d1878b Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Thu, 19 Jun 2025 04:39:44 -0400 Subject: [PATCH 58/92] d_library: fix collecting transitive data --- d/d.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index ccdbe62..fc3ad28 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -279,7 +279,7 @@ def _d_library_impl_common(ctx, extra_flags = []): d_exports = public_srcs, transitive_d_srcs = depinfo.transitive_d_srcs, data = ctx.files.data, - transitive_data = depset(depinfo.data), + transitive_data = depset(depinfo.data, transitive = [depinfo.transitive_data]), transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), link_flags = depinfo.link_flags, linkopts = ctx.attr.linkopts, @@ -352,7 +352,7 @@ def _d_library_impl_common(ctx, extra_flags = []): d_exports = public_srcs, transitive_d_srcs = depinfo.transitive_d_srcs, data = ctx.files.data, - transitive_data = depset(depinfo.data), + transitive_data = depset(depinfo.data, transitive = [depinfo.transitive_data]), transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), link_flags = depinfo.link_flags, linkopts = ctx.attr.linkopts, From bda9be330055277b23b7513978319e4aa02bf14f Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Fri, 20 Jun 2025 08:27:06 -0400 Subject: [PATCH 59/92] d_lib: use hdrs-only d_library instead of d_source_library In preparation for d_source_library removal --- d/d.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index fc3ad28..3139d45 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -851,9 +851,9 @@ def d_lib( if exports_lib: # Create a d_source_library with the exported files. - d_source_library( + d_library( name = exports_lib, - srcs = hdrs + exports_hdrs + exports_no_hdrs, + hdrs = hdrs + exports_hdrs + exports_no_hdrs, imports = imports, string_imports = string_imports, data = data, From 0ed24b23c39d48820165841a4467ad2a18af6391 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Fri, 20 Jun 2025 09:43:50 -0400 Subject: [PATCH 60/92] d_binary/d_test: add link_order It's a hack and I don't quite like it, but we have lots of dependency cycles and run with `--DRT-oncycle=ignore`, so we sometimes need to influence the linking order. --- d/d.bzl | 40 ++++++++++++++++++++---- tests/circular_deps/BUILD | 32 ++++++++++++++++++- tests/circular_deps/circular_deps_test.d | 14 +++++++++ tests/circular_deps/lib_a.d | 10 +++++- tests/circular_deps/lib_b.d | 6 ++++ 5 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 tests/circular_deps/circular_deps_test.d diff --git a/d/d.bzl b/d/d.bzl index 3139d45..871d077 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -115,16 +115,39 @@ def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): [version_flag + "=%s" % v for v in depinfo.versions.to_list()] ) -def _build_link_arglist(ctx, objs, out, depinfo, c_compiler, link_flags): +def _sort_objects(objs, link_order): + """Sorts the objects in the order they need to be linked.""" + if not link_order: + return [o.path for o in objs] + return [ + obj.path for i, obj in sorted(enumerate(objs), key=lambda x: link_order.get(x[1].path, x[0])) + ] + +def _link_order_dict(objs, link_order): + """Builds a dictionary mapping object file paths to their link order index.""" + if not link_order: + return {} + size = len(objs) + link_order_dict = dict() + for k, v in link_order.items(): + idx = int(v) + if idx < 0: + idx = size - 1 - idx + for p in k.files.to_list(): + link_order_dict[p.path] = idx + return link_order_dict + +def _build_link_arglist(ctx, objs, out, depinfo, c_compiler, link_flags, link_order): """Returns a list of strings constituting the D link command arguments.""" + all_objs = objs + depset(transitive = [depinfo.libs, depinfo.transitive_libs]).to_list() + sorted_objs = _sort_objects(all_objs, _link_order_dict(all_objs, link_order)) return ( _compilation_mode_flags(ctx) + (["-gcc=%s" % c_compiler.files.to_list()[0].path] if c_compiler else []) + (link_flags or []) + ["-of" + out.path] + - [f.path for f in depset(transitive = [depinfo.libs, depinfo.transitive_libs]).to_list()] + depinfo.link_flags + - objs + sorted_objs ) def _setup_deps(ctx, deps, name): @@ -420,11 +443,12 @@ def _d_binary_impl_common(ctx, extra_flags = []): # Build link command link_args = _build_link_arglist( ctx = ctx, - objs = [d_obj.path] if d_obj else [], + objs = [d_obj] if d_obj else [], depinfo = depinfo, out = d_bin, c_compiler = toolchain.c_compiler, link_flags = toolchain.link_flags, + link_order = ctx.attr.link_order, ) link_inputs = depset( @@ -671,6 +695,10 @@ _d_library_attrs = { "exports": attr.label_list(allow_files = D_FILETYPE), } +_d_binary_attrs = { + "link_order": attr.label_keyed_string_dict(), +} + # _d_compile_attrs = { # "_d_compiler": attr.label( # default = Label("//d:dmd"), @@ -720,14 +748,14 @@ d_source_library = rule( d_binary = rule( _d_binary_impl, - attrs = dict(_d_common_attrs.items()), + attrs = dict(_d_common_attrs.items() + _d_binary_attrs.items()), executable = True, toolchains = [D_TOOLCHAIN], ) d_test = rule( _d_test_impl, - attrs = dict(_d_common_attrs.items()), + attrs = dict(_d_common_attrs.items() + _d_binary_attrs.items()), executable = True, test = True, toolchains = [D_TOOLCHAIN], diff --git a/tests/circular_deps/BUILD b/tests/circular_deps/BUILD index 886b595..06699e7 100644 --- a/tests/circular_deps/BUILD +++ b/tests/circular_deps/BUILD @@ -1,5 +1,5 @@ -load("//d:d.bzl", "d_lib") +load("//d:d.bzl", "d_lib", "d_test") d_lib( name = "lib_a", @@ -18,4 +18,34 @@ d_lib( deps = [ ":lib_a_exports", ], +) + +d_test( + name = "circular_deps_test", + srcs = ["circular_deps_test.d"], + link_order = { + ":lib_a": "-1", # lib_a must be linked last + }, + args = [ + "--DRT-oncycle=ignore", + ], + deps = [ + ":lib_a", + ":lib_b", + ], +) + +d_test( + name = "circular_deps_test2", + srcs = ["circular_deps_test.d"], + link_order = { + ":lib_a": "-1", # lib_a must be linked last + }, + args = [ + "--DRT-oncycle=ignore", + ], + deps = [ + ":lib_b", + ":lib_a", + ], ) \ No newline at end of file diff --git a/tests/circular_deps/circular_deps_test.d b/tests/circular_deps/circular_deps_test.d new file mode 100644 index 0000000..d65b9b5 --- /dev/null +++ b/tests/circular_deps/circular_deps_test.d @@ -0,0 +1,14 @@ +module tests.circular_deps.circular_deps_test; + +void main() {} + +unittest +{ + import tests.circular_deps.lib_a; + import tests.circular_deps.lib_b; + + assert(f(1) == 4); + assert(g(1) == 3); + assert(h(1) == 2); + assert(globalVar == 10); +} diff --git a/tests/circular_deps/lib_a.d b/tests/circular_deps/lib_a.d index 2c77335..fe8b554 100644 --- a/tests/circular_deps/lib_a.d +++ b/tests/circular_deps/lib_a.d @@ -2,10 +2,18 @@ module tests.circular_deps.lib_a; import tests.circular_deps.lib_b; +__gshared int globalVar = 2; + int f(int x) { return x + g(x); } int h(int x) { return x + 1; -} \ No newline at end of file +} + +shared static this() { + import std.stdio; + globalVar += 3; + writeln("lib_a initialized"); +} diff --git a/tests/circular_deps/lib_b.d b/tests/circular_deps/lib_b.d index e0db626..f51df99 100644 --- a/tests/circular_deps/lib_b.d +++ b/tests/circular_deps/lib_b.d @@ -5,3 +5,9 @@ import tests.circular_deps.lib_a; int g(int x) { return x + h(x); } + +shared static this() { + import std.stdio; + globalVar *= 2; + writeln("lib_b initialized"); +} From 0f5116ed48fd8ae1f4e7375c6d7455126ae8b6cb Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Tue, 1 Jul 2025 16:45:19 -0400 Subject: [PATCH 61/92] rules_d: remove repo_name from module definition --- MODULE.bazel | 1 - README.md | 18 +++++++++--------- tests/c_library_usage/BUILD | 2 +- tests/c_library_usage_no_wrapper/BUILD | 2 +- tests/d_library_usage/BUILD | 2 +- tests/directory_srcs/BUILD | 4 ++-- tests/fiber_thread_usage/BUILD | 2 +- tests/lib_that_depends_on_lib/BUILD | 2 +- tests/lib_that_depends_on_lib_test/BUILD | 2 +- tests/simple/BUILD | 2 +- tests/simple_as_binary/BUILD | 2 +- tests/simple_c_library/BUILD | 2 +- tests/simple_d_library/BUILD | 2 +- tests/simplest/BUILD | 2 +- 14 files changed, 22 insertions(+), 23 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 893a1a7..b63d86f 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,5 @@ module( name = "rules_d", - repo_name = "io_bazel_rules_d", ) bazel_dep( diff --git a/README.md b/README.md index 8d16a41..60dbd11 100644 --- a/README.md +++ b/README.md @@ -30,13 +30,13 @@ external repositories for the D toolchain: ```python load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( - name = "io_bazel_rules_d", + name = "rules_d", urls = ["https://github.com/bazelbuild/rules_d/archive/bcf137e3c9381545ce54715632bc1d31c51ee4da.tar.gz"], sha256 = "a32847bf2ae634563dece49c4dc8353956b64ba5c2d01ce811ea243e1a21b5b7", strip_prefix = "rules_d-bcf137e3c9381545ce54715632bc1d31c51ee4da", ) -load("@io_bazel_rules_d//d:repositories.bzl", "rules_d_toolchains") +load("@rules_d//d:repositories.bzl", "rules_d_toolchains") rules_d_toolchains() # rules_d_toolchains(ctype = "ldc") # If you want to use LDC instead of DMD ``` @@ -153,7 +153,7 @@ The library `foo` is built using a `d_library` target: `foo/BUILD`: ```python -load("@io_bazel_rules_d//d:d.bzl", "d_library") +load("@rules_d//d:d.bzl", "d_library") d_library( name = "foo", @@ -280,7 +280,7 @@ Build the C library using the `cc_library` rule and then use the `greeter/BUILD`: ```python -load("@io_bazel_rules_d//d:d.bzl", "d_source_library") +load("@rules_d//d:d.bzl", "d_source_library") cc_library( name = "native_greeter_lib", @@ -301,7 +301,7 @@ the C library: `hello_world/BUILD`: ```python -load("@io_bazel_rules_d//d:d.bzl", "d_source_library") +load("@rules_d//d:d.bzl", "d_source_library") d_binary( name = "hello_world", @@ -418,7 +418,7 @@ The `hello_lib` library is built using a `d_library` target: `hello_lib/BUILD`: ```python -load("@io_bazel_rules_d//d:d.bzl", "d_library") +load("@rules_d//d:d.bzl", "d_library") d_library( name = "hello_lib", @@ -442,7 +442,7 @@ The `hello_world` binary is built using a `d_binary` target: `hello_world/BUILD`: ```python -load("@io_bazel_rules_d//d:d.bzl", "d_library") +load("@rules_d//d:d.bzl", "d_library") d_binary( name = "hello_world", @@ -591,7 +591,7 @@ To build the library and unit test: `hello_lib/BUILD`: ```python -load("@io_bazel_rules_d//d:d.bzl", "d_library", "d_test") +load("@rules_d//d:d.bzl", "d_library", "d_test") d_library( name = "greeter", @@ -672,7 +672,7 @@ that takes the `d_library` `foo` as its dependency: `foo/BUILD`: ```python -load("@io_bazel_rules_d//d:d.bzl", "d_library", "d_docs") +load("@rules_d//d:d.bzl", "d_library", "d_docs") d_library( name = "foo", diff --git a/tests/c_library_usage/BUILD b/tests/c_library_usage/BUILD index caf85f0..06c0cc7 100644 --- a/tests/c_library_usage/BUILD +++ b/tests/c_library_usage/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_test") +load("@rules_d//d:d.bzl", "d_test") d_test( name = "c_library_usage", diff --git a/tests/c_library_usage_no_wrapper/BUILD b/tests/c_library_usage_no_wrapper/BUILD index 8e152f9..8552a7a 100644 --- a/tests/c_library_usage_no_wrapper/BUILD +++ b/tests/c_library_usage_no_wrapper/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_test") +load("@rules_d//d:d.bzl", "d_test") d_test( name = "c_library_usage_no_wrapper", diff --git a/tests/d_library_usage/BUILD b/tests/d_library_usage/BUILD index f668a20..a1a4d2f 100644 --- a/tests/d_library_usage/BUILD +++ b/tests/d_library_usage/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_test") +load("@rules_d//d:d.bzl", "d_test") d_test( name = "d_library_usage", diff --git a/tests/directory_srcs/BUILD b/tests/directory_srcs/BUILD index 9c440a5..8f3c810 100644 --- a/tests/directory_srcs/BUILD +++ b/tests/directory_srcs/BUILD @@ -1,5 +1,5 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_test") -load("@io_bazel_rules_d//tests/directory_srcs:directory_generator.bzl", "directory_generator") +load("@rules_d//d:d.bzl", "d_test") +load("@rules_d//tests/directory_srcs:directory_generator.bzl", "directory_generator") # Provides a single declared directory File as its output in Default Info, # containing a copy of all srcs. This is similar to capturing the output of the diff --git a/tests/fiber_thread_usage/BUILD b/tests/fiber_thread_usage/BUILD index 6836ce4..3380ce2 100644 --- a/tests/fiber_thread_usage/BUILD +++ b/tests/fiber_thread_usage/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_test") +load("@rules_d//d:d.bzl", "d_test") d_test( name = "fiber_thread_usage", diff --git a/tests/lib_that_depends_on_lib/BUILD b/tests/lib_that_depends_on_lib/BUILD index 3c09675..7e6f693 100644 --- a/tests/lib_that_depends_on_lib/BUILD +++ b/tests/lib_that_depends_on_lib/BUILD @@ -1,6 +1,6 @@ package(default_visibility = ["//visibility:public"]) -load("@io_bazel_rules_d//d:d.bzl", "d_library") +load("@rules_d//d:d.bzl", "d_library") d_library( name = "lib_that_depends_on_lib", diff --git a/tests/lib_that_depends_on_lib_test/BUILD b/tests/lib_that_depends_on_lib_test/BUILD index 2c8b87b..63982d4 100644 --- a/tests/lib_that_depends_on_lib_test/BUILD +++ b/tests/lib_that_depends_on_lib_test/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_test") +load("@rules_d//d:d.bzl", "d_test") d_test( name = "lib_that_depends_on_lib_test", diff --git a/tests/simple/BUILD b/tests/simple/BUILD index 429a644..1e672d6 100644 --- a/tests/simple/BUILD +++ b/tests/simple/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_test") +load("@rules_d//d:d.bzl", "d_test") d_test( name = "simple", diff --git a/tests/simple_as_binary/BUILD b/tests/simple_as_binary/BUILD index c1168c1..a9ce516 100644 --- a/tests/simple_as_binary/BUILD +++ b/tests/simple_as_binary/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_binary") +load("@rules_d//d:d.bzl", "d_binary") d_binary( name = "simple", diff --git a/tests/simple_c_library/BUILD b/tests/simple_c_library/BUILD index 278aedf..292bd77 100644 --- a/tests/simple_c_library/BUILD +++ b/tests/simple_c_library/BUILD @@ -1,6 +1,6 @@ package(default_visibility = ["//visibility:public"]) -load("@io_bazel_rules_d//d:d.bzl", "d_source_library") +load("@rules_d//d:d.bzl", "d_source_library") cc_library( name = "simple_c_library", diff --git a/tests/simple_d_library/BUILD b/tests/simple_d_library/BUILD index 59eb77a..1004b3a 100644 --- a/tests/simple_d_library/BUILD +++ b/tests/simple_d_library/BUILD @@ -1,6 +1,6 @@ package(default_visibility = ["//visibility:public"]) -load("@io_bazel_rules_d//d:d.bzl", "d_library") +load("@rules_d//d:d.bzl", "d_library") d_library( name = "simple_d_library", diff --git a/tests/simplest/BUILD b/tests/simplest/BUILD index 2f494b9..e489339 100644 --- a/tests/simplest/BUILD +++ b/tests/simplest/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_test") +load("@rules_d//d:d.bzl", "d_test") d_test( name = "simplest", From 7cbf409e57275cc6926cc83efe057d0d2a4d45e4 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 13 Jul 2025 05:29:48 -0400 Subject: [PATCH 62/92] weka-ldc: use 1.30.0-weka19 --- d/repositories.bzl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/d/repositories.bzl b/d/repositories.bzl index b2233b9..e8d79b1 100644 --- a/d/repositories.bzl +++ b/d/repositories.bzl @@ -79,13 +79,13 @@ def fetch_ldc(version = None): build_file = LDC_BUILD_FILE, ) -def fetch_weka_ldc(version = "1.30.0-weka19-pre"): +def fetch_weka_ldc(version = "1.30.0-weka19"): http_archive( name = "weka_ldc_linux_x86_64", urls = [ "https://github.com/weka/ldc/releases/download/v{version}/ldc2-{version}-linux-x86_64.tar.xz".format(version = version), ], - sha256 = "ce716c73dc2689da7bff9b7b5d414fae5b90b77bca5ab533e830dfffc9929199", + sha256 = "bf15208ae97e0ee68cd66d2d18327d808c0eabc47ae2e3e9d22d110f3aae569c", strip_prefix = "ldc2-{version}-linux-x86_64".format(version = version), build_file = LDC_BUILD_FILE, ) @@ -100,7 +100,7 @@ def rules_d_toolchains(ctype = "dmd", version = None): fetch_dmd() fetch_ldc(version = version) fetch_weka_ldc() - + elif ctype == "weka-ldc": # Special case for Weka LDC, which is a fork of LDC fetch_weka_ldc(version = version) From 4ef8cdfd662348180416f7c39dd5874dc9c2f666 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 13 Jul 2025 06:08:56 -0400 Subject: [PATCH 63/92] d_library/d_lib: add implementation_deps Similarly how `cc_library` has it, see [1]. The idea is sometimes your dependency is a pure implementation details and should be completely opaque to your users. So if `lib_a` imports `lib_b` and `lib_b` imports `lib_c` but from the non-exported part **only**, no change to `lib_c` should cause rebuilds in `lib_a`. But with normal `deps` with collect exported files _transitively_, so a change to the exported part of `lib_c` **will** cause a rebuild of `lib_a`. `implementation_deps` allows to avoid it. [1]: https://bazel.build/reference/be/c-cpp#cc_library.implementation_deps --- d/d.bzl | 42 ++++++++++++++++++++++++-------- tests/implementation_deps/BUILD | 17 +++++++++++++ tests/implementation_deps/liba.d | 6 +++++ tests/implementation_deps/libb.d | 7 ++++++ 4 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 tests/implementation_deps/BUILD create mode 100644 tests/implementation_deps/liba.d create mode 100644 tests/implementation_deps/libb.d diff --git a/d/d.bzl b/d/d.bzl index 871d077..abb09fb 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -150,7 +150,7 @@ def _build_link_arglist(ctx, objs, out, depinfo, c_compiler, link_flags, link_or sorted_objs ) -def _setup_deps(ctx, deps, name): +def _setup_deps(ctx, deps, impl_deps, name): """Sets up dependencies. Walks through dependencies and constructs the commands and flags needed @@ -159,6 +159,7 @@ def _setup_deps(ctx, deps, name): Args: ctx: The context of the current target. deps: List of deps labels from ctx.attr.deps. + impl_deps: List of deps labels from ctx.attr.implementation_deps. name: Name of the current target. Returns: @@ -241,6 +242,20 @@ def _setup_deps(ctx, deps, name): fail("D targets can only depend on d_library, d_source_library, or " + "cc_library targets.", dep) + impl_srcs = [] + for dep in impl_deps: + if DInfo in dep and hasattr(dep[DInfo], "d_lib"): + ddep = dep[DInfo] + libs.append(ddep.d_lib) + transitive_libs.append(ddep.transitive_libs) + impl_srcs.extend(ddep.d_exports) + elif CcInfo in dep: + native_libs = a_filetype(ctx, _get_libs_for_static_executable(dep)) + libs.extend(native_libs) + transitive_libs.append(depset(native_libs)) + else: + fail("Implementation dependencies can only depend on d_library or cc_library targets.", dep) + return struct( libs = depset(libs), transitive_libs = depset(transitive = transitive_libs), @@ -252,6 +267,7 @@ def _setup_deps(ctx, deps, name): string_imports = depset(string_imports).to_list(), link_flags = depset(link_flags).to_list(), generated_srcs = generated_srcs, + impl_srcs = impl_srcs, ) def _handle_generated_srcs(ctx, generated_srcs, d_compiler): @@ -267,7 +283,7 @@ def _handle_generated_srcs(ctx, generated_srcs, d_compiler): [ "#!/bin/sh", "set -e", - ] + + ] + [ "mkdir -p $(dirname %s)\n" % loc + "ln -s $PWD/%s %s" % (src.path, loc) for src, loc in generated_srcs.items() @@ -286,7 +302,7 @@ def _d_library_impl_common(ctx, extra_flags = []): # Dependencies deps = ctx.attr.deps + ([toolchain.libphobos] if toolchain.libphobos != None else []) + ([toolchain.druntime] if toolchain.druntime != None else []) - depinfo = _setup_deps(ctx, ctx.attr.deps, ctx.label.name) + depinfo = _setup_deps(ctx, ctx.attr.deps, ctx.attr.implementation_deps, ctx.label.name) public_srcs = ctx.files.hdrs + ctx.files.exports if not public_srcs: @@ -314,7 +330,7 @@ def _d_library_impl_common(ctx, extra_flags = []): generated_srcs = depinfo.generated_srcs, ), ] - + #d_lib = ctx.actions.declare_file((ctx.label.name + ".lib") if _is_windows(ctx) else ("lib" + ctx.label.name + ".a")) d_lib = ctx.actions.declare_file(ctx.label.name + ".o") @@ -345,7 +361,8 @@ def _d_library_impl_common(ctx, extra_flags = []): ctx.files.hdrs + ctx.files.exports + ctx.files.data + - depinfo.data, + depinfo.data + + depinfo.impl_srcs, transitive = [ depinfo.transitive_d_srcs, depinfo.transitive_data, @@ -396,7 +413,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): # Dependencies deps = ctx.attr.deps + ([toolchain.libphobos] if toolchain.libphobos != None else []) + ([toolchain.druntime] if toolchain.druntime != None else []) - depinfo = _setup_deps(ctx, deps, ctx.label.name) + depinfo = _setup_deps(ctx, deps, [], ctx.label.name) d_obj = None toolchain_files = [ @@ -646,16 +663,16 @@ def _d_header_generator_impl(ctx): toolchain = ctx.toolchains[D_TOOLCHAIN] if not toolchain.hdrgen_flags: fail("d_header_generator requires a toolchain with hdrgen_flags set.") - + d_compiler = toolchain.d_compiler.files.to_list()[0] infile = ctx.file.src if not infile: fail("d_header_generator requires a single source file.") - + if not infile.path.endswith(".d"): fail("d_header_generator only supports .d files, got: %s" % infile.path) - + header = ctx.actions.declare_file(ctx.label.name + ".di") ctx.actions.run( @@ -693,6 +710,7 @@ _d_common_attrs = { _d_library_attrs = { "hdrs": attr.label_list(allow_files = D_FILETYPE, allow_empty = True), "exports": attr.label_list(allow_files = D_FILETYPE), + "implementation_deps": attr.label_list(), } _d_binary_attrs = { @@ -786,6 +804,7 @@ def d_lib( exports = [], exports_no_hdrs = [], deps = [], + implementation_deps = [], include_workspace_root = True, is_generated = False, generated_srcs = {}, @@ -813,6 +832,7 @@ def d_lib( exports: List of D source files to export, which will have headers generated for them. exports_no_hdrs: List of D source files to export without generating headers. deps: List of dependencies for this library. + implementation_deps: List of implementation dependencies for this library. include_workspace_root: Whether to include the workspace root in import paths. is_generated: Whether this library is generated (used for generated sources). generated_srcs: A dictionary mapping generated source files to their desired locations. @@ -841,7 +861,7 @@ def d_lib( exports_hdrs.append(hdr) di_name = target[:-2] + ".di" # Replace .d with .di new_generated_srcs[hdr] = di_name - + if not test: d_library( name = name, @@ -854,6 +874,7 @@ def d_lib( hdrs = hdrs + exports_hdrs, exports = exports_no_hdrs, deps = deps, + implementation_deps = implementation_deps, include_workspace_root = include_workspace_root, is_generated = is_generated, generated_srcs = new_generated_srcs, @@ -871,6 +892,7 @@ def d_lib( hdrs = hdrs + exports_hdrs, exports = exports_no_hdrs, deps = deps, + implementation_deps = implementation_deps, include_workspace_root = include_workspace_root, is_generated = is_generated, generated_srcs = new_generated_srcs, diff --git a/tests/implementation_deps/BUILD b/tests/implementation_deps/BUILD new file mode 100644 index 0000000..0fded26 --- /dev/null +++ b/tests/implementation_deps/BUILD @@ -0,0 +1,17 @@ +load("//d:d.bzl", "d_lib") + +d_lib( + name = "liba", + srcs = ["liba.d"], + implementation_deps = [ + "//tests/simple_d_library", + ], +) + +d_lib( + name = "libb", + srcs = ["libb.d"], + deps = [ + ":liba", + ], +) \ No newline at end of file diff --git a/tests/implementation_deps/liba.d b/tests/implementation_deps/liba.d new file mode 100644 index 0000000..40dbfc0 --- /dev/null +++ b/tests/implementation_deps/liba.d @@ -0,0 +1,6 @@ +module tests.implementation_deps.liba; + +int public_func(int x) { + import tests.simple_d_library.simple_library; + return plusOne(x); +} \ No newline at end of file diff --git a/tests/implementation_deps/libb.d b/tests/implementation_deps/libb.d new file mode 100644 index 0000000..056b0d1 --- /dev/null +++ b/tests/implementation_deps/libb.d @@ -0,0 +1,7 @@ +module tests.implementation_deps.libb; + +import tests.implementation_deps.liba; + +int libb_func(int x) { + return public_func(x); +} \ No newline at end of file From 6b120d9d1a973b3486a0eb43210c49c7c6323c83 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Tue, 15 Jul 2025 10:47:14 -0400 Subject: [PATCH 64/92] d_lib: check if exportslib works with generated sources it does not --- tests/circular_deps_with_gensrcs/BUILD | 61 +++++++++++++++++++ .../circular_deps_test.d | 14 +++++ tests/circular_deps_with_gensrcs/lib_a.d | 19 ++++++ tests/circular_deps_with_gensrcs/lib_b.d | 13 ++++ 4 files changed, 107 insertions(+) create mode 100644 tests/circular_deps_with_gensrcs/BUILD create mode 100644 tests/circular_deps_with_gensrcs/circular_deps_test.d create mode 100644 tests/circular_deps_with_gensrcs/lib_a.d create mode 100644 tests/circular_deps_with_gensrcs/lib_b.d diff --git a/tests/circular_deps_with_gensrcs/BUILD b/tests/circular_deps_with_gensrcs/BUILD new file mode 100644 index 0000000..0d17abe --- /dev/null +++ b/tests/circular_deps_with_gensrcs/BUILD @@ -0,0 +1,61 @@ + +load("//d:d.bzl", "d_lib", "d_test") + +genrule( + name = "lib_a_preprocess", + srcs = ["lib_a.d"], + outs = ["lib_a_preprocessed.d"], + cmd = "cp $< $@", +) + +d_lib( + name = "lib_a", + srcs = ["lib_a_preprocessed.d"], + exports = ["lib_a_preprocessed.d"], + exports_lib = "lib_a_exports", + generated_srcs = { + "lib_a_preprocessed.d": "lib_a.d", + }, + deps = [ + ":lib_b", + ], +) + +d_lib( + name = "lib_b", + srcs = ["lib_b.d"], + exports = ["lib_b.d"], + deps = [ + ":lib_a_exports", + ], +) + +d_test( + name = "circular_deps_test", + srcs = ["circular_deps_test.d"], + link_order = { + ":lib_a": "-1", # lib_a must be linked last + }, + args = [ + "--DRT-oncycle=ignore", + ], + deps = [ + ":lib_a", + ":lib_b", + ], +) + +d_test( + name = "circular_deps_test2", + srcs = ["circular_deps_test.d"], + link_order = { + ":lib_a": "-1", # lib_a must be linked last + }, + args = [ + "--DRT-oncycle=ignore", + ], + deps = [ + ":lib_b", + ":lib_a", + ], +) \ No newline at end of file diff --git a/tests/circular_deps_with_gensrcs/circular_deps_test.d b/tests/circular_deps_with_gensrcs/circular_deps_test.d new file mode 100644 index 0000000..f05e47a --- /dev/null +++ b/tests/circular_deps_with_gensrcs/circular_deps_test.d @@ -0,0 +1,14 @@ +module tests.circular_deps_with_gensrcs.circular_deps_test; + +void main() {} + +unittest +{ + import tests.circular_deps_with_gensrcs.lib_a; + import tests.circular_deps_with_gensrcs.lib_b; + + assert(f(1) == 4); + assert(g(1) == 3); + assert(h(1) == 2); + assert(globalVar == 10); +} diff --git a/tests/circular_deps_with_gensrcs/lib_a.d b/tests/circular_deps_with_gensrcs/lib_a.d new file mode 100644 index 0000000..c5b8a38 --- /dev/null +++ b/tests/circular_deps_with_gensrcs/lib_a.d @@ -0,0 +1,19 @@ +module tests.circular_deps_with_gensrcs.lib_a; + +import tests.circular_deps_with_gensrcs.lib_b; + +__gshared int globalVar = 2; + +int f(int x) { + return x + g(x); +} + +int h(int x) { + return x + 1; +} + +shared static this() { + import std.stdio; + globalVar += 3; + writeln("lib_a initialized"); +} diff --git a/tests/circular_deps_with_gensrcs/lib_b.d b/tests/circular_deps_with_gensrcs/lib_b.d new file mode 100644 index 0000000..8074e69 --- /dev/null +++ b/tests/circular_deps_with_gensrcs/lib_b.d @@ -0,0 +1,13 @@ +module tests.circular_deps_with_gensrcs.lib_b; + +import tests.circular_deps_with_gensrcs.lib_a; + +int g(int x) { + return x + h(x); +} + +shared static this() { + import std.stdio; + globalVar *= 2; + writeln("lib_b initialized"); +} From 749d91814168a1a038f784c3685d88b7850802aa Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 16 Jul 2025 05:40:27 -0400 Subject: [PATCH 65/92] d_library: generated source wrapper don't create broken symlinks. TODO: filter generated_sources dictionary and add validation --- d/d.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/d/d.bzl b/d/d.bzl index abb09fb..51e4e29 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -286,7 +286,7 @@ def _handle_generated_srcs(ctx, generated_srcs, d_compiler): ] + [ "mkdir -p $(dirname %s)\n" % loc + - "ln -s $PWD/%s %s" % (src.path, loc) for src, loc in generated_srcs.items() + "[ -f $PWD/%s ] && ln -s $PWD/%s %s" % (src.path, src.path, loc) for src, loc in generated_srcs.items() ] + [ "%s $*" % d_compiler.path, ]), From 0445c2b6f53c6d4ab7c8ae00498c3808a9a7c160 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 16 Jul 2025 05:41:50 -0400 Subject: [PATCH 66/92] d_library: allow files in generated_srcs --- d/d.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/d/d.bzl b/d/d.bzl index 51e4e29..05ca594 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -703,7 +703,7 @@ _d_common_attrs = { "versions": attr.string_list(), "include_workspace_root": attr.bool(default = True), "is_generated": attr.bool(default = False), - "generated_srcs": attr.label_keyed_string_dict(), + "generated_srcs": attr.label_keyed_string_dict(allow_files = True), "deps": attr.label_list(), } From be134209e1d4c64e9ca15646e7fbe18dade79030 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sat, 16 Aug 2025 09:23:47 -0400 Subject: [PATCH 67/92] generated_srcs: try handling sources in other packages --- d/d.bzl | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/d/d.bzl b/d/d.bzl index 05ca594..b22d681 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -150,6 +150,15 @@ def _build_link_arglist(ctx, objs, out, depinfo, c_compiler, link_flags, link_or sorted_objs ) +def _find_gensrc_location(loc, src): + if loc.startswith("@"): + fail("Cannot place the generated source %s into location %s" % ( + src, loc)) + if loc.startswith("//"): + label = Label(loc) + return label.package + "/" + label.name + return src.label.package + "/" + loc + def _setup_deps(ctx, deps, impl_deps, name): """Sets up dependencies. @@ -195,7 +204,7 @@ def _setup_deps(ctx, deps, impl_deps, name): string_imports = [_build_import(ctx.label, im, gen_dir_for_imports) for im in ctx.attr.string_imports] link_flags = [] generated_srcs = { - src.files.to_list()[0]: src.label.package + "/" + loc for src, loc in ctx.attr.generated_srcs.items()} + src.files.to_list()[0]: _find_gensrc_location(loc, src) for src, loc in ctx.attr.generated_srcs.items()} for dep in deps: if DInfo in dep and hasattr(dep[DInfo], "d_lib"): # The dependency is a d_library. From d65184c835c3a4848b0beb2b4169b5d917ebb28e Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Fri, 12 Sep 2025 16:47:36 +0200 Subject: [PATCH 68/92] start new README --- README.md | 696 +----------------------------------------------------- 1 file changed, 3 insertions(+), 693 deletions(-) diff --git a/README.md b/README.md index 60dbd11..3983106 100644 --- a/README.md +++ b/README.md @@ -1,695 +1,5 @@ -[![Build status](https://badge.buildkite.com/255dd622ff5647b60b08b6578e49df80f78c9b0d88f2758491.svg)](https://buildkite.com/bazel/rules-d) +# A very opinionated fork of https://github.com/bazel-contrib/rules_d -# D rules +## Differences with `bazel-contrib/rules_d` -## Status - -We make sure this repository works with the latest version of Bazel, but no -other development is planned. - -Volunteers are welcome. If you want to use the rules, consider contributing to -this repository and becoming a maintainer. - -## Rules - - - -## Setup - -To use the D rules, add the following to your `WORKSPACE` file to add the -external repositories for the D toolchain: - -```python -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -http_archive( - name = "rules_d", - urls = ["https://github.com/bazelbuild/rules_d/archive/bcf137e3c9381545ce54715632bc1d31c51ee4da.tar.gz"], - sha256 = "a32847bf2ae634563dece49c4dc8353956b64ba5c2d01ce811ea243e1a21b5b7", - strip_prefix = "rules_d-bcf137e3c9381545ce54715632bc1d31c51ee4da", -) - -load("@rules_d//d:repositories.bzl", "rules_d_toolchains") -rules_d_toolchains() -# rules_d_toolchains(ctype = "ldc") # If you want to use LDC instead of DMD -``` - -## Roadmap - -* Generate documentation using [`ddox`](https://github.com/rejectedsoftware/ddox) - for `d_docs` rule. -* Support for other options as defined in the [Dub package - format](http://code.dlang.org/package-format?lang=json) -* Support for specifying different configurations of a library, closer to - [Dub's model for configurations](http://code.dlang.org/package-format?lang=json#configurations) -* Workspace rule for retrieving dependencies from [Dub](http://code.dlang.org/) - - -## d_library - -```python -d_library(name, srcs, deps, includes, linkopts, versions) -``` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Attributes
name - Name, required -

A unique name for this rule.

-

- This name will be used as the name of the library built by this rule. -

-
srcs - List of labels, required -

List of D .d source files used to build the library.

-
deps - List of labels, optional -

List of libraries to be linked to this library target.

-

- These can either be other d_library targets, - source-only d_source_library targets, or - cc_library targets if linking a native library. -

-
imports - List of strings, optional -

List of import dirs to add to the compile line.

-

- These will be passed to the D compiler via -I flags. -

-
linkopts - List of strings, optional -

List of flags that are added to the D linker command.

-

- These will be passed to the D compiler via -L flags. -

-
versions - List of strings, optional -

List of versions to be defined during compilation.

-

- Versions are used for conditional compilation and are enabled in the - code using version condition blocks. These versions - listed here will be passed to the D compiler using - -version flags. -

-
- -### Example - -Suppose you have the following directory structure for a D project: - -``` -[workspace]/ - WORKSPACE - foo/ - BUILD - foo.d - bar.d - baz.d -``` - -The library `foo` is built using a `d_library` target: - -`foo/BUILD`: - -```python -load("@rules_d//d:d.bzl", "d_library") - -d_library( - name = "foo", - srcs = [ - "foo.d", - "bar.d", - "baz.d", - ], -) -``` - - -## d_source_library - -```python -d_source_library(name, srcs, deps, includes, linkopts, versions) -``` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Attributes
name - Name, required -

A unique name for this rule.

-
srcs - List of labels, required -

- List of D .d source files that comprises this source - library target. -

-
deps - List of labels, optional -

List of library targets depended on by this target.

-

- These can either be other d_source_library targets or - cc_library targets, such as when this source library - target implements the D interface for a native library. Any native - libraries will be linked by d_library targets that - depend on this target. -

-
imports - List of strings, optional -

List of import dirs to add to the compile line.

-

- These will be passed to the D compiler via -I flags for - any d_library targets that depend on this target. -

-
linkopts - List of strings, optional -

List of flags that are added to the D linker command.

-

- These will be passed to the D compiler via -L flags for - any d_library targets that depend on this target. -

-
versions - List of strings, optional -

List of version flags to be defined during compilation.

-

- Versions are used for conditional compilation and are enabled in the - code using version condition blocks. These versions - listed here will be passed to the D compiler using - -version flags for any d_library targets - that depend on this target. -

-
- -### Example - -Suppose you have the following directory structure for a project building a -C library and a [D interface](http://dlang.org/interfaceToC.html) for the C -library: - -``` -[workspace]/ - WORKSPACE - greeter/ - BUILD - native_greeter.c - native_greeter.h - native_greeter.d - hello_world - BUILD - hello_world.d -``` - -Build the C library using the `cc_library` rule and then use the -`d_source_library` to define the target for the D interface for the C -`native_greeter` library: - -`greeter/BUILD`: - -```python -load("@rules_d//d:d.bzl", "d_source_library") - -cc_library( - name = "native_greeter_lib", - srcs = ["native_greeter.c"], - hdrs = ["native_greeter.h"], -) - -d_source_library( - name = "native_greeter", - srcs = ["native_greeter.d"], - deps = [":native_greeter_lib"], -) -``` - -Other targets can directly depend on the `d_source_library` target to link -the C library: - -`hello_world/BUILD`: - -```python -load("@rules_d//d:d.bzl", "d_source_library") - -d_binary( - name = "hello_world", - srcs = ["hello_world.d"], - deps = ["//greeter:native_greeter"], -) -``` - - -## d_binary - -```python -d_binary(name, srcs, deps, includes, linkopts, versions) -``` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Attributes
name - Name, required -

A unique name for this rule.

-

- This name will be used as the name of the binary built by this rule. -

-
srcs - List of labels, required -

List of D .d source files used to build the binary.

-
deps - List of labels, optional -

List of libraries to be linked to this binary target.

-

- These can either be other d_library targets, - source-only d_source_library targets, or - cc_library targets if linking a native library. -

-
imports - List of strings, optional -

List of import dirs to add to the compile line.

-

- These will be passed to the D compiler via -I flags. -

-
linkopts - List of strings, optional -

List of flags that are added to the D linker command.

-

- These will be passed to the D compiler via -L flags. -

-
versions - List of strings, optional -

List of versions to be defined during compilation.

-

- Versions are used for conditional compilation and are enabled in the - code using version condition blocks. These versions - listed here will be passed to the D compiler using - -version flags. -

-
- -Suppose you have the following directory structure for a D project: - -``` -[workspace]/ - WORKSPACE - hello_lib/ - BUILD - greeter.d - hello_world - BUILD - hello_world.d -``` - -The source file `hello_lib/greeter.d` defines a module `greeter`: - -```d -module greeter; -... -``` - -The `hello_lib` library is built using a `d_library` target: - -`hello_lib/BUILD`: - -```python -load("@rules_d//d:d.bzl", "d_library") - -d_library( - name = "hello_lib", - srcs = ["greeter.d"], -) -``` - -By default, import paths are from the root of the workspace. Thus, the source -for the `hello_world` binary, `hello_world.d`, would import the `greeter` -module as follows: - -```d -import hello_lib.greeter; -``` - -However, this can be changed via the `imports` attribute on the `d_library` -rule. - -The `hello_world` binary is built using a `d_binary` target: - -`hello_world/BUILD`: - -```python -load("@rules_d//d:d.bzl", "d_library") - -d_binary( - name = "hello_world", - srcs = ["hello_world.d"], - deps = ["//hello_lib"], -) -``` - - -## d_test - -```python -d_test(name, srcs, deps, includes, linkopts, versions) -``` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Attributes
name - Name, required -

A unique name for this rule.

-

- This name will be used as the name of the test built by this rule. -

-
srcs - List of labels, required -

List of D .d source files used to build the test.

-
deps - List of labels, optional -

List of libraries to be linked to this test target.

-

- These can either be other d_library targets, - source-only d_source_library targets, or - cc_library targets if linking a native library. -

-
imports - List of strings, optional -

List of import dirs to add to the compile line.

-

- These will be passed to the D compiler via -I flags. -

-
linkopts - List of strings, optional -

List of flags that are added to the D linker command.

-

- These will be passed to the D compiler via -L flags. -

-
versions - List of strings, optional -

List of versions to be defined during compilation.

-

- Versions are used for conditional compilation and are enabled in the - code using version condition blocks. These versions - listed here will be passed to the D compiler using - -version flags. -

-
- -### Example - -Suppose you have the following directory structure for a D project: - -``` -[workspace]/ - WORKSPACE - hello_lib/ - BUILD - greeter.d - greeter_test.d -``` - -`hello_lib/greeter.d`: - -```d -module greeter; - -import std.stdio; -import std.string; - -class Greeter { - private string greeting; - - public: - this(in string greeting) { - this.greeting = greeting.dup; - } - - string makeGreeting(in immutable string thing) { - return format("%s %s!", this.greeting, thing); - } - - void greet(in immutable string thing) { - writeln(makeGreeting(thing)); - } -} -``` - -`hello_lib/greeter_test.d`: - -```d -import hello_lib.greeter; - -unittest { - auto greeter = new Greeter("Hello"); - assert(greeter.makeGreeting("world") == "Hello world!"); -} - -void main() {} -``` - -To build the library and unit test: - -`hello_lib/BUILD`: - -```python -load("@rules_d//d:d.bzl", "d_library", "d_test") - -d_library( - name = "greeter", - srcs = ["greeter.d"], -) - -d_test( - name = "greeter_test", - srcs = ["greeter_test.d"], - deps = [":greeter"], -) -``` - -The unit test can then be run using: - -```sh -bazel test //hello_lib:greeter_test -``` - - -## d_docs - -```python -d_docs(name, dep) -``` - - - - - - - - - - - - - - - - - - - - - -
Attributes
name - Name, required -

A unique name for this rule.

-
dep - Label, required -

The label of the target to generate code documentation for.

-

- d_docs can generate HTML code documentation for the - source files of d_library, d_source_library, - d_binary, or d_test targets. -

-
- -### Example - -Suppose you have the following directory structure for a D project: - -``` -[workspace]/ - WORKSPACE - foo/ - BUILD - foo.d - bar.d - baz.d -``` - -The `foo/` directory contains the sources for the `d_library` `foo`. To -generate HTML documentation for the `foo` library, define a `d_docs` target -that takes the `d_library` `foo` as its dependency: - -`foo/BUILD`: - -```python -load("@rules_d//d:d.bzl", "d_library", "d_docs") - -d_library( - name = "foo", - srcs = [ - "foo.d", - "bar.d", - "baz.d", - ], -) - -d_docs( - name = "foo_docs", - dep = ":foo", -) -``` - -Running `bazel build //foo:foo_docs` will generate a zip file containing the -HTML documentation generated from the source files. See the official D language -documentation on the [Documentation Generator](http://dlang.org/ddoc.html) for -more information on the conventions for source documentation. +1. TBD From ace42bf6fc42419de645bf6a55b91b91feb71f6d Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 15 Oct 2025 17:28:51 +0200 Subject: [PATCH 69/92] config: add DToolchainConfigInfo provider not used so far --- d/config.bzl | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 d/config.bzl diff --git a/d/config.bzl b/d/config.bzl new file mode 100644 index 0000000..e35da95 --- /dev/null +++ b/d/config.bzl @@ -0,0 +1,29 @@ +""" +Configuration information for the D toolchain. +""" + +DToolchainConfigInfo = provider( + doc = "Configuration information for the D toolchain.", + fields = [ + # binaries + "d_compiler", + "c_compiler", + # libraries + "libphobos", + "libphobos_src", + "druntime", + "druntime_src", + # flags that can differ for different toolchains + "lib_flags", + "import_flags", # unused + "version_flag", + "hdrgen_flags", + # compilation modes + "copts_per_mode", + "copts_common", + "linkopts_per_mode", + "linkopts_common", + "global_versions_per_mode", + "global_versions_common", + ], +) From 174fc1a1de0c025ea460a3c121537a71cc5f1afc Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 15 Oct 2025 17:34:03 +0200 Subject: [PATCH 70/92] d_toolchain: fix the d_compiler config --- d/toolchain.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/d/toolchain.bzl b/d/toolchain.bzl index bce2810..e192691 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -50,7 +50,7 @@ d_toolchain = rule( "d_compiler": attr.label( executable = True, # allow_files = True, - cfg = "host", + cfg = "exec", ), "c_compiler": attr.label( executable = True, From 89927ae4ae8b5e7c2954bb6ba8931746006bbc03 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Fri, 17 Oct 2025 08:25:48 -0400 Subject: [PATCH 71/92] Add common flags shared by all compilation modes --- d/d.bzl | 9 +++++++-- d/toolchain.bzl | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index b22d681..a525392 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -62,8 +62,8 @@ def _default_compilation_mode_flags(ctx): else: return DEFAULT_COMPILATION_MODE_FLAGS_POSIX[ctx.var["COMPILATION_MODE"]] -def _compilation_mode_flags(ctx): - """Returns a list of flags based on the compilation_mode.""" +def _compilation_mode_flags_helper(ctx): + """Helper function to return the flags for the compilation mode.""" toolchain = ctx.toolchains[D_TOOLCHAIN] compilation_mode = ctx.var["COMPILATION_MODE"] default_flags = _default_compilation_mode_flags(ctx) @@ -76,6 +76,11 @@ def _compilation_mode_flags(ctx): else: fail("Invalid compilation mode: %s" % compilation_mode) +def _compilation_mode_flags(ctx): + """Returns a list of flags based on the compilation mode.""" + toolchain = ctx.toolchains[D_TOOLCHAIN] + return (toolchain.common_flags or []) + _compilation_mode_flags_helper(ctx) + def _format_version(name): """Formats the string name to be used in a --version flag.""" return name.replace("-", "_") diff --git a/d/toolchain.bzl b/d/toolchain.bzl index e192691..2356163 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -37,6 +37,7 @@ def _d_toolchain_impl(ctx): druntime = ctx.attr.druntime, druntime_src = ctx.attr.druntime_src, version_flag = ctx.attr.version_flag, + common_flags = ctx.attr.common_flags, fastbuild_flags = ctx.attr.fastbuild_flags, dbg_flags = ctx.attr.dbg_flags, opt_flags = ctx.attr.opt_flags, @@ -69,6 +70,7 @@ d_toolchain = rule( "druntime": attr.label(), "druntime_src": attr.label(), "version_flag": attr.string(), + "common_flags": attr.string_list(), "fastbuild_flags": attr.string_list(), "dbg_flags": attr.string_list(), "opt_flags": attr.string_list(), From 9a68219782d4852b6f6448149f6f6ad8b4b7e438 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Fri, 17 Oct 2025 08:41:43 -0400 Subject: [PATCH 72/92] Support passing config by label --- d/toolchain.bzl | 70 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/d/toolchain.bzl b/d/toolchain.bzl index 2356163..a0ce656 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -1,4 +1,5 @@ load("@bazel_skylib//rules:common_settings.bzl", "string_setting") +load("//d:config.bzl", "DToolchainConfigInfo") D_TOOLCHAIN = "//d:toolchain_type" @@ -25,24 +26,54 @@ D_TOOLCHAIN = "//d:toolchain_type" # ) def _d_toolchain_impl(ctx): - toolchain_info = platform_common.ToolchainInfo( - name = ctx.label.name, - d_compiler = ctx.attr.d_compiler, - c_compiler = ctx.attr.c_compiler, - lib_flags = ctx.attr.lib_flags, - link_flags = ctx.attr.link_flags, - import_flags = ctx.attr.import_flags, - libphobos = ctx.attr.libphobos, - libphobos_src = ctx.attr.libphobos_src, - druntime = ctx.attr.druntime, - druntime_src = ctx.attr.druntime_src, - version_flag = ctx.attr.version_flag, - common_flags = ctx.attr.common_flags, - fastbuild_flags = ctx.attr.fastbuild_flags, - dbg_flags = ctx.attr.dbg_flags, - opt_flags = ctx.attr.opt_flags, - hdrgen_flags = ctx.attr.hdrgen_flags, - ) + config = ctx.attr.config[DToolchainConfigInfo] if ctx.attr.config else None + if config == None: + # TODO: deprecate this + toolchain_info = platform_common.ToolchainInfo( + name = ctx.label.name, + d_compiler = ctx.attr.d_compiler, + c_compiler = ctx.attr.c_compiler, + lib_flags = ctx.attr.lib_flags, + link_flags = ctx.attr.link_flags, + import_flags = ctx.attr.import_flags, + libphobos = ctx.attr.libphobos, + libphobos_src = ctx.attr.libphobos_src, + druntime = ctx.attr.druntime, + druntime_src = ctx.attr.druntime_src, + version_flag = ctx.attr.version_flag, + common_flags = ctx.attr.common_flags, + fastbuild_flags = ctx.attr.fastbuild_flags, + dbg_flags = ctx.attr.dbg_flags, + opt_flags = ctx.attr.opt_flags, + hdrgen_flags = ctx.attr.hdrgen_flags, + global_versions_common = [], + global_versions_per_mode = { + "fastbuild": [], + "dbg": [], + "opt": [], + }, + ) + else: + toolchain_info = platform_common.ToolchainInfo( + name = ctx.attr.name, + d_compiler = config.d_compiler or ctx.attr.d_compiler, + c_compiler = config.c_compiler or ctx.attr.c_compiler, + lib_flags = config.lib_flags or ctx.attr.lib_flags, + link_flags = (config.linkopts_common + config.linkopts_per_mode[ctx.var["COMPILATION_MODE"]]) or ctx.attr.link_flags, + import_flags = config.import_flags or ctx.attr.import_flags, + libphobos = config.libphobos or ctx.attr.libphobos, + libphobos_src = config.libphobos_src or ctx.attr.libphobos_src, + druntime = config.druntime or ctx.attr.druntime, + druntime_src = config.druntime_src or ctx.attr.druntime_src, + version_flag = config.version_flag or ctx.attr.version_flag, + common_flags = config.common_flags or ctx.attr.common_flags, + fastbuild_flags = config.copts_per_mode["fastbuild"] or ctx.attr.fastbuild_flags, + dbg_flags = config.copts_per_mode["dbg"] or ctx.attr.dbg_flags, + opt_flags = config.copts_per_mode["opt"] or ctx.attr.opt_flags, + hdrgen_flags = config.hdrgen_flags, + global_versions_common = config.global_versions_common, + global_versions_per_mode = config.global_versions_per_mode, + ) return [toolchain_info] d_toolchain = rule( @@ -75,5 +106,8 @@ d_toolchain = rule( "dbg_flags": attr.string_list(), "opt_flags": attr.string_list(), "hdrgen_flags": attr.string_list(), + "config": attr.label( + providers = [DToolchainConfigInfo], + ), }, ) From aa8c9de5ebcbc85587cfdc8dbc6c778fb4ae23a2 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Fri, 17 Oct 2025 08:49:41 -0400 Subject: [PATCH 73/92] Actually pass global_versions to compile --- d/d.bzl | 6 +++++- d/toolchain.bzl | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index a525392..5053826 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -107,6 +107,10 @@ def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): gen_dir = ctx.genfiles_dir.path if ctx.attr.is_generated else None ws_root = gen_dir if ctx.attr.is_generated else "." + + versions = depset( + toolchain.global_versions_common + toolchain.global_versions_per_mode[ctx.var["COMPILATION_MODE"]], + transitive = [depinfo.versions]) return ( _compilation_mode_flags(ctx) + extra_flags + [ @@ -117,7 +121,7 @@ def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): ["-I%s" % im for im in depinfo.imports] + ["-J%s" % im for im in depinfo.string_imports] + # toolchain.import_flags + - [version_flag + "=%s" % v for v in depinfo.versions.to_list()] + [version_flag + "=%s" % v for v in versions.to_list()] ) def _sort_objects(objs, link_order): diff --git a/d/toolchain.bzl b/d/toolchain.bzl index a0ce656..ee7ee93 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -10,14 +10,14 @@ D_TOOLCHAIN = "//d:toolchain_type" # "ldc", # ], # ) -# +# # config_setting( # name = "dmd", # flag_values = { # ":compiler_type": "dmd", # }, # ) -# +# # config_setting( # name = "ldc", # flag_values = { @@ -66,7 +66,7 @@ def _d_toolchain_impl(ctx): druntime = config.druntime or ctx.attr.druntime, druntime_src = config.druntime_src or ctx.attr.druntime_src, version_flag = config.version_flag or ctx.attr.version_flag, - common_flags = config.common_flags or ctx.attr.common_flags, + common_flags = config.copts_common or ctx.attr.common_flags, fastbuild_flags = config.copts_per_mode["fastbuild"] or ctx.attr.fastbuild_flags, dbg_flags = config.copts_per_mode["dbg"] or ctx.attr.dbg_flags, opt_flags = config.copts_per_mode["opt"] or ctx.attr.opt_flags, From 938e5bd39d40f2131553237213ad3f6aab6b4f07 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Thu, 23 Oct 2025 11:11:07 -0400 Subject: [PATCH 74/92] d_binary: add support for dynamic symbol list for linking --- d/d.bzl | 4 ++- examples/dynamic_symbols/BUILD | 13 ++++++++++ examples/dynamic_symbols/dynamic_symbols.d | 26 ++++++++++++++++++++ examples/dynamic_symbols/dynamic_symbols.txt | 4 +++ 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 examples/dynamic_symbols/BUILD create mode 100644 examples/dynamic_symbols/dynamic_symbols.d create mode 100644 examples/dynamic_symbols/dynamic_symbols.txt diff --git a/d/d.bzl b/d/d.bzl index 5053826..b5306bc 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -154,6 +154,7 @@ def _build_link_arglist(ctx, objs, out, depinfo, c_compiler, link_flags, link_or _compilation_mode_flags(ctx) + (["-gcc=%s" % c_compiler.files.to_list()[0].path] if c_compiler else []) + (link_flags or []) + + (["-L--dynamic-list=%s" % ctx.files.dynamic_symbols[0].path] if ctx.files.dynamic_symbols else []) + ["-of" + out.path] + depinfo.link_flags + sorted_objs @@ -487,7 +488,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): ) link_inputs = depset( - [d_obj] if d_obj else [], + ([d_obj] if d_obj else []) + ([ctx.files.dynamic_symbols[0]] if ctx.files.dynamic_symbols else []), transitive = [depinfo.libs, depinfo.transitive_libs] + toolchain_files, ) @@ -732,6 +733,7 @@ _d_library_attrs = { } _d_binary_attrs = { + "dynamic_symbols" : attr.label(allow_files = True), "link_order": attr.label_keyed_string_dict(), } diff --git a/examples/dynamic_symbols/BUILD b/examples/dynamic_symbols/BUILD new file mode 100644 index 0000000..659241e --- /dev/null +++ b/examples/dynamic_symbols/BUILD @@ -0,0 +1,13 @@ +package(default_visibility = ["//visibility:public"]) + +load("//d:d.bzl", "d_binary") + +d_binary( + name = "dynamic_symbols", + srcs = ["dynamic_symbols.d"], + dynamic_symbols = ":dynamic_symbols.txt", + deps = [ + "//examples/hello_lib:greeter", + "//examples/hello_lib:native_greeter", + ], +) diff --git a/examples/dynamic_symbols/dynamic_symbols.d b/examples/dynamic_symbols/dynamic_symbols.d new file mode 100644 index 0000000..1bd0235 --- /dev/null +++ b/examples/dynamic_symbols/dynamic_symbols.d @@ -0,0 +1,26 @@ +// Copyright 2015 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import std.stdio; +import examples.hello_lib.greeter; +import examples.hello_lib.native_greeter; + +void main() { + Greeter greeter = new Greeter("Hello"); + greeter.greet("World"); + + NativeGreeter* nativeGreeter = native_greeter_new("Hello"); + native_greeter_greet(nativeGreeter, "World"); + native_greeter_free(nativeGreeter); +} diff --git a/examples/dynamic_symbols/dynamic_symbols.txt b/examples/dynamic_symbols/dynamic_symbols.txt new file mode 100644 index 0000000..53f38aa --- /dev/null +++ b/examples/dynamic_symbols/dynamic_symbols.txt @@ -0,0 +1,4 @@ +{ +a; +b; +}; From 26ecbf6c762be88f1c2120340f76732cff389141 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Tue, 28 Oct 2025 12:19:52 -0400 Subject: [PATCH 75/92] d_binary/d_test: don't ignore linkopts --- d/d.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/d/d.bzl b/d/d.bzl index b5306bc..a5f9d3e 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -483,7 +483,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): depinfo = depinfo, out = d_bin, c_compiler = toolchain.c_compiler, - link_flags = toolchain.link_flags, + link_flags = toolchain.link_flags + ["-L%s" % linkopt for linkopt in ctx.attr.linkopts], link_order = ctx.attr.link_order, ) From ac21cb53f038fe1bc1dc8ec11b45884b0f5b8993 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sat, 1 Nov 2025 09:56:02 -0400 Subject: [PATCH 76/92] Make all files of toolchain.d_compiler available --- d/d.bzl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index a5f9d3e..50ac827 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -393,7 +393,7 @@ def _d_library_impl_common(ctx, extra_flags = []): ctx.actions.run( inputs = compile_inputs, - tools = [d_compiler, generated_srcs_wrapper] if generated_srcs_wrapper else [d_compiler], + tools = toolchain.d_compiler.files.to_list() + [generated_srcs_wrapper] if generated_srcs_wrapper else [], outputs = [d_lib], mnemonic = "Dcompile", executable = generated_srcs_wrapper if generated_srcs_wrapper else d_compiler, @@ -467,7 +467,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): ) ctx.actions.run( inputs = compile_inputs, - tools = [d_compiler, generated_srcs_wrapper] if generated_srcs_wrapper else [d_compiler], + tools = toolchain.d_compiler.files.to_list() + [generated_srcs_wrapper] if generated_srcs_wrapper else [], outputs = [d_obj], mnemonic = "Dcompile", executable = generated_srcs_wrapper if generated_srcs_wrapper else d_compiler, @@ -494,7 +494,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): ctx.actions.run( inputs = link_inputs, - tools = [d_compiler] + (toolchain.c_compiler.files.to_list() if toolchain.c_compiler else []), + tools = toolchain.d_compiler.files.to_list() + (toolchain.c_compiler.files.to_list() if toolchain.c_compiler else []), outputs = [d_bin], mnemonic = "Dlink", executable = d_compiler, @@ -669,7 +669,7 @@ def _d_docs_impl(ctx): ddoc_inputs = depset(target.srcs, transitive = [target.transitive_srcs] + toolchain_files) ctx.actions.run_shell( inputs = ddoc_inputs, - tools = [d_compiler], + tools = toolchain.d_compiler.files.to_list(), outputs = [d_docs_zip], mnemonic = "Ddoc", command = " ".join(doc_cmd), @@ -696,7 +696,7 @@ def _d_header_generator_impl(ctx): ctx.actions.run( inputs = [ctx.file.src], - tools = [d_compiler], + tools = toolchain.d_compiler.files.to_list(), outputs = [header], mnemonic = "Dhdrgen", executable = d_compiler, From c372bee6c91e75b575c21a7717f80b4fbc48451b Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sat, 1 Nov 2025 10:40:48 -0400 Subject: [PATCH 77/92] weka-ldc: bump to 1.30.0-weka20 to get `-fdebug-prefix-map` support --- d/repositories.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/d/repositories.bzl b/d/repositories.bzl index e8d79b1..ef8580e 100644 --- a/d/repositories.bzl +++ b/d/repositories.bzl @@ -79,13 +79,13 @@ def fetch_ldc(version = None): build_file = LDC_BUILD_FILE, ) -def fetch_weka_ldc(version = "1.30.0-weka19"): +def fetch_weka_ldc(version = "1.30.0-weka20"): http_archive( name = "weka_ldc_linux_x86_64", urls = [ "https://github.com/weka/ldc/releases/download/v{version}/ldc2-{version}-linux-x86_64.tar.xz".format(version = version), ], - sha256 = "bf15208ae97e0ee68cd66d2d18327d808c0eabc47ae2e3e9d22d110f3aae569c", + sha256 = "7c502c5f09535dd9c85b4fa054682a8b078ef155807d73a0ec551d12b26afcbc", strip_prefix = "ldc2-{version}-linux-x86_64".format(version = version), build_file = LDC_BUILD_FILE, ) From 8fd5dcc07d94a4882fe011f12b4f93de2fc5b647 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sat, 1 Nov 2025 11:23:14 -0400 Subject: [PATCH 78/92] d_compiler all files: fix bug --- d/d.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 50ac827..d159165 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -393,7 +393,7 @@ def _d_library_impl_common(ctx, extra_flags = []): ctx.actions.run( inputs = compile_inputs, - tools = toolchain.d_compiler.files.to_list() + [generated_srcs_wrapper] if generated_srcs_wrapper else [], + tools = toolchain.d_compiler.files.to_list() + ([generated_srcs_wrapper] if generated_srcs_wrapper else []), outputs = [d_lib], mnemonic = "Dcompile", executable = generated_srcs_wrapper if generated_srcs_wrapper else d_compiler, @@ -467,7 +467,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): ) ctx.actions.run( inputs = compile_inputs, - tools = toolchain.d_compiler.files.to_list() + [generated_srcs_wrapper] if generated_srcs_wrapper else [], + tools = toolchain.d_compiler.files.to_list() + ([generated_srcs_wrapper] if generated_srcs_wrapper else []), outputs = [d_obj], mnemonic = "Dcompile", executable = generated_srcs_wrapper if generated_srcs_wrapper else d_compiler, From c6956c8a7572b463ff64ab64ca734a623765b2a1 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sat, 1 Nov 2025 18:16:43 -0400 Subject: [PATCH 79/92] weka-ldc: fix hash after update --- d/repositories.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/d/repositories.bzl b/d/repositories.bzl index ef8580e..c123a35 100644 --- a/d/repositories.bzl +++ b/d/repositories.bzl @@ -85,7 +85,7 @@ def fetch_weka_ldc(version = "1.30.0-weka20"): urls = [ "https://github.com/weka/ldc/releases/download/v{version}/ldc2-{version}-linux-x86_64.tar.xz".format(version = version), ], - sha256 = "7c502c5f09535dd9c85b4fa054682a8b078ef155807d73a0ec551d12b26afcbc", + sha256 = "0a6001fb4975361724b1975eb49cde70ef53546f78b281a69446121072342f7a", strip_prefix = "ldc2-{version}-linux-x86_64".format(version = version), build_file = LDC_BUILD_FILE, ) From ffeb6fc7db7dcd71a4b2f6eba1a57143dd643dcf Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sat, 1 Nov 2025 18:18:11 -0400 Subject: [PATCH 80/92] d_library: support for -fdebug-prefix-map --- d/BUILD | 1 + d/config.bzl | 1 + d/d.bzl | 22 ++++++++++++---------- d/toolchain.bzl | 3 +++ 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/d/BUILD b/d/BUILD index e4f6fab..cf2eae8 100644 --- a/d/BUILD +++ b/d/BUILD @@ -105,6 +105,7 @@ d_toolchain( hdrgen_flags = [ "-Honly", ], + debug_repo_root_override = "/source", ) toolchain( diff --git a/d/config.bzl b/d/config.bzl index e35da95..399427d 100644 --- a/d/config.bzl +++ b/d/config.bzl @@ -25,5 +25,6 @@ DToolchainConfigInfo = provider( "linkopts_common", "global_versions_per_mode", "global_versions_common", + "debug_repo_root_override", ], ) diff --git a/d/d.bzl b/d/d.bzl index d159165..6809dee 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -289,30 +289,31 @@ def _setup_deps(ctx, deps, impl_deps, name): impl_srcs = impl_srcs, ) -def _handle_generated_srcs(ctx, generated_srcs, d_compiler): +def _handle_generated_srcs(ctx, generated_srcs, d_compiler, debug_repo_root_override): """Handles the generated source files.""" - if not generated_srcs: + if not generated_srcs and not debug_repo_root_override: return (ctx.files.srcs, None) mapped_srcs = [src if src not in generated_srcs else generated_srcs[src] for src in ctx.files.srcs] - generated_srcs_file = ctx.actions.declare_file(ctx.label.name + "_generated_srcs_wrapper.sh") + wrapper = ctx.actions.declare_file(ctx.label.name + "_d_compile_wrapper.sh") + debug_prefix_map = "-fdebug-prefix-map=$PWD=%s " % debug_repo_root_override if debug_repo_root_override else "" ctx.actions.write( - output = generated_srcs_file, + output = wrapper, content = "\n".join( [ - "#!/bin/sh", + "#!/bin/bash", "set -e", ] + [ "mkdir -p $(dirname %s)\n" % loc + "[ -f $PWD/%s ] && ln -s $PWD/%s %s" % (src.path, src.path, loc) for src, loc in generated_srcs.items() ] + [ - "%s $*" % d_compiler.path, + "%s %s$*" % (d_compiler.path, debug_prefix_map), ]), is_executable = True, ) - return (mapped_srcs, generated_srcs_file) + return (mapped_srcs, wrapper) def _d_library_impl_common(ctx, extra_flags = []): """Implementation of the d_library rule.""" @@ -367,7 +368,7 @@ def _d_library_impl_common(ctx, extra_flags = []): args = ctx.actions.args() args.add_all(compile_args) - mapped_srcs, generated_srcs_wrapper = _handle_generated_srcs(ctx, depinfo.generated_srcs, d_compiler) + mapped_srcs, generated_srcs_wrapper = _handle_generated_srcs(ctx, depinfo.generated_srcs, d_compiler, toolchain.debug_repo_root_override) args.add_all(mapped_srcs) @@ -391,12 +392,13 @@ def _d_library_impl_common(ctx, extra_flags = []): ], ) + executable = generated_srcs_wrapper if generated_srcs_wrapper else d_compiler ctx.actions.run( inputs = compile_inputs, tools = toolchain.d_compiler.files.to_list() + ([generated_srcs_wrapper] if generated_srcs_wrapper else []), outputs = [d_lib], mnemonic = "Dcompile", - executable = generated_srcs_wrapper if generated_srcs_wrapper else d_compiler, + executable = executable, arguments = [args], use_default_shell_env = True, progress_message = "Compiling D library " + ctx.label.name, @@ -457,7 +459,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): args = ctx.actions.args() args.add_all(compile_args) - mapped_srcs, generated_srcs_wrapper = _handle_generated_srcs(ctx, depinfo.generated_srcs, d_compiler) + mapped_srcs, generated_srcs_wrapper = _handle_generated_srcs(ctx, depinfo.generated_srcs, d_compiler, toolchain.debug_repo_root_override) args.add_all(mapped_srcs) diff --git a/d/toolchain.bzl b/d/toolchain.bzl index ee7ee93..a24b199 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -52,6 +52,7 @@ def _d_toolchain_impl(ctx): "dbg": [], "opt": [], }, + debug_repo_root_override = ctx.attr.debug_repo_root_override, ) else: toolchain_info = platform_common.ToolchainInfo( @@ -73,6 +74,7 @@ def _d_toolchain_impl(ctx): hdrgen_flags = config.hdrgen_flags, global_versions_common = config.global_versions_common, global_versions_per_mode = config.global_versions_per_mode, + debug_repo_root_override = config.debug_repo_root_override, ) return [toolchain_info] @@ -106,6 +108,7 @@ d_toolchain = rule( "dbg_flags": attr.string_list(), "opt_flags": attr.string_list(), "hdrgen_flags": attr.string_list(), + "debug_repo_root_override": attr.string(), "config": attr.label( providers = [DToolchainConfigInfo], ), From f005215f971ccd050ab0f69bb8af52f0975c81ed Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sun, 2 Nov 2025 06:03:01 -0500 Subject: [PATCH 81/92] rules_d: also pass compiler runfiles --- d/d.bzl | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 6809dee..5c68409 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -29,6 +29,14 @@ ZIP_PATH = "/usr/bin/zip" DInfo = provider() +def _with_runfiles(tool): + """Returns a list of files _and_ runfiles for `tool`.""" + files = tool.files.to_list() + runfiles = tool[DefaultInfo].default_runfiles + if runfiles: + files += runfiles.files.to_list() + return files + def _files_directory(files): """Returns the shortest parent directory of a list of files.""" dir = files[0].dirname @@ -395,7 +403,7 @@ def _d_library_impl_common(ctx, extra_flags = []): executable = generated_srcs_wrapper if generated_srcs_wrapper else d_compiler ctx.actions.run( inputs = compile_inputs, - tools = toolchain.d_compiler.files.to_list() + ([generated_srcs_wrapper] if generated_srcs_wrapper else []), + tools = _with_runfiles(toolchain.d_compiler) + ([generated_srcs_wrapper] if generated_srcs_wrapper else []), outputs = [d_lib], mnemonic = "Dcompile", executable = executable, @@ -469,7 +477,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): ) ctx.actions.run( inputs = compile_inputs, - tools = toolchain.d_compiler.files.to_list() + ([generated_srcs_wrapper] if generated_srcs_wrapper else []), + tools = _with_runfiles(toolchain.d_compiler) + ([generated_srcs_wrapper] if generated_srcs_wrapper else []), outputs = [d_obj], mnemonic = "Dcompile", executable = generated_srcs_wrapper if generated_srcs_wrapper else d_compiler, @@ -496,7 +504,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): ctx.actions.run( inputs = link_inputs, - tools = toolchain.d_compiler.files.to_list() + (toolchain.c_compiler.files.to_list() if toolchain.c_compiler else []), + tools = _with_runfiles(toolchain.d_compiler) + (_with_runfiles(toolchain.c_compiler) if toolchain.c_compiler else []), outputs = [d_bin], mnemonic = "Dlink", executable = d_compiler, @@ -671,7 +679,7 @@ def _d_docs_impl(ctx): ddoc_inputs = depset(target.srcs, transitive = [target.transitive_srcs] + toolchain_files) ctx.actions.run_shell( inputs = ddoc_inputs, - tools = toolchain.d_compiler.files.to_list(), + tools = _with_runfiles(toolchain.d_compiler), outputs = [d_docs_zip], mnemonic = "Ddoc", command = " ".join(doc_cmd), @@ -698,7 +706,7 @@ def _d_header_generator_impl(ctx): ctx.actions.run( inputs = [ctx.file.src], - tools = toolchain.d_compiler.files.to_list(), + tools = _with_runfiles(toolchain.d_compiler), outputs = [header], mnemonic = "Dhdrgen", executable = d_compiler, From 8e04e2a54943670316b85aa834ebf11f253702be Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Tue, 4 Nov 2025 11:42:48 -0500 Subject: [PATCH 82/92] add `output_bc_flags` to toolchain/config not used yet --- d/config.bzl | 1 + d/toolchain.bzl | 3 +++ 2 files changed, 4 insertions(+) diff --git a/d/config.bzl b/d/config.bzl index 399427d..ab80659 100644 --- a/d/config.bzl +++ b/d/config.bzl @@ -18,6 +18,7 @@ DToolchainConfigInfo = provider( "import_flags", # unused "version_flag", "hdrgen_flags", + "output_bc_flags", # compilation modes "copts_per_mode", "copts_common", diff --git a/d/toolchain.bzl b/d/toolchain.bzl index a24b199..f85039c 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -46,6 +46,7 @@ def _d_toolchain_impl(ctx): dbg_flags = ctx.attr.dbg_flags, opt_flags = ctx.attr.opt_flags, hdrgen_flags = ctx.attr.hdrgen_flags, + output_bc_flags = ctx.attr.output_bc_flags, global_versions_common = [], global_versions_per_mode = { "fastbuild": [], @@ -72,6 +73,7 @@ def _d_toolchain_impl(ctx): dbg_flags = config.copts_per_mode["dbg"] or ctx.attr.dbg_flags, opt_flags = config.copts_per_mode["opt"] or ctx.attr.opt_flags, hdrgen_flags = config.hdrgen_flags, + output_bc_flags = config.output_bc_flags, global_versions_common = config.global_versions_common, global_versions_per_mode = config.global_versions_per_mode, debug_repo_root_override = config.debug_repo_root_override, @@ -108,6 +110,7 @@ d_toolchain = rule( "dbg_flags": attr.string_list(), "opt_flags": attr.string_list(), "hdrgen_flags": attr.string_list(), + "output_bc_flags": attr.string_list(), "debug_repo_root_override": attr.string(), "config": attr.label( providers = [DToolchainConfigInfo], From d224b97e5ff0b0810245caa4c94074ed0a6e620f Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 5 Nov 2025 08:43:27 -0500 Subject: [PATCH 83/92] Add test with compile_via_bc --- tests/d_library_compile_via_bc/BUILD | 9 +++++++++ tests/d_library_compile_via_bc/simple_library.d | 6 ++++++ 2 files changed, 15 insertions(+) create mode 100644 tests/d_library_compile_via_bc/BUILD create mode 100644 tests/d_library_compile_via_bc/simple_library.d diff --git a/tests/d_library_compile_via_bc/BUILD b/tests/d_library_compile_via_bc/BUILD new file mode 100644 index 0000000..5653250 --- /dev/null +++ b/tests/d_library_compile_via_bc/BUILD @@ -0,0 +1,9 @@ +package(default_visibility = ["//visibility:public"]) + +load("@rules_d//d:d.bzl", "d_library") + +d_library( + name = "simple_d_library", + compile_via_bc = True, + srcs = ["simple_library.d"], +) diff --git a/tests/d_library_compile_via_bc/simple_library.d b/tests/d_library_compile_via_bc/simple_library.d new file mode 100644 index 0000000..5b162ad --- /dev/null +++ b/tests/d_library_compile_via_bc/simple_library.d @@ -0,0 +1,6 @@ +module simple_library; + +int plusOne(uint x) +{ + return x + 1; +} From d5eed2491588b50db2f7ab82785e941e846a9f4f Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 5 Nov 2025 08:46:02 -0500 Subject: [PATCH 84/92] LDC toolchains support output-bc flag --- d/BUILD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/d/BUILD b/d/BUILD index cf2eae8..f0e4bc4 100644 --- a/d/BUILD +++ b/d/BUILD @@ -74,6 +74,7 @@ d_toolchain( lib_flags = [ "-lib", "-oq", ], + output_bc_flags = ["--output-bc"], ) toolchain( @@ -106,6 +107,7 @@ d_toolchain( "-Honly", ], debug_repo_root_override = "/source", + output_bc_flags = ["--output-bc"], ) toolchain( From 18fd4b0e1ed0f1b19e3645c7819727c0af35ad60 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 5 Nov 2025 10:21:15 -0500 Subject: [PATCH 85/92] very basic compile_via_bc support To be actually useful, we need: 1. a way to set codegen flags 2. probably also expose bc libs with the DInfo --- d/d.bzl | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 5c68409..6c0801c 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -125,6 +125,7 @@ def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): "-of" + out.path, "-w", ] + + (toolchain.output_bc_flags if ctx.attr.compile_via_bc else []) + (["-I%s" % ws_root] if ctx.attr.include_workspace_root else []) + ["-I%s" % im for im in depinfo.imports] + ["-J%s" % im for im in depinfo.string_imports] + @@ -328,6 +329,9 @@ def _d_library_impl_common(ctx, extra_flags = []): toolchain = ctx.toolchains[D_TOOLCHAIN] d_compiler = toolchain.d_compiler.files.to_list()[0] + if ctx.attr.compile_via_bc and not toolchain.output_bc_flags: + fail("'compile_via_bc' requires a toolchain with 'output_bc_flags' set") + # Dependencies deps = ctx.attr.deps + ([toolchain.libphobos] if toolchain.libphobos != None else []) + ([toolchain.druntime] if toolchain.druntime != None else []) depinfo = _setup_deps(ctx, ctx.attr.deps, ctx.attr.implementation_deps, ctx.label.name) @@ -361,11 +365,14 @@ def _d_library_impl_common(ctx, extra_flags = []): #d_lib = ctx.actions.declare_file((ctx.label.name + ".lib") if _is_windows(ctx) else ("lib" + ctx.label.name + ".a")) d_lib = ctx.actions.declare_file(ctx.label.name + ".o") + d_lib_bc = None + if ctx.attr.compile_via_bc: + d_lib_bc = ctx.actions.declare_file(ctx.label.name + ".bc") # Build compile command. compile_args = _build_compile_arglist( ctx = ctx, - out = d_lib, + out = d_lib if not d_lib_bc else d_lib_bc, depinfo = depinfo, extra_flags = ["-c"] + extra_flags, ) @@ -404,7 +411,7 @@ def _d_library_impl_common(ctx, extra_flags = []): ctx.actions.run( inputs = compile_inputs, tools = _with_runfiles(toolchain.d_compiler) + ([generated_srcs_wrapper] if generated_srcs_wrapper else []), - outputs = [d_lib], + outputs = [d_lib] if not d_lib_bc else [d_lib_bc], mnemonic = "Dcompile", executable = executable, arguments = [args], @@ -412,6 +419,20 @@ def _d_library_impl_common(ctx, extra_flags = []): progress_message = "Compiling D library " + ctx.label.name, ) + if d_lib_bc: + # need to compile .bc -> .o in an extra step + # this is a hack, just hoping there is some clang is not good + # TODO: enforce this is only used with toolchain.c_compiler + clang = toolchain.c_compiler.files[0] if toolchain.c_compiler else "clang" + ctx.actions.run( + inputs = [d_lib_bc], + tools = _with_runfiles(toolchain.c_compiler) if toolchain.c_compiler else [], + outputs = [d_lib], + executable = clang, + arguments = ["-c", "-o", d_lib.path, d_lib_bc.path], + use_default_shell_env = True, + progress_message = "Compiling bitcode for D library " + ctx.label.name, + ) return [ DefaultInfo( files = depset([d_lib]), @@ -440,6 +461,9 @@ def _d_binary_impl_common(ctx, extra_flags = []): d_bin = ctx.actions.declare_file(ctx.label.name + ".exe" if _is_windows(ctx) else ctx.label.name) d_compiler = toolchain.d_compiler.files.to_list()[0] + if ctx.attr.compile_via_bc and not ctx.files.srcs: + fail("'compile_via_bc' only makes sense if you have sources to compile") + # Dependencies deps = ctx.attr.deps + ([toolchain.libphobos] if toolchain.libphobos != None else []) + ([toolchain.druntime] if toolchain.druntime != None else []) depinfo = _setup_deps(ctx, deps, [], ctx.label.name) @@ -452,12 +476,19 @@ def _d_binary_impl_common(ctx, extra_flags = []): ] if ctx.files.srcs: + d_obj_bc = None + + if ctx.attr.compile_via_bc: + if not toolchain.output_bc_flags: + fail("'compile_via_bc' requires a toolchain with 'output_bc_flags' set") + d_obj_bc = ctx.actions.declare_file(ctx.label.name + ".bc") + d_obj = ctx.actions.declare_file(ctx.label.name + (".obj" if _is_windows(ctx) else ".o")) # Build compile command compile_args = _build_compile_arglist( ctx = ctx, depinfo = depinfo, - out = d_obj, + out = d_obj if not d_obj_bc else d_obj_bc, extra_flags = ["-c"] + extra_flags, ) @@ -478,7 +509,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): ctx.actions.run( inputs = compile_inputs, tools = _with_runfiles(toolchain.d_compiler) + ([generated_srcs_wrapper] if generated_srcs_wrapper else []), - outputs = [d_obj], + outputs = [d_obj] if not d_obj_bc else [d_obj_bc], mnemonic = "Dcompile", executable = generated_srcs_wrapper if generated_srcs_wrapper else d_compiler, arguments = [args], @@ -486,6 +517,21 @@ def _d_binary_impl_common(ctx, extra_flags = []): progress_message = "Compiling D binary " + ctx.label.name, ) + if d_obj_bc: + # need to compile .bc -> .o in an extra step + # this is a hack, just hoping there is some clang is not good + # TODO: enforce this is only used with toolchain.c_compiler + clang = toolchain.c_compiler.files[0] if toolchain.c_compiler else "clang" + ctx.actions.run( + inputs = [d_obj_bc], + tools = _with_runfiles(toolchain.c_compiler) if toolchain.c_compiler else [], + outputs = [d_obj], + executable = clang, + arguments = ["-c", "-o", d_obj.path, d_obj_bc.path], + use_default_shell_env = True, + progress_message = "Compiling bitcode for D binary " + ctx.label.name, + ) + # Build link command link_args = _build_link_arglist( ctx = ctx, @@ -733,6 +779,7 @@ _d_common_attrs = { "include_workspace_root": attr.bool(default = True), "is_generated": attr.bool(default = False), "generated_srcs": attr.label_keyed_string_dict(allow_files = True), + "compile_via_bc": attr.bool(default = False), "deps": attr.label_list(), } From 924717c3abc5ebd46a7718da834841373c99363b Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 5 Nov 2025 10:40:03 -0500 Subject: [PATCH 86/92] Add codegen_flags to toolchain --- d/config.bzl | 1 + d/d.bzl | 4 ++-- d/toolchain.bzl | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/d/config.bzl b/d/config.bzl index ab80659..cea2601 100644 --- a/d/config.bzl +++ b/d/config.bzl @@ -24,6 +24,7 @@ DToolchainConfigInfo = provider( "copts_common", "linkopts_per_mode", "linkopts_common", + "codegen_opts_common", # TODO: do we need per_mode? "global_versions_per_mode", "global_versions_common", "debug_repo_root_override", diff --git a/d/d.bzl b/d/d.bzl index 6c0801c..e0c22e8 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -429,7 +429,7 @@ def _d_library_impl_common(ctx, extra_flags = []): tools = _with_runfiles(toolchain.c_compiler) if toolchain.c_compiler else [], outputs = [d_lib], executable = clang, - arguments = ["-c", "-o", d_lib.path, d_lib_bc.path], + arguments = toolchain.codegen_flags + ["-c", "-o", d_lib.path, d_lib_bc.path], use_default_shell_env = True, progress_message = "Compiling bitcode for D library " + ctx.label.name, ) @@ -527,7 +527,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): tools = _with_runfiles(toolchain.c_compiler) if toolchain.c_compiler else [], outputs = [d_obj], executable = clang, - arguments = ["-c", "-o", d_obj.path, d_obj_bc.path], + arguments = toolchain.codegen_flags + ["-c", "-o", d_obj.path, d_obj_bc.path], use_default_shell_env = True, progress_message = "Compiling bitcode for D binary " + ctx.label.name, ) diff --git a/d/toolchain.bzl b/d/toolchain.bzl index f85039c..3dfefe4 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -42,6 +42,7 @@ def _d_toolchain_impl(ctx): druntime_src = ctx.attr.druntime_src, version_flag = ctx.attr.version_flag, common_flags = ctx.attr.common_flags, + codegen_flags = ctx.attr.codegen_flags, fastbuild_flags = ctx.attr.fastbuild_flags, dbg_flags = ctx.attr.dbg_flags, opt_flags = ctx.attr.opt_flags, @@ -69,6 +70,7 @@ def _d_toolchain_impl(ctx): druntime_src = config.druntime_src or ctx.attr.druntime_src, version_flag = config.version_flag or ctx.attr.version_flag, common_flags = config.copts_common or ctx.attr.common_flags, + codegen_flags = config.codegen_opts_common or ctx.attr.codegen_flags, fastbuild_flags = config.copts_per_mode["fastbuild"] or ctx.attr.fastbuild_flags, dbg_flags = config.copts_per_mode["dbg"] or ctx.attr.dbg_flags, opt_flags = config.copts_per_mode["opt"] or ctx.attr.opt_flags, @@ -106,6 +108,7 @@ d_toolchain = rule( "druntime_src": attr.label(), "version_flag": attr.string(), "common_flags": attr.string_list(), + "codegen_flags": attr.string_list(default = []), "fastbuild_flags": attr.string_list(), "dbg_flags": attr.string_list(), "opt_flags": attr.string_list(), From 132dea95b8263fb94a5fbaa7def6adadc3a2a104 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Fri, 7 Nov 2025 10:31:36 -0500 Subject: [PATCH 87/92] Add per-mode codegen flags We actually need to pass optimization options to codegen --- d/config.bzl | 3 ++- d/d.bzl | 6 ++++-- d/toolchain.bzl | 16 +++++++++++++--- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/d/config.bzl b/d/config.bzl index cea2601..61ee9d7 100644 --- a/d/config.bzl +++ b/d/config.bzl @@ -24,7 +24,8 @@ DToolchainConfigInfo = provider( "copts_common", "linkopts_per_mode", "linkopts_common", - "codegen_opts_common", # TODO: do we need per_mode? + "codegen_opts_common", + "codegen_opts_per_mode", "global_versions_per_mode", "global_versions_common", "debug_repo_root_override", diff --git a/d/d.bzl b/d/d.bzl index e0c22e8..bf43502 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -421,6 +421,7 @@ def _d_library_impl_common(ctx, extra_flags = []): if d_lib_bc: # need to compile .bc -> .o in an extra step + codegen_flags = toolchain.codegen_common_flags + toolchain.codegen_per_mode_flags[ctx.var["COMPILATION_MODE"]] # this is a hack, just hoping there is some clang is not good # TODO: enforce this is only used with toolchain.c_compiler clang = toolchain.c_compiler.files[0] if toolchain.c_compiler else "clang" @@ -429,7 +430,7 @@ def _d_library_impl_common(ctx, extra_flags = []): tools = _with_runfiles(toolchain.c_compiler) if toolchain.c_compiler else [], outputs = [d_lib], executable = clang, - arguments = toolchain.codegen_flags + ["-c", "-o", d_lib.path, d_lib_bc.path], + arguments = codegen_flags + ["-c", "-o", d_lib.path, d_lib_bc.path], use_default_shell_env = True, progress_message = "Compiling bitcode for D library " + ctx.label.name, ) @@ -519,6 +520,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): if d_obj_bc: # need to compile .bc -> .o in an extra step + codegen_flags = toolchain.codegen_common_flags + toolchain.codegen_per_mode_flags[ctx.var["COMPILATION_MODE"]] # this is a hack, just hoping there is some clang is not good # TODO: enforce this is only used with toolchain.c_compiler clang = toolchain.c_compiler.files[0] if toolchain.c_compiler else "clang" @@ -527,7 +529,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): tools = _with_runfiles(toolchain.c_compiler) if toolchain.c_compiler else [], outputs = [d_obj], executable = clang, - arguments = toolchain.codegen_flags + ["-c", "-o", d_obj.path, d_obj_bc.path], + arguments = codegen_flags + ["-c", "-o", d_obj.path, d_obj_bc.path], use_default_shell_env = True, progress_message = "Compiling bitcode for D binary " + ctx.label.name, ) diff --git a/d/toolchain.bzl b/d/toolchain.bzl index 3dfefe4..b851a9f 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -27,6 +27,11 @@ D_TOOLCHAIN = "//d:toolchain_type" def _d_toolchain_impl(ctx): config = ctx.attr.config[DToolchainConfigInfo] if ctx.attr.config else None + codegen_opts_per_mode = { + "fastbuild": ctx.attr.codegen_fastbuild_flags, + "dbg": ctx.attr.codegen_dbg_flags, + "opt": ctx.attr.codegen_opt_flags, + } if config == None: # TODO: deprecate this toolchain_info = platform_common.ToolchainInfo( @@ -42,10 +47,11 @@ def _d_toolchain_impl(ctx): druntime_src = ctx.attr.druntime_src, version_flag = ctx.attr.version_flag, common_flags = ctx.attr.common_flags, - codegen_flags = ctx.attr.codegen_flags, fastbuild_flags = ctx.attr.fastbuild_flags, dbg_flags = ctx.attr.dbg_flags, opt_flags = ctx.attr.opt_flags, + codegen_common_flags = ctx.attr.codegen_common_flags, + codegen_per_mode_flags = codegen_opts_per_mode, hdrgen_flags = ctx.attr.hdrgen_flags, output_bc_flags = ctx.attr.output_bc_flags, global_versions_common = [], @@ -70,10 +76,11 @@ def _d_toolchain_impl(ctx): druntime_src = config.druntime_src or ctx.attr.druntime_src, version_flag = config.version_flag or ctx.attr.version_flag, common_flags = config.copts_common or ctx.attr.common_flags, - codegen_flags = config.codegen_opts_common or ctx.attr.codegen_flags, fastbuild_flags = config.copts_per_mode["fastbuild"] or ctx.attr.fastbuild_flags, dbg_flags = config.copts_per_mode["dbg"] or ctx.attr.dbg_flags, opt_flags = config.copts_per_mode["opt"] or ctx.attr.opt_flags, + codegen_common_flags = config.codegen_opts_common or ctx.attr.codegen_common_flags, + codegen_per_mode_flags = config.codegen_opts_per_mode or codegen_opts_per_mode, hdrgen_flags = config.hdrgen_flags, output_bc_flags = config.output_bc_flags, global_versions_common = config.global_versions_common, @@ -108,10 +115,13 @@ d_toolchain = rule( "druntime_src": attr.label(), "version_flag": attr.string(), "common_flags": attr.string_list(), - "codegen_flags": attr.string_list(default = []), "fastbuild_flags": attr.string_list(), "dbg_flags": attr.string_list(), "opt_flags": attr.string_list(), + "codegen_common_flags": attr.string_list(default = []), + "codegen_fastbuild_flags": attr.string_list(), + "codegen_dbg_flags": attr.string_list(), + "codegen_opt_flags": attr.string_list(), "hdrgen_flags": attr.string_list(), "output_bc_flags": attr.string_list(), "debug_repo_root_override": attr.string(), From e04b4eb8692c919c29fea6d2153352c9762a7520 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Fri, 7 Nov 2025 10:43:14 -0500 Subject: [PATCH 88/92] Use llc as a bitcode compiler This is questionable: most resources say llc is only for debugging and in production people should use clang as a driver. But clang has different backend options wrt to ldc, while llc has exactly the same. In the long run, I guess the right way is to use _ldc_ as a driver. But right now it doesn't seem to support .bc -> .o compilation. --- d/config.bzl | 1 + d/d.bzl | 33 ++++++++++++++++++++------------- d/toolchain.bzl | 7 +++++++ 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/d/config.bzl b/d/config.bzl index 61ee9d7..dfdce8b 100644 --- a/d/config.bzl +++ b/d/config.bzl @@ -8,6 +8,7 @@ DToolchainConfigInfo = provider( # binaries "d_compiler", "c_compiler", + "llc_compiler", # libraries "libphobos", "libphobos_src", diff --git a/d/d.bzl b/d/d.bzl index bf43502..7180cdf 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -422,15 +422,18 @@ def _d_library_impl_common(ctx, extra_flags = []): if d_lib_bc: # need to compile .bc -> .o in an extra step codegen_flags = toolchain.codegen_common_flags + toolchain.codegen_per_mode_flags[ctx.var["COMPILATION_MODE"]] - # this is a hack, just hoping there is some clang is not good - # TODO: enforce this is only used with toolchain.c_compiler - clang = toolchain.c_compiler.files[0] if toolchain.c_compiler else "clang" + # this is a hack, just hoping there is some llc is not good + # TODO: enforce this is only used with toolchain.llc_compiler + # This also _could_ be clang, but aligning LDC backend options with + # clang ones is non-trivial, whereas llc has exactly the same options + # as ldc does. + llc = toolchain.llc_compiler.files.to_list()[0] if toolchain.llc_compiler else "llc" ctx.actions.run( inputs = [d_lib_bc], - tools = _with_runfiles(toolchain.c_compiler) if toolchain.c_compiler else [], + tools = _with_runfiles(toolchain.llc_compiler) if toolchain.llc_compiler else [], outputs = [d_lib], - executable = clang, - arguments = codegen_flags + ["-c", "-o", d_lib.path, d_lib_bc.path], + executable = llc, + arguments = codegen_flags + ["--filetype=obj", "-o", d_lib.path, d_lib_bc.path], use_default_shell_env = True, progress_message = "Compiling bitcode for D library " + ctx.label.name, ) @@ -483,7 +486,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): if not toolchain.output_bc_flags: fail("'compile_via_bc' requires a toolchain with 'output_bc_flags' set") d_obj_bc = ctx.actions.declare_file(ctx.label.name + ".bc") - + d_obj = ctx.actions.declare_file(ctx.label.name + (".obj" if _is_windows(ctx) else ".o")) # Build compile command compile_args = _build_compile_arglist( @@ -519,17 +522,21 @@ def _d_binary_impl_common(ctx, extra_flags = []): ) if d_obj_bc: + # TODO: this code is almost exactly the same as in d_library # need to compile .bc -> .o in an extra step codegen_flags = toolchain.codegen_common_flags + toolchain.codegen_per_mode_flags[ctx.var["COMPILATION_MODE"]] - # this is a hack, just hoping there is some clang is not good - # TODO: enforce this is only used with toolchain.c_compiler - clang = toolchain.c_compiler.files[0] if toolchain.c_compiler else "clang" + # this is a hack, just hoping there is some llc is not good + # TODO: enforce this is only used with toolchain.llc_compiler + # This also _could_ be clang, but aligning LDC backend options with + # clang ones is non-trivial, whereas llc has exactly the same options + # as ldc does. + llc = toolchain.llc_compiler.files.to_list()[0] if toolchain.llc_compiler else "llc" ctx.actions.run( inputs = [d_obj_bc], - tools = _with_runfiles(toolchain.c_compiler) if toolchain.c_compiler else [], + tools = _with_runfiles(toolchain.llc_compiler) if toolchain.llc_compiler else [], outputs = [d_obj], - executable = clang, - arguments = codegen_flags + ["-c", "-o", d_obj.path, d_obj_bc.path], + executable = llc, + arguments = codegen_flags + ["--filetype=obj", "-o", d_obj.path, d_obj_bc.path], use_default_shell_env = True, progress_message = "Compiling bitcode for D binary " + ctx.label.name, ) diff --git a/d/toolchain.bzl b/d/toolchain.bzl index b851a9f..67143cf 100644 --- a/d/toolchain.bzl +++ b/d/toolchain.bzl @@ -38,6 +38,7 @@ def _d_toolchain_impl(ctx): name = ctx.label.name, d_compiler = ctx.attr.d_compiler, c_compiler = ctx.attr.c_compiler, + llc_compiler = ctx.attr.llc_compiler, lib_flags = ctx.attr.lib_flags, link_flags = ctx.attr.link_flags, import_flags = ctx.attr.import_flags, @@ -67,6 +68,7 @@ def _d_toolchain_impl(ctx): name = ctx.attr.name, d_compiler = config.d_compiler or ctx.attr.d_compiler, c_compiler = config.c_compiler or ctx.attr.c_compiler, + llc_compiler = config.llc_compiler or ctx.attr.llc_compiler, lib_flags = config.lib_flags or ctx.attr.lib_flags, link_flags = (config.linkopts_common + config.linkopts_per_mode[ctx.var["COMPILATION_MODE"]]) or ctx.attr.link_flags, import_flags = config.import_flags or ctx.attr.import_flags, @@ -102,6 +104,11 @@ d_toolchain = rule( allow_files = True, cfg = "exec", ), + "llc_compiler": attr.label( + executable = True, + allow_files = True, + cfg = "exec", + ), "lib_flags": attr.string_list( default = ["-lib"], ), From c352e936cd7cb1350d0b3124364c6cd6da417dd8 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sat, 8 Nov 2025 08:46:14 -0500 Subject: [PATCH 89/92] d_binary: don't complain if there are not sources with compile_via_bc --- d/d.bzl | 3 --- 1 file changed, 3 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 7180cdf..7147a04 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -465,9 +465,6 @@ def _d_binary_impl_common(ctx, extra_flags = []): d_bin = ctx.actions.declare_file(ctx.label.name + ".exe" if _is_windows(ctx) else ctx.label.name) d_compiler = toolchain.d_compiler.files.to_list()[0] - if ctx.attr.compile_via_bc and not ctx.files.srcs: - fail("'compile_via_bc' only makes sense if you have sources to compile") - # Dependencies deps = ctx.attr.deps + ([toolchain.libphobos] if toolchain.libphobos != None else []) + ([toolchain.druntime] if toolchain.druntime != None else []) depinfo = _setup_deps(ctx, deps, [], ctx.label.name) From a930b08deec1d2aff335c37fd45e1df97b3f22d8 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sat, 8 Nov 2025 10:07:54 -0500 Subject: [PATCH 90/92] Collect transitive bc/non-bc libs such that we can do something smart with them, like pass bc libs directly to linker to get LTO, or pre-compile them together. --- d/d.bzl | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 7147a04..717a80f 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -195,6 +195,8 @@ def _setup_deps(ctx, deps, impl_deps, name): libs: List of Files containing the target's direct library dependencies. transitive_libs: List of Files containing all of the target's transitive libraries. + transitive_bc_libs: List of transitive deps as bc files (where they exist) + transitive_non_bc_libs: List of transitive deps that don't exists as bc d_srcs: List of Files representing D source files of dependencies that will be used as inputs for this target. versions: List of D versions to be used for compiling the target. @@ -211,7 +213,11 @@ def _setup_deps(ctx, deps, impl_deps, name): gen_dir = ctx.genfiles_dir.path libs = [] + libs_bc = [] + libs_non_bc = [] transitive_libs = [] + transitive_libs_bc = [] + transitive_libs_non_bc = [] d_srcs = [] data = [] transitive_d_srcs = [] @@ -230,7 +236,14 @@ def _setup_deps(ctx, deps, impl_deps, name): ddep = dep[DInfo] if ddep.d_lib: libs.append(ddep.d_lib) + if ddep.d_lib_bc: + libs_bc.append(ddep.d_lib_bc) + else: + libs_non_bc.append(ddep.d_lib) transitive_libs.append(ddep.transitive_libs) + transitive_libs_bc.append(ddep.transitive_libs_bc) + transitive_libs_non_bc.append(ddep.transitive_libs_non_bc) + d_srcs += ddep.d_exports transitive_d_srcs.append(ddep.transitive_d_srcs) data += ddep.data @@ -252,6 +265,8 @@ def _setup_deps(ctx, deps, impl_deps, name): data += ddep.data transitive_data.append(ddep.transitive_data) transitive_libs.append(ddep.transitive_libs) + transitive_libs_bc.append(ddep.transitive_libs_bc) + transitive_libs_non_bc.append(ddep.transitive_libs_non_bc) link_flags += ["-L%s" % linkopt for linkopt in ddep.linkopts] imports += ddep.imports if ddep.is_generated: @@ -264,7 +279,9 @@ def _setup_deps(ctx, deps, impl_deps, name): # The dependency is a cc_library native_libs = a_filetype(ctx, _get_libs_for_static_executable(dep)) libs.extend(native_libs) + libs_non_bc.extend(native_libs) transitive_libs.append(depset(native_libs)) + transitive_libs_non_bc.append(depset(native_libs)) else: fail("D targets can only depend on d_library, d_source_library, or " + @@ -275,18 +292,30 @@ def _setup_deps(ctx, deps, impl_deps, name): if DInfo in dep and hasattr(dep[DInfo], "d_lib"): ddep = dep[DInfo] libs.append(ddep.d_lib) + if ddep.d_lib_bc: + libs_bc.append(ddep.d_lib_bc) + else: + libs_non_bc.append(ddep.d_lib) transitive_libs.append(ddep.transitive_libs) + transitive_libs_bc.append(ddep.transitive_libs_bc) + transitive_libs_non_bc.append(ddep.transitive_libs_non_bc) impl_srcs.extend(ddep.d_exports) elif CcInfo in dep: native_libs = a_filetype(ctx, _get_libs_for_static_executable(dep)) libs.extend(native_libs) + libs_non_bc.extend(native_libs) transitive_libs.append(depset(native_libs)) + transitive_libs_non_bc.append(depset(native_libs)) else: fail("Implementation dependencies can only depend on d_library or cc_library targets.", dep) return struct( libs = depset(libs), + libs_bc = depset(libs_bc), + libs_non_bc = depset(libs_non_bc), transitive_libs = depset(transitive = transitive_libs), + transitive_libs_bc = depset(transitive = transitive_libs_bc), + transitive_libs_non_bc = depset(transitive = transitive_libs_non_bc), transitive_d_srcs = depset(d_srcs, transitive = transitive_d_srcs), data = depset(data).to_list(), transitive_data = depset(transitive = transitive_data), @@ -352,6 +381,8 @@ def _d_library_impl_common(ctx, extra_flags = []): data = ctx.files.data, transitive_data = depset(depinfo.data, transitive = [depinfo.transitive_data]), transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), + transitive_libs_bc = depset(transitive = [depinfo.libs_bc, depinfo.transitive_libs_bc]), + transitive_libs_non_bc = depset(transitive = [depinfo.libs_non_bc, depinfo.transitive_libs_non_bc]), link_flags = depinfo.link_flags, linkopts = ctx.attr.linkopts, versions = depinfo.versions, @@ -367,7 +398,7 @@ def _d_library_impl_common(ctx, extra_flags = []): d_lib = ctx.actions.declare_file(ctx.label.name + ".o") d_lib_bc = None if ctx.attr.compile_via_bc: - d_lib_bc = ctx.actions.declare_file(ctx.label.name + ".bc") + d_lib_bc = ctx.actions.declare_file(ctx.label.name + ".bc.o") # Build compile command. compile_args = _build_compile_arglist( @@ -420,7 +451,7 @@ def _d_library_impl_common(ctx, extra_flags = []): ) if d_lib_bc: - # need to compile .bc -> .o in an extra step + # need to compile .bc.o -> .o in an extra step codegen_flags = toolchain.codegen_common_flags + toolchain.codegen_per_mode_flags[ctx.var["COMPILATION_MODE"]] # this is a hack, just hoping there is some llc is not good # TODO: enforce this is only used with toolchain.llc_compiler @@ -448,12 +479,15 @@ def _d_library_impl_common(ctx, extra_flags = []): data = ctx.files.data, transitive_data = depset(depinfo.data, transitive = [depinfo.transitive_data]), transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), + transitive_libs_bc = depset(transitive = [depinfo.libs_bc, depinfo.transitive_libs_bc]), + transitive_libs_non_bc = depset(transitive = [depinfo.libs_non_bc, depinfo.transitive_libs_non_bc]), link_flags = depinfo.link_flags, linkopts = ctx.attr.linkopts, versions = depinfo.versions, imports = depinfo.imports, string_imports = depinfo.string_imports, d_lib = d_lib, + d_lib_bc = d_lib_bc, is_generated = ctx.attr.is_generated, generated_srcs = depinfo.generated_srcs, ), @@ -520,7 +554,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): if d_obj_bc: # TODO: this code is almost exactly the same as in d_library - # need to compile .bc -> .o in an extra step + # need to compile .bc.o -> .o in an extra step codegen_flags = toolchain.codegen_common_flags + toolchain.codegen_per_mode_flags[ctx.var["COMPILATION_MODE"]] # this is a hack, just hoping there is some llc is not good # TODO: enforce this is only used with toolchain.llc_compiler @@ -624,6 +658,8 @@ def _d_source_library_impl(ctx): transitive_data = [] transitive_libs = [] transitive_transitive_libs = [] + transitive_transitive_libs_bc = [] + transitive_transitive_libs_non_bc = [] transitive_imports = depset() transitive_string_imports = depset() transitive_linkopts = depset() @@ -642,6 +678,8 @@ def _d_source_library_impl(ctx): transitive_linkopts = depset(ddep.linkopts, transitive = [transitive_linkopts]) transitive_versions = depset(transitive = [ddep.versions, transitive_versions]) transitive_transitive_libs.append(ddep.transitive_libs) + transitive_transitive_libs_bc.append(ddep.transitive_libs_bc) + transitive_transitive_libs_non_bc.append(ddep.transitive_libs_non_bc) generated_srcs = generated_srcs | ddep.generated_srcs elif CcInfo in dep: @@ -662,6 +700,8 @@ def _d_source_library_impl(ctx): transitive_d_srcs = depset(transitive = transitive_d_srcs, order = "postorder"), transitive_data = depset(transitive = transitive_data, order = "postorder"), transitive_libs = depset(transitive_libs, transitive = transitive_transitive_libs), + transitive_libs_bc = depset(transitive_libs, transitive = transitive_transitive_libs_bc), + transitive_libs_non_bc = depset(transitive_libs, transitive = transitive_transitive_libs_non_bc), imports = [_build_import(ctx.label, im, gen_dir) for im in ctx.attr.imports] + transitive_imports.to_list(), string_imports = [_build_import(ctx.label, im, gen_dir) for im in ctx.attr.string_imports] + transitive_string_imports.to_list(), linkopts = ctx.attr.linkopts + transitive_linkopts.to_list(), From f4266b16774d2700b222f3d29e71dca3308e7ebf Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Tue, 18 Nov 2025 04:13:19 -0500 Subject: [PATCH 91/92] d_binary: add `use_lto` --- d/d.bzl | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/d/d.bzl b/d/d.bzl index 717a80f..a1ef590 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -157,7 +157,11 @@ def _link_order_dict(objs, link_order): def _build_link_arglist(ctx, objs, out, depinfo, c_compiler, link_flags, link_order): """Returns a list of strings constituting the D link command arguments.""" - all_objs = objs + depset(transitive = [depinfo.libs, depinfo.transitive_libs]).to_list() + if not ctx.attr.use_lto: + transitive_libs = [depinfo.libs, depinfo.transitive_libs] + else: + transitive_libs = [depinfo.libs_bc, depinfo.libs_non_bc, depinfo.transitive_libs_bc, depinfo.transitive_libs_non_bc] + all_objs = objs + depset(transitive = transitive_libs).to_list() sorted_objs = _sort_objects(all_objs, _link_order_dict(all_objs, link_order)) return ( _compilation_mode_flags(ctx) + @@ -510,13 +514,12 @@ def _d_binary_impl_common(ctx, extra_flags = []): toolchain.druntime_src.files if toolchain.druntime_src != None else depset(), ] + d_obj_bc = None if ctx.files.srcs: - d_obj_bc = None - - if ctx.attr.compile_via_bc: + if ctx.attr.compile_via_bc or ctx.attr.use_lto: if not toolchain.output_bc_flags: - fail("'compile_via_bc' requires a toolchain with 'output_bc_flags' set") - d_obj_bc = ctx.actions.declare_file(ctx.label.name + ".bc") + fail("'compile_via_bc' and 'use_lto' require a toolchain with 'output_bc_flags' set") + d_obj_bc = ctx.actions.declare_file(ctx.label.name + ".bc.o") d_obj = ctx.actions.declare_file(ctx.label.name + (".obj" if _is_windows(ctx) else ".o")) # Build compile command @@ -572,10 +575,11 @@ def _d_binary_impl_common(ctx, extra_flags = []): progress_message = "Compiling bitcode for D binary " + ctx.label.name, ) + obj = d_obj_bc if ctx.attr.use_lto else d_obj # Build link command link_args = _build_link_arglist( ctx = ctx, - objs = [d_obj] if d_obj else [], + objs = [obj] if obj else [], depinfo = depinfo, out = d_bin, c_compiler = toolchain.c_compiler, @@ -583,9 +587,13 @@ def _d_binary_impl_common(ctx, extra_flags = []): link_order = ctx.attr.link_order, ) + if ctx.attr.use_lto: + libs = [depinfo.libs_bc, depinfo.libs_non_bc, depinfo.transitive_libs_bc, depinfo.transitive_libs_non_bc] + else: + libs = [depinfo.libs, depinfo.transitive_libs] link_inputs = depset( - ([d_obj] if d_obj else []) + ([ctx.files.dynamic_symbols[0]] if ctx.files.dynamic_symbols else []), - transitive = [depinfo.libs, depinfo.transitive_libs] + toolchain_files, + ([obj] if obj else []) + ([ctx.files.dynamic_symbols[0]] if ctx.files.dynamic_symbols else []), + transitive = libs + toolchain_files, ) ctx.actions.run( @@ -596,7 +604,7 @@ def _d_binary_impl_common(ctx, extra_flags = []): executable = d_compiler, arguments = link_args, use_default_shell_env = True, - progress_message = "Linking D binary " + ctx.label.name, + progress_message = "Linking " + ("(with LTO) " if ctx.attr.use_lto else "") + "D binary " + ctx.label.name, ) return [ @@ -838,6 +846,7 @@ _d_library_attrs = { _d_binary_attrs = { "dynamic_symbols" : attr.label(allow_files = True), "link_order": attr.label_keyed_string_dict(), + "use_lto": attr.bool(default = False), } # _d_compile_attrs = { From c73b60d994d70571d42e074f2481e8843df42d51 Mon Sep 17 00:00:00 2001 From: "mend-for-github-com[bot]" <50673670+mend-for-github-com[bot]@users.noreply.github.com> Date: Wed, 19 Nov 2025 10:59:31 +0000 Subject: [PATCH 92/92] Add .whitesource configuration file --- .whitesource | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .whitesource diff --git a/.whitesource b/.whitesource new file mode 100644 index 0000000..327ddac --- /dev/null +++ b/.whitesource @@ -0,0 +1,30 @@ +{ + "scanSettings": { + "configMode": "AUTO", + "configExternalURL": "", + "projectToken": "", + "baseBranches": [] + }, + "checkRunSettings": { + "vulnerableCheckRunConclusionLevel": "failure", + "displayMode": "diff", + "useMendCheckNames": true + }, + "issueSettings": { + "minSeverityLevel": "LOW", + "issueType": "DEPENDENCY" + }, + "remediateSettings": { + "workflowRules": { + "enabled": true + } + }, + "imageSettings":{ + "imageTracing":{ + "enableImageTracingPR": false, + "addRepositoryCoordinate": false, + "addDockerfilePath": false, + "addMendIdentifier": false + } + } +} \ No newline at end of file