Referencing an external project from a sub project in gradle - gradle

I have a project setup like so where my projects are all in sibling folders relative to one another:
+ mainApp
+ mylib
+ mylib2
mainApp references the mylib library project that is not in its root with the following in my settings.gradle:
include ':app', ':mylib'
project(':mylib').projectDir=new File('..\\mylib')
However, the issue is that the mylib project depends on another lib - mylib2. I can essentially do the same thing and reference mylib2 using settings.gradle and building mylib works fine.
The problem is when I try to build mainApp, it cannot find mylib2 because the settings.gradle of a sub-project is not ran, only the root settings.gradle is ran. So, when the build.gradle file of mylib references mylib2, it cannot find mylib2.
I do not want to add a reference to mylib2 from mainApp, I want mylib2 to be brought in by mylib.
Is there a way to bring in mylib2 from the build.gradle file of mylib ?

It seems like you have a wrong understanding of subprojects.
Every "Project Tree" has a rootProject. This rootProject is the only project that should have a settings.gradle wich includes all subprojects. So if all of your 3 Projects belog together, then they must all be included in the settings.gradle.
References to other foreign project should be added as dependencies. Note that you can only reference Artifacts this way.
You did not make it very clear, but it seems like you want to use the project "mylib" as a Library for the source code of "mainApp"
If those are java projects you can simply add the jar file produced by "mylib" to the compile configuration of "mainApp":
apply plugin: 'java'
dependencies {
compile fileTree(dir:'../myLib/build/libs', include : '**/*.jar')
}
For other languages you have to use the language specific support for that language.

Related

only single gradle sub-project among multiple sub-projects can resolve symbols from a shared sourceset folder in intellj

I am working on a gradle project which has multiple sub-projects. To simplify the problem description, I am using a simple project here.
The project structure looks like
/client-v1
/src
/main
/java
/v1
Client.java
build.gradle
/client-v2/
/src
/main
/java
/v2
Client.java
build.gradle
/common
/src
/main
/java
/common
Util.java
settings.gradle
client-v1 and client-v2 are sub-projects and /common is a sourceSet folder. The settings.gradle is
rootProject.name = 'client'
include('client-v1', 'client-v2')
The build.gradle in client-v1 and client-v2 has the sourceSet definition as below.
sourceSets {
main {
java {
srcDir '../common/src/main/java'
}
}
}
gradle build works fine in project root, client-v1 folder and client-v2 folder. Also my vscode resolves all the symbols in client-v1, client-v2, and common.
Here is the problem. However, in Intellij-idea(IntelliJ Community 2021.1), client-v2 doesn't recognize the Common symbol whereas client-v2 does.
For example,
package client.v1;
import common.Util; // Okay
...
package client.v2;
import common.Util; // Cannot resolve symbol 'Util'
...
So, I updated the settings.gradle to remove the client-v1 as below:
rootProject.name = 'client'
include('client-v2')
Then the Cannot resolve symbol 'Util' error messages in client-v2's Client.java disappears in intellj.
So it seems like that the intellij enables only single gradle project to resolve symbols from a sourceSet. Is it true? Is there any way to address the problem?
It is a limitation of the IDE: IDEA-214527 Two modules in a project cannot share the same content root.

Gradle include build

How include some files (folders) from build directory, after project compile?
I have project with such structure
root
--moduleA
--moduleB
So I want after build all project
moduleA.jar include build directory from moduleA and build directory from moduleB
I found small example https://gist.github.com/marcokrikke/5481001
But it don't work on multi-project builds
Add info
github.com/feedm3/spring-boot-gwt
After compile all GWT filesd exists in
ext.buildDir = "${project.buildDir}/gwt"
ext.extraDir = "${project.buildDir}/extra"
And they must be in jar
This example work fine. But I have problem with multi-project builds

How do I use Gradle to build a special JAR with only a subset of classes?

I have been given a project A that needs access to class files from another project B. More precisely, A only needs classes compiled from the B/ejb/C/src portion of the B/ tree:
B/ejb/C/src/com/company/admin/Foo.java
B/ejb/C/src/com/company/admin/FooHome.java
B/ejb/C/src/com/company/admin/FooBean.java
B/ejb/NOTNEEDED/src/com/company/data/...
The person who had this A project before used JBuilder and included in the source definition pointers to the parallel project's B/ejb/C/src. The A project builds a jar which includes classes compiled from this other tree. I'm trying to figure out how to do this using Gradle. I want to make a B/build.gradle in the B project that will create a B-C-version.jar of .class files compiled from these sources:
B/ejb/C/src/com/company/admin/Foo.java
B/ejb/C/src/com/company/admin/FooHome.java
B/ejb/C/src/com/company/admin/FooBean.java
that I would then publish to Maven and access from the A project.
i.e., the B-C-version.jar would ideally only have these classes:
com/company/admin/Foo.class
com/company/admin/FooHome.class
but if B-C-version.jar had these classes:
com/company/admin/*.class
that would also be OK. How can I make such a thing using a build.gradle in the B project?
You can simply declare a custom Jar task like
task cJar(type: Jar) {
baseName = project.name + '-C'
from sourceSets.main.output
include 'com/company/admin/Foo.class', 'com/company/admin/FooHome.class'
}
or you can make a dedicated sourceset for your api that you then use from your other B code and from your A code, then you don't need to work with includes and update the include if you need to add files, but you just place them in the source folder of the source set and you are done, something like
sourceSets { c }
task cJar(type: Jar) {
baseName = project.name + '-C'
from sourceSets.c.output
}
Then you could also declare dependencies separately and get the correct ones drawn in transitively and so on. But it might be overkill in your situation.

Gradle specify settings dir path for a sub project

In a multi-project build I have a module that in itself is composed of two sub-projects. If I just want the option of building the top-level module but also ensure both the sub-projects within it are also built, how I do achieve this?
include 'moduleA', 'moduleB', 'moduleC' (root project settings.gradle)
project(':moduleC').projectDir = new File('path to custom module that includes sub-projects)
project(':moduleC').settingsDir = ?? (gradle fails because there is no settingsDir path)
but moduleC has a settings.gradle in itself that has
include 'api'
include 'server'
Now I want both these to be triggered when I specify gradlew :moduleC:build, but instead it just builds moduleC root project. Is there a way? This use case does seem valid to me (i.e. for modularity, you want to keep the inclusion of sub-projects at moduleC's level and not at root level).
Thanks,
Paddy
As of Gradle 2.2, only a single settings.gradle per build is supported. If that file contains include "moduleC:api" and include "moduleC:server", then running gradle build from moduleC's project directory will also build api and server.

Having difficulty setting up Gradle multiproject build for existing repository layout

I'm trying to craft a Gradle multiproject build for a situation in which my project layout is already dictated to me. I have something like this:
-->Shared\
---->SharedComponent1\
------>build.gradle
------>src\
...
---->SharedComponent2\
------>build.gradle
...
-->Product1\
---->ProductComponent1\
------>build.gradle
---->ProductComponent2\
------>build.gradle
...
---->build\
------>settings.gradle
My settings.gradle looks like this:
rootProject.name = 'Product1'
rootProject.projectDir = new File( "${ProjectsRoot}" )
include 'Shared:SharedComponent1'
include 'Shared:SharedComponent2'
include 'Product1:ProductComponent1'
include 'Product1:ProductComponent2'
When I run Gradle in the build folder like this:
gradle -PProjectsRoot=c:\my\project\root\dir projects
I get:
:projects
------------------------------------------------------------
Root project
------------------------------------------------------------
Root project 'build'
No sub-projects
To see a list of the tasks of a project, run gradle <project-path>:tasks
For example, try running gradle :tasks
BUILD SUCCESSFUL
i.e. it doesn't find the projects I'm trying to build.
Is what I'm trying to do possible with Gradle's multiproject support? Or am I barking up the wrong tree?
A couple of pointers:
Gradle strictly separates the logical project hierarchy (the way Gradle organizes your build into a logical hierarchy of projects) from the physical directory layout. Just about any mapping is possible. (One exception that comes to mind is that you can't have two projects sharing the same project directory.)
To implement a custom directory layout, you'll have to set projectDir for all projects, not just the root project. You should use relative paths, e.g. rootProject.projectDir = new File(settingsDir, "../foo") and project(":sub1").projectDir = new File(rootDir, "bar"). Here, settingsDir refers to the directory containing settings.gradle, and rootDir is a shorthand for rootProject.projectDir.
To configure projects generically, you can recursively walk (root)Project.children. Note that settings.gradle and build.gradle use different types to represent a project - ProjectDescriptor and Project, respectively.
Gradle has to be invoked from the directory containing settings.gradle, or a subdirectory thereof. From a usability perspective, it is therefore best to put settings.gradle into the root of the directory hierarchy.
For more information, see Settings in the Gradle Build Language Reference, and the Multi-Project Builds chapter in the Gradle User Guide.
For completeness, the settings.gradle that solved my specific example above is as follows:
rootProject.name = 'Product1'
def projectTreeRootDir = new File( "${ProjectsRoot}" )
// Shared components
def sharedRootDir = new File( projectTreeRootDir, 'Shared' )
include ':SharedComponent1'
project( ':SharedComponent1' ).projectDir = new File( sharedRootDir, 'SharedComponent1' )
include ':SharedComponent2'
project( ':SharedComponent2' ).projectDir = new File( sharedRootDir, 'SharedComponent2' )
// Product components
includeFlat 'ProductComponent1', 'ProductComponent2'
Clearly this doesn't scale to large numbers of subprojects and it could be done significantly better using the hints provided by Peter above.

Resources