Introducing the new C++ plugins

This post introduces some new plugins for C++ that we’ve been working on. These plugins can build C++ libraries and applications. They work on macOS, Linux, and Windows with GCC, Clang and Visual C++/Visual Studio.

The plugins will eventually replace the software model plugins and take advantage of many new features baked into Gradle core, such as a rich dependency management engine, build cache, composite builds, finer grained parallel execution, build scans, and more. For background, see our post on the State and Future of the Gradle Software Model.

We welcome any feedback you may have about these plugins. You can leave feedback on the Gradle forums or raise issues on the Gradle native GitHub repository.

Building an application

You can find all of the samples from this post in the Gradle native samples GitHub repository. Let’s look at building a simple application.

The build script should look familiar to anyone who has used Gradle’s Java plugins:

plugins {
    id 'cpp-application'
}

This application has no dependencies, and the C++ source files and headers live in the default location: the src/main/cpp directory. Since this is Gradle, you can easily configure the source locations to match whatever layout your project has, including the common pattern of putting everything in one directory.

Here’s the result of running ./gradlew assemble on this sample:

./gradlew assemble

Take a look at the build scan for this build to see what happened in more detail.

compile debug timeline

The plugins automatically find the compiler, linker and other tools to build the application. The result ends up installed in the build/install directory ready to run.

IDE support

Xcode is currently supported for C++ projects. You can just run ./gradlew xcode and open the generated workspace. Support for generating Visual Studio solutions will be added early this year and support for other IDEs will be gradually added after that.

Here is the result of running ./gradlew xcode on the sample:

./gradlew xcode

This is how the workspace looks in Xcode:

Xcode integration

Dependencies

The plugin uses Gradle’s dependency management features, just like other plugins such as the Java or Android plugins. This means, for example, transitive dependencies work just fine.

Let’s add a dependency on a library to the application. In this sample, the C++ library is downloaded from a Maven repository. You don’t have to install the library anywhere manually, and everyone who runs the build will use the version specified in the build script, rather than whatever version happens to be installed on their machine.

The build script defines a Maven repository and declares a dependency on another sample C++ library:

repositories {
    maven {
        // In this sample, we used a local Maven repository, 
        // but Maven Central or Artifactory server can be used.
        url 'http://localhost:8000/'
    }
}

dependencies {
    implementation 'org.gradle.cpp-samples:math:1.5'
}

Here is the result of running ./gradlew assemble. Gradle downloads the headers and shared library binary and compiles and links against these:

./gradlew assemble

The build scan shows more detail, including the downloads.

app assemble build scan network activity

Here is how this project looks in Xcode:

Xcode integration

Tests

Basic unit testing is supported out of the box. Here is a sample that uses Google Test, downloaded from a Maven repository. We published the binaries using this fork of Google Test, which simply adds a Gradle build.

The build script declares a dependency on Google test and a Maven repository that can be used to locate the Google test binaries:

plugins {
    id 'cpp-unit-test'
}
repositories {
    maven {
        url 'https://repo.gradle.org/gradle/libs-snapshots-local/'
    }
}
dependencies {
    // Currently we have to encode the operating system and architecture in 
    // the dependency name. This will disappear in later releases
    unitTestImplementation 'org.gradle.cpp-samples:googletest_macosx_x86-64_4.5:1.9.0-SNAPSHOT'
}

Here is the result of running ./gradlew check. Gradle downloads the Google test library, compiles the C++ source and tests and then runs the tests:

./gradlew check

build scan for math check

Richer reporting, build scan support, parallel execution and filtering for Google Test will be added this year with support for other C++ testing frameworks after that.

Fast builds

The plugins can produce debug and release builds of the application or library using Gradle’s new variant-aware dependency management, so that debug builds are compiled and linked against debug library binaries, and release builds are compiled and linked against release library binaries. When you build the debug build, which is the default, Gradle builds only the debug builds of the libraries that you need, rather than building everything.

Developer and CI builds are fast. C++ compilation is a cacheable task, so you can avoid unnecessary and long compilation times when using the build cache. Gradle Enterprise comes with a build cache backend. You don’t need to use the --parallel option as Gradle does incremental and parallel compilation and linking by default.

Let’s run some clean builds that use the build cache:

./gradlew assemble with build cache

You can see that the second build is faster, as the result is fetched from the build cache rather than recompiled. Build scans for non-cached build and cached build.

cached vs non-cached assemble

Publishing C++ libraries

The new plugins can publish C++ libraries to a Maven or Ivy repository. Support for other kinds of repositories will be added later. Here is the build for the library we saw earlier.

The build script adds a Maven repository to publish the binaries to:

plugins {
    id 'cpp-library'
    id 'maven-publish'
}

group = 'org.gradle.cpp-samples'
version = '1.5'

publishing {
    repositories {
        maven {
            // In this sample, we used a local maven repository, 
            // but Maven Central or Artifactory server can be used.
            url 'http://localhost:8000/'
        }
    }
}

Here is the result of running ./gradlew publish:

./gradlew publish

Composite builds

Composite builds also work the same as in Java projects. This sample using a composite build combines builds so they can be worked on together:

rootProject.name = 'app'

includeBuild 'list-library'
includeBuild 'utilities-library'

Here’s the result in Xcode. The application and the libraries it uses are available to edit, build and test together:

Xcode integration

Finally, it’s easy to set up a CI build for our application. We’ve added configuration for Travis CI.

Native Samples Travis CI

Your Feedback Wanted

These plugins are a work in progress and have some limitations. For example, binary publishing doesn’t understand operating system or architecture yet. We’ll continue to improve these plugins, make them stable, and eventually will deprecate the software model plugins.

Please try these plugins out and let us know what you think. The easiest way to get started is to clone the native samples repository and follow the instructions. Our samples use a Gradle nightly build, so you’ll see the latest and greatest developments there. Some changes are already showing up in the 4.5 release candidates.

We’d love to hear what you think works well, what’s confusing, and what is missing that would block you from using Gradle to build C++ software. You can also leave feedback on the Gradle forums or raise issues on the Gradle native GitHub repository.