I figured out what was going wrong. It was a combination of poor copy/paste skills and the fact that Groovy is a dynamic language.
First, let's look at the definition of the sv(Closure)
function again:
SourceDirectorySet sv(@Nullable Closure configureClosure) {
configure(configureClosure, getSv());
return this;
}
Once I moved this code to an own Groovy file and used the IDE to show me what is getting called, I noticed that it wasn't calling the function I expected. I was expecting a call to org.gradle.util.ConfigureUtil.configure
. Since this is part of the public API, I expected it to be imported by default in the build script. As this page states, this is not the case.
To solve the issue, it's enough to add the following import:
import static org.gradle.util.ConfigureUtil.configure
This will get rid of the cryptic closure related error. It is replaced by the following error, though:
Cannot cast object 'SourceSet_Decorated@a6abab9' with class 'SourceSet_Decorated' to class 'org.gradle.api.file.SourceDirectorySet'
This is caused by the copy/paste error I mentioned. When I wrote the SourceSet
class, I drew heavily from org.gradle.api.tasks.SourceSet
(and org.gradle.api.internal.tasks.DefaultSourceSet
). If we look at the java(Closure)
method there, we'll see it has the following signature:
SourceSet java(@Nullable Closure configureClosure);
Notice that it returns SourceSet
and not SourceDirectorySet
like in my code. Using the proper return type fixes the issue:
SourceSet sv(@Nullable Closure configureClosure)
With this new return type, let's look again at the configuration code for the source set:
sourceSets {
main {
sv {
include '*.sv'
}
}
}
Initially, I thought it was supposed to work as follows: pass main { ... }
as a Closure
to sourceSets
, pass sv { ... }
as a Closure
to main
, and handle the include ...
part inside sourceDirectorySet
. I banged my head against the wall for a while, because I couldn't find any code in that class hierarchy that takes closures like this.
Now, I think the flow is slightly different: pass main { ... }
as a Closure
to sourceSets
(as initially thought), but call the sv(Closure)
function on main
(of type sourceSet
), passing it { include ... }
as the argument.
Bonus: There was one more issue that wasn't related to the "compile" errors I was having.
Even after getting the code to run without errors, it still wasn't behaving as expected. I had some files with the *.svh
extension that were still getting picked up. This is because, when calling getSv()
, it was creating a new SourceDirectorySet
each time. Any configuration that was done previously was getting thrown away each time that this function was called.
Making the sourceDirectorySet
a class member and moving its creation to the constructor fixed the issue:
private SourceDirectorySet sv
SourceSet(String name, ObjectFactory objectFactory) {
// ...
sv = objectFactory.sourceDirectorySet('sv',
'SystemVerilog source')
sv.srcDir("src/${name}/sv")
}
SourceDirectorySet getSv() {
return sv
}