Skip to content

Commit

Permalink
Add the Windows import library to the providers when building a cdylib (
Browse files Browse the repository at this point in the history
#1044)

Co-authored-by: UebelAndre <github@uebelandre.com>
  • Loading branch information
ddeville and UebelAndre committed Dec 6, 2021
1 parent 7ef755b commit cbfffbc
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 5 deletions.
21 changes: 17 additions & 4 deletions rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -777,10 +777,21 @@ def rustc_compile_action(
else:
formatted_version = ""

outputs = [crate_info.output]

# For a cdylib that might be added as a dependency to a cc_* target on Windows, it is important to include the
# interface library that rustc generates in the output files.
interface_library = None
if toolchain.os == "windows" and crate_info.type == "cdylib":
# Rustc generates the import library with a `.dll.lib` extension rather than the usual `.lib` one that msvc
# expects (see https://github.com/rust-lang/rust/pull/29520 for more context).
interface_library = ctx.actions.declare_file(crate_info.output.basename + ".lib")
outputs.append(interface_library)

ctx.actions.run(
executable = ctx.executable._process_wrapper,
inputs = compile_inputs,
outputs = [crate_info.output],
outputs = outputs,
env = env,
arguments = args.all,
mnemonic = "Rustc",
Expand All @@ -806,20 +817,20 @@ def rustc_compile_action(
dep_info,
DefaultInfo(
# nb. This field is required for cc_library to depend on our output.
files = depset([crate_info.output]),
files = depset(outputs),
runfiles = runfiles,
executable = crate_info.output if crate_info.type == "bin" or crate_info.is_test or out_binary else None,
),
]
if toolchain.target_arch != "wasm32":
providers += establish_cc_info(ctx, attr, crate_info, toolchain, cc_toolchain, feature_configuration)
providers += establish_cc_info(ctx, attr, crate_info, toolchain, cc_toolchain, feature_configuration, interface_library)

return providers

def _is_dylib(dep):
return not bool(dep.static_library or dep.pic_static_library)

def establish_cc_info(ctx, attr, crate_info, toolchain, cc_toolchain, feature_configuration):
def establish_cc_info(ctx, attr, crate_info, toolchain, cc_toolchain, feature_configuration, interface_library):
"""If the produced crate is suitable yield a CcInfo to allow for interop with cc rules
Args:
Expand All @@ -829,6 +840,7 @@ def establish_cc_info(ctx, attr, crate_info, toolchain, cc_toolchain, feature_co
toolchain (rust_toolchain): The current `rust_toolchain`
cc_toolchain (CcToolchainInfo): The current `CcToolchainInfo`
feature_configuration (FeatureConfiguration): Feature configuration to be queried.
interface_library (File): Optional interface library for cdylib crates on Windows.
Returns:
list: A list containing the CcInfo provider
Expand Down Expand Up @@ -877,6 +889,7 @@ def establish_cc_info(ctx, attr, crate_info, toolchain, cc_toolchain, feature_co
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
dynamic_library = crate_info.output,
interface_library = interface_library,
)
else:
fail("Unexpected case")
Expand Down
3 changes: 2 additions & 1 deletion test/unit/cc_info/cc_info_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ def _assert_cc_info_has_library_to_link(env, tut, type, ccinfo_count):

if type == "cdylib":
asserts.true(env, library_to_link.dynamic_library != None)
asserts.equals(env, None, library_to_link.interface_library)
if _is_dylib_on_windows(env.ctx):
asserts.true(env, library_to_link.interface_library != None)
asserts.true(env, library_to_link.resolved_symlink_dynamic_library == None)
else:
asserts.equals(env, None, library_to_link.interface_library)
asserts.true(env, library_to_link.resolved_symlink_dynamic_library != None)
asserts.equals(env, None, library_to_link.resolved_symlink_interface_library)
asserts.equals(env, None, library_to_link.static_library)
Expand Down
4 changes: 4 additions & 0 deletions test/unit/win_interface_library/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
load(":win_interface_library_analysis_test.bzl", "win_interface_library_analysis_test_suite")

############################ UNIT TESTS #############################
win_interface_library_analysis_test_suite(name = "win_interface_library_analysis_test_suite")
6 changes: 6 additions & 0 deletions test/unit/win_interface_library/bin.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
extern "C" void hello(void);

int main(int argc, char **argv) {
hello();
return 0;
}
4 changes: 4 additions & 0 deletions test/unit/win_interface_library/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#[no_mangle]
pub extern "C" fn hello() {
println!("Hello");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""Analysis tests for exporting the Windows interface library."""

load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
load("@rules_cc//cc:defs.bzl", "cc_binary")
load("//rust:defs.bzl", "rust_shared_library")

def _win_interface_library_test_impl(ctx):
env = analysistest.begin(ctx)
target = analysistest.target_under_test(env)

files = target[DefaultInfo].files.to_list()
cc_library = target[CcInfo].linking_context.linker_inputs.to_list()[0].libraries[0]

# Make sure that we have both the `.dll` and the `.dll.lib` file in the default info's files
asserts.equals(env, len(files), 2)
asserts.true(env, files[0].basename.endswith(".dll"))
asserts.true(env, files[1].basename.endswith(".dll.lib"))

# Make sure that the cc_library has both a dynamic and interface library
asserts.true(env, cc_library.dynamic_library != None)
asserts.true(env, cc_library.interface_library != None)

return analysistest.end(env)

win_interface_library_test = analysistest.make(_win_interface_library_test_impl)

def win_interface_library_analysis_test_suite(name):
"""Analysis tests for exporting the Windows interface library.
Args:
name: the test suite name
"""
rust_shared_library(
name = "mylib",
srcs = ["lib.rs"],
target_compatible_with = ["@platforms//os:windows"],
)

cc_binary(
name = "mybin",
srcs = ["bin.cc"],
deps = [":mylib"],
target_compatible_with = ["@platforms//os:windows"],
)

win_interface_library_test(
name = "win_interface_library_test",
target_under_test = ":mylib",
target_compatible_with = ["@platforms//os:windows"],
)

native.test_suite(
name = name,
tests = [":win_interface_library_test"],
)

0 comments on commit cbfffbc

Please sign in to comment.