On 29 Nov 2013, at 8:02 am, Daz DeBoer <darrell.deb...@gradleware.com> wrote:
> > > > On Thu, Nov 28, 2013 at 11:46 AM, Steven Walters <kemu...@gmail.com> wrote: > > It's important to be clear about the difference between core concepts in the > > model (like the logical structure of a CppSourceSet, CSourceSet, Component, > > etc) from what is simply a 'convention' that maps that logical structure to > > the filesystem. > > > > Regarding the underlying model, I think we probably need quite a bit of > > flexibility: > > 1. Each LanguageSourceSet should be able to have a set of private header > > files, that only apply to that source set. > > 2. A component should have a separate shared HeaderDirectorySet that is > > shared between all LanguageSourceSets in a component. > > 3. A component should have an API HeaderDirectorySet that is available to > > any other component that depends on this component > > > > Regarding the layout conventions for this model, we have a number of > > options, and we don't have to choose just one. The basic convention in > > Gradle should be simple, consistent, work for many projects, and > > (importantly) easy to replace with your own. > > > > - For 1. we could assume that headers are mixed with the sources (empty > > HeaderDirectorySet) but make it easy to add additional directories. > > - For 2. we might use the current convention of 'headers' or perhaps > > 'include' is better. > > - For 3. I think defaulting to the shared headers might make sense? > > > > In my interpretation of the above header/include categories, I see > #1 could be nomenclated as "language private" > > Remember that a component may contain multiple source sets of a particular > language. Not sure how useful this is, but it's currently possible. There’re some important use cases for this: - Source that is relevant only for certain variants, eg for a given operating system, or flavour, or architecture - Generated source - Keeping the dependencies of different sets of source files separate, particularly when combined with one or both of the above use cases. And for each of these use cases, it’s often the case that the source in question also includes some headers in addition to some source files. > However, I'll stick to 'language-private' for now. > > #2 as "component private" > #3 as "component public" > > With this nomenclature, it raises an eyebrow to default the 'component > public' set to the 'component private' set. > > Trying to exemplify these to validate the scenarios (in attempts to > clarify the necessity/uses of them) > #1 makes seems to make sense as a language could have internal common > APIs for handling basic functionality that isn't needed outside of > that language, such as > * macros in ASM > * commonolizing string charset conversions in C/C++ > > > #2 is bit more of a peculiar scenario > > Most use cases that _I've_ particularly seen around possibly wanting > #2 is of the form > A) Language X declares functions or variables that language Y > implements. - 'Y' is implementing for 'B' > B) Language X declares functions or variables that language Y can > read/access. - 'Y' is using 'B' > > Exemplifying A, > C/C++ headers declare functions that (pure/non-inlined) ASM code implements. > depending on the ASM compiler, it may or may not be able to directly > include the C/C++ headers. > - If the ASM compiler can, then those headers would be 'shared' > - If not, then the C/C++ headers could remain 'private'. > > Exemplifying B, > My interpretation of the example Michael started with, around the > "resource.h" would fall under this: > "resources" declares and implements variables that C/C++ can access > (to call appropriate Windows APIs upon them) > > In a very strict interpretation, C++ being able to use C headers and > call C functions/use C variables also falls here. > I'm not really familiar with Obj-C at all, but given the 'C' > derivative naming, seems like it should be able to access C > functionality like C++ can. > > > However, is there a need/benefit of modeling "component private" specifically? > It seems that _within a component_, allowing native languages to > access other languages' "private" headers would be just as simple. > > Or, a possibility here is that "component private" is modeled but > simply defaults to the collection of private headers for each of the > native languages... > > OK so the question is whether the 'component-private' / 'language-private > distinction makes sense at all. Perhaps this would be over-complicating > things for the sake of unneeded flexibility? I don’t think it’s unneeded at all. The reality is that there are often headers that define things that are visible to all the source of the component, but not things outside the component. These might contain internal constants, type definitions, c function prototypes, and so on. These headers need to be visible to every source file, regardless of language. This is exactly the problem that kicked off the discussion. The complexity comes from trying to define visibility in terms of the source language - the role that a given file plays in a component isn’t (only) a function of the language file. Plus often a header file encodes multiple languages (via preprocessor #ifdefs) so fits into multiple language buckets. Instead, I think what we’re after is something like: 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) -- Adam Murdoch Gradle Co-founder http://www.gradle.org VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting http://www.gradleware.com