-
Notifications
You must be signed in to change notification settings - Fork 21
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
Dynamically set dependency classifiers depending on platform #250
Comments
Just a preface: I'm not sure I ever added a dependency with a classifier in a project I worked on, so I don't know all that much about it. For bleep I've tried to reduce the surface of dependencies somewhat, and drop a few ivyisms in particular. I begrudgingly kept the So after adding that, I saw that typically all classifiers were added unconditionally, for instance in zio-http. So my hypothesis was that it would always be fine to just spell all of them out and add all to the build, and then let your code choose to load whatever it needed from the jars, and that would be that. Any insights into what kind of pain that approach can bring? :D |
Yeah I guess I could use pytorch-platform as dependency which does essentially that, depending on all native artifacts. Picking the right native lib at runtime already works fine. The only downside is increased artifact size but I can live with that. I guess I could still offer a variant with a |
I'd still like to be able to easily switch to the GPU variant in the build without having to edit package scripts
import bleep.{BleepScript, Commands, Started}
import bleep.rewrites.BuildRewrite
import bleep.model
import bleep.model.Dep.JavaDependency
object AddGPUClassifier extends BuildRewrite {
override val name = model.BuildRewriteName("gpu")
override protected def newExplodedProjects(oldBuild: model.Build): Map[model.CrossProjectName, model.Project] =
oldBuild.explodedProjects.map { case (crossName, p) =>
(
crossName,
p.copy(dependencies = p.dependencies.map {
case d: JavaDependency if d.moduleName.value == "pytorch-platform" => d.copy(moduleName = d.moduleName.map(_ + "-gpu"))
case d: JavaDependency if d.baseModuleName.value == "pytorch" && d.publication.classifier.nonEmpty =>
d.copy(publication = d.publication.withClassifier(d.publication.classifier.map(_ + "-gpu")))
case other => other
})
)
}
}
object GPU extends BleepScript("GPU") {
override val rewrites: List[BuildRewrite] = List(AddGPUClassifier)
def run(started: Started, commands: Commands, args: List[String]): Unit = {
started.logger.error("Adding gpu classifier for PyTorch")
}
} So I this seems to work fine creating a modified bloop config under |
The script writing experience is amazing BTW! |
No, not possible. You could extend your script to call My recommendation for Notes about publication
Static buildsIt is my belief that builds are simple, and simple things should be static and declarative. I'm trying to create a simple build tool (pardon the pun) for such simple projects, which I believe are ~all projects out there. One meaning of "simple" is "easy to understand", but it can imply other qualities as well. Take for instance recent Apple machines: ARM64 machines with near-perfect x86_64 emulation. It's easy to flip-flop between architectures without noticing. Thousands of engineer hours have gone into that compatibility, from custom silicon all the way up to user-land code. And then it would reach a JVM build tool which breaks it, if you generated your build for one arch and ended up running it with another. It is my hope that we can express enough builds without this kind of dynamism in the core of Dynamic builds in a static build worldThere are builds which really, really are dynamic - they exist. Let's take the Scala 3 build as an example:
What would that look like in a Note sure yet. One idea is to write a Dynamic buildsSo yeah, that's where I'm coming from. Then there is reality. Reality is that I don't know if my assumptions are good yet, so let's keep the discussion open going forwards. You have come up with a somewhat enticing use-case, and I'm sure there will be others. If we reach a decision to give users the power to do what you describe here, it'll likely be as a thing in the build file format. For instance the format already supports a limited form of string replacements, so you can say things like Another option we have is to have a tool of your choice generate the build file, see #185 . Currently on the fence on that as well, for pretty much the reasons given above. |
Awesome! It really feels so liberating after all this years of trying to express the same things inside sbt and similar :) |
Thanks for the explanation. I completely agree with you regarding simple, static and declarative builds. I'm realizing that what makes my use-case somewhat difficult is not so much the need to depend on native libs, which already works by adding all classifiers or perhaps in the future even better with The challenge is that there's also an additional GPU axis, and unfortunately, I can't just add the Even if I could though, I probably want to control the behavior while hacking on the project, i.e. I want to disable GPU support for tests or debugging reasons. And I still might want to publish a variants with and without GPU support, that is, different dependencies. The GPU config axis is of course quite project specific. Other than that, I expect the build to be quite static though, so I'm not giving up hope yet. :D For hacking on the project it might be OK to switch between the variants manually, but then you'd have to be careful not to accidentally commit that change. Generating the build with #185 based on some local (not in git) config switch could be a cleaner way to do it. I.e. a But then I wonder, what if I could still have a default I'm not sure, would that bring us too far into dynamic/sbt land again? ;) |
Thanks for working with me through long explanations here @sbrunk :)
What if we pretend the dependency with classifier was just a dependency with a different maven coordinate - what would you have done then? Maybe you can model this in your build as two separate projects, one which depend on the projects:
foo-gpu:
sources: ../shared
foo:
sources: ../shared That way you can work on the one you want, run tests against both (or only one, you'll still have all the normal source directories for each project), mount the one you want (or both!) in your IDE?
If you don't need to mount the gpu build variant in your IDE, we are very close to a solution in this direction with current bleep as well. You have a build rewrite, and you can write scripts with that build rewrite for each of It'll be a bit slower performing since you need to compile scripts and start a JVM before handing it off to bloop, but that's exactly what I wanted with bleep. If you do simple things it'll be fast, and if you need more complex things that's when you pay the performance cost of compiling and starting JVMs.
I think this direction with build variants produced by build rewrites is fairly promising, in that the builds are immutable (deriving a new build doesn't change the original build), and you have an original build which makes sense without the rewrites. If we end up needing all this power, we could in theory lift the build variants into the build file as a first class thing: build-variants:
gpu: scripts/com.foo.ApplyGpuBuildRewrite
projects: ...
Thoughts? :) |
This is something we actually have already available here with
I really like this approach. It's simple, static, easy to understand. Fits well into what you envision for bleep builds I guess. :) In fact, I just tried the shared sources variant (although an upstream project should work just as well here) with a template for common deps and
Even though I think I'll try the other approach for now, I'm curious how i.e. a
Yes, this is pretty much what I had imagined how rewrites could be used when I first reading the docs. IMHO It's a powerful and quite general approach that could cover many use-cases where more flexibility is required. |
I have a project where I depend on native artifacts which have a different classifier per platform. So in a bleep.yaml, I have the following dependency:
I can set the classifier manually and it totally works fine, but now I'd like to automatically detect the current platform and set the classifier accordingly (JavaCPP already has a function that can be used for that). To make things more complicated, there's also a gpu suffix in the mix which I'd like to be able to append to the classifier as an additional manual configuration.
For sbt there's a plugin called sbt-javacpp which does exactly that (among a few other things).
I'm fairly new to bleep, so I'd like to ask whether this is doable and what would be the best way to do it. I.e. using build rewrites?
The text was updated successfully, but these errors were encountered: