Multiple platforms and multiple toolchains for native binary compiling

I’m using Gradle 2.4 and I’m trying to compile a native C++ application for two different platforms (desktop and embedded) using two different GCC toolchains; one toolchain for one platform and another toolchain for the other platform. However, Gradle seems to be using the one GCC toolchain for both platforms. Here’s an example:

model {
    platforms {
        desktop {
            operatingSystem 'linux'
            architecture 'x86'
        }
        embedded {
            operatingSystem 'linux'
            architecture 'x86'
        }
    }
    toolChains {
        desktop_gcc(Gcc) {
            target('desktop')
        }
        embedded_gcc(Gcc) {
            target('embedded')
            path '/path/to/embedded/gcc'
        }
    }
}

When I run the example above, the desktop_gcc compiles both platforms. If I remove desktop_gcc, then embedded_gcc compiles both platforms.

Is this the expected behavior? I assumed that the desktop_gcc would be used to compile the desktop platform, and the embedded_gcc would be used to compile the embedded platform.

I suppose the problem I’m really trying to solve is, how do I change the Gcc path for only specific platforms? I’ve tried this:

toolChains {
    gcc(Gcc) {
        target('embedded') {
            path '/path/to/embedded/gcc'
        }
        target('desktop')
    }
}

and it just uses the ‘/path/to/embedded/gcc’ for both platforms.

Did you ever figure this out?

I did not. I haven’t tried it again since Gradle 2.4 though.

We are simply picking the first compatible toolchain we can find. We consider both equally capable of building your binary since they are both targeting the same OS and architecture. In the future we may decide to add more dimensions of compatibility. In the meantime you should be able to assign the appropriate toolchain to your binary by keying off of targetPlatform.

model {
    toolChains {
        gcc_foo(Gcc)
        gcc_bar(Gcc)
    }
    platforms {
        foo
        bar 
    }
    components {
        main(NativeExecutableSpec) {
            targetPlatform "foo"
            targetPlatform "bar"
            
            binaries.all {
                toolChain = toolChains["gcc_${targetPlatform.name}"]
            }
        }
    }
}

My only other suggestion is if the GCC executables are distinguished by different names (e.g., embedded-gcc vs desktop-gcc), you can do everything as a single tool chain:

	toolChains {
		gcc(Gcc) {
			target("embedded") {
				cppCompiler.executable = "${platform}-gcc"
			}
			target("desktop")
		}
	}

The tool chain selection process isn’t very configurable right now.

Thanks! Is this also still a valid solution? I’m using 2.2.1 in Android Studio.

According to the docs the toolChain property on a binary is read-only (https://docs.gradle.org/current/dsl/org.gradle.nativeplatform.NativeBinarySpec.html#org.gradle.nativeplatform.NativeBinarySpec:toolChain). Does this really work?

I am trying to do something similar, albeit a little different: I need to use standard gcc and Emscripten toolchain to build C++ library to two versions of the library:

  • regular .dll shared library
  • and .js module after transpiling C++ code to JavaScript

After jumping through a few hoops and implementing a custom toolchain, I was able to build *.js library, but every time I try to register both toolchains and two target machines (one Windows:x86 and another Windows:Node_12), Gradle ends up building only the Windows:x86 version.

Is this intended behavior that Gradle picks first target machine compatible with current build machine OS? Or could I still be missing something?

P.S.: after Going through Gradle code, I see that Gradle only builds for machines that use the OS as the build host. So my custom toolchain is targeted to ‘host:Node_12’.