Native cpp: exclude specific files from source set depending on toolchain or OS

I want to exclude specific files from a CppSourceSet depending on the toolchain or operating system. Here is what I tried:

ITAToolkit(NativeLibrarySpec) {
    targetPlatform "x86"
    targetPlatform "x64"
    sources.cpp.source.srcDir "src/${name}/src"
    sources.cpp.source.include "*.cpp"
    sources.cpp.exportedHeaders.srcDir "src/${name}/include"
    sources.cpp.exportedHeaders.include "**/*.h"
    sources.cpp.lib library: 'libsndfile', linkage: 'shared'
    sources.cpp.lib library: 'pcre', linkage: 'static'
    sources.cpp.lib library: 'pcrecpp', linkage: 'static'
    sources.cpp.source.exclude 'ITAAtomicOpsCpp11Impl.cpp'
    binaries.all {
        cppCompiler.define 'PCRE_STATIC'
        // ****** here is the important section: ******
        sources {
            if (!targetPlatform.operatingSystem.windows) {
                // *** this makes gradle unhappy:
                cpp.source.exclude "ITAAtomicOpsWin32Impl.cpp"
            }
            if (!(toolChain in Gcc)) {
                // *** this makes gradle unhappy:
                cpp.source.exclude 'ITAAtomicOpsGCCBuiltinsImpl.cpp'
            }
        }
    }
}

The error message I get is:
`> Exception thrown while executing model rule: model.components > create(ITAToolkit) > org.gradle.platform.base.internal.DefaultComponentSpecIdentifier@ced65fee.getBinaries() > all()

No such property: cpp for class: org.gradle.model.ModelMap`

How can I access the CppSourceSet from within the binaries.all block?
Thanks in advance!

At this stage, the CppSourceSet for a component is referenced by the binary, so what you are trying to do won’t work, since you’re trying to modify the same sourceSet instance in both cases. (We are likely to change this so that the binary gets a copy of the source set instead, but it hasn’t happened yet).

The way to make this work is with a separate sourceSet per tool chain: see the native-binaries/assembler and native-binaries/sourceset-variant samples in the Gradle distribution, or here.

Does this mean I can’t put anything in the source set before the binaries.all block because then i can’t have separate source sets per tool chain? Where can I find a list of available platforms? In the sourceset-variant example there are platformWindows, platformLinux, and platformMacOSX. In the assembler example there is platformAsm. Are there platforms like platformGcc or platformVisualCpp?
I would like to exclude the file ITAAtomicOpsWin32Impl.cpp on each platform/tool chain that isn’t VisualCpp and exclude ITAAtomicOpsGCCBuiltinsImpl.cpp for anything but GCC builds. Right now my work around is using the preprocessor to exclude the code in the cpp files with compiler specific predefined macros (_MSC_VER, __GNUC__).
Well, I guess I don’t really understand what’s happening under the hood in the DSL/cpp plugin. Can you point me to the source code of the cpp plugin? Perhaps reading the source code can clear up a few things.
Thanks for the help! :smiley:

Those “platforms” are just the names chosen for binary-specific source sets: they could be called anything at all. Consider the sourceset-variant example: the important bit is that for each binary, we’re detecting the operating system and adding a special source set just for that binary, containing the binary-specific sources. There is still the main ‘c’ source set, that includes all of the sources in src/main/c by default.

So to exclude particular source files for particular platforms, you’ll need to:

  1. Exclude all platform-specific sources from the main source set shared by all binaries: main.sources.c
  2. For each binary, define a new source set that includes the platform-specific sources.

Of course, this would be way simpler if each binary had a copy of the ‘main’ source set: then you’d be able to exclude per-binary. But since this source set instance is shared among all binaries, modifying it for one binary ends up modifying it for all. Your use case gives us further motivation to improve this, but it doesn’t help you now!

I think now I understand! But I have another question: if all the source sets in a component depend on the same library, I have to add that dependency to all source sets explicitly, right? There is currently no way to define a component dependency that is automatically applied to all source sets in the component? Like e.g. sources.all { lib library: ... }.

Correct. Or you can declare a shared source set with that dependency, and have all of the other source sets depend on that source set.

That sounds useful. How do I declare a source set dependency? I couldn’t find an example.

The DSL guide mentions this in the documentation for the source set’s lib

The sourceset-variant sample uses it, but doesn’t call it out specifically. In this example, we’re using the default c source set created by the plugin.

We really should add a specific example in this section of the user guide. Would you be interested in adding a section?

I had seen the DSL documentation, but I couldn’t figure out how to apply what is written there. So thanks a lot for pointing out the example! What would I need to do to add a section on this topic to the user guide?

You’ll have to submit a pull request from your github account. The user guide is generated by the ‘docs’ gradle subproject. This is where you’ll have to add your example.

… And to do so, you’ll also have to sign a CLA with Gradle (you can see the ‘contribute’ section on gradle.org)

Thanks for the info. I’m wondering why I have to enter a job title in the CLA form for individual contributors.