On 24/01/2013, at 12:57 AM, Luke Daley wrote:

> 
> On 17/01/2013, at 11:54 PM, Adam Murdoch <[email protected]> wrote:
> 
>> 
>> On 17/01/2013, at 11:20 PM, Luke Daley wrote:
>> 
>>> What's the relationship between a component and a “functional source set”?
>> 
>> It varies. The model would be something like this:
>> 
>> - A component is physically represented using one or more packagings.
>> - A packaging is built from one or more input build items.
>> - A packaging is a build item.
>> - A (functional) source set is a build item.
>> 
>> So, for a Java library, it'd look like this:
>> 
>> production source set ---> production class packaging ---> production jar 
>> packaging
>> 
>> Add in some test fixtures:
>> 
>> production class packaging ---+
>>                              +---> test fixture class packaging ---> test 
>> fixture jar packaging
>> test fixture source set ------+
>> 
>> Maybe add some source and docs:
>> 
>>                        +---> api doc packaging
>> production source set --+
>>                        +---> source packaging
>> 
>> The production jar, test fixture jar, api doc and source packagings are all 
>> aspects of the Java library component.
>> 
>> For a C library, it might look like this:
>> 
>> production source set --+--> windows 32bit shared lib packaging
>>                        +--> windows 32bit static lib packaging
>>                        +--> linux 64bit shared lib packaging
>>                        +--> …
>> 
>> Each of these platform-specific packagings, along with the API docs and 
>> source packagings, are all aspects of the component.
> 
> The term “packaging” really starts to break down here. It seems intuitive to 
> say that a classes dir and a jar are the same thing packaged differently, but 
> if you try and say that javadoc is another type of packaging it doesn't feel 
> natural. 
> 
> I originally took you to mean that different packagings were functionally 
> equivalent, but required different methods of consumption.

That's what I meant. The stuff above isn't quite right. All of the things above 
are build items. Some of them are ways of packaging a component (ie a packaging 
is-a build item).

> It seems that you're using it in a more general sense, something closer to 
> “facet”. The javadoc and the class files are different facets of the same 
> logical entity.
> 
> So maybe components have facets, and a facet can be packaged in different 
> ways.

We've been calling this a 'usage'. That is, there are a number of ways you can 
use a given type of component, and a given usage implies one or more (mutually 
exclusive) packagings:

* One such usage might be to read the API documentation for the component, 
where the API docs can be packaged as a directory of HTML, or a ZIP file or a 
PDF.
* Another might be to compile some source against it (to build a windows 32 bit 
debug binary), where the headers can be packaged as a directory of headers. Or 
as a ZIP, or in a distribution.
* Another might be to link a binary against it (to build a windows 32 bit debug 
binary), where the library is packaged as a .lib or a .so file, depending on 
platform.
* Another might be to link it at runtime (into a windows 32 but debug 
executable), where the library is packaged as a .dll or a .so, depending on the 
platform.

> 
> 
>> 
>> So far, a given source set ends up in a single component. But that doesn't 
>> necessarily need to be the case:
>> 
>> For an Android app, the graph might look like this:
>> 
>> production source set --------------+
>> 'lite' product flavour source set --+--> 'lite release' class packaging --> 
>> 'lite release' apk packaging
>> 'release' build type source set ----+
>> 
>> production source set --------------+
>> 'lite' product flavour source set --+--> 'lite debug' class packaging --> 
>> 'lite debug' apk packaging
>> 'debug' build type source set ------+
>> 
>> production source set --------------+
>> 'pro' product flavour source set --+--> 'pro debug' class packaging --> 'pro 
>> debug' apk packaging
>> 'debug' build type source set ------+
>> 
>> Here, there are 2 components: the 'lite' and the 'pro' edition of the app 
>> (*). Each component has 2 packagings: a 'release' and a 'debug' packaging. A 
>> given source set can end up in multiple packagings for multiple components, 
>> and a given component is built from multiple source sets.
> 
> Seems solid.
> 
> One question for me is whether the graph from component back to the source 
> (or really, the first inputs that Gradle knows about) is captured anywhere. 
> At the moment we don't really capture this. We go as far as sourceSet → class 
> files, but that's it.
> 
> More on this below…
> 
>>> What if the definition of a component included the source? Or maybe, a 
>>> certain kind of “buildable” component.
>> 
>> I think pretty much every component is buildable in some way, but not 
>> necessarily buildable by Gradle. It makes sense to have some kind of link 
>> back to the source that the component is assembled from. We might add 
>> 'source packaging' as a first-class concept, where one way to package up a 
>> component is to simply provide an archive containing its source files. For 
>> some components - e.g. a C header-file only library or a javascript library 
>> - this may be the only way that the component is packaged.
> 
> Would we infer the source? Or require manual specification (even if that's 
> done conventionally via a plugin)?
> 
> There's potentially a complex graph from one or more source sets, connected 
> to one or more “packagings” to the final component. It seems like it's  
> tempting to try and infer it, but I'm not sure this is scalable to complex 
> scenarios. Probably better to just use conventions to hide this and if you 
> stray off that path you're responsible for matching things up.

I agree.

We might offer some way to back chain from a given build item, and infer its 
transitive inputs, similar to make. So, if I say 'there is a java library 
component called main', we might have some rules that say:
- A java library 'n' can be packaged as a jar binary called 'n'.
- A jar binary called 'n' can be built from a class directory binary called 'n'
- A class directory binary called 'n' can be built from a source set called 'n'.
- A source set called 'n' includes java source from 'src/n/java'.

So, we can work backwards through these rules, and infer from the presence Java 
source files in 'src/main/java' how to build a java library called 'main'. 
There's still a graph of build items here, so that the java source set is a 
transitive input into the final binary.

Our conventions might just be a set of these kinds of rules, and the statement 
'this project produces a java library called main'.

The rules for how to infer the inputs for a given build item would:
- Allow a given rule to be replaced. So, in the above, I might state: A java 
library 'n' can be packaged as an API jar binary called 'n-api' and an 
implementation jar binary called 'n-impl', but keep the remaining rules.
- Be lazy, so that we trigger them only for those build items that are required 
for the given build.

So we might end up with:

- Build items have inputs and are built from their inputs.
- Rules can be used to infer the inputs for a given build item.
- Rules can be used to infer how to build a given built item from its inputs.


--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com

Reply via email to