Search code examples
windowsdllbazelldbazel-cpp

Bazel. Building and linking .dll under Windows 11 using custom MinGW toolchain


I'm trying to build dynamic library, then build executable, then link them together using Bazel. The toolchain is custom and uses MinGW ucrt64 GCC tools under Windows 11 Pro.

My BUILD file:

DLL_HDRS = ["math_import_defs.h", "math_dll_interface.h"]

load("//main:dll_library.bzl", "dll_library")

cc_binary(
    name = "sum_numbers_mingw",
    srcs = ["main.cpp"] + DLL_HDRS, 
    dynamic_deps = [":math_d_shared"]                   
)

dll_library(
    name = "math_d",
    srcs = ["math_dll_interface.cpp"],
    hdrs = DLL_HDRS,
    deps = [":math"],
    defines = ["MATH_DLL"]
)

cc_library(
    name = "math",
    srcs = ["math.cpp"],
    hdrs = ["math.h"],
    copts = ["-std=c++17"]
)

.bzl file with dll_library definition:

load("@rules_cc//cc:defs.bzl", "cc_library")
load("@rules_cc//examples:experimental_cc_shared_library.bzl", "cc_shared_library")

def dll_library(
        name,
        srcs = [],
        deps = [],
        hdrs = [],
        visibility = None,
        **kwargs):               
    static_library_name = name + "_static"
    dll_lib_name = name + "_shared"
    
    cc_library(
        name = static_library_name,
        srcs = srcs,
        hdrs = hdrs,
        deps = deps,        
        **kwargs
    )
    
    cc_shared_library(
        name = dll_lib_name,                        
        deps = [":" + static_library_name] 
    )

Everything goes fine until ld receives -lmath_d_shared option:

C:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lmath_d_shared: No such file or directory

This is because cc_shared_library generates libmath_d_shared.so library, but ld doesn't look for .so under Windows. Renaming library to libmath_d_shared.dll and running build again without deletion of previously generated targets solves the problem. ld finds libmath_d_shared.dll and everything works as expected.

Tried to tweak my toolchain by additional:

artifact_name_pattern(
    category_name = "dynamic_library",
    prefix = "lib",
    extension = ".dll",
)

in the artifact_name_patterns field.

It forces Bazel to add extension .dll to all generated dynamic libraries. But, for some reason, Bazel doesn't remove suffix .dll from library name while passing -l option to ld. So it passes -lmath_d_shared.dll option. Then ld can't find the library, because file libmath_d_shared.dll.dll doesn't exist.

Looking for workaround for this case. I need to, either fix the library name stripping process prior passing -l option to ld, or to implement renaming my library from .so to .dll automatically before linking with executable.

Appreciate any help. Thanks.


Solution

  • Got this fixed by creating this pull request. Merged into bazel release 7.1.0 here.