On Dec 1, 2008, at 10:12 PM, Benjamin Klum wrote:
Hello Adam,
Are they Gradle projects, or do you want to use Gradle to coordinate
Ant or Maven builds? Out of curiosity, if they are all Gradle
projects, what does the multi-project support do or not do that
means you can't use it to solve your problem?
let's assume they are Gradle projects. From what I've read in the
user guide, multi-project builds require you to structure the member
projects in a hierarchy. OK, in v0.4 sub projects may reside in
arbitrary physical locations (hello Hans, I've just read your reply)
but the relation between the projects still has to be a hierarchical
one - a tree: A sub project S always has exactly one parent project
P even if S does not have to reside within the directory of P. Is
this correct? If not, the discussion is over :) But in case it's
true, I'll describe a use case for which I think that a hierarchical
project structure is unnecessarily restricting and redundant if you
already have declared dependencies.
Background: I'm about writing an application with plug-in support
using OSGi. The application is divided into following modules at
runtime:
* One application core, which provides the main functionality and
serves as plug-in host (technically it's an OSGi bundle that
registers a service).
* Several plug-ins. A plug-in adds functionality (technically an
OSGi bundle that consumes the core service).
* Several distributions. A distribution is a compilation of the
application core with a specific set of plug-ins "preinstalled" (a
distribution is also responsible for starting up the OSGi container).
It makes sense to have this kind of modularization also at build
time. In particular, I'd like each runtime module (a module can be
the application core, a plug-in or a distribution) to correspond to
exactly one development module.
Assuming we've following concrete modules:
* Application core
* Plug-in 1 (depends on application core)
* Plug-in 2 (depends on application core)
* Plug-in 3 (depends on application core)
* Distribution 1 (contains application core with plug-ins 1 and 2)
* Distribution 2 (contains application core with plug-ins 1 and 3)
Now I'd like to build like in the following scenario:
1. I check out the whole code base into a flat directory structure
(distribution-one, application-core, plug-in-one, ...).
2. I modify the code of distribution 1 and trigger a clean build.
Application core, plug-in 1 and plug-in 2 are automatically built
before distribution 1 because distribution 1 depends on them.
3. I modify the code of distribution 2 and trigger a clean build.
Application core, plug-in 1 and plug-in 3 are automatically built
before distribution 2 because distribution 2 depends on them.
Do you see? If I should declare a parent project for plug-in 1,
which one should I take? Distribution 1 or distribution 2 - both
qualify as parent projects. Why should I establish a hierarchy at
all if it wouldn't correctly reflect the dependencies anyway?
What I'm trying to say: Shouldn't it be enough to declare
**dependencies** between modules in order to let a build system
figure out a reasonable multi-project build order? Dependency
declarations form a directed acyclic graph, a less-restricted data
structure than a tree. So why should I put any effort into
structuring projects into a tree if I've already declared the exact
dependencies between them? I know, it's common to make project
hierarchies (e.g. Maven modules) - but why?
Maybe I'm just missing a simple but important point here ... if so,
please give me a hint :)
Here we go ;). From a Gradle perspective there are two kind of build
dependencies between what you call development projects. One is a
(build) runtime dependency. If you build Java projects, such a
dependency is usually established because the build of one projects
depends on build artifacts of another project. Those kind of
dependencies are not modeled as a tree by Gradle, they form an acyclic
graph. It is very important to note that the order in which the
projects are build is different from the order of the project tree. As
you have said, a build system should figure the build order, based on
the runtime dependencies. And that is what Gradle does.
But there is another kind of dependency. Those are configuration time
dependencies. Here is were the notion of parent and child is used.
Let's play with your example above. The dependencies you have
described above are build runtime dependencies. Let's say you want to
have some common manifest entries or define common dependencies (e.g.
log4j, junit) for your development projects. None of the projects
above look like a good parent for this. If you had only one
distribution, the distribution might be a good parent, but this is not
the case here. Somewhere your settings.gradle has to live. Lets say it
lives in the same directory as the top level directory of your
projects. That would constitute a hierarchical layout. You can (you
don't need to) now add a build.gradle to this directory and do things
like:
subprojects {
usePlugin('java')
usePlugin('osgi') // Gradle 0.5 comes with an OSGi plugin for
generating OSGi bundles :)
manifest ...
dependencies {
testCompile ...
}
}
The gradle build has two phases. One is the configuration, the other
the execution. In this case it is important that the parent script is
evaluated before the subproject scripts, as the subproject scripts may
assume that the JavaPlugin has been applied. So we have a
configuration order, which is by default from top to bottom (but it is
configurable). Now let's assume you want to build an
ueberdistribution. In this case the build runtime dependencies are
opposite to the configuration time dependencies (something not
possible with Maven).
The whole topic is also covered in chapter 14 of the user's guide.
- Hans
--
Hans Dockter
Gradle Project lead
http://www.gradle.org
---------------------------------------------------------------------
To unsubscribe from this list, please visit:
http://xircles.codehaus.org/manage_email