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

 

Reply via email to