Native platform specific sources AND headers


(Jerzy Mikucki) #1

Hi,
I think I’m having trouble with something very simple for other devs here, but I just can’t figure it out on my own.

I’m writing a multiplatform C++ project. It will run on embedded and on linux PC. To get this to work as expected, I would like to have platform specific files (both cpp and hpp files). I keep some configuration variables in hpp files.

So when I write a basic gradle project with common sources and platform specific ones, I can’t use exported headers across SourceSets. For example:

apply plugin: 'cpp'

model {
    platforms {
        linux64 {
            architecture "x64"
            operatingSystem "linux"
        }
    }

    components {
        myBin(NativeExecutableSpec) {
            targetPlatform "linux64"

            sources {
                cpp {
                    source {
                        srcDir "code/common"
                        include "*.cpp"
                    }
                    exportedHeaders {
                        srcDir "code/include"
                        include "*.hpp"
                    }
                }
            }

            binaries.all {
                if (targetPlatform.operatingSystem.linux) {
                    sources {
                        linux64(CppSourceSet) {
                            source
                            {
                                srcDir "code/platform/linux64"
                                include "*.cpp"
                            }
                            exportedHeaders {
                                srcDir "code/platform/linux64"
                                include "*.hpp"
                            }
                        }
                    }
                }
            }
        }
    }
}

In my case file code/common/main.cpp tries to use the header code/platform/linux64/platform.hpp and it fails.

I found a similar topic to my issue: [SOLVED] [Native build] Conditional sources sets, but for me it doesn’t work with headers as I would expect.

Any suggestions? I think I’ve seen some discussion on having a separate exported headers and nonexported ones - was there any progress on thin in latest builds (2.6 or 2.7)?

Btw I solved it in other project with specifying two separate sourcesets and taking only one into compilation, but it’s a lot of duplication.


(Jerzy Mikucki) #2

Hi,

I hope you guy will not mind that I’m reviving this thread, but the problem I had before is still live and kicking. As you can read in the post above, I can’t figure out a good way of sharing header files between platform specific parts of code and the common part. Even though I guess this is something that is a “known issue” I upload also a zip with a test project that shows the issue. I simplified it to show that also any headers, even though they are exportedHeaders are not share between sourceSets in the same binary.

Is there anything that could be done about that - I will try to take a look at the gradle code, but I’m more C++ developer and it may be out of my expertize.

CppHeadersWithGradle.zip (4.1 KB)


#3

Separate source sets are compiled separately, so I wouldn’t expect a file in the linux64 source set to be available in the cpp source set. You can make this work by adding a dependency between the source sets. That will make the exported headers from one source set available when compiling another source set.

This makes your sample project compile.

model {
    components {
       myBin.sources.common.lib myBin.sources.linux64
    }
}

(Jerzy Mikucki) #4

I’m really grateful that you found the time to take a look at that. I will test it in a minute (I will try to make two flavors with different shared header files).

Thank you very much. I will upload the corrected example when I get it ready.


(Jerzy Mikucki) #5

Ok, I spent some time on your suggestion. Adding lib definition helped in that case, but I think I didn’t define the example well enough. The main idea was to have a platform specific code/headers that could used with a common code/headers in a given spec. I modified the example to reflect that with addition of your suggestion of adding the dependency.

CppHeadersWithGradleFlavors.zip (3.6 KB)

The build.gradle file looks like this now (fails due to trying to mutate sourcesets):

apply plugin: ‘cpp’

model {
    flavors {
        vanilla
        chocolate
    }
    
    components {
        myBin(NativeExecutableSpec) {
            sources {
                common(CppSourceSet) {
                    source {
                        srcDir "code/common"
                        include "*.cpp"
                    }
                    exportedHeaders {
                        srcDir "code/include"
                    }
                }
            }
        
            binaries.all {
                if (flavor == flavors.vanilla) {
                    component.sources {
                        vanilla(CppSourceSet) {
                            source {
                                srcDir "code/flavor/vanilla"
                                include "*.cpp"
                            }
                            exportedHeaders {
                                srcDir "code/flavor/vanilla"
                            }
                        }
                    }
            
                    component.sources.common.lib component.sources.vanilla
                }
                if (flavor == flavors.chocolate) {
                    component.sources {
                        chocolate(CppSourceSet) {
                            source {
                                srcDir "code/flavor/chocolate"
                                include "*.cpp"
                            }
                            exportedHeaders {
                                srcDir "code/flavor/chocolate"
                            }
                        }
                    }
                    component.sources.common.lib component.sources.chocolate
                }
                
            }
        }
    }
}

And my error:
Attempt to mutate closed view of model of type ‘org.gradle.model.ModelMap<org.gradle.language.base.LanguageSourceSet>’ given to rule 'myBin(org.gradle.nativeplatform.NativeExecutableSpec)

I guess I just try to do something really silly.

Thanks again Daz for your help,
Jerzy