'build' for subproject is done after main project


(tom) #1

i have a main project witch includes a sub project grpc
When i do :

./gradlew build
:grpc:extractIncludeProto
:grpc:extractProto UP-TO-DATE
:grpc:generateProto
:grpc:compileJava
:grpc:processResources
:grpc:classes
:grpc:jar
:compileJava
:processResources UP-TO-DATE
:classes
:war
:assemble
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test
:check
:build
:grpc:assemble
:grpc:extractIncludeTestProto
:grpc:extractTestProto UP-TO-DATE
:grpc:generateTestProto UP-TO-DATE
:grpc:compileTestJava UP-TO-DATE
:grpc:processTestResources UP-TO-DATE
:grpc:testClasses UP-TO-DATE
:grpc:test UP-TO-DATE
:grpc:check UP-TO-DATE
:grpc:build

In the main project the :grpc:build is executed after the the build of the main project.
This causes me to use (when a test fails in the main project)

./gradlew cleanEclipse grpc:build eclipse

to build my project and not

./gradlew cleanEclipse build eclipse

why is the order of ‘build’ reversed?
While the jar is build first for the subproject which is correct.


(Steve Cohen) #2

I’m not the expert and they will correct me if I’m wrong, but I believe what your log is indicating is that the main project build STARTS first. It does nothing but kick of the subprojects’ builds, which then start, and their starts are logged at that point in time, which must of necessity follow the start of the main project. There is not in the standard output a logging of when an action ENDs. If there were, this “nesting” would be apparent.


(tom) #3

The use case i am having is :
There is a bug in the main project a test is failing,
So i want to see in eclipse what is wrong.
The main project depends on the output of the build folder of the sub project (protobuf generated java files)

if i run

./gradlew cleanEclipse build eclipse

the command starts with the main project and it stopts when the test fails.
Stopping when a test fails is ok, but in eclipse i can not see the output of the project the main project depends on, so i can not debug it.

If the ‘build’ command would have been executed first on the sup project (and maybe also the test run on the subproject first) i would be able to debug in eclipse the main project (now i can not because classes in the build folder of the sub project are missing).

when the test fails it looks like

./gradlew build
:grpc:extractIncludeProto
:grpc:extractProto UP-TO-DATE
:grpc:generateProto
:grpc:compileJava
:grpc:processResources
:grpc:classes
:grpc:jar
:compileJava
:processResources UP-TO-DATE
:classes
:war
:assemble
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test

So it stops at the test, i have no problem here. But i don’t have the build folder of the sub project while nothing is wrong in the sub project.

Basically i would like to change the order gradle generates the build folders. First sub projects and then the main project, because the main project can depend on the sub projects, just like it does for jar files.


(Steve Cohen) #4

I’m not sure but I don’t think you should be including tests or code in your rootProject. In any case, I have never done it. In my root project I include things like repository definitions, properties, and the like, not code or tests.

Are you planning to access the code from your rootProject in your subprojects? If so, how?

You might consider putting the common code in another subproject and have the other subprojects dependOn that common code.


(tom) #5

Only main project will acces the sub project. Compiling the whole project works because i can define

compile project (’:grpc’)

but for ‘build’ it is not posible to say the build of this project depends on the sub project so build the subproject first.


(Steve Cohen) #6

I urge you to have a close look at Chapter 24, User’s Guide. It’s a little on the abstract side, since many of the examples don’t actually build anything, they just print stuff, but there’s still useful information there. Pay particular attention to Section 24.9.

Avoid changing the configuration of other projects at execution time.

I realize that the way you’re thinking about this makes sense to you, but there are other ways of thinking about this that would probably work better.


(Stefan Oehme) #7

Hi Tom,

Gradle executes task in the order of their dependencies. Your root project only depends on the production code of your sub project, so that’s what it’s going to do first. Everything else is in undetermined order.

If you need something else from the sub project in your root project, then your root project should declare the appropriate dependencies.

Please provide some more information on what you are trying to do/what your root project needs from the sub project.

Cheers,
Stefan


(tom) #8

Thanks for your answer, now i know its undetermined.

Some more info.

The subproject is a protobuf project, it only contains a protobuf file that generates files with the protobuf plugin

apply plugin: ‘com.google.protobuf’

these generated files are available when running the ‘gradlew build’ command, they are available in the build folder.

to acces these generated files from other projects in an IDE i add to the protobuf project :

idea {
module {
sourceDirs += file("${protobuf.generatedFilesBaseDir}/main/java");
sourceDirs += file("${protobuf.generatedFilesBaseDir}/main/grpc");
}
}

eclipse{
classpath {
file {
withXml {
def node = it.asNode()
node.appendNode(‘classpathentry’, [kind: ‘src’, path: “build/generated/source/proto/main/grpc”])
node.appendNode(‘classpathentry’, [kind: ‘src’, path: “build/generated/source/proto/main/java”])
}
}
}
}

now the other project can acces the generated files in eclipse and idea.

this works when fine when all projects build correctly because then all ‘build’ commands are executed.
But this does not work when a test fails. because gradle stops building at the project the test fails.
So If a test fails in the main project the sub project does not get the build folder available.


(Stefan Oehme) #9

First of all, the fact that you have to add this IDE configuration means that the protobuf plugin is not well implemented. Please open a bug report against that plugin. It should automatically add the generated source folders to the corresponding sourceSets. Then the IDEs would pick it up automatically.

Secondly I don’t understand why the generated classes are not there, because in the console output you posted, the :grpc:generateProto task is run before the parent project.


(tom) #10

Hello, just if other people have the same problem.

I can fix it by doing --continue

so then i get something like

./gradlew clean cleanEclipse build eclipse --continue

this way when a test fails the build continues and you can debug in eclipse.


(Stefan Oehme) #11

Can you please comment on this? Based on the log output you posted there seems to be no problem. The protobuf files are created before the parent, so they will be there in Eclipse too. No need for that workaround you posted above.


(tom) #12

The files are available to build the jars. and all jars are there. (this works as expected)
i can compile and deploy the project.
But eclipse does not use jars of other projects to compile, it uses the classes from the other projects.
So it needs the source code (.java files) available. To get the java files available i do ‘build’, the build steps are done after the compile steps. But are not executed when a test fails.


(Stefan Oehme) #13

The generateProto task is run, so the Java files are there, see your console output above. If the jar is created, then everything that goes into that jar is created before obviously. So I don’t get what is missing in the upstream project.


(tom) #14

You are correct, looks like the plugin could do a better job.

I was just a bit confused by the order of the execution steps, they make more sense zo me now. Thank you.