-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
[Feature Request] Add a new "non-transitive" java strict deps enum value #4821
Comments
Not ever adding the transitive dependencies to Java compile actions doesn't work, because javac needs to read the class files in transitive dependencies in some cases (unfortunately, it escapes me what those are :( ) In addition to that, I'd much rather not complicate our Java rules with yet another strict deps mode for something Scala specific. How about making a separate flag for Scala? Even better, it can be just a |
What is a “—define”?
…On Tue, 20 Mar 2018 at 15:40 lberki ***@***.***> wrote:
Not ever adding the transitive dependencies to Java compile actions
doesn't work, because javac needs to read the class files in transitive
dependencies in some cases (unfortunately, it escapes me what those are :( )
In addition to that, I'd much rather not complicate our Java rules with
yet another strict deps mode for something Scala specific. How about making
a separate flag for Scala? Even better, it can be just a --define, in
which case this is doable without changing Bazel at all.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#4821 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABUIFyMbgShL03GKyjshRaV2fGcSPcmEks5tgQa8gaJpZM4Slakl>
.
|
The Let's ask @laurentlb what he prefers -- adding a bespoke command line option to Bazel specifically for Scala (even though Scala is implemented in Skylark) or adding a key-value map? In the long term, the latter is much more preferable, since we'll eventually need to define configuration fragments in Skylark, but we may not want to commit to any specific option on that. And in that case, a single command-line option is much simpler to eventually deprecate. |
Thanks for the explanation.
…On Wed, 21 Mar 2018 at 11:57 lberki ***@***.***> wrote:
The --define Bazel command line option; for better or worse, it allows
one to define $(VAR)-style variables in BUILD files. Mind you, I consider
that as a misfeature, but I thought --define was sufficiently well
entrenched so that another use for it is preferable to adding a command
line option to Bazel for something that's implemented in Skylark. However,
I just realized that it's not available in Skylark.
Let's ask @laurentlb <https://github.com/laurentlb> what he prefers --
adding a bespoke command line option to Bazel specifically for Scala (even
though Scala is implemented in Skylark) or adding a key-value map? In the
long term, the latter is much more preferable, since we'll eventually need
to define configuration fragments in Skylark, but we may not want to commit
to any specific option on that. And in that case, a single command-line
option is much simpler to eventually deprecate.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#4821 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABUIFyC-1bBexvGwmTlRQuihc2yu9kSHks5tgiP_gaJpZM4Slakl>
.
|
Sure :) Would you be okay with a separate flag, however it is implemented, for Scala strict deps? |
Yes
…On Wed, Mar 21, 2018 at 1:51 PM lberki ***@***.***> wrote:
Sure :) Would you be okay with a separate flag, however it is implemented,
for Scala strict deps?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#4821 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABUIF9_cNmza-YVN-KDtJF17Anyj9QpIks5tgj64gaJpZM4Slakl>
.
|
Sorry to hijack the original request, but I've also found a use for |
@laurentlb @gregestren FYI for the new flag specific to a Skylark rule set in Bazel core. If you don't answer, I assume you are okay with adding something like @tomlu -- before I send a change to implement this, are you okay with adding the "scala strict deps" flag to Bazel core? |
@hmemcpy -- it appears that we won't go the |
Sorry for the delay. Can you send a message to bazel-dev or follow this process: https://bazel.build/designs/skylark/skylark-design-process.html Having a flag or anything hardcoded, used only in a Skylark rule, seems wrong (or at least, a temporary workaround). I think this should be discussed first. We should at least have an idea of where we're going. (sorry, I'll be away this week, but other people can comment on the plan) |
I don't understand this request. Are you saying you want to pass only direct jars to your scalac invocations? You can just do that straight in the rule implementation, can you not? I don't think it works, anyway, because compilation requires the full transitive classpath even with strict deps. Consider three rules, A, B, and C, each with a single class. This is a Java example, but I imagine Scala will be the same. class A { class B extends A { class C { Even though C only has a direct dep on B, compilation still requires A because of the inheritance. Incremental compilations can potentially use a reduced classpath if you instrument the compiler to see what it is truly using, but that's not what we're talking about is it? |
Scala does not require the full transitive path. It sometimes requires some transitive jars, but not all. Sadly, the user experience is not great: we just get an error sometimes that a jar we need is missing, but we don’t have an message which tells us where to find it. The full transitive classpath could be very bad for scala performance because ijar is substantially less effective for scala and scalac is so much slower than javac. |
This:
Seems to be directly at odds with this:
Yes, and as I explained, you cannot know in advance which transitive jars are needed, and the set wouldn't be stable. This is why I think this request cannot really work. Changing code can cause cascading non-local compilation failures, as the transitive jars required further up the build graph can shift.
Right :( Just to be clear, this is not directly a bazel problem, right? You'd have the same problem in any build system, if you use the same number of targets?
Is scalac slower at cracking open the classpath jars? ijar really only buys you smaller (in bytes) jars on the classpath. It doesn't reduce the number of jars on the classpath. I suppose it does help incremental cache hit rate, in case you modify method bodies only. |
Java compilations doesn't use the full transitive classpath either, but the hard part is knowing up-front which subset is needed. How do you handle that for scala?
I thought ijar was disabled for scala because of macros. Or are there places where ijar is still used with scala, and other reasons why it's less effective than for Java? |
We use ijar on all non macro targets. We require users to declare if a target has macros. For external jars, which we assume don’t change much and may have macros, we don’t use ijar in most cases (again since scala jars are just jars, users can circumvent this and use different options in scala_import). Why is ijar less effective with scala? Because the scala signature, an annotation in the jar, is preserved in its entirety. This has meta data which will effectively change on almost any change a user can make. Lastly, while it is true that an upstream target can make a change that causes downstream targets to fail, that is also true of the transitive deps world: an upstream target could remove a dependency that a downstream target was using directly. Without that dependency transitively showing up downstream fails. You may have some fancy plugins to prevent this in your java rules interaction with javac but we don’t have that now for scala. So in practice, requiring users to name all jars works fairly well. In my view, the main missing thing is an error when you have an explicit dependency that is not used. |
Can we fix that?
There's also a bytecode-based implementation of strict dependency enforcement that's used for |
It's a good as can be without removing macros. Though the premise is subjective. The types of all members are represented in the ScalaSignature, even privates because they can be used by macros. But implementations of methods are not in the signature. So the accuracy of the premise depends if you alter member types in "almost any change".
It's not necessary Scala-specific. Java jars can have dependencies that ijars do not. I assume this case is low-value enough that Java just has not done it.
More generally, having non-Skylark rules seems wrong, and a violation of abstraction. Unfortunately, the blessed Google Languages remain in Bazel core, and their useful abilities also remain there. I think this should not be flag, but rather an attribute. Typically, build code is made to work with many flag options; the flags make relatively minor adjustments to overall behavior. Transitive vs non-transitive is a fundamental difference in the build code that is written. |
This might already be clear from the thread but just in case it isn't: The above doesn't contradict if you take into account that usually scalac requires what people expect but sometimes it also needs (transitive) jars that people don't expect. Stipe people have been using this form for some time and are happy with it (@johnynek you are happy with it with respect to the alternative right?)
I'm not sure I understand what you mean. If you use strict-deps error the above scenario you describe won't happen because the downstream target can't directly use a dependency and not declare it. Additionally we have support exactly for that in rules_scala so I'm not sure I understand what you're referring to.
I seriously disagree since I think this should be a global decision and I'd rather not have everyone copy paste this setting in their BUILD files |
Flags reduce verbosity at the expense of sharing code with any project that uses a different set of flags. Classic global pros + cons. |
to the question of "can we fix ijar to work better for scala" posed here: we have a ticket here: The problem is that fixing ijar for scala is really tightly coupled to the scala compiler, and even the version of scala (2.11 vs 2.12, etc...). Speaking to scala compiler and sbt contributors, they have been somewhat pessimistic about doing this. SBT tries to do this but has had many bugs over the years and still is probably not totally bug free. Even then, sbt extracts a fingerprint to detect change, if things have not changed, we use the old jar, if it has changed, we may need to recompile. Bazel does not allow this: we can't tell bazel to only rerun an action if this function of the inputs has changed vs requiring a re-run any time any input has changed. I have requested the ability to define "cache keys" for inputs (buck supports this). So far I have not had much success getting bazel developers excited about this. |
@laurentlb |
I've recently watched this talk by a pants developer. It actually pushed me much more towards trying to work with non-transitive class-paths for performance reasons. |
FYI I created #5021 for removal of transitivity of --strict_java_deps, because it makes portable BUILDs impossible. |
@ittaiz as I have mentioned: we use non-transitive classpaths at Stripe, and I continue to be happy with the outcome. The main thing we need is an error when we have a jar that we never use so we don't accumulate cruft. Caching in this case is working very well. |
The thing pants does with direct deps + direct deps of direct deps is similar to Without the fallback, only using direct deps ends up making builds fragile. The compiler needs to load transitive classes for reasons that are unobvious and easy to perturb. For example, adding an overload of a method being called which references a type that wasn't already being loaded could break the caller and force them to add additional direct deps. @johnynek are you compiling against direct deps only, or direct deps + direct deps of direct deps, like the pants feature? What has your experience been with the fragility issue I mentioned? |
@lberki what would be the next step in addressing this issue? |
I'm trying to understand the situation here. @ittaiz How are you currently using By looking at the documentation, the FWIU this FR is about globally controlling what ends up on the scalc compiletime classpath. Is that correct? If so, it shouldn't impact javac compilations. Can you explain why rules_scala can not use the current values of Anyhow, I think what this FR is about is conceptually different than the |
Thank you for contributing to the Bazel repository! This issue has been marked as stale since it has not had any activity in the last 2.5 years. It will be closed in the next 14 days unless any other activity occurs or one of the following labels is added: "not stale", "awaiting-bazeler". Please reach out to the triage team ( |
This issue has been automatically closed due to inactivity. If you're still interested in pursuing this, please reach out to the triage team ( |
Description of the problem / feature request:
Add a new
strict_java_deps
value- "non-transitive"Feature requests: what underlying problem are you trying to solve with this feature?
The underlying problem I'm trying to resolve is that
ijar
is less than optimal for scala code which means using strict-deps as it's used in java rules (always pass the full transitive classpath as inputs) might have performance issues in terms of many redundant triggers (again due to problems withijar
and its applicability to scala).Solving the root cause with
ijar
itself is not on anyone's horizon (and sounds like it's a very big undertaking).Currently rules_scala defaults to only passing the direct dependencies and it's overloading the strict_java_deps values to mean that off\default is only pass the direct dependencies.
This will probably come at a surprise to some users who use both java and scala rules since "off" means completely the other way around for java rules.
My suggestion is to add a new value "non-transitive" which we can use to only pass the direct dependencies.
Our other alternative is to still overload an existing value "strict" and decide that it means the above.
It's only relevant if "strict" is not planned to be removed since it's doc says "Transition to strict by default".
Have you found anything relevant by searching the web?
Further discussion in bazelbuild/rules_scala#423
cc @johnynek @pauldraper
The text was updated successfully, but these errors were encountered: