Conditional compilation based on presence of external library

1,348 views
Skip to first unread message

glin...@gmail.com

unread,
Apr 6, 2016, 2:38:21 PM4/6/16
to bazel-discuss
We have a library which is limited to a certain number of seats by license, so only some developers can have it installed.

What is the best mechanism for handling this in bazel? We looked at environments, which didn't seem to quite fit. config_setting() with --define command line almost works, but the problem is we need a way to stop the WORKSPACE from looking for the library.

Any suggestions?

Thanks!

Alex Humesky

unread,
Apr 6, 2016, 3:35:49 PM4/6/16
to glin...@gmail.com, bazel-discuss
You say that the library gets installed, so are you getting the library into your build through a local_repository or new_local_repository rule in your workspace file? What should happen when that library isn't available (i.e., how does the code compile)? e.g., do you have a dummy implementation somewhere?

One idea might be to use a  bind() rule to bind a target (the target that rules in your repo will use) to the local_repository or new_local_repository that pulls in the library when the library is present, or if it's not, bind it to a target in dummy implementation package (which can live in your repo). I'm not sure how you would nicely switch between the real implementation and the dummy implementation without having to edit your workspace file.

Another idea would be to create a skylark repository rule:
It could check for the presence of the library, and if it's there, use the real implementation / BUILD file, and if it's not, create a dummy BUILD file / implementation.

--
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/cee084b2-95c0-4001-a694-bacacd93408b%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

glin...@gmail.com

unread,
Apr 6, 2016, 3:50:15 PM4/6/16
to bazel-discuss, glin...@gmail.com
The library comes in through new_local_repository currently. The goal is that if the library is unavailable, all packages that depend on it should not be built. There is no dummy implementation.

Changing the workspace manually is not really an option, as we want to run one version of the workspace for everyone.

repository_rule looks promising, thanks! Will try that out and report back.

Alex Humesky

unread,
Apr 6, 2016, 4:00:35 PM4/6/16
to glin...@gmail.com, bazel-discuss
I see, so the problem is that, even though it's fine for the code to fail to compile if the library isn't there, the workspace file fails because it looks for the library (the directory?) with new_local_repository?

glin...@gmail.com

unread,
Apr 6, 2016, 4:16:27 PM4/6/16
to bazel-discuss, glin...@gmail.com
Yes, exactly. Basically if you don't have the library installed, we want bazel to ignore things that depend on it.

Brian Silverman

unread,
Apr 7, 2016, 1:20:40 PM4/7/16
to glin...@gmail.com, bazel-discuss
We have a somewhat similar problem: we want Bazel to ignore some targets under certain combinations of --compiler=, --config=, etc. Our current solution is a wrapper script around the bazel command which basically appends $(bazel query 'let universe = deps(//...) in rdeps($universe, attr("tags", "(\[|, )(exclude_tag_a|exclude_tag_b)(\]|, )", $universe))' | sed 's/^/-/g') to the command line. I think you could do something similar by marking dummy targets created by your custom repository_rule with a tag and doing a query like that to exclude all of them from builds.

There are currently a few downsides to this approach: it requires using some kind of wrapper script (which could be tools/bazel if you're careful, but still), and it means having to load many various packages before the actual build command starts, which slows it down. You could make the package loading issue better by parsing the command line and restricting //... in the deps(//...) to something more specific, but that's kind of hard to do correctly. I think that at some point it might make sense to integrate this "ignore targets with any of these tags" functionality more directly to remove the need for a separate query. Does anybody else have comments on adding that?

Damien Martin-guillerez

unread,
Apr 7, 2016, 5:14:32 PM4/7/16
to Brian Silverman, glin...@gmail.com, bazel-discuss
We already have --test_tag_filters for test, imo it would be logical to have --build_tag_flters too

Alex Humesky

unread,
Apr 7, 2016, 5:29:30 PM4/7/16
to Damien Martin-guillerez, Brian Silverman, glin...@gmail.com, bazel-discuss
I was about to send the following:
The issue is slightly different I think. If you have a rule that looks for files that don't exist, bazel won't give an error so long as you don't try to build that rule or anything that depends on it. That's different from a new_local_repository or local_repository rule, which will fail if the directory doesn't exist.

Then thought I better actually test it, and it does appear that even if you put a rule like this in your workspace file:

new_local_repository(
  name = "foo",
  path = "/foo/bar", # doesn't exist
  build_file_content = "")

bazel won't give an error unless you actually try to use the repository or something that depends on it. So I'm not sure that I understand the question anymore.
Is your question that you want to do things like "bazel build //..." and have it ignore things that depend on the failing repository?
You could try subtracting the packages that would fail, "bazel build -- //... -//package/that/would/fail/...", which might not be too bad if you don't have to subtract too many packages.
Or you could build specific targets that don't depend on the library.

Brian Silverman

unread,
Apr 7, 2016, 5:41:57 PM4/7/16
to Alex Humesky, Damien Martin-guillerez, glin...@gmail.com, bazel-discuss
'"bazel build //..." and have it ignore things that depend on the failing repository' is exactly what I want to do, and I think it's the same thing as @glinscott. The problem with the -//package/that/would/fail/... approach is you have to exclude any other packages which depend on the problematic one(s) transitively too, which I've found to be unmaintainable pretty quickly.

Also, I really like the ability to say "test everything that's supported", which rules out specifying specific targets.

A --build_tag_filters flag which excludes any targets with the specified tags (and their reverse dependencies) would work great for me.
Reply all
Reply to author
Forward
0 new messages