Add a new parameter to rule cc_library: compile_only_deps. It should work as described in document Bazel finer grained C++ dependency types:
These are only used to compile .cc files. Linking semantics are the same as with 'deps'.
Example: Say that you have the following libraries:
cc_binary(
name = "a",
srcs = ["a.cc"],
deps = [":b"],
)
cc_library(
name = "b",
srcs = ["b.cc"],
compile_only_deps = [":c"],
deps = [":d"],
)
cc_library(
name = "c",
hdrs = ["c.h"],
)
cc_library(
name = "d",
hdrs = ["d.h"],
)
The compile_only_deps in "b" is only used when compiling "b.cc". It is not used transitively when compiling "a.cc". In other words, when compiling "b.cc" the compiler sees both "c.h" and "d.h". When compiling "a.cc", the compiler only sees "d.h".
If the public headers in your library have a dependency, use deps. If only the source files in your library have a dependency, use compile_only_deps.
The problem is that deps might leak headers to other libraries. If only the source files in your cc_library need a dependency, this dependency should not be exposed to other libraries that depend on you. The new parameter 'compile_only_deps' makes it possible to avoid this problem.
I know that the recommendation is to only include headers from direct dependencies, but since bazel does not enforce this today, there is a risk that you by mistake include headers from a transitive dependency that you should not be allowed to see.
This problem has been discussed in the bazel-discuss Google group. (There I called compiled_only_deps "private dependencies").
compile_only_deps used to be available in bazel. See Marcel Hlopko’s post in the above link. Back then bazel distinguished between “interface deps” and “implementation deps”, but deps and compile_only_deps seem to be the new terminology. The long term plan seems to be to let bazel detect compile_only_deps automatically, but it requires clang modules, layering_check and include scanning. It will take time before all this is in place, and probably even more time before clang modules can be enabled for our code base. We need the compile_only_deps parameter as an intermediate solution.
Compile-only dependencies is a common feature in other build systems. One example is GN, the build system in Chromium. There parameter 'deps' means compile_only_deps, and 'public_deps' means deps.
Another user, George Gensure, has implemented support for compile-only deps in an older bazel fork. My work group is also willing to implement this feature.
Does the new compile_only_deps parameter has any impact on the bazel query language? I guess that compile_only_deps should be treated like deps in queries, for instance in somepath(...) or allpaths(...) queries, but I am not sure.
Another question in my work group is if compile_only_deps has any impact on cyclic dependencies. Should a -> b -> c -> a always be handled the same as other cycles if dependency c -> a is a compile_only_deps?
Magnus,
Can https://docs.bazel.build/versions/master/be/c-cpp.html#hdrs help?
Can https://docs.bazel.build/versions/master/be/c-cpp.html#hdrs help?
Hmm, I don't see how. May I ask you to elaborate on how the "hdrs" parameter can solve the problem?
@werkt, you mentioned that you might polish your "impl_deps" implementation and create a PR (However, you will need to rename "impl_deps" to "compile_only_deps".) Do you think that this is possible? My work group would be very thankful :)
Yes, although there were some substantial changes that are hampering me (both internally and externally) from getting this up to HEAD of master. I will see what I can do, as I've wanted this in place for a while.
That sounds awesome. Thanks for trying to get this into master!
Thank you George!
Most helpful comment
8482 - a little later than I would have liked, but applied to master with test