Native Binaries: how to get explicit platform subdirectories during build

It seems that, when gradle is only building for one target platform, when it generates the resulting binaries under the build directory, it does not create a subdirectory identifying the platform for which the binaries were built. Only when multiple platform builds are explicitly produced will it create subdirectories for the build results that identify the platform.

However, when I make built binaries available for consumers, I would like to have the platform explicitly identified within the path to the binary. I do not want to name binaries differently based on the platform for which they were built.

It is easiest to do this if the file system produced under the build directory already contains a subdirectory that includes the platform information. If it doesn’t, then I have to find a way, after the build has completed, to identify what platforms were used to produce the resulting binaries, construct a path containing that information in a different location, and then relocate the build binaries to this new location.

The question is:
a) For builds that only produce binaries for a single target platform, is there a way to get gradle to create a sub-folder under the build folder within the path to the built binaries that explicitly identifies the target platform?
b) If there isn’t a way to get gradle to create this sub-folder during the build, how can I create an alternative file system containing the built binaries that does explicitly identify the target platform after the build has completed?

I’ll give an explicit example so there is something concrete to model:

Example

Assume that, after a static library project has been built, I want to drop all of the exported header files under <projecDir>/Include, and the library binary under <projectDir>/Lib/<targetPlatform>/<buildType>. These are the artifacts that will be delivered to our CI system, and dependent projects will assume that that is where header and lib files will be found.

I’ve tried two variants of this in my gradle.build file, the one below gets me closest to what I need, but I can’t determine how to get the platform information into the copied path for the Lib output. Note: on the system where this build is run, gradle is only producing output for the x86 target platform. It’s impossible to tell which platform it chose by inspecting the contents of build/libs.

apply plugin: 'cpp'

model {

    platforms {
        x86 { architecture 'x86' }
        x64 { architecture 'x86_64' }
    }

    buildTypes {
        debug
        release
    }
    
    binaries {
        // ...
    }

    components {
        main(NativeLibrarySpec) {
            sources {
                binaries.withType(SharedLibraryBinarySpec) { buildable = false }
            }
        }
    }
}

task publishHeaders( type: Copy ) {
    from 'src/main/headers'
    into 'Include'
}

task publishLib( type: Copy ) {
    from 'build/libs/main/static'
    into 'Lib'
}

build.finalizedBy publishHeaders
build.finalizedBy publishLib

Hey,

you should be able to reference the task that creates the lib directly:

model {
    components {
        main(NativeLibrarySpec) {
            ...
        }
    }

    tasks {
        publishLib(Copy) {
	        from createMainStaticLibrary
		into 'Lib'
        }
    }
}

…this is insufficient - that task only drops the release variant of main.lib under the `Lib’ folder with no target platform information in the path. There must be a subfolder for the targetPlatform, and under that a subfolder for the build type.

That is, the final file system should look like:

<projectDir>/Lib/windows_x86/debug/main.lib
<projectDir>/Lib/windows_x86/release/main.lib

…and, if multiple platforms are built, the result should look like so without having to make any changes to the build script:

<projectDir>/Lib/windows_x86/debug/main.lib
<projectDir>/Lib/windows_x86/release/main.lib
<projectDir>/Lib/x64/debug/main.lib
<projectDir>/Lib/x64/release/main.lib

…with the 32-bit libs under the x86 folder and the 64-bit libs under x64.

So far, I can’t find a way to get the targetPlatform information in the context of a task, much less be sure that the right variants go under the right folders.

I think I resolved my problem, though I’m not sure it’s ideal. By explicitly specifying more than one targetPlatform elements on the components, this has the effect of creating subdirectories named after the targetPlatform even when the system on which the components are build can only build one targetPlatform variant.

So, with the build script below, the default build on the target system always produces an explicit patform subdirectory:

apply plugin: 'cpp'

model {

    platforms {
        windows_x86 {
           architecture 'x86'
           operatingSystem 'windows'
        }
        linux_x64 {
           architecture 'x86_64'
           operatingSystem 'linux'
        }
    }

    buildTypes {
        debug
        release
    }
    
    binaries {
        // ...
    }

    components {
        main(NativeLibrarySpec) {
            targetPlatform 'windows_x86'
            targetPlatform 'linux_x64'
            sources {
                binaries.withType(SharedLibraryBinarySpec) { buildable = false }
            }
        }
    }
}