3. I use a mingw toolchain for windows, and mingw does not necessarily require an interface library to import a dll. The requirement that all shared_libraries in a cc_import must have an interface_library on windows (activated by targets_windows feature), instead becomes an obstacle.
To mend problem 1., i used the "manual" tag, and use a cc_library in the end that depends on the linux or windows shared library chain.
To fix problem 2, i had to create a rule that can select one output from many.
And to fix problem 3. I use mingw:s dlltool.exe to create an interface library for me.
# A function that selects one output from many
load(":select_files.bzl", "select_files")
# A function that creates a .def file from a list of inputs.
load(":win_def_file.bzl", "win_def_file")
# A function that creates a MinGW interface library.
load("interface_library.bzl", "interface_library")
# This is a simple cc_shared_library rule for building a DLL Windows
# and building a .so for unix, that can be depended on by other cc rules.
#
# Example usage:
# cc_shared_library(
# name = "hellolib",
# srcs = [
# "hello-library.cpp",
# ],
# hdrs = ["hello-library.h"],
# # Define COMPILING_DLL to export symbols during compiling the DLL.
# copts = ["/DCOMPILING_DLL"],
# )
#
def cc_shared_library(
name,
srcs = [],
hdrs = [],
exports = [],
visibility = None,
**kwargs):
so_name = name + ".so"
dll_name = name + ".dll"
exports_name = name + "_exports"
import_lib_name_msvc = name + "_import_lib_msvc"
import_lib_name_mingw = name + "_import_lib_mingw"
import_dll_target_name = name + "_dll_import"
import_so_target_name = name + "_so_import"
select_dll_name = name + "_dll_select"
### Windows ###
# Create a def file for exports.
win_def_file(
name = exports_name,
exports = exports,
tags = ["manual"],
)
# Build the shared library
native.cc_binary(
name = dll_name,
srcs = srcs + hdrs,
linkshared = 1,
win_def_file = ":" + exports_name,
tags = ["manual"],
**kwargs
)
# Get the import library for the dll (always built for MSVC)
native.filegroup(
name = import_lib_name_msvc,
srcs = [":" + dll_name],
output_group = "interface_library",
tags = ["manual"],
)
# Create the interface library for mingw
# (Of course I could build this in my toolchain instead).
interface_library(
name = import_lib_name_mingw,
def_file = ":" + exports_name,
tags = ["manual"],
)
# Select the DLL (might be transitive DLL:s added)
# If I try to select the DLL name, I still get the rule.
select_files(
name = select_dll_name,
srcs = [":" + dll_name],
files = [dll_name],
tags = ["manual"],
)
# Because we cannot directly depend on cc_binary from other cc rules in deps attribute,
# we use cc_import as a bridge to depend on the dll (windows).
native.cc_import(
name = import_dll_target_name,
interface_library = select({
":mingw": ":" + import_lib_name_mingw,
":msvc": ":" + import_lib_name_msvc,
}),
shared_library = ":" + select_dll_name,
tags = ["manual"],
)
### Linux ###
# Linux case, Build the shared library.
native.cc_binary(
name = so_name,
srcs = srcs + hdrs,
linkshared = 1,
tags = ["manual"],
**kwargs
)
# Linux case, just import the shared_library.
native.cc_import(
name = import_so_target_name,
shared_library = ":" + so_name,
tags = ["manual"],
)
### Combined ###
# Create a new cc_library to also include the headers needed for the shared library
native.cc_library(
name = name,
hdrs = hdrs,
visibility = visibility,
deps = select({
":win_x86_32": [":" + import_dll_target_name],
":win_x86_64": [":" + import_dll_target_name],
"//conditions:default": [":" + import_so_target_name],
}),
)