Building C++ Applications
This guide demonstrates how to use Gradle’s Build Init plugin to produce a C++ application that follows Gradle conventions.
What you’ll need
-
About NN
-
A text editor
-
A command prompt
-
The Java Development Kit (JDK), version 8 or higher
-
A Gradle distribution, version 5.5.1 or better
-
An installed C++ compiler. See which C++ tool chains are supported by Gradle.
Check the user manual
Gradle comes with a built-in plugin called the Build Init plugin. It is documented in the Gradle User Manual.
The plugin provides a task, called init
, that generates the project. The plugin also uses the (also built-in) wrapper
task to create a Gradle wrapper script, gradlew
.
Setup
The first step is to create a folder for the new project and change directory into it.
$ mkdir building-cpp-applications $ cd building-cpp-applications
Run the init task
From inside the new project directory, run the init
task and select cpp-application
project type when prompted. For the other questions, press enter to use the default values.
$ gradle init Select type of project to generate: 1: basic 2: cpp-application 3: cpp-library 4: groovy-application 5: groovy-library 6: java-application 7: java-library 8: kotlin-application 9: kotlin-library 10: scala-library Enter selection (default: basic) [1..10] 2 Select build script DSL: 1: groovy 2: kotlin Enter selection (default: groovy) [1..2] Project name (default: building-cpp-applications): BUILD SUCCESSFUL in 1s 2 actionable tasks: 2 executed
If you prefer the Kotlin DSL, you can select kotlin
for the build script DSL.
The init
task runs the wrapper
task first, which generates the gradlew
and gradlew.bat
wrapper scripts. Then it creates the new project with the following structure:
├── build.gradle
├── gradle (1)
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main
│ ├── cpp (2)
│ │ └── app.cpp
│ └── headers (3)
│ └── app.h
└── test (4)
└── cpp
└── app_test.cpp
├── build.gradle.kts
├── gradle (1)
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle.kts
└── src
├── main
│ ├── cpp (2)
│ │ └── app.cpp
│ └── headers (3)
│ └── app.h
└── test (4)
└── cpp
└── app_test.cpp
1 | Generated folder for wrapper files |
2 | Default C++ source folder |
3 | Default C++ header folder |
4 | Default C++ test folder |
The Gradle source layout convention can be customize to fit any source layout. See customizing C++ source section of the C++ chapter in User Manual as well as the custom source layout sample for a demonstration. |
Review the generated project files
The settings.gradle
file is heavily commented, but has only one active line:
/*
* This file was generated by the Gradle 'init' task.
*
* The settings file is used to specify which projects to include in your build.
*
* Detailed information about configuring a multi-project build in Gradle can be found
* in the user manual at https://docs.gradle.org/5.3/userguide/multi_project_builds.html
*/
rootProject.name = 'building-cpp-applications'
/*
* This file was generated by the Gradle 'init' task.
*
* The settings file is used to specify which projects to include in your build.
*
* Detailed information about configuring a multi-project build in Gradle can be found
* in the user manual at https://docs.gradle.org/5.3/userguide/multi_project_builds.html
*/
rootProject.name = "building-cpp-applications"
This sets the name of the root project to "building-cpp-applications", which overrides the default behavior of naming the project after the directory it’s in.
The generated build.gradle
file also has many comments. The active portion is reproduced here:
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample CPP project to get you started.
*/
plugins {
// Apply the cpp-application plugin to add support for building CPP applications
id 'cpp-application'
// Apply the cpp-unit-test plugin to add support for building and running CPP test applications
id 'cpp-unit-test'
}
// Set the target operating system and architecture for this application
application {
targetMachines.add(machines.macOS.x86_64)
}
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample CPP project to get you started.
*/
plugins {
// Apply the cpp-application plugin to add support for building CPP applications
`cpp-application`
// Apply the cpp-unit-test plugin to add support for building and running CPP test applications
`cpp-unit-test`
}
// Set the target operating system and architecture for this application
application {
targetMachines.add(machines.macOS.x86_64)
}
The build file adds the cpp-application
and cpp-unit-test
plugins:
-
The
cpp-application
plugin automatically generates application component configurable via application extension DSL. -
The
cpp-unit-test
plugin automatically generates a executable component that depends on the application. It also adds a new verification task. The verification tasks arecheck
tasks that assemble and test a binary. The unit test component configurable via the unitTest extension DSL.
The file src/main/cpp/app.cpp
is shown here:
/*
* This C++ source file was generated by the Gradle 'init' task.
*/
#include <iostream>
#include <stdlib.h>
#include "app.h"
std::string building_cpp_applications::Greeter::greeting() {
return std::string("Hello, World!");
}
int main () {
building_cpp_applications::Greeter greeter;
std::cout << greeter.greeting() << std::endl;
return 0;
}
The exported header, src/main/headers/app.h
is shown here:
/*
* This C++ source file was generated by the Gradle 'init' task.
*/
#ifndef APP_H
#define APP_H
#include <string>
namespace building_cpp_applications {
class Greeter {
public:
std::string greeting();
};
}
#endif
The test application, src/test/cpp/app_test.cpp
is shown next:
/*
* This C++ source file was generated by the Gradle 'init' task.
*/
#include "app.h"
#include <cassert>
int main() {
building_cpp_applications::Greeter greeter;
assert(greeter.greeting().compare("Hello, World!") == 0);
return 0;
}
The generated test file has a single test using the standard library assert function.
The test instantiates the Greeter
class, invokes the greeting()
method, and checks that the returned value is equals to the expected string.
The cpp-unit-test plugin can also be used to test your application binaries using Google Test as demonstrated in the simple library sample.
|
Execute the build
To build the project, run the build
task. You can use the regular gradle
command, but when a project includes a wrapper script, it is considered good form to use it instead.
$ ./gradlew build > Task :compileTestCpp > Task :compileDebugCpp > Task :relocateMainForTest > Task :linkDebug > Task :installDebug > Task :assemble > Task :linkTest > Task :installTest > Task :runTest > Task :test > Task :check > Task :build BUILD SUCCESSFUL 8 actionable tasks: 8 executed
The first time you run the wrapper script, gradlew , there may be a delay while that version of gradle is downloaded and stored locally in your ~/.gradle/wrapper/dists folder.
|
The build
task compiles the C++ sources, link the object files, and runs the tests.
Dependencies to other projects isn’t covered in this guide. To learn more about that subject, have a look at the transitive dependency sample for a demonstration. |
Gradle integrate with several IDEs: Visual Studio, Xcode and Clion. To learn more, have a look at their respective linked documentation to configure those IDE integration in your project. |
Application package
As part of the the build process, Gradle package the main and test application for distribution on other system.
The installDebug
and installTest
task copies the executable and generate a shell script for executing the application.
The following listing shows the content of the build/install
folder:
├── main │ └── debug │ ├── building-cpp-applications (1) │ └── lib │ └── building-cpp-applications (2) └── test ├── building-cpp-applicationsTest (1) └── lib └── building-cpp-applicationsTest (3)
1 | The script for executing the application variant |
2 | The main executable binary (debug variant) |
3 | The test executable binary |
When a build has dependencies, every dependent shared libraries are also copied into the installation folder. The shell scripts then properly configure the library path so the package can be relocated. Have a look at the transitive dependency sample for a demonstration. |
Run the application
Look inside the build
folder and you will notice the appearance of a exe
folder.
By convention Gradle will place all applications in subfolders named according to the component name.
In this case you will find your assembled executable in build/exe/main/debug
and it will be called building-cpp-applications
(or building-cpp-applications.exe
under Windows).
Now run your newly built executable.
$ ./build/exe/main/debug/building-cpp-applications Hello, World!
Summary
You have created an C++ application with unit tests. In doing so, you saw:
-
How to generate a C++ application
-
How the generate build file and sample C++ files are structured
-
How to run the build with it’s tests
-
How to execute the application from the command line
Next Steps
-
Make your way to the native samples repository to see the C++ plugins in action for common scenarios such as transitive dependencies and custom source layout.
Help improve this guide
Have feedback or a question? Found a typo? Like all Gradle guides, help is just a GitHub issue away. Please add an issue or pull request to gradle-guides/building-cpp-applications and we’ll get back to you.