For example:
lib_a
is an internal library. It exposes interface header alpha.h
.
lib_b
is an API library. It includes alpha.h
in beta.c
and exposes interface header beta.h
which does not include alpha.h
.
exe_c
is a test app that utilizes lib_b
. Since it is "external" to API library lib_b
, it should not have access to internal library lib_a
's headers, namely alpha.h
.
Now, is there a way to prevent the include path of alpha.h
from being added to exe_c
's compilation command-line?
Update 5/24/22: Bazel added an implementation_deps feature.
This is possible with a custom rule and macro.
Here's how you can write a macro my_cc_library
so that you can do something like this
my_cc_library(
name = "b",
hdrs = [
"b.h",
],
srcs = [
"b.cc",
]
impl_deps = [
"//a:a",
],
)
And targets that depend on b
will not be able to include headers from dependency a
.
Add a custom rule that takes a base library and forms a new CcInfo provider with only the headers you want to expose.
def _my_cc_slim_library(ctx):
cc_info = ctx.attr.base_library[CcInfo]
compilation_ctx = cc_info.compilation_context
compilation_ctx_p = cc_common.create_compilation_context(
headers = depset(direct=ctx.files.hdrs),
includes = compilation_ctx.includes,
quote_includes = compilation_ctx.quote_includes,
)
dep_cc_infos = [dep[CcInfo] for dep in ctx.attr.deps]
cc_info_p = cc_common.merge_cc_infos(
cc_infos = [
CcInfo(
compilation_context = compilation_ctx_p,
linking_context = cc_info.linking_context,
)
] + dep_cc_infos,
)
return [cc_info_p]
my_cc_slim_library = rule(
implementation = _my_cc_slim_library,
attrs = {
"base_library": attr.label(mandatory=True, providers = [CcInfo]),
"hdrs": attr.label_list(allow_files=True),
"deps": attr.label_list(providers = [CcInfo]),
},
)
Add the custom macro my_cc_library
. This macro will create a base library and then use the rule my_cc_slim_library
to strip out the unwanted header dependencies.
def my_cc_library(
name,
hdrs = [],
deps = [],
impl_deps = [],
**kwargs):
native.cc_library(
name = name + "-base",
hdrs = hdrs,
deps = deps + impl_deps,
**kwargs)
my_cc_slim_library(
name = name,
hdrs = hdrs,
base_library = name + "-base",
deps = deps,
)
Now here's how to use it in the example.
bazel/my_cc_library.bzl
<- contains the custom rule and macro
a/a.h
int do_a();
a/a.cc
#include "a/a.h"
int do_a() {
return 1;
}
a/BUILD
package(default_visibility = ["//visibility:public"])
cc_library(
name = "a",
hdrs = [
"a.h",
],
srcs = [
"a.cc",
],
)
b/b.h
int do_b();
b/b.cc
#include "a/a.h"
int do_b() {
return do_a() + 2;
}
b/BUILD
load(
"//bazel:my_cc_library.bzl",
"my_cc_library",
)
package(default_visibility = ["//visibility:public"])
my_cc_library(
name = "b",
hdrs = [
"b.h",
],
srcs = [
"b.cc",
],
impl_deps = [
"//a:a",
],
)
main.cc
#include <iostream>
// #include "a/a.h" <- this would cause an error
#include "b/b.h"
int main() {
std::cout << do_b() << std::endl;
return 0;
}
BUILD
cc_binary(
name = "exe",
srcs = [
"main.cc",
],
deps = [
"//b:b",
],
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With