Replacing a cc_library from cc_binary?

482 views
Skip to first unread message

Magnus Andersson

unread,
Aug 24, 2017, 10:28:55 AM8/24/17
to bazel-discuss
Hi,

I am investigating replacing a GNU Make-based build system for a large C code base with Bazel. There is one feature in our current build system that seems to be missing from Bazel:

In a cc_library, is it possible to replace any cc_library, and its dependencies, in the dependency graph with another cc_library?

Example:

Say that we have the following cc_binary:

  cc_binary(
      name
= "bin",
      deps
= ["lib-a"],
 
)


  cc_library
(
      name
= "lib-a",
      deps
= ["lib-b"],
 
)


  cc_library
(
      name
= "lib-b",
      deps
= ["lib-c"],
 
)


  cc_library
(
      name
= "lib-c",
 
)


Is it possible to replace "lib-b", and its dependency to "lib-c", with another cc_library, say "lib-b-stub", from cc_binary?

  cc_binary(
      name
= "bin",
      deps
= ["lib-a"], replace("lib-b", "lib-b-stub"), # Is something like this possible?
 
)


We need this feature to replace real libraries with stub implementations in our test binaries.

BR,
Magnus

Magnus Andersson

unread,
Aug 28, 2017, 7:54:49 AM8/28/17
to bazel-discuss
I have received some answers via email, and they can be summarized with "No, this is not possible".

I was a bit unclear in my first post. I don't want to replace a direct dependency, but a transitive dependency.

In my example we had this cc_binary:

 cc_binary(
      name
= "bin",
      deps
= ["lib-a"],
 
)

and the following transitive dependencies: lib-a -> lib-b -> lib-c.

I don't want to replace the dependency to "lib-a". Instead I want to replace a dependency further down the chain, like replacing "lib-b" (and "lib-c") with "lib-b-stub".

Do you think this is a feature that we should add to Bazel? We will need it in order to migrate from GNU Make to Bazel.

Marcel Hlopko

unread,
Aug 28, 2017, 8:42:33 AM8/28/17
to Magnus Andersson, bazel-discuss
(readding bazel-discuss after accidentally clicking reply, not reply-all)

The `select` solution requires you to change the lib-a target, yes. Is that a problem? There is no way to do this transitively from the top of the build tree, and I don't think we should add this feature to the bazel C++ rules, unless I'm proven it will be heavily used :) And even then we need to wait for dynamic configurations to be fully implemented.

You can also wait for Skylark C++ api, and implement this behavior in skylark (but that will come in O(months)).

Sorry I don't have a better answer for you...

On Mon, Aug 28, 2017 at 1:46 PM Magnus Andersson <magnus.a...@gmail.com> wrote:
Hi Marcel,

Thanks for your answer! However, I don't think it will solve my issue.

I was a bit unclear in my first post. I don't want to replace a direct dependency, but a transitive dependency.

In my example we had this cc_binary:

  cc_binary(
      name 
= "bin",
      deps 
= ["lib-a"],
  
)

and the following transitive dependencies: lib-a -> lib-b -> lib-c.

I don't want to replace the dependency to "lib-a". Instead I want to replace a cc_library further down in the dependency chain, like "lib-b" or "lib-c".

I suppose the answer is "No, this is not possible". Do you think that this is a feature that we should add to Bazel? If the community accepts this new feature, a group from my company can implement it.

BR,
Magnus


2017-08-28 12:46 GMT+02:00 Marcel Hlopko <hlo...@google.com>:
Hi Magnus,

You cannot do it in the same way as you were used to right now. What you need is to have multiple configurations in a single build, and that is work in progress (it's a complex problem to make it scale). But if you can live with two separate bazel invocations, you can make it work using select:

config_setting(
    name = "mocked_deps",
    values = {"define": "mocked_deps=true"}
)

cc_binary(
    name = "main",
    srcs = [ "main.cc" ],
    deps = select({
        ":mocked_deps": [":mocked"],
        "//conditions:default": ["real_dep"]
    }),
)

cc_library(
    name = "mocked",
    srcs = [ "mocked.cc" ],
)

cc_library(
    name = "real_dep",
    srcs = [ "real_dep.cc" ],
)

If you run bazel with:

bazel build :main --define=mocked_deps=true     

the mocked dep is used. If you just run:

bazel build :main 

it will use real dependencies.

Is this what you were trying to accomplish?

--
You received this message because you are subscribed to the Google Groups "bazel-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bazel-discus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/bazel-discuss/c2212e76-6634-4b4c-91b9-17f298c8fcd3%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Marcel Hlopko
--
-- 
Marcel Hlopko | Software Engineer | hlo...@google.com | 

Google Germany GmbH | Erika-Mann-Str. 33  | 80636 München | Germany | Geschäftsführer: Geschäftsführer: Paul Manicle, Halimah DeLaine Prado | Registergericht und -nummer: Hamburg, HRB 86891

--
-- 
Marcel Hlopko | Software Engineer | hlo...@google.com | 

Google Germany GmbH | Erika-Mann-Str. 33  | 80636 München | Germany | Geschäftsführer: Geschäftsführer: Paul Manicle, Halimah DeLaine Prado | Registergericht und -nummer: Hamburg, HRB 86891

Magnus Andersson

unread,
Aug 28, 2017, 9:23:43 AM8/28/17
to bazel-discuss, magnus.a...@gmail.com
Thanks for the answer!

This feature would be heavily used within my company, and we are prepared to implement it in Bazel if you change your mind and think it should be added.

BR,
Magnus

pehe...@gmail.com

unread,
Aug 29, 2017, 2:17:15 AM8/29/17
to bazel-discuss
Hi!
Maybe it can be done with an extra_action that overwrites the original output? Then you can replace the original implementation with the stub.
Are there any plans in Bazel to allow extra_action from BUILD files directly instead of via the command line?
/Peter

Marcel Hlopko

unread,
Aug 30, 2017, 3:08:40 AM8/30/17
to pehe...@gmail.com, bazel-discuss
Hi,

extra actions cannot overwrite the original output, and I don't think they should.

There are no plans to enable extra actions from BUILD file because nobody asked for it yet :)

--
You received this message because you are subscribed to the Google Groups "bazel-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bazel-discus...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
--

pehe...@gmail.com

unread,
Aug 30, 2017, 3:21:56 AM8/30/17
to bazel-discuss, pehe...@gmail.com
Ok thanks for the information.
So there is no way to stub a component in transitive dependent component?
We think it would be a good feature, like in e.g. bitbake with append recipes.
/Peter

Marcel Hlopko

unread,
Aug 30, 2017, 3:45:10 AM8/30/17
to pehe...@gmail.com, bazel-discuss
At the moment, only the select approach I described before. And/or having separate targets with mocked and real deps, maybe created using macros.

In general these features affecting transitive dependencies have a potential risk in large codebases. They require global knowledge of the entire dependency graph, and if that is even manageable, they break very often. That's why we prefer not to introduce these feature if possible.

To me, the select approach seems preferable - the decision what is mocked is made right in the target that depends on the 'mockable' library, not somewhere far away.

Another approach could be to rearrange your dependencies and require cc_test to depend on all 'mockable' libraries directly, so you can use mocked variants where appropriate.


For more options, visit https://groups.google.com/d/optout.

pehe...@gmail.com

unread,
Aug 30, 2017, 4:41:10 AM8/30/17
to bazel-discuss, pehe...@gmail.com
Ok thank you for the replay,
Peter
Reply all
Reply to author
Forward
0 new messages