From: Adam Murdoch [mailto:adam.murd...@gradleware.com] Sent: Thursday, November 28, 2013 11:52 PM
> 1. Primitive language source sets that contain source files of a given language. Headers and source files would live in different source sets. > 2. A way to declare dependencies between language source sets. > 3. A way to combine language source sets of a given type into a composite source set of the same type. > 4. A way to define a logical source set, where each logical source set represents some logical entity with an API and implementation. A logical source set would have, by convention, a public headers source set, a shared headers source set, and a bunch of implementation language source sets. Any of these can be empty. There would be, by convention, a dependency from each implementation source set on the shared headers and the public headers, and a dependency from the shared headers on the public headers. When you declare a dependency on a logical source set, the only thing you can see are the public headers. > 5. A library component has-a logical source set. > 6. An executable component has-a logical source set with no public headers. > In other words, it's just more of the same - a graph of things with dependencies between them, with some conventional wiring. > As far as convention for a component goes, I'd do something like this: > - A language source set for each implementation language. > - No language private headers. You'd be able to define them if you needed, by defining a new header source set and adding a dependency from the specific language source set on the header source set. > - Shared header source set contains any header files found in `src/${component.name}/include` (say) > - Public header source set contains ant headers found in `src/${component.name}/public` (say) This graph is getting deep J So what would the DSL look like for such a list? Because I think it'd be easier to visualize through the DSL. Something like this (still fairly new to Groovy so there is likely a better way/syntax in many cases, but I'm more wondering about how well it'd fit the model)? sources { mylibrary { // C++ sources (part 1) cppsourcepart1(Language.Cpp) { <typical source set stuff> } // C++ sources (part 2) cppsourcepart2(Language.Cpp) { <typical source set stuff> } // C++ sources (combined as in #3) cppsource(Language.Cpp) { sources cppsourcepart1, cppsourcepart2 include objcheaders // #2, but not needed in this case because of the logical source set shared list } // C++ headers (internal) cppheaders(Language.Cpp) { <typical source set stuff> } // C++ headers (API) cppapi(Language.Cpp) { <typical source set stuff> } // Objective-C sources objcsource(Language.ObjectiveC) { <typical source set stuff> } // Objective-C headers objcheaders(Language.ObjectiveC) { <typical source set stuff> } // Logical source set, #4 mylib { implementation cppsource, objcsource shared cppheaders, objcheaders public cppapi } } } There's probably a way to make it less verbose, although most of it would be behind the scenes if the source layout fits the conventions Gradle would use. And obviously the names (implementation/shared/public) are just examples. I think this example also differs a bit from your description because you mention having 0 or 1 public and shared source sets, and here there are 2 shared source sets. And while talking about the DSL (and to continue something I started talking about with operating systems in a previous email), I noticed the design document mentions ARM, PowerPC and cross compilation. Right now there is just a single element that identifies the platform (x86_64, armv7, armv8, .) but I think it would make sense to make it become a family/type pair, so this: architecture 'armv7' Would be the same as: architecture family: 'armv7' type: 'default' Because just taking gcc as an example, on top of the many ARM architectures it supports (via -arch), there are also a lot of target processor types (via -mcpu). Cf http://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html. Now, while detecting all possible architectures (or at least the ones we want to support) is not too hard, detecting all possible processor variants would be a horrible task, especially considering how many manufacturers provide a special gcc build that targets their own specific microprocessor. So it could just be a string and then Gradle detects a set of known types. For example for the Intel architecture it'd make it possible to know if we enable optimizations for Pentium Pro, MMX, SSE, etc. If it's not a recognized type, it just gets passed to the compiler and worst case, the compile fails with an error about an unsupported architecture. It may also be worth adding a third parameter to specify the type of FPU. Michael