On 27.12.2017 10:04, Cédric Champeau wrote:
[...]
The consequence, however, is that any change to a Java class in Groovy
core is going to produce a different compiler.
This is fine in the IDE, as long as I do not have to bootstrap
immediately... which I do not have to.
But I must say the IDEA setup is still annoying as hell. I freshly
generated the modules and ended up with a project I cannot compile,
because of the examples. I then switched to build, but ignore errors,
which resulted in my main (FileSystemCompiler, GroovyMain) classes not
being found, because they have not been compiled and I did not add the
Groovy global lib. Then I added the bootstrap and while the main classes
now have been found, they have been of course from the bootstrap, not
the source. I will always have to have a really, really, really good
look at things to see if I am using bootstrap or not. I mean imagine you
remove a class and then run from the IDE to see if your test still
works. And it will, because the damn class is still in the bootstrap
jar, which of course you did not create a new one. I easily lost more
than half a day just trying to setup things again. Together with the
installation and fixing of intellij itself... that was no fun day at all
and lost time for Groovy development.
For Gradle, which is
aware of inputs/outputs, it means that the compiler has changed, and
that it needs to recompile downstream consumers (subprojects) and, of
course, re-execute their tests. This is the _correct behavior_. Gradle
is right to do so, because the compiler has changed, so the bytecode
generated might be different, but also since Groovy provides a runtime,
it also needs to re-execute the tests because the runtime has changed.
What I explain is also true of the other tasks we use, like groovydoc,
or docgenerator.
that part is perfectly fine.
Now, let me explain why changing the strategy to use
compiler N-1 is not necessarily a good idea for us: as I explained,
Groovy also comes with a runtime. Say that in Groovy 3, we decide to get
rid of call site caching, to only use invokedynamic. Then it means that
the runtime of Groovy 3 will no longer include call site caching.
However, the Groovy classes of the compiler would have been compiled
with call site caching, so a _consumer_ of the compiler would fail,
because those classes would no longer be there at runtime!
Of course one might say "then you can use the invokedynamic version" of
Groovy to compile Groovy 3, which leads to the last bit of complexity of
our build.
What you normally do is compiler with N-1 to get a compiler for N' and
then use that compiler to get the real N. Very common strategy. Of
course that means in a build where we would depend on an older release
(N-1), we not be able to use features in the new version (N') before we
have created N', which can actually compile the new features. And only
then N could be compiled using the new features from N'. Using Java is
kind of like saying we stay with N'. So there are pros and cons to this
approach, it surely does not make things more easy from the build side.
It would make the program code more easy and would be better in terms of
"eat you own dog food".
what me really prevents from doing something like this is that the
static compiler has to many fallbacks to dynamic code where I do not
want them.
Some would have noticed that we now have a "testAll" task for
each project. This task executes tests with the "indy" version of the
compiler. Which means that in practice, we produce 2 versions of the
compiler, not just one. This was the main reason for the complexity of
the previous build, that I recently got rid of by using a different
strategy and leveraging the Gradle build cache. So, instead of using the
same outputs for both compilers, they are now separate, and we can run
the tests in 2 flavors. The consequence is that tests are executed twice
(one for `test`, the other for `testWithIndy`), but the outcome is much
cleaner.
I hope this clarifies things a bit. Now for daily development, you can use:
./gradlew :test : will only execute the call site caching version of
tests for the "core" project
./gradlew :testWithIndy : will only execute the indy version of tests
for the "core" project
./gradlew :testAll : will execute both flavors of tests (indy and non
indy) for the "core" project
And of course you can do the same for any subproject:
./gradlew :groovy-xml:test
You can also choose precisely which test to execute by adding `--tests
*MyTest*` to the command line.
testAll and testWithIndy I did not realize,thanks.
bye Jcohen