// Copyright (C) 2024 Gradle, Inc.
//
// Licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 4.0 International License.;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

[[building_cpp_projects]]
= Building {cpp} projects

Gradle uses a convention-over-configuration approach to building native projects.
If you are coming from another native build system, these concepts may be unfamiliar at first, but they serve a purpose to simplify build script authoring.

We will look at {cpp} projects in detail in this chapter, but most of the topics will apply to other supported native languages as well.
If you don’t have much experience with building native projects with Gradle, take a look at the {cpp} tutorials for step-by-step instructions on how to build various types of basic {cpp} projects as well as some common use cases.

The {cpp} plugins covered in this chapter were https://blog.gradle.org/introducing-the-new-cpp-plugins[introduced in 2018] and we recommend users to use those plugins over <<native_software.adoc#native_software,the older Native plugins>> that you may find references to.

[[sec:cpp_introduction]]
== Introduction

The simplest build script for a {cpp} project applies the {cpp} application plugin or the {cpp} library plugin and optionally sets the project version:

====
include::sample[dir="snippets/cpp/basic/kotlin",files="build.gradle.kts[tags=apply-cpp-plugin]"]
include::sample[dir="snippets/cpp/basic/groovy",files="build.gradle[tags=apply-cpp-plugin]"]
====

By applying either of the {cpp} plugins, you get a whole host of features:

 * `compileDebugCpp` and `compileReleaseCpp` tasks that compiles the {cpp} source files under _src/main/cpp_ for the well-known debug and release build types, respectively.
 * `linkDebug` and `linkRelease` tasks that link the compiled {cpp} object files into an executable for applications or shared library for libraries with shared linkage for the debug and release build types.
 * `createDebug` and `createRelease` tasks that assemble the compiled {cpp} object files into a static library for libraries with static linkage for the debug and release build types.

For any non-trivial {cpp} project, you’ll probably have some file dependencies and additional configuration specific to _your_ project.

The {cpp} plugins also integrates the above tasks into the standard <<base_plugin#sec:base_tasks,lifecycle tasks>>. The task that produces the development binary is attached to `assemble`.  By default, the development binary is the debug variant.

The rest of the chapter explains the different ways to customize the build to your requirements when building libraries and applications.

[[sec:introducing_build_variants-cpp]]
== Introducing build variants

Native projects can typically produce several different binaries, such as debug or release ones, or ones that target particular platforms and processor architectures.
Gradle manages this through the concepts of _dimensions_ and _variants_.

A dimension is simply a category, where each category is orthogonal to the rest.
For example, the "build type" dimension is a category that includes debug and release.
The "architecture" dimension covers processor architectures like x86-64 and PowerPC.

A variant is a combination of values for these dimensions, consisting of exactly one value for each dimension.
You might have a "debug x86-64" or a "release PowerPC" variant.

Gradle has built-in support for several dimensions and several values within each dimension.
You can find a list of them in the <<plugin_reference.adoc#native_languages,native plugin reference chapter>>.

[[sec:cpp_source_sets]]
== Declaring your source files

Gradle’s {cpp} support uses a `ConfigurableFileCollection` directly from the link:{groovyDslPath}/org.gradle.language.cpp.CppApplication.html[application] or link:{groovyDslPath}/org.gradle.language.cpp.CppLibrary.html[library] script block to configure the set of sources to compile.

Libraries make a distinction between private (implementation details) and public (exported to consumer) headers.

You can also configure sources for each binary build for those cases where sources are compiled only on certain target machines.

.Sources and {cpp} compilation
image::cpp-sourcesets-compilation.png[]

Test sources are configured on each test suite script block. See <<cpp_testing.adoc#cpp_testing,Testing {cpp} projects>> chapter.

[[sec:cpp_dependency_management_overview]]
== Managing your dependencies

The vast majority of projects rely on other projects, so managing your project's dependencies is an important part of building any project.
Dependency management is a big topic, so we will only focus on the basics for {cpp} projects here.
If you’d like to dive into the details, check out the <<getting_started_dep_man.adoc#dependency-management-in-gradle,introduction to dependency management>>.

Gradle provides support for consuming pre-built binaries from Maven repositories published by Gradle footnote:[Unfortunately, Conan and Nuget repositories aren’t yet supported as core features].

We will cover how to add dependencies between projects within a multi-build project.

Specifying dependencies for your {cpp} project requires two pieces of information:

 * Identifying information for the dependency (project path, Maven GAV)
 * What it’s needed for, e.g. compilation, linking, runtime or all of the above.

This information is specified in a `dependencies {}` block of the {cpp} `application` or `library` script block.
For example, to tell Gradle that your project requires library `common` to compile and link your production code, you can use the following fragment:

====
include::sample[dir="snippets/cpp/basic/kotlin",files="build.gradle.kts[tags=cpp-dependency-mgmt]"]
include::sample[dir="snippets/cpp/basic/groovy",files="build.gradle[tags=cpp-dependency-mgmt]"]
====

The Gradle terminology for the three elements is as follows:

 * _Configuration_ (ex: `implementation`) - a named collection of dependencies, grouped together for a specific goal such as compiling or linking a module
 * _Project reference_ (ex: `project(':common')`) - the project referenced by the specified path

You can find a more comprehensive glossary of dependency management terms <<glossary.adoc#dependency_management_terminology,here>>.

As far as configurations go, the main ones of interest are:

 * `implementation` - used for compilation, linking and runtime
 * `cppCompile__Variant__` - for dependencies that are necessary to compile your production code but shouldn’t be part of the linking or runtime process
 * `nativeLink__Variant__` - for dependencies that are necessary to link your code but shouldn’t be part of the compilation or runtime process
 * `nativeRuntime__Variant__` - for dependencies that are necessary to run your component but shouldn’t be part of the compilation or linking process

You can learn more about these and how they relate to one another in the <<plugin_reference.adoc#native_languages,native plugin reference chapter>>.

Be aware that the <<cpp_library_plugin.adoc#cpp_library_plugin,{cpp} Library Plugin>> creates an additional configuration — `api` — for dependencies that are required for compiling and linking both the module and any modules that depend on it.

We have only scratched the surface here, so we recommend that you read the <<getting_started_dep_man.adoc#dependency-management-in-gradle,dedicated dependency management chapters>> once you’re comfortable with the basics of building {cpp} projects with Gradle.

Some common scenarios that require further reading include:

 * Defining a custom <<supported_repository_types.adoc#sec:maven-repo,Maven-compatible>> repository
 * Declaring dependencies with <<dependency_versions.adoc#sec:declaring-dependency-with-changing-version,changing>> (e.g. SNAPSHOT) and <<dependency_versions.adoc#sec:declaring-dependency-with-dynamic-version,dynamic>> (range) versions
 * Declaring a sibling <<declaring_dependencies_basics.adoc#sec:project-dependencies,project as a dependency>>
 * <<dependency_constraints.adoc#dependency-constraints,Controlling transitive dependencies and their versions>>
 * Testing your fixes to 3rd-party dependency via <<composite_builds.adoc#composite_builds,composite builds>> (a better alternative to publishing to and consuming from <<supported_repository_types.adoc#sec:maven-local,Maven Local>>)

You’ll discover that Gradle has a rich API for working with dependencies — one that takes time to master, but is straightforward to use for common scenarios.

[[sec:cpp_compile_link]]
== Compiling and linking your code
Compiling your code can be trivially easy if you follow the conventions:

1. Put your source code under the _src/main/cpp_ directory
2. Declare your compile dependencies in the `implementation` configurations (see the previous section)
3. Run the `assemble` task

We recommend that you follow these conventions wherever possible, but you don’t have to.

There are several options for customization, as you’ll see next.

NOTE: All link:{groovyDslPath}/org.gradle.language.cpp.tasks.CppCompile.html[CppCompile] tasks are incremental and cacheable.

[[sec:cpp_supported_tool_chain]]
=== Supported tool chain

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.
Gradle selects the first tool chain that can build for the target operating system and architecture.
In the future, Gradle will consider source and ABI compatibility when selecting a tool chain.

Gradle has general support for the three major tool chains on major operating system: Clang footnote:[Installed with Xcode on macOS], GCC footnote:[Installed through Cygwin and MinGW for 32- and 64-bits architecture on Windows] and Visual {cpp} footnote:[Installed with Visual Studio 2010 to 2019] (Windows-only).
GCC and Clang installed using Macports and Homebrew have been reported to work fine, but this isn’t tested continuously.

==== Windows

To build on Windows, install a compatible version of Visual Studio.
The {cpp} plugins will discover the Visual Studio installations and select the latest version.
If automatic discovery does not work, you can configure Visual Studio using the `toolChains` block.

====
include::sample[dir="snippets/cpp/basic/kotlin",files="build.gradle.kts[tags=cpp-toolchain]"]
include::sample[dir="snippets/cpp/basic/groovy",files="build.gradle[tags=cpp-toolchain]"]
====

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

==== macOS

To build on macOS, you should install Xcode.
The {cpp} plugins will discover the Xcode installation using the system PATH.

The {cpp} plugins also work with GCC and Clang installed with Macports or Homebrew footnote:[Macports and Homebrew installation of GCC and Clang is not officially supported].
To use one of the Macports or Homebrew, you will need to add Macports/Homebrew to the system PATH.

==== Linux

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

[[sec:custom_cpp_source_set_paths]]
=== Customizing file and directory locations

Imagine you have a legacy library project that uses an _src_ directory for the production code and private headers and _include_ directory for exported headers.
The conventional directory structure won’t work, so you need to tell Gradle where to find the source and header files.
You do that via the `application` or `library` script block.

Each component script block, as well as each binary, defines where it’s source code resides.
You can override the convention values by using the following syntax:

====
include::sample[dir="snippets/cpp/basic/kotlin/common",files="build.gradle.kts[tags=cpp-source-set]"]
include::sample[dir="snippets/cpp/basic/groovy/common",files="build.gradle[tags=cpp-source-set]"]
====

Now Gradle will only search directly in _src_ for the source and private headers and in _include_ for public headers.

[[sec:custom_cpp_compile_link]]
=== Changing compiler and linker options

Most of the compiler and linker options are accessible through the corresponding task, such as `compile__Variant__Cpp`, `link__Variant__` and `create__Variant__`.
These tasks are of type link:{groovyDslPath}/org.gradle.language.cpp.tasks.CppCompile.html[CppCompile], link:{groovyDslPath}/org.gradle.nativeplatform.tasks.LinkSharedLibrary.html[LinkSharedLibrary] and link:{groovyDslPath}/org.gradle.nativeplatform.tasks.CreateStaticLibrary.html[CreateStaticLibrary] respectively.
Read the task reference for an up-to-date and comprehensive list of the options.

For example, if you want to change the warning level generated by the compiler for all variants, you can use this configuration:

====
include::sample[dir="snippets/cpp/basic/kotlin",files="build.gradle.kts[tags=cpp-compiler-options-all-variants]"]
include::sample[dir="snippets/cpp/basic/groovy",files="build.gradle[tags=cpp-compiler-options-all-variants]"]
====

It’s also possible to find the instance for a specific variant through the `BinaryCollection` on the `application` or `library` script block:

====
include::sample[dir="snippets/cpp/basic/kotlin",files="build.gradle.kts[tags=cpp-compiler-options-per-variants]"]
include::sample[dir="snippets/cpp/basic/groovy",files="build.gradle[tags=cpp-compiler-options-per-variants]"]
====

[[sec:select_cpp_target_machines]]
=== Selecting target machines

By default, Gradle will attempt to create a {cpp} binary variant for the host operating system and architecture.
It is possible to override this by specifying the set of `TargetMachine` on the `application` or `library` script block:

====
include::sample[dir="snippets/cpp/basic/kotlin",files="build.gradle.kts[tags=cpp-select-target-machines]"]
include::sample[dir="snippets/cpp/basic/groovy",files="build.gradle[tags=cpp-select-target-machines]"]
====

[[sec:cpp_packaging]]
== Packaging and publishing

How you package and potentially publish your {cpp} project varies greatly in the native world.
Gradle comes with defaults, but custom packaging can be implemented without any issues.

 * Executable files are published directly to Maven repositories.
 * Shared and static library files are published directly to Maven repositories along with a zip of the public headers.
 * For applications, Gradle also supports installing and running the executable with all of its shared library dependencies in a known location.

[[sec:cleaning_cpp_build]]
== Cleaning the build

The {cpp} Application and Library Plugins add a `clean` task to you project by using the <<base_plugin.adoc#base_plugin,base plugin>>.
This task simply deletes everything in the `layout.buildDirectory` directory, hence why you should always put files generated by the build in there.
The task is an instance of Delete and you can change what directory it deletes by setting its `dir` property.

[[sec:building_cpp_libraries]]
== Building {cpp} libraries

The unique aspect of library projects is that they are used (or "consumed") by other {cpp} projects.
That means the dependency metadata published with the binaries and headers — in the form of Gradle Module Metadata — is crucial.
In particular, consumers of your library should be able to distinguish between two different types of dependencies: those that are only required to compile your library and those that are also required to compile the consumer.

Gradle manages this distinction via the <<cpp_library_plugin.adoc#cpp_library_plugin,{cpp} Library Plugin>>, which introduces an _api_ configuration in addition to the _implementation_ once covered in this chapter.
If the types from a dependency appear as unresolved symbols of the static library or within the public headers then that dependency is exposed via your library’s public API and should, therefore, be added to the _api_ configuration.
Otherwise, the dependency is an internal implementation detail and should be added to _implementation_.

If you’re unsure of the difference between an API and implementation dependency, the <<cpp_library_plugin.adoc#sec:cpp_library_api_vs_implementation,{cpp} Library Plugin>> chapter has a detailed explanation.
In addition, you can see a basic, practical example of building a {cpp} library in the corresponding link:../samples/sample_building_cpp_libraries.html[sample].

[[sec:building_cpp_applications]]
== Building {cpp} applications

See the <<cpp_application_plugin.adoc#cpp_application_plugin,{cpp} Application Plugin>> chapter for more details, but here’s a quick summary of what you get:

 * `install` create a directory containing everything needed to run it
 * Shell and Windows Batch scripts to start the application

You can see a basic example of building a {cpp} application in the corresponding link:../samples/sample_building_cpp_applications.html[sample].
