# Building OpenTelemetry C++ SDK with Visual Studio 2019, CMake and Ninja

## Preface

These instructions are focused on developers and integrators, providing a hassle-free
and FAST option of building OpenTelemetry C++ SDK with Visual Studio on Windows.

The process is optimized for both scenarios:

- SDK developer experience on developer machine.
- final product CI/CD pipeline.

## Build System Components

Visual Studio 2019 is a Full-featured integrated development environment (IDE) for
Android, iOS, Windows, web, and cloud. There are three editions:

- FREE [Community Edition](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community&rel=16)
- [Professional Edition](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Professional&rel=16)
- [Enterprise Edition](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Enterprise&rel=16)

There is also no-IDE 'headless' set of command line tools available as
`Visual Studio 2019 Build Tools` package. You may install it on Windows
via [Chocolatey package manager](https://community.chocolatey.org/packages/visualstudio2019buildtools).

You may also use Visual Studio with Windows 10 Subsystem for Linux to cross-compile
the SDK [targeting Linux distributions](https://code.visualstudio.com/docs/cpp/config-wsl).
Linux build process is largely identical to Windows process described below,
with `tools/setup-buildtools.sh` and `tools/build.sh` running on Linux.

Older versions of Visual Studio, such as 2015 and 2017 are known to work well
with CMake and Ninja. However, these old versions are not covered by instructions
below. If you would like to contribute additional instructions for older versions,
feel free to contribute a Pull Request detailing your build experience with older
versions.

[CMake](https://cmake.org/) is cross-platform free and open-source software for
build automation, testing, packaging and installation of software by using a
compiler-independent method. CMake is not a build system but rather it generates
another system's build files.

[MSBuild](https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild?view=vs-2019)
is a default build system used by Visual Studio for loading and building software
projects.

[Ninja](https://ninja-build.org/) is a small build system with a focus on speed.
It differs from other build systems in two major respects: it is designed to have
its input files generated by a higher-level build system, and it is designed
to run builds as fast as possible.

[Chocolatey package manager](https://chocolatey.org/) has the largest online registry
of Windows packages. Chocolatey packages encapsulate everything required to manage
a particular piece of software into one deployment artifact by wrapping installers,
executables, zips, and/or scripts into a compiled package file.

[vcpkg](https://vcpkg.io/en/index.html) is a free C/C++ package manager for acquiring
and managing libraries. Choose from over 1500 open source libraries to download
and build in a single step or add your own private libraries to simplify your
build process. Maintained by the Microsoft C++ team and open source contributors.

## Installing Prerequisites

Please install the following software:

- Install Visual Studio 2019 with C/C++ development tools, including CMake tools.
[This article](https://docs.microsoft.com/en-us/cpp/build/cmake-projects-in-visual-studio?view=msvc-160)
 explains the fundamentals of working with CMake projects in Visual Studio.

- Install [Git tools for Windows](https://git-scm.com/downloads).

Setup script below uses Chocolatey to install the following components:

- `vswhere` - utility to auto-discover Visual Studio installation.
- `cmake`
- `git`
- `vcpkg` to download, compile and install 3rd party C++ libraries from source.

List of C++ dependencies compiled and installed via `vcpkg`:

- [Google Test](https://github.com/google/googletest)
- [Google Benchmark](https://github.com/google/benchmark)
- [Microsoft GSL](https://github.com/microsoft/GSL)
- [nlohmann/json](https://github.com/nlohmann/json)
- [Abseil](https://github.com/abseil/abseil-cpp)
- [Protocol Buffers](https://github.com/protocolbuffers/protobuf)
- [gRPC](https://github.com/grpc/grpc)
- [Prometheus C++ client](https://github.com/jupp0r/prometheus-cpp)
- [cURL](https://github.com/curl/curl)

## Command Line Build Process

Start `Command Prompt` as Administrator and execute the following commands:

```console
git clone --recursive https://github.com/open-telemetry/opentelemetry-cpp
cd opentelemetry-cpp
tools\setup-buildtools.cmd
tools\build.cmd
```

Let's dissect the flow:

```console
git clone --recursive https://github.com/open-telemetry/opentelemetry-cpp
```

SDK will be cloned recursively with remote submodule dependencies.

```console
cd opentelemetry-cpp
tools\setup-buildtools.cmd
```

The necessary build tools are installed. This step requires elevation to install
additional tooling, e.g. CMake to `Program Files`. The necessary dependencies are
being built using [vcpkg package manager](https://vcpkg.io/en/index.html). This
one-time step is time-consuming - about up to 5-10 minutes. It has to be done once
during the initial installation and configuration of build tools and dependencies.

```console
tools\build.cmd
```

The build of all SDK components is done using CMake + ninja in less than couple
minutes. Above script shows you how to build both configurations:

- `nostd`  - OpenTelemetry implementation of standard containers.
- `stdlib` - Standard Template Library containers.

You may execute this workflow in a docker container. Please refer to generic
instructions that detail how to [run build build tools in a docker container](https://docs.microsoft.com/en-us/visualstudio/install/build-tools-container?view=vs-2019).

## Building in Visual Studio 2019 IDE

- Run as Administrator: `tools\setup-buildtools.cmd` to install the necessary
build tooling. This script installs all build tools and builds all 3rd party
dependencies from source using [vcpkg package manager](https://vcpkg.io/en/index.html).
- Launch Visual Studio 2019 IDE.
- Use `Open a local folder` option to open the folder where you cloned the
  source code.
- Right-click on `CMakeLists.txt` and choose `Generate Cache for opentelemetry-cpp`.
- In the top bar menu - select `Build -> Build All` to build SDK, Exporters and Tests.
- You can use [Google Test Adapter](https://marketplace.visualstudio.com/items?itemName=ChristianSoltenborn.GoogleTestAdapter)
Visual Studio extension to run all SDK and Exporter tests in IDE.
- You can individually select and run only given tests or examples.

Visual Studio provides an excellent debugging and troubleshooting experience,
with incremental builds using Ninja typically taking just one click to build
and less than a few seconds for the build to complete.

## Build time comparison between `MSBuild` and `Ninja`

After the initial set of 3rd party dependencies have been built via
`tools\setup-buildtools.cmd`, we can benchmark the OpenTelemetry C++ SDK build
times with [MSBuild](https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild?view=vs-2019)
vs with [Ninja](https://ninja-build.org/).

[ptime utility](https://community.chocolatey.org/packages/ptime) may be used
to measure the total execution time for two build configurations built in one
run: `nostd-debug` and `stdlib-debug`.

### MSBuild build timing

```console
set CMAKE_GEN=Visual Studio 16 2019
ptime build.cmd
...
Execution time: 543.701 s
```

### Ninja build timing

```console
REM Unset CMAKE_GEN= - default is ninja with autodetection of ninja.exe tool path
set CMAKE_GEN=
ptime build.cmd
...
Execution time: 105.158 s
```

## Conclusion

It is strongly recommended to build the SDK with *Ninja* since it is at least x5
times faster than MSBuild for a full clean build. Incremental builds with *Ninja*
are also considerably faster. Each incremental build is taking about 10 seconds
total for 2 build configurations. Absolute time may differ depending on machine
being benchmarked. Relative ratio on most machines demonstrates that building
with *Ninja* build system greatly optimizes your development cycle. Not only it
saves your development time, optimizes your CI/CD cycle, but it is also much more
environmentally friendly.
