Is it not possible in a Gradle multi-project setup to use external dependencies outside the main project folder?
Like in the settings.gradle file, can I not have something like
include 'C:\some\path\to\dependent\project\ChildA','ChildB'
or do I have to always include the dependent projects in the parent project folder?
Assuming the following filesystem hierarchy:
|
\ workspace
|
\
MyProject
|
\
DependencyA
Add the following into your settings.gradle in MyProject:
include '..:DependencyA'
and inside your inner build.gradle of MyProject
dependencies {
compile project(':..:DependencyA')
}
Repeat for as many projects as you have that depend on DependencyA.
Related
Let's say you have 2 gradle projects. The first is a multi project with 2 java sub-projects:
rootProject
:my:subProject1
:myother:subProject2
The second gradle project is a single project that includeBuild's the root project:
secondProject
includeBuild '../rootProject'
I want to make a compile dependency of :my:subProject1 into secondProject.
So basically I want to add the following to secondProject's build.gradle file:
dependency {
compile(project(':my:subProject1'))
}
When I try to do that, it returns error: Project with path ':my:subProject1' could not be found in root project 'secondProject'
I seems like I can only resolve the dependency when I do the dependency as group:artifact:version. For example: my.root.project:subProject1:1.0.0. But why would it make me do that? Why not let me access the composite build's project hierarchy?
Only one settings.gradle should exist on the root, remove all setting.gradle files in any subfolders
Define the projects on the settings.gradle file of the root folder
include ':sub1', ':sub2', ':sub3'
Add compile project(":sub1") to your build.gradle under dependencies block:
dependencies{
compile project(":sub1")
}
This is just how these composite builds work. They basically act as if you published the other project to maven local prior to including it. so this means you need to depend on the version number of the split project.
After updating to Intellij 2017.2, building my project creates an /out directory that contains generated source files and resource files. These files duplicate files that are already contained in /build and result in duplicate class compiler errors for the generated classes. Any ideas on a fix I need in Gradle or IntelliJ?
IntelliJ IDEA is no longer sharing the output with Gradle, please see this ticket for details.
You can either override it via the following configuration:
allprojects {
apply plugin: 'idea'
idea {
module {
outputDir file('build/classes/main')
testOutputDir file('build/classes/test')
}
}
if(project.convention.findPlugin(JavaPluginConvention)) {
// Change the output directory for the main and test source sets back to the old path
sourceSets.main.output.classesDir = new File(buildDir, "classes/main")
sourceSets.test.output.classesDir = new File(buildDir, "classes/test")
}
}
or delegate the build to Gradle: File | Settings | Build, Execution, Deployment | Build Tools | Gradle | Runner => Delegate IDE build/run actions to gradle.
File | Project Structure | Project Settings | Modules | Paths tab | Compiler output
Select 'Inherit project compile output path' to continue using /build for build artifacts
Here is my understanding:
Basically, this is a work-around for an incompatibility issue between
Gradle build path and IDEA output path.
the issue is - https://github.com/gradle/gradle/issues/2315
the solution is - keep these two directories seperate, therefore you have two (out/ and build/) https://youtrack.jetbrains.com/issue/IDEA-189063
Is it possible to set parent project of a child gradle project.
In my case, all parent and child project lies on same level in the file hierarchy. For example
code
/parent project
build.gradle
/child project1
build.gradle
/child project2
build.gradle
Here porject 1 depends on project2, so i am referring them as
compile project(':../project2')
also in my settings.gradle file , i have
include '../child_project1'
include '../child_project1'
with this i am able to run tasks from parent project folder but individual tasks are not running from child projects.
I know this is an old question but you can do this by specifying the child project like this in your settings.gradle:
include ':A'
project(':A').projectDir = new File('../A')
Check out section 20.3.2.2. of the Gradle doc on Multi-project builds. One can use includeFlat in the settings.gradle file.
I want to set up a large-ish project, and I'm told that gradle is the way to do it.
I'm very confused by Gradle, and the entire system seems like a lot of magic, hand-waving, and knowledge that I don't want to read all 60 chapters of the Gradle guide to grok.
I'm going to end up with the following components:
ProtoBuf files defining a bunch of messages
Java Library 1 and tests (dependent on the ProtoBufs)
Java Library 2 and tests (dependent on Java Library 1)
Java Applications (dependent on Java Library 2)
Android Application (dependent on Java Library 2)
iOS Application
Duplicates of all of the Java stuff, but for Python, C++, and Objective-C)
I want to be able to build and test everything in one large shot. So normally I'd build a tree like this:
project/ proto/
lib1/ java/ src/
test/
python/ src/
test/
...
lib2/ java/ src/
test/
python/ src/
test/
...
app1/ java/ src/
test/
python/ src/
test/
...
app2/ java/ src/
test/
python/ src/
test/
...
android/ src/
test/
iOS/ src/
test/
I get that build iOS from gradle might not be possible, so I'm happy to ignore it for now.
Is this an appropriate structure to use? How do I structure and place my gradle.build files so that libraries can be used by other teams properly? How do I make sure my dependencies are tight so that libraries include only the minimum set of what they need to include?
Gradle build files seem to leave a bunch of potentially unused tasks littered around. Do I just try to ignore these?
The structure I resided on was based on grouping similar projects into subproject structures.
project/client/core/common-android
project/client/core/features-android
project/client/core/ui-android
project/client/app/client-android
project/server/admin
project/server/base
project/server/util
project/server/api-deployment
project/bundles/bundle1
project/bundles/bundle2
project/bundles/bundle3
project/bundles/bundle4
This structure make using subproject much more intuitive then flat directory structures. Now we can apply configurations to the subproject that are similar. My final project structure looks like this
------------------------------------------------------------
Root project
------------------------------------------------------------
Root project 'platform'
+--- Project ':client' - Client: Android core projects
| +--- Project ':client:common-android' - Client: Common library for Android aar
| +--- Project ':client:features-android' - Client: Features library for Android aar
| +--- Project ':client:ui-android' - Client: UI library for Android aar
| +--- Project ':client:app-android' - Client: Apk client Android apk
+--- Project ':bundles' - bundles: OSGi bundles container project
| +--- Project ':bundles:bundle1' - bundles: OSGi bundle jar
| +--- Project ':bundles:bundle2' - bundles: OSGi bundle jar
| +--- Project ':bundles:bundle3' - bundles: OSGi bundle jar
| +--- Project ':bundles:bundle4' - bundles: OSGi bundle jar
\--- Project ':server' - Server: Coriolis root project
+--- Project ':server:admin' - Server: admin jar
+--- Project ':server:base' - Server: jar base
+--- Project ':server:apiDeployment' - Server: platform deployment war
\--- Project ':server:util' - Server: utils jar
Since we don't want the parent projects to know as little as possible about their children we can let each grouping of projects configure itself during configuration via the settings.gradle
settings.gradle:
rootProject.name = 'platform'
Map<String, String> projectProperties = startParameter.getProjectProperties()
projectProperties.put('platform', true.toString())
// TODO: Make project imports smarter by removing hardcoding of paths
def subprojects = settingsDir.listFiles(new FileFilter() {
#Override
boolean accept(File file) {
return file.isDirectory() && (file.name == 'client' || file.name == 'server')
}
})
for (File file : subprojects) {
println "Found subproject directory: $file.absolutePath"
switch (file.name) {
case 'client':
def androidHome = 'ANDROID_HOME'
// any non-null value will add android modules to the build.
// Assumption is only a valid SDK location will be set.
if (System.getenv(androidHome)) {
def clientFile = new File("$file.absolutePath/core/childProjectSettings.gradle")
if (clientFile.exists()) {
println "Adding android client"
include ':client'
project(":client").projectDir = clientFile.parentFile
apply from: clientFile.absolutePath
}
} else {
println "WARNING: Environment variable {$androidHome} not set. Not adding Android modules as they are " +
"impossible to build without the Android SDK being installed. To install the Android SDK " +
"please see: http://developer.android.com/sdk/installing/index.html"
}
break
case 'server':
def serverFile = new File("$file.absolutePath/server/childProjectSettings.gradle")
if (serverFile.exists()) {
println "Adding server"
include ':server'
project(':server').projectDir = serverFile.parentFile
apply from: serverFile.absolutePath
}
def bundlesFile = new File("$file.absolutePath/bundles/childProjectSettings.gradle")
if (bundlesFile.exists() && !projectProperties.containsKey('noBundles')) {
println "Adding osgi bundles"
include ':bundles'
project(':bundles').projectDir = bundlesFile.parentFile
apply from: bundlesFile.absolutePath
}
break
default:
println "Unknown subproject found: $file.absolutePath"
}
}
Now only subprojects that exist on the disk will be included, we can remove the remaining hardcoding for a more dynamic example but this is simpler. Then we create a file (in this example) childProjectSettings.gradle for each of our project groupings (client, server, bundles). Your childProjectSettings.gradle should specify it's subprojects in a way that it doesn't need to be updated every time a new subproject is added.
childProjectSettings.gradle:
File moduleSettingsDir = new File("$settingsDir.absolutePath/server", "bundles")
println "Bundles sees settings dir as: $moduleSettingsDir.absolutePath"
def bundleDirectories = moduleSettingsDir.listFiles(new FileFilter() {
#Override
boolean accept(File pathname) {
return pathname.isDirectory()
}
})
// get a reference to this project's descriptor so we can add subprojects
ProjectDescriptor bundles = project(':bundles')
bundleDirectories.each { File bundleDir ->
if (new File(bundleDir, "build.gradle").exists()) {
// normalize project names (blah-blah -> blahBlah)
def bundleName = bundleDir.name
if (bundleName.contains("-")) {
def names = bundleDir.name.split("-")
bundleName = names[0] + names[1].capitalize()
}
// include a subproject in the build
include ":bundles:$bundleName"
// default location will be wrong lets update the project's directory
project(":bundles:$bundleName").projectDir = bundleDir
// add the project as a subproject giving us better grouping
bundles.children.add(project(":bundles:$bundleName"))
}
}
project(':bundles').children.each {
println "Parent {$it.parent} found child {$it} in path {$it.path} using buildScript {$it.buildFile $it.path}"
}
Gradle build files seem to leave a bunch of potentially unused tasks littered around. Do I just try to ignore these?
It's not the build files that create the tasks it's the plugins that are applied in the build.gradle files. To keep the tasks as tight as possible then only declare plugins in the build.gradle that it's actually used. Tasks are not inherited from dependency projects but declared dependencies are inherited from dependency projects.
*There is an important note here all dependencies are transitive by default so if ui depends on core which declares the gson dependency then ui will by default have gson in it's classpath.
For your question about the source folders a more gradle structure would probably look more like the below. Where your groups of apps would be lib1:java|lib1:python|lib2:java|lib2:python|app1:java|app1:python|app2:java|app2:python each of theses would be a subproject of their containing group.
Then lib1 project contains two subproject lib1:java and lib1:python each compiled with the plugins in their own build.gradle files. Common code can be placed in a custom plugin in the buildSrc if needed.
project/ proto/
lib1/ java/ src/main/java/
src/main/javaTest/
python/ src/main/python/
src/main/pythonTest/
...
lib2/ java/ src/main/java/
src/main/javaTest/
python/ src/main/python/
src/main/pythonTest/
...
app1/ java/ src/main/java/
src/main/javaTest/
python/ src/main/python/
src/main/pythonTest/
...
app2/ java/ src/main/java/
src/main/javaTest/
python/ src/main/python/
src/main/pythonTest/
...
android/ src/
test/
iOS/ src/
test/
So I have two gradle projects: P1 and P2. P2 does not depend on P1 to build, however, during the build phase of P2, I want to build P1, add it to my resources folder and then add that folder to P2's jar.
I am still new to the whole gradle thing, so I am looking for an example build.gradle that would do something like this.
Thanks!
EDIT: It should be noted that P1 and P2 are both modules within the same project.
My project structure looks like this:
Root Project
Root Project
|
|__P1
| |
| |__build.grdale
|
|__P2
| |
| |__build.gradle
|
|__settings.gradle
My settings.gradle looks like this:
include 'P1', 'P2'
So I ended up finding a similar question here: Gradle: how to copy subproject jar to another subproject when task is run?
The build gradle should end up looking something like this:
task fix(dependsOn: ':P1:jar', type: Copy) {
from tasks.getByPath(':P1:jar')
into 'path/to/resources'
}
build.dependsOn fix