Gradle 3: how to add to model elements from inside a custom plugin?

I have a build.gradle file that is used to build C++ files across a number of platforms. This is done in a number of projects, all of which target the same platforms. I’d like to move this code to a separate plugin to minimise the code in the build file.

So, I have the following at the moment in build.gradle:

model {
    platforms {
        "osx-x86_64" {
            operatingSystem "osx"
            architecture "x86_64"
        }

        "stm32f4xx-arm" {
            architecture "arm"
        }
        
        "windows" {
            operatingSystem "windows"
            architecture "x86_64"
        }
        
        "linux" {
            operatingSystem "linux"
            architecture "x86_64"
        }

        "pi" {
            operatingSystem "linux"
            architecture "arm"
        }

    }

    toolChains {
        clang(Clang)

        gcc(Gcc) {

            target('stm32f4xx-arm') {
                def prefix = "arm-none-eabi-"
                cCompiler.executable         = prefix + cCompiler.executable
                cppCompiler.executable       = prefix + cppCompiler.executable
                assembler.executable         = prefix + assembler.executable
                linker.executable            = prefix + linker.executable
                staticLibArchiver.executable = prefix + staticLibArchiver.executable
            }

            target('windows') {
                def prefix = "x86_64-w64-mingw32-"
                cCompiler.executable         = prefix + cCompiler.executable
                cppCompiler.executable       = prefix + cppCompiler.executable
                assembler.executable         = prefix + assembler.executable
                linker.executable            = prefix + linker.executable
                staticLibArchiver.executable = prefix + staticLibArchiver.executable
            }

            target('linux') {
                def prefix = "x86_64-linux-"
                cCompiler.executable         = prefix + cCompiler.executable
                cppCompiler.executable       = prefix + cppCompiler.executable
                assembler.executable         = prefix + assembler.executable
                linker.executable            = prefix + linker.executable
                staticLibArchiver.executable = prefix + staticLibArchiver.executable
            }

            target('pi') {
                def prefix = "arm-none-linux-gnueabi-"
                cCompiler.executable         = prefix + cCompiler.executable
                cppCompiler.executable       = prefix + cppCompiler.executable
                assembler.executable         = prefix + assembler.executable
                linker.executable            = prefix + linker.executable
                staticLibArchiver.executable = prefix + staticLibArchiver.executable
            }

        }

    }
}

How do I move this to a plugin? I can’t access the model elements from inside the Plugin.apply() method, as that uses project space, not the model space. I don’t know how to use this in a RuleSource rule.

That would probably be implemented in a Groovy plugin like this:

import org.gradle.model.Mutate
import org.gradle.model.RuleSource
import org.gradle.nativeplatform.toolchain.Clang
import org.gradle.nativeplatform.toolchain.Gcc
import org.gradle.nativeplatform.toolchain.NativeToolChainRegistry
import org.gradle.platform.base.PlatformContainer

public class MyPlugin extends RuleSource {
    @Mutate
    void addPlatforms(PlatformContainer platforms) {
        platforms.create("osx-x86_64") { platform ->
            platform.operatingSystem "osx"
            platform.architecture "x86_64"
        }
        
        // ...
    }
    
    @Mutate
    void addToolChains(NativeToolChainRegistry toolChains) {
        toolChains.create("clang", Clang)
        
        toolChains.create("gcc", Gcc) { gcc ->
            gcc.target('stm32f4xx-arm') {
                def prefix = "arm-none-eabi-"
                cCompiler.executable = prefix + cCompiler.executable
                // ...
            }
            
            // ...
        }
    }
}

Hope this helps =)

Thank you very much, much appreciated.