Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

generate implicit _java import targets for every scala_library as an alternative to scala_export_to_java #115

Closed
wants to merge 1 commit into from

Conversation

ghost
Copy link

@ghost ghost commented Dec 2, 2016

I have spent some time benchmarking the bazel build of our internal Java/Scala codebase and came to the conclusion that a big chunk of our build time is spent generating deploy JARs of Scala targets caused by scala_export_to_java rules. Since a deploy JAR includes all transitive dependencies of a Scala target, having lots of these nodes in our dependency graphs essentially makes our build quadratic instead of linear. Further, having a deploy JAR as a dependency of a java_library rule also means that instantiation's dependencies have to be way less strict, since chances are good they can be already found somewhere in the transitive dependencies, and bazel can't force people to add them.

As a consequence, I've implemented the attached hack that allows us to bypass generating these deploy JARs, and also has the nice side effect of forcing much more strict dependencies when Java depends on Scala. The gist of it is that I've made scala_library into a macro that doesn't just instantiate the original scala_library rule, but also implicitly generates a java_import target that can be used from other java_* rules while still exporting all necessary Scala exports required. Since the scala_library might depend on other java_library rules itself, however, I had to make bazel "forget" about the JAR outs of those rules, since otherwise the native Java rule implementation in bazel complains about the fact that a java_* rule has a dependency on the JAR out of a java_library rule instead of on that target itself. I implemented that by piping every export and runtime dependency of the scala_library through a no-op genrule which I lovingly dubbed "making a yolocopy". Note that for all of this to work out in the end, I also had to adjust the names of the JAR outs of the scala_* rules so they exactly match the ones of the java_* rules, since my macro has no way of knowing whether such a dependency is Java or Scala just from its target name string.

Using this hack improved the build time of our mixed Java/Scala codebase from 358s to 161s on my laptop, which is a more than 2x speedup. Note that I timed this from a cold cache and with the persistent scalac worker activated. To give you some idea of the codebase, we have 424 Scala source files in 148 scala_library targets and 276 Java source files in 109 java_library targets.

I'm putting this PR up mainly for reference and to give an idea on what is currently needed to get a linear complexity mixed Java/Scala build, and I certainly don't expect this to get merged in the presented hacky form. However, the speedup we got is so significant that we have started using this internally, so if somebody has ideas of how to do this in a less hacky way, please shout :)

…alternative to the very expensive scala_export_to_java
@googlebot
Copy link

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed, please reply here (e.g. I signed it!) and we'll verify. Thanks.


  • If you've already signed a CLA, it's possible we don't have your GitHub username or you're using a different email address. Check your existing CLA data and verify that your email is set on your git commits.
  • If you signed the CLA as a corporation, please let us know the company's name.

@bazel-io
Copy link
Member

bazel-io commented Dec 2, 2016

Can one of the admins verify this patch?

@dinowernli
Copy link
Contributor

cc @johnynek @smparkes @petemounce

Based on the massive impact this has had, we've actually decided to merge this into our fork of the scala rules. However, there may very well be a nicer way of doing this. Does anybody have any thoughts?

@johnynek
Copy link
Member

johnynek commented Dec 2, 2016

Interesting approach.

My hope is that the work that is mentioned here:
bazelbuild/bazel#970

specifically the API for making a java provider, ships in the next release of bazel. Then we can do this totally first class and have any native java rule depend on the scala rules. Since you have this work around, I'd rather not merge if we have that hope (though they don't commit to a timespan except to say they are coding now).

Note this PR also relates to #57

@ittaiz
Copy link
Member

ittaiz commented Dec 2, 2016 via email

@johnynek
Copy link
Member

With #227 you should be able to have standard java targets depend on scala. Please reopen if you find any issues with the latest.

@johnynek johnynek closed this Jun 29, 2017
@ghost
Copy link
Author

ghost commented Jun 29, 2017

Thanks a lot for pinging me here @johnynek - I will upgrade to 0.5.2 and try to migrate to the new rules - much looking forward to this working natively without hacks!

@ghost
Copy link
Author

ghost commented Aug 4, 2017

We successfully upgraded our build to bazel 0.5.3 and the new version of the Scala rules. Everything seems to work nicely so far and build times are the same compared to using the attached hack (i.e. not quadratic), so we no longer need it at all.

Thanks a lot for fixing this issue, it is highly appreciated!

@johnynek
Copy link
Member

johnynek commented Aug 5, 2017

@improbafabian nice to hear! Seems like things are working well these days.

I think the main issue open is cross compilation (or at least easily targeting a particular scala version)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants