Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions d/private/rules/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@ bzl_library(
deps = ["//d/private/rules:common"],
)

bzl_library(
name = "cc_toolchain",
srcs = ["cc_toolchain.bzl"],
visibility = [
"//d:__subpackages__",
"//docs:__subpackages__",
],
deps = [
"@rules_cc//cc:action_names_bzl",
"@rules_cc//cc:find_cc_toolchain_bzl",
"@rules_cc//cc/common",
],
)

bzl_library(
name = "common",
srcs = ["common.bzl"],
Expand All @@ -24,6 +38,7 @@ bzl_library(
],
deps = [
"//d/private:providers",
"//d/private/rules:cc_toolchain",
"@bazel_lib//lib:expand_make_vars",
"@bazel_skylib//lib:dicts",
"@bazel_skylib//lib:paths",
Expand All @@ -38,7 +53,10 @@ bzl_library(
"//d:__subpackages__",
"//docs:__subpackages__",
],
deps = ["//d/private/rules:common"],
deps = [
"//d/private/rules:common",
"@rules_cc//cc:find_cc_toolchain_bzl",
],
)

bzl_library(
Expand All @@ -48,5 +66,8 @@ bzl_library(
"//d:__subpackages__",
"//docs:__subpackages__",
],
deps = ["//d/private/rules:common"],
deps = [
"//d/private/rules:common",
"@rules_cc//cc:find_cc_toolchain_bzl",
],
)
4 changes: 3 additions & 1 deletion d/private/rules/binary.bzl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""D test rule for compiling binaries."""

load("@rules_cc//cc:find_cc_toolchain.bzl", "use_cc_toolchain")
load("//d/private/rules:common.bzl", "TARGET_TYPE", "compilation_action", "runnable_attrs")

def _d_binary_impl(ctx):
Expand All @@ -9,6 +10,7 @@ def _d_binary_impl(ctx):
d_binary = rule(
implementation = _d_binary_impl,
attrs = runnable_attrs,
toolchains = ["//d:toolchain_type"],
toolchains = ["//d:toolchain_type"] + use_cc_toolchain(),
fragments = ["cpp"],
executable = True,
)
95 changes: 95 additions & 0 deletions d/private/rules/cc_toolchain.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""
Helper functions to extract the C++ toolchain and linker options for linking.
"""

load("@rules_cc//cc:action_names.bzl", "CPP_LINK_EXECUTABLE_ACTION_NAME")
load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain")
load("@rules_cc//cc/common:cc_common.bzl", "cc_common")

_UNSUPPORTED_FEATURES = [
# These toolchain features require special rule support and will thus break
# with D.
# Taken from rules_go
"thin_lto",
"module_maps",
"use_header_modules",
"fdo_instrument",
"fdo_optimize",
# This is a nonspecific unsupported feature which allows the authors of C++
# toolchain to apply separate flags when compiling D code.
"rules_d_unsupported_feature",
]

_LINKER_OPTIONS_DENYLIST = {
# Don't link C++ libraries
"-lstdc++": None,
"-lc++": None,
"-lc++abi": None,
# libm and libobjc are added by the D compiler already, so suppress them here, to avoid warnings
"-lm": None,
"-lobjc": None,
"-fobjc-link-runtime": None,
# --target is passed by the D compiler
"--target=": None,
# --target passed by the D compiler conflicts with -mmacosx-version-min set by cc_toolchain
"-mmacosx-version-min=": None,
}

def _match_option(option, pattern):
if pattern.endswith("="):
return option.startswith(pattern)
else:
return option == pattern

def _filter_options(options, denylist):
return [
option
for option in options
if not any([_match_option(option, pattern) for pattern in denylist])
]

def find_cc_toolchain_for_linking(ctx):
"""
Find the C++ toolchain and linker options for linking.

Args:
ctx: The rule context
Returns:
A struct with the following fields:
- cc_toolchain: The C++ toolchain
- cc_compiler: The C/C++ compiler
- cc_linking_options: The linker options
- env: The environment variables to set for the linker
"""
cc_toolchain = find_cc_toolchain(ctx)
feature_configuration = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain,
unsupported_features = _UNSUPPORTED_FEATURES,
)
linker_variables = cc_common.create_link_variables(
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
is_linking_dynamic_library = False,
)
cc_compiler = cc_common.get_tool_for_action(
feature_configuration = feature_configuration,
action_name = CPP_LINK_EXECUTABLE_ACTION_NAME,
)
cc_linking_options = _filter_options(cc_common.get_memory_inefficient_command_line(
feature_configuration = feature_configuration,
action_name = CPP_LINK_EXECUTABLE_ACTION_NAME,
variables = linker_variables,
), _LINKER_OPTIONS_DENYLIST)
env = cc_common.get_environment_variables(
feature_configuration = feature_configuration,
action_name = CPP_LINK_EXECUTABLE_ACTION_NAME,
variables = linker_variables,
)

return struct(
cc_toolchain = cc_toolchain,
cc_compiler = cc_compiler,
cc_linking_options = cc_linking_options,
env = env,
)
29 changes: 27 additions & 2 deletions d/private/rules/common.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ load("@bazel_skylib//lib:dicts.bzl", "dicts")
load("@bazel_skylib//lib:paths.bzl", "paths")
load("@rules_cc//cc/common:cc_info.bzl", "CcInfo")
load("//d/private:providers.bzl", "DInfo")
load("//d/private/rules:cc_toolchain.bzl", "find_cc_toolchain_for_linking")

D_FILE_EXTENSIONS = [".d", ".di"]

Expand Down Expand Up @@ -37,6 +38,10 @@ runnable_attrs = dicts.add(
{
"env": attr.string_dict(doc = "Environment variables for the binary at runtime. Subject of location and make variable expansion."),
"data": attr.label_list(allow_files = True, doc = "List of files to be made available at runtime."),
"_cc_toolchain": attr.label(
default = "@rules_cc//cc:current_cc_toolchain",
doc = "Default CC toolchain, used for linking. Remove after https://github.com/bazelbuild/bazel/issues/7260 is flipped (and support for old Bazel version is not needed)",
),
},
)

Expand Down Expand Up @@ -142,6 +147,8 @@ def compilation_action(ctx, target_type = TARGET_TYPE.LIBRARY):
args.add_all(toolchain.linker_flags)
args.add_all(linker_flags.to_list(), format_each = "-L=%s")
output = None
cc_toolchain = None
env = ctx.var
if target_type in [TARGET_TYPE.BINARY, TARGET_TYPE.TEST]:
for dep in d_deps:
args.add_all(dep.libraries)
Expand All @@ -150,6 +157,23 @@ def compilation_action(ctx, target_type = TARGET_TYPE.LIBRARY):
args.add_all(["-main", "-unittest"])
output = ctx.actions.declare_file(_binary_name(ctx, ctx.label.name))
args.add(output, format = "-of=%s")
cc_linker_info = find_cc_toolchain_for_linking(ctx)
env = dict(cc_linker_info.env)
env.update({
"CC": cc_linker_info.cc_compiler, # Have to use the env variable here, since DMD doesn't support -gcc= flag
# Ok, this is a bit weird. Local toolchain from rules_cc works fine if we don't set PATH here.
# But doesn't work if we set it to an empty string.
# OTOH the toolchain from toolchains_llvm doesn't work without setting PATH here. (Can't find the linker executable)
# Even though the cc_wrapper script adds "/usr/bin" to the PATH variable,
# it only works if the PATH is already in the environment. (I think they have to `export`)
# So toolchains_llvm works if we set PATH to "" but doesn't work if we don't set it at all.
# So, to get to a common ground, we set PATH to something generic.
"PATH": "/bin:/usr/bin:/usr/local/bin",
})
if _get_os(ctx) != "windows":
# DMD doesn't support -Xcc on Windows
args.add_all(cc_linker_info.cc_linking_options, format_each = "-Xcc=%s")
cc_toolchain = cc_linker_info.cc_toolchain
elif target_type == TARGET_TYPE.LIBRARY:
args.add("-lib")
output = ctx.actions.declare_file(_static_library_name(ctx, ctx.label.name))
Expand All @@ -169,11 +193,12 @@ def compilation_action(ctx, target_type = TARGET_TYPE.LIBRARY):

ctx.actions.run(
inputs = inputs,
tools = [cc_toolchain.all_files] if cc_toolchain else [],
outputs = [output],
executable = toolchain.d_compiler[DefaultInfo].files_to_run,
arguments = [args],
env = ctx.var,
use_default_shell_env = target_type != TARGET_TYPE.LIBRARY, # True to make the linker work properly
env = env,
use_default_shell_env = False,
mnemonic = "Dcompile",
progress_message = "Compiling D %s %s" % (target_type, ctx.label.name),
)
Expand Down
4 changes: 3 additions & 1 deletion d/private/rules/test.bzl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""D test rule for compiling and running D unit tests."""

load("@rules_cc//cc:find_cc_toolchain.bzl", "use_cc_toolchain")
load("//d/private/rules:common.bzl", "TARGET_TYPE", "compilation_action", "runnable_attrs")

def _d_test_impl(ctx):
Expand All @@ -9,6 +10,7 @@ def _d_test_impl(ctx):
d_test = rule(
implementation = _d_test_impl,
attrs = runnable_attrs,
toolchains = ["//d:toolchain_type"],
toolchains = ["//d:toolchain_type"] + use_cc_toolchain(),
fragments = ["cpp"],
test = True,
)
Loading