2.10-rc2: Native Binaries: VisualCpp toolchain using 32-bit cross-compiler by default

I was troubleshooting a compilation problem on a relatively simple source tree, and so ran gradle in debug mode to see how it was issuing the compiler commands, and was pretty surprised to find this:

[org.gradle.process.internal.DefaultExecHandle] Starting process 'command 'C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\amd64_x86\cl.exe''

That is the 32-bit cross-compiler version of cl.exe, which I have no interest in using on my x64 system (this is supposed to be an x64 build) and can’t seem to find a way to change it.

I found this pull request:

…which apparently aimed to fix this problem, but if it was ever committed, it seems to have been backed out. Either that, or I’ve missed something basic about how to instruct gradle to use the standard cl.exe binary for native compiles on my system.

I’m assuming this is a bug, can anybody else either confirm or inform me how to get gradle to use the native compiler executable?

This may not be a bug - it may just be that I haven’t figured out how to get gradle to produce x64 builds on my x64 system. This is just a test project with no dependencies, so I can’t see a reason for gradle not to be using the native x64 compiler.

It’s just the default on Windows for historical reasons, I imagine it’ll change.

You can specify your own platform and define which components build for that platform.
https://docs.gradle.org/current/userguide/nativeBinaries.html#native_binaries:platform

Here’s a sample using it:

OK - so, it’s not sufficient to define the platforms element with all the desired variants, I need to also specify targetPlatform on each component in order to get the platform variants I’m interested in?

This doesn’t seem self-consistent with buildType definitions, which I only need to specify under the model element in order to get all of those variants built by default, and it also doesn’t seem consistent with the documentation:

For a default component, Gradle will attempt to create a native binary variant for each and every combination of buildType, platform and flavor defined for the project. It is possible to override this on a per-component basis, by specifying the set of targetBuildTypes, targetPlatform and/or targetFlavors.

Reading the above, you get the impression that you only need to add component level entries to constrain the default build to produce only the variants defined there.

@sterling: I’m finding what looks like two kinds of problems, and I don’t (yet) know whether this is only happening with the visualCpp toolchain or is common across all tool chains:

  1. The default build behavior only automatically builds the buildType and (for libraries) the shared and static variants, not the available platform variants, and it seems to prefer building the 32-bit platform variant, even on 64-bit operating systems, at least for the visualCpp tool chain.
  2. At least for visualCpp, even if you only define a single platform with an architecture of x86_64, the default build will not produce a 64-bit build.

Here is an example build.gradle that exhibits this behavior on my system:

apply plugin: 'cpp'

model {

    platforms {
        x64 { architecture 'x86_64' }
    }

    buildTypes {
        debug
        release
    }
    
    binaries {
        all {
            println 'configuring variant: ' + name + '.' + targetPlatform.name + '.' + buildType.name
        }
    }

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

When I run .\gradlew build on this project, this is the output I get:

configuring variant: debugSharedLibrary.windows_x86.debug
configuring variant: debugStaticLibrary.windows_x86.debug
configuring variant: releaseSharedLibrary.windows_x86.release
configuring variant: releaseStaticLibrary.windows_x86.release

and I can verify from --debug output that the 32-bit cross-compiler is invoked. So, I haven’t even defined a 32-bit platform, but I’m only getting 32-bit libs. This feels like a bug to me. It’s definitely unexpected, given the content of this build.gradle file.

The only way I can get a 64-bit binary out of this build is by modifying the components element like so:

    components {
        example(NativeLibrarySpec) {
            targetPlatform 'x64'
            sources {
                binaries.withType(SharedLibraryBinarySpec) { buildable = false }
            }
        }
    }

After making this modification, I then get this output (and I can see from --debug output that the 64-bit compiler is invoked):

configuring variant: debugSharedLibrary.x64.debug
configuring variant: debugStaticLibrary.x64.debug
configuring variant: releaseSharedLibrary.x64.release
configuring variant: releaseStaticLibrary.x64.release

I can confirm that this behavior is also seen with the gcc tool chain as well. I have an RHEL system for which the problem is reversed. If I define both a 32-bit and 64-bit platform, the default build will only build the 64-bit variant by default. And, if I only define a 32-bit platform, gradle will still only build the 64-bit variant by default.

In order to get 32-bit output on a gcc system with 32-bit cross-compile support, I have to explicitly list the platform variants in the component.