SBT: How to add subproject build-dependency on other subproject?

1,634 views
Skip to first unread message

Haoyi Li

unread,
Feb 9, 2014, 10:50:53 PM2/9/14
to scala-user
Since the SBT people have decided that the best place for questions to get asked and not answered is StackOverflow, I'm going to post this here in case anyone has a clue:

http://stackoverflow.com/questions/21506134/sbt-how-to-add-subproject-build-dependency-on-other-subproject

I feel like this isn't that obscure a requirement, so someone out there must have bumped into this before and found a solution or workaround.

Tony Sloane

unread,
Feb 9, 2014, 11:08:49 PM2/9/14
to Haoyi Li, scala-user
I note that your dependency is on an SBT plugin not on a regular SBT sub-project, which I haven’t tried, so I’m not sure if our experience is relevant.

We use “dependsOn” for classpath dependencies between sub-projects. You don’t mention dependsOn in your SO question so perhaps you’re not aware of it.

See here for an example of its use:


It’s documented here:


section “Classpath dependencies”.

regards,
Tony

Haoyi Li

unread,
Feb 9, 2014, 11:23:16 PM2/9/14
to Tony Sloane, scala-user
dependsOn doesn't work for a SBT-plugin dependency =( I wish it did, and I tried.

Tony Sloane

unread,
Feb 9, 2014, 11:27:52 PM2/9/14
to Haoyi Li, scala-user
I thought that was probably the case. I think you should update your SO question since you currently ask about dependency on another subproject not a plugin (in the title) and don’t mention that you’ve tried dependsOn.

Good luck with your quest. Sorry I can’t be of any help.

Tony

Haoyi Li

unread,
Feb 9, 2014, 11:38:18 PM2/9/14
to Tony Sloane, scala-user
I've done so, thanks!

Josh Suereth

unread,
Feb 10, 2014, 4:12:02 PM2/10/14
to Haoyi Li, Tony Sloane, scala-user
WHat do you mean by "sbt plugin dependency".

You want project B to depend on the *jar* of the project A or you want to *use the plugin* from Project A in Project B's build?


--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Haoyi Li

unread,
Feb 10, 2014, 4:15:03 PM2/10/14
to Josh Suereth, Tony Sloane, scala-user
The latter; I want to use subproject A (which is a plugin) in subproject B's build. Whether via jar, or direct classpath references, or by sacrificing chickens to appease the dark gods, I don't really care.

Josh Suereth

unread,
Feb 10, 2014, 4:50:22 PM2/10/14
to Haoyi Li, Tony Sloane, scala-user
Unfortunately, this means they need to actually be separate builds.

The other thing you can do is just put project A's sources in:  `project/src/main/scala` and have the code available for project B.

That doesn't help if you want to release project A as well...

What's the use case/example build? I may be able to think of a few ideas and help you out.  

There *is* a way you can reference the plugin as an "external" thing, like: https://github.com/sbt/sbt-native-packager/blob/master/test-project/project/project/build.scala#L3-L4

There I have a sample project embedded in the plugin project, but I'm not trying ot ever release both at the same time, and oyu load both buidls separately.

In any case, If I know more why you want what you want, may be able to guide better.


Haoyi Li

unread,
Feb 10, 2014, 11:17:29 PM2/10/14
to Josh Suereth, Tony Sloane, scala-user
@Josh,

The use case is this project, and the problem is as described here. Basically I have a plugin that needs to be used to test a subproject, but also needs to be publishable separately so other people can use it to test stuff.

Currently I'm doing the "copy everything into project/src/main/scala" route, but that has the downside that it makes any error in the plugin make me unable to enter the SBT prompt, which is not what I want. It also makes @paulp mad.

Another viable solution (if it exists?) would be to instantiate the test framework reflectively. One subproject's test framework is done this way, but the other project requires the testframework to be instantiated with some arguments passed to it by SBT, and I'm not aware of any way to do this reflectively.

Josh Suereth

unread,
Feb 11, 2014, 10:01:25 AM2/11/14
to Haoyi Li, Tony Sloane, scala-user
On Mon, Feb 10, 2014 at 11:17 PM, Haoyi Li <haoy...@gmail.com> wrote:
@Josh,

The use case is this project, and the problem is as described here. Basically I have a plugin that needs to be used to test a subproject, but also needs to be publishable separately so other people can use it to test stuff.

Currently I'm doing the "copy everything into project/src/main/scala" route, but that has the downside that it makes any error in the plugin make me unable to enter the SBT prompt, which is not what I want. It also makes @paulp mad.

Another viable solution (if it exists?) would be to instantiate the test framework reflectively. One subproject's test framework is done this way, but the other project requires the testframework to be instantiated with some arguments passed to it by SBT, and I'm not aware of any way to do this reflectively.



I'll have to look into the build to help out.  @paulp is easily angered, especially when it comes to sbt.   You can pass arguments to test frameworks via strings, e.g. 

Josh Suereth

unread,
Feb 11, 2014, 10:03:17 AM2/11/14
to Haoyi Li, Tony Sloane, scala-user
Wow, google misinterpreted a copy-past for "send".


testOptions += Tests.Argument(TestFrameworks.JUnit, "-q", "-v")




That's how you can pass test options down to a framework reflectively.   If you need help working on a totally reflective-based approach let me know.  You really really want to try to do this for max flexibility.  You can then just have `dependsOn(jsPlugin % "test")` and be done then.



If you have time, I can jump on irc or g+ to discuss in person.   Very much excited about uTest myself.


- josh

Haoyi Li

unread,
Feb 11, 2014, 11:48:04 AM2/11/14
to Josh Suereth, Tony Sloane, scala-user
They're not command-line arguments though, but structured scala-object arguments, in my case an entire Rhino interpreter. Perhaps it's possible to restructure my code to work without passing structured data objects, but that seems like a last ditch thing (since unnecessary serializing-to-strings is the root of all evil)

Jason Zaugg

unread,
Feb 11, 2014, 11:58:20 AM2/11/14
to Haoyi Li, Josh Suereth, Tony Sloane, scala-user
On Tue, Feb 11, 2014 at 5:48 PM, Haoyi Li <haoy...@gmail.com> wrote:
They're not command-line arguments though, but structured scala-object arguments, in my case an entire Rhino interpreter. Perhaps it's possible to restructure my code to work without passing structured data objects, but that seems like a last ditch thing (since unnecessary serializing-to-strings is the root of all evil)

Another option that might help is:


testOptions in Test += Tests.Cleanup( (loader: ClassLoader) => ... )
You can then reflectively work with the test classpath, and work with classes that aren't on on the build classpath itself.

-jason

Haoyi Li

unread,
Feb 11, 2014, 12:09:32 PM2/11/14
to Jason Zaugg, Josh Suereth, Tony Sloane, scala-user
You can then reflectively work with the test classpath, and work with classes that aren't on on the build classpath itself.

That seems very promising! I could probably strong-arm SBT to make it work and get my modules in line using that technique. 

I'd still prefer the non-reflective approach as the proper layering (i.e. code that runs as pat of SBT should live on the build classpath, and be part of the plugin) but if all else fails...

Haoyi Li

unread,
Feb 12, 2014, 12:28:50 AM2/12/14
to Jason Zaugg, Josh Suereth, Tony Sloane, scala-user
Looking at things in more detail, I'm again shying away from passing the things to my TestFramework as strings. I basically want to pass this guy:


Which means I'll need to serialize a whole pile of trash:


inputs: Seq[File], 
classpath: Seq[File],
console: Option[Console],
trace: (=> Throwable) => Unit

Into strings and deserialize them later, including some fellas where it isn't entirely clear how to serialize (how do you properly serialize a (=> Throwable) => Unit?). Any idea ideas, obscure multi-project build features, or anything that I could try? Worst come to worst I fall back to bash, but that's clearly not ideal

Josh Suereth

unread,
Feb 12, 2014, 10:50:39 AM2/12/14
to Haoyi Li, Jason Zaugg, Tony Sloane, scala-user
Could you move all the unit tests into an sbt-scripted test?

This would let you use your sbt plugin in the test as well as have direct class-level dependencies between the two projects.  The tests would be in a forked sbt that has access to the plugin-jars directly.

I realize it's a bit odd....

Haoyi Li

unread,
Feb 12, 2014, 12:29:18 PM2/12/14
to Josh Suereth, Jason Zaugg, Tony Sloane, scala-user
I realize it's a bit odd....

An odd solution to match an odd problem: a circularly-self-testing unit-test library executing on two different runtimes at the *same time* is about the oddest problem you can get!

Are there any performance/semantic gotchas from using SBT scripted tests? It actually sounds like exactly what I want. 

Josh Suereth

unread,
Feb 12, 2014, 4:45:56 PM2/12/14
to Haoyi Li, Jason Zaugg, Tony Sloane, scala-user
You'll take a slight hit starting up the sub-sbt when testing.  Also, output logs aren't default, you'll have to either look in the log file or `set scriptedBufferLog := false` to see them.  It'll aggregate them all as one conceptual 'test'.

If you need exmaples, let me know.
Reply all
Reply to author
Forward
0 new messages