Flat directory structure for multimodules? - sbt

Is it possible, with SBT to use a flat directory structure for multimodules?
That is, instead of having:
- parent
|- child_a
|- child_b
to simply have:
- parent
- child_a
- child_b
I have tried the later and configured the parent project/Build.scala with:
lazy val child_a = Project(id = "child_a",
base = file("../child_a"))
But when doing an sbt command, like sbt package, I get to following error:
[error] java.lang.AssertionError: assertion failed: Directory D:\src\child_a is not contained in build root D:\src\parent

The solution is ProjectRef.
Directory ... not contained in build root ... is an issue for Project - but not for ProjectRef. If You switch to ProjectRef it will go. If you define in main project's build.sbt:
lazy val root = (project in file ("."))
.aggregate(helper_library)
.dependsOn(helper_library)
lazy val helper_library = ProjectRef(file("../helper_library"), "helper_library")
then the helper_library and the main project are siblings regarding the directory structure - as you wished in your question - at the same time, the main project aggregates to, and depends on helper_library.

I don't think this is possible.

Related

CMake-qt: Including Autogened file from sibling Project. How to do it right?

commonLib is a collection of Files used for some other Targets declared in sibling folders which are then added to the parent CMakeLists.txt via add_subdirectory(). commonLib contains foo.h and foo.ui (which is translated to ui_foo.h by AUTOUIC)
otherLib includes foo.h from commonLib.
It feels like I am missing something obvious.
Is it necessary to use something like target_link_libraries?
Can I add the autogen folder of commonLib to the include folders of otherLib? (with target_include_directories(commonLib PRIVATE ${AUTOGEN_FOLDER_OF_otherLib}) )
How do I make sure commonLib is autogen-ed before otherLib?
Please let me know if there is information missing for understanding the problem.
I am using cmake-converter to convert existing .sln files to CMakeLists.txt.
I assumed finding success with using target properties like:
* AUTOGEN_TARGET_DEPENDS
* AUTOGEN_BUILD_DIR
but I failed.
commonLib contains following code:
find_package(Qt5 REQUIRED COMPONENTS Widgets)
set_target_properties(${PROJECT_NAME} PROPERTIES
AUTOUIC ON
)
otherLib contains following code:
add_dependencies(${PROJECT_NAME}
commonLib
)
I expected CMake to successfully generate the ui_foo.h from commonLib (which it actually does in the folder commonLib_autogen/include_) and then use ui_foo.h for compilation with otherLib.
Resulting Errormessage is:
d:\path\to\otherLib\../otherLib/foo.h(6): fatal error C1083: Cannot open include file: 'ui_foo.h': No such file or directory [D:\build_dir_of\otherLib\otherLib.vcxproj]
The Problem was the use of
# include "ui_foo.h"
in the header (foo.h). Moving the include to the foo.cpp file and forward declaring the Ui::FooBar like this:
namespace Ui { class FooBar; }
resolved it.

Absolute path of the project root directory in Julia

The project root directory of a file located in PROJECT_ROOT/lib/code.jl can be accessed with this code:
root = dirname(dirname(#__FILE__))
Using dirname() twice seems pretty ugly. Is there a better way to do this? With Ruby, I would use this code:
root = File.expand_path('../', File.dirname(__FILE__))
Thanks for making me find out about:
"/"*relpath((#__FILE__)*"/../..","/")
According to ?relpath, it gives a path from the location of the second argument in the file-system, to the first argument. Is this better than the double dirname solution?
A variant of the same niceness is:
normpath(joinpath(#__FILE__,"..",".."))
Closest to Ruby equivalent might be:
realpath(dirname(#__FILE__)*"/..")
I like to use
module Foo
const PROJECT_ROOT = pkgdir(Foo)
end # module
where the definition of PROJECT_ROOT can also be replaced by
const PROJECT_ROOT = dirname(dirname(pathof(Foo)))
Or, you could use
const PROJECT_ROOT = pkdir(#__MODULE__)
I just use
const PROJECT_ROOT = #__DIR__
from inside my _init.jl file, which resides in the project root directory (next to the src directory) and gives you a canonical path.
I get my _init.jl files automatically executed when opening a Julia session from inside that directories by having
isfile("_init.jl") && include(joinpath(pwd(), "_init.jl"))
in my ~/.julia/config/startup.jl file. If you started Julia elsewhere, you have to include("_init.jl") it (or respective relative path) manually.

How to execute clean task in dependent projects from a task?

How do I clean dependent projects in SBT from inside the code of a task?
I've checked before this related questions:
SBT: Traverse project dependency graph
get reference to "child" projects from "parent" in sbt
but I'm getting a little lost with strange syntax.
I've tried this:
projectDependencies.value.foreach { p =>
System.out.println(s"Cleaning ${p.name}")
(clean.all(ScopeFilter(inProjects(new LocalProject(p.name))))).value
}
but SBT complains about dynamic scope:
Illegal dynamic reference: p
Use the following in build.sbt:
val selectDeps = ScopeFilter(inDependencies(ThisProject))
clean in Compile := clean.all(selectDeps).value
Based on the solution offered by Jacek Laskowski (thanks), here is a more complete snippet:
val cleanDependencies = taskKey[Seq[Unit]]("Clean dependencies of current project")
lazy val MyProject = project.settings(Seq(
cleanDependencies <<= clean.all(ScopeFilter(inDependencies(ThisProject))),
package <<= package.dependsOn(clean, cleanDependencies)
): _*)

Where to place resources, e.g. images, that scaladoc can use?

I am currently writing the documentation of an API written in Scala. I would like to include several diagrams to make the code more understandable.
I am wondering where to put resources (such as diagrams) in order that they can be automatically imported by an invocation of scaladoc, and how to refer to these resources in the documentation of the code.
For example, let's assume that I use sbt. My code is located in the src/main/scala directory. Here is an example of a scala package object for package foo:
/**
* Provides main classes of the bar API.
*
* ==Overview==
* Main classes are depicted on the following diagram:
* <img src="path/to/diagram-foo.svg" />
*
*/
package object foo {
}
Where should 'diagram-foo.svg' be located in my project in order to be visible to scaladoc? Subsequently, what is the correct value of path/to/ in the img tag?
WARNING It may be a hack as I know very little about scaladoc.
Since <img src="../path/to/diagram-foo.svg" /> is just a regular HTML you just need to copy necessary assets to the doc target path so the img resolves.
You can use the following copyDocAssetsTask custom task that with (doc in Compile) and src/main/doc-resources directory gives you what you want. The point is to copy images to the directory where the documentation is generated, i.e. (target in (Compile, doc)).value.
build.sbt:
lazy val copyDocAssetsTask = taskKey[Unit]("Copy doc assets")
copyDocAssetsTask := {
println("Copying doc assets")
val sourceDir = file("src/main/doc-resources")
val targetDir = (target in (Compile, doc)).value
IO.copyDirectory(sourceDir, targetDir)
}
copyDocAssetsTask <<= copyDocAssetsTask triggeredBy (doc in Compile)
Obviously the directory where you place the images is arbitrary, and when you decide otherwise, just update the custom task accordingly.
Thanks, I used an adaptation of this that I hope might help others, particularly on multi-module projects:
First, unidoc at https://github.com/sbt/sbt-unidoc will merge your scaladoc from multi-module projects into a single location, which is typically what you want. Then the following in build.sbt:
lazy val copyDocAssetsTask = taskKey[Unit]("Copy unidoc resources")
copyDocAssetsTask := {
println("Copying unidoc resources")
val sourceDir = file("src/main/doc-resources")
val targetDir = (target in (Compile, doc)).value.getParentFile
println(s"from ${sourceDir.getAbsolutePath} to ${targetDir.getAbsolutePath}")
IO.copyDirectory(sourceDir, new java.io.File(targetDir, "unidoc"))
}
copyDocAssetsTask := (copyDocAssetsTask triggeredBy (unidoc in Compile)).value
then put your documents under src/main/doc-resources in the root project in subdirectories following your package structure for the path to your class with the scaladoc to include the diagram (this just saves you having to mess around with parent directories in the URL) and embed something like:
<img src="DesignModel.svg" width="98%"/> in your scaladoc
e.g. if this scaladoc was in a class in package com.someone.thing in any project in the multi-module build, the DesignModel.svg file would go in src/main/doc-resources/com/someone/thing inside the root project.

How to share version values between project/plugins.sbt and project/Build.scala?

I would like to share a common version variable between an sbtPlugin and the rest of the build
Here is what I am trying:
in project/Build.scala:
object Versions {
scalaJs = "0.5.0-M3"
}
object MyBuild extends Build {
//Use version number
}
in plugins.sbt:
addSbtPlugin("org.scala-lang.modules.scalajs" % "scalajs-sbt-plugin" % Versions.scalaJs)
results in
plugins.sbt:15: error: not found: value Versions
addSbtPlugin("org.scala-lang.modules.scalajs" % "scalajs-sbt-plugin" % Versions.scalaJs)
Is there a way to share the version number specification between plugins.sbt and the rest of the build, e.g. project/Build.scala?
sbt-buildinfo
If you need to share version number between build.sbt and hello.scala, what would you normally do? I don't know about you, but I would use sbt-buildinfo that I wrote.
This can be configured using buildInfoKeys setting to expose arbitrary key values like version or some custom String value. I understand this is not exactly what you're asking but bear with me.
meta-build (turtles all the way down)
As Jacek noted and stated in Getting Started Guide, the build in sbt is a project defined in the build located in project directory one level down. To distinguish the builds, let's define the normal build as the proper build, and the build that defines the proper build as meta-build. For example, we can say that an sbt plugin is a library of the root project in the meta build.
Now let's get back to your question. How can we share info between project/Build.scala and project/plugins.sbt?
using sbt-buildinfo for meta-build
We can just define another level of build by creating project/project and add sbt-buildinfo to the (meta-)meta-build.
Here are the files.
In project/project/buildinfo.sbt:
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.3.2")
In project/project/Dependencies.scala:
package metabuild
object Dependencies {
def scalaJsVersion = "0.5.0-M2"
}
In project/build.properties:
sbt.version=0.13.5
In project/buildinfo.sbt:
import metabuild.Dependencies._
buildInfoSettings
sourceGenerators in Compile <+= buildInfo
buildInfoKeys := Seq[BuildInfoKey]("scalaJsVersion" -> scalaJsVersion)
buildInfoPackage := "metabuild"
In project/scalajs.sbt:
import metabuild.Dependencies._
addSbtPlugin("org.scala-lang.modules.scalajs" % "scalajs-sbt-plugin" % scalaJsVersion)
In project/Build.scala:
import sbt._
import Keys._
import metabuild.BuildInfo._
object Builds extends Build {
println(s"test: $scalaJsVersion")
}
So there's a bit of a boilerplate in project/buildinfo.sbt, but the version info is shared across the build definition and the plugin declaration.
If you're curious where BuildInfo is defined, peek into project/target/scala-2.10/sbt-0.13/src_managed/.
For the project/plugins.sbt file you'd have to have another project under project with the Versions.scala file. That would make the definition of Versions.scalaJs visible.
The reason for doing it is that *.sbt files belong to a project build definition at the current level with *.scala files under project to expand on it. And it's...turtles all the way down, i.e. sbt is recursive.
I'm not sure how much the following can help, but it might be worth to try out - to share versions between projects - plugins and the main one - you'd have to use ProjectRef as described in the answer to RootProject and ProjectRef:
When you want to include other, separate builds directly instead of
using their published binaries, you use "source dependencies". This is
what RootProject and ProjectRef declare. ProjectRef is the most
general: you specify the location of the build (a URI) and the ID of
the project in the build (a String) that you want to depend on.
RootProject is a convenience that selects the root project for the
build at the URI you specify.
My proposal is to hack. For example, in build.sbt you can add a task:
val readPluginSbt = taskKey[String]("Read plugins.sbt file.")
readPluginSbt := {
val lineIterator = scala.io.Source.fromFile(new java.io.File("project","plugins.sbt")).getLines
val linesWithValIterator = lineIterator.filter(line => line.contains("scalaxbVersion"))
val versionString = linesWithValIterator.mkString("\n").split("=")(1).trim
val version = versionString.split("\n")(0) // only val declaration
println(version)
version
}
When you call readPluginSbt you will see the contents of plugins.sbt. You can parse this file and extract the variable.
For example:
resolvers += Resolver.sonatypeRepo("public")
val scalaxbVersion = "1.1.2"
addSbtPlugin("org.scalaxb" % "sbt-scalaxb" % scalaxbVersion)
addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.5.1")
You can extract scalaxbVersion with regular expressions/split:
scala> val line = """val scalaxbVersion = "1.1.2""""
line: String = val scalaxbVersion = "1.1.2"
scala> line.split("=")(1).trim
res1: String = "1.1.2"

Resources