# Building C++ applications and libraries

✨ | Please be aware that the DSL and APIs may change in later Gradle versions as we add new features with respect to our incubating feature lifecycle.

Gradle’s C plugins add support for building applications and libraries written in C. These plugins were introduced in 2018 and we recommend new projects to use these plugins over the older Native plugins. This chapter makes heavy use of a large collection of samples.

## Features

The C++ plugins provide:

- Support for building C++ libraries and applications on Windows, Linux, and macOS.

- Support for building variants of the same project for different architectures and operating systems.

- Incremental and parallel compilation.

- Cacheable compilation with Gradle’s build cache.

- Dependency management features like any Java project built with Gradle.

  - Composite build support.

  - External dependency resolution from repositories.

  - Source dependencies.

- Publishing of libraries and applications to repositories.

- Unit test execution.

- Integration with various IDEs (Xcode, Visual Studio, CLion).

- Automatic discovery of popular tool chains (Visual C++, GCC, Clang).

- Integration with build scans.

## Plugin overview

Unlike the software model native plugins, the new C++ plugins rely on a familiar DSL and configuration model.

When the C++ plugin is applied to the project, Gradle registers an extension for the type of project (application or library). All configuration is done through this extension or the tasks registered by the plugin.

## Incremental Compilation

Before invoking the compiler, Gradle analyzes the dependencies between source and header files. When a file changes, Gradle uses this dependency information to select which files need to be recompiled. When macros or compiler arguments change, Gradle must recompile all source files.

Gradle tracks the contents of files, so changes to just the timestamp of a header file (i.e., touching a header file) will not cause Gradle to recompile the affected source files.

If Gradle is unable to determine the relationship between source files and header files, it will fall back to compiling everything to be safe.

## Parallel Compilation

Gradle uses a single build worker pool to concurrently compile and link C++ binaries by default. No special configuration is required to enable parallel compilation.

The worker pool size is determined by the number of available processors on the build machine (as reported to the build JVM). To explicitly set the number of workers use the `--max-workers` command-line option or `org.gradle.workers.max` system property. There is generally no need to change this setting from its default.

This build worker pool is shared across all tasks. This means that when using parallel project execution, the maximum number of concurrent compilation operations does not increase. For example, if the build machine has 4 processing cores and 10 projects are compiling in parallel, Gradle will only try to compile 4 files at a time and not 40.

## Cached Compilation

Gradle uses the inputs to a compilation task to calculate a build cache key. This key uniquely identifies the output of the compilation task. When the build cache is enabled, Gradle will first check for a match of the build cache key in a local or remote cache. When there is a hit, Gradle extracts the compilation output into the expected location.

The build cache key takes into consideration:

- Version and type of the compiler

- Any macros or compiler arguments

- Contents of the source files

- Contents of the header files

- Transitive headers used by the source or header files

- Version of Gradle

## Building an application

Apply the `cpp-application` plugin. You can configure a CppApplication in a `application` block.

By default, when building a C++ application, the project name will be used as the name of the executable. For Windows, `.exe` will be added.

See a sample.

## Building a library

Apply the `cpp-library` plugin. You can configure a CppLibrary in a `library` block.

By default, when building a C++ library, the project name will be used as the name of the library. Depending on the operating system, Gradle will add `.so`, `.dylib` or `.dll` for shared libraries or `.a` or `.lib` for static libraries. Gradle will assume you only want a shared library unless otherwise configured.

See a sample.

If you only want static libraries, you can do that too.

## C++ source layout

By default, Gradle assumes a C++ library or application’s sources are in `src/main/cpp`.

For a library, Gradle assumes its public headers are in `src/main/public`. Header files can be mixed into `src/main/cpp`, but these headers will be treated as private and not exposed to downstream consumers.

Gradle assumes C++ source files end in `.cpp`, `.c+\+` or `.cc`.

## Declaring dependencies

Dependencies can be declared in a similar way to other Gradle plugins, like Java, with the main difference being that the `dependencies` block is inside the `application` or `library` block.

C applications only have `implementation` level dependencies. C libraries have `api` and `implementation` dependencies.

Dependencies that are `implementation` only are not shared with downstream consumers. `api` dependencies form a part of the public API for a library.

Gradle automatically knows when to use the headers, link time or runtime usage of a dependency.

### Project Dependencies

Project dependencies are just like project dependencies in Java projects. Gradle will export public header paths to downstream consumers and build libraries when required.

See a sample.

### External Dependencies

External dependencies are like external dependencies in Java projects. Gradle will automatically fetch a dependency’s headers and link/runtime files. The compile and link tasks will be configured to search for headers or libraries in Gradle’s dependency cache.

See a sample.

### Publishing

✨ | The Gradle metadata format is unstable and likely to change in incompatible ways. This will cause previously published artifacts to no longer be resolved properly. We will announce when this format is stable.

For C++ applications, Gradle will publish the executable.

For C++ libraries, Gradle will publish a header zip and any supporting binaries (shared or static).

Gradle also publishes additional information about the artifacts (a "Gradle metadata" file) that will be used when resolving dependencies. Gradle needs the additional metadata to select the appropriate variant (e.g., macOS vs Windows).

See a sample.

## Configure for different targets

From a C++ library or application, Gradle generates what we call a binary. This binary is a variant of a component which has been assigned a particular build type (e.g., debug) and target machine (e.g., 32-bit Windows). Only binaries that may be built on the current host are generated by Gradle.

You can configure variant specific things, such as dependencies.

### Debug and Release

Gradle creates two build types:

- Debug - variants of this type are debuggable and not optimized

- Release - variant of this type are debuggable and optimized

Under the covers, Gradle passes the appropriate compiler arguments for these build types.

Debugging symbols are extracted and stored in a separate file for the release build type, if necessary.

### Target Machine

Gradle assumes the C++ application or library only targets the current host unless told otherwise. When building for multiple target machines, you need to declare this in the build configuration so the published metadata is created correctly.

See a sample.

## IDE integration

Gradle provides plugins for Visual Studio and Xcode.

When used with the C plugins, Gradle will generate metadata files used by these IDEs. As much as possible, we've tried to make the IDE delegate to Gradle when compiling and linking C applications and libraries.

JetBrains maintains a separate integration with CLion.

Try generating a project with one of our samples!

## Unit Testing support

Unit testing support is very limited right now. Gradle makes no assumptions about the type of unit testing framework being used. Gradle automatically links the test executable with the object files produced for the development binary. If the binary is an executable, Gradle will relocate the `main` symbol so you can test code in an application without conflicting with the test executable’s `main` symbol.

In the future, Gradle make come with support out-of-the-box for a particular testing framework or make it easier to integrate your own.

See a sample.

## Tool chain support

Gradle offers the ability to execute the same build using different tool chains. When you build a native binary, Gradle will attempt to locate a tool chain installed on your machine that can build the binary.

The following tool chains are supported:

Operating System | Tool Chain | Notes
--- | --- | ---
Linux | GCC |
Linux | Clang |
macOS | XCode | Uses the Clang tool chain bundled with XCode.
Windows | Visual C++ | Windows XP and later, Visual C++ 2010 to 2017.
Windows | GCC with Cygwin 32 and Cygwin 64 | Windows XP and later.
Windows | GCC with MinGW and MinGW64 | Windows XP and later.

### Tool chain installation

To build C++ projects, you will need to have a compatible tool chain installed:

#### Windows

To build on Windows, install a compatible version of Visual Studio. The C++ plugins will discover the Visual Studio installations and select the latest version. There is no need to mess around with environment variables or batch scripts. This works fine from a Cygwin shell or the Windows command-line.

Alternatively, you can install Cygwin with GCC or MinGW. Clang is currently not supported.

#### macOS

To build on macOS, you should install XCode. The C++ plugins will discover the XCode installation using the system PATH.

The native plugins also work with GCC and Clang bundled with Macports. To use one of the Macports tool chains, you will need to make the tool chain the default using the `port select` command and add Macports to the system PATH.

#### Linux

To build on Linux, install a compatible version of GCC or Clang. The C++ plugins will discover GCC or Clang using the system PATH.

## Limitations

The C++ plugins come with a few caveats and limitations:

- While you can publish executable and shared libraries to Maven repositories, you cannot publish to Ivy repositories.

- The metadata format used by the C++ plugin is unstable and may change between Gradle versions in incompatible ways. This limitation is expected to be removed in the next Gradle release (5.3).

- C++ libraries are expected to have all of the same headers for all variants.

- Support for "pre-built" dependencies is not a first class citizen, but there are several approaches to dealing with them:

  - Add them directly as file dependencies.

  - Resolve them as an external dependency

  - Wrap the existing build system with a Gradle layer

- The default set of C++ source extensions is not configurable.

- Currently, the plugins only support building C++ out of the box. It’s possible to build C applications with some effort.

- Pre-compiled header support is not supported out of the box, but it’s possible.

- Cross-compilation is not supported out of the box.

## Feedback and Contributing

Issues specific to the C++ plugins and Gradle-Native related features are tracked on a separate repository. If you run into problems or have a feature request, please open an issue up over here.

If you’re interested in contributing to Gradle-Native development and the C++ plugins, please contact us through a GitHub issue.