Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions .docs/AZURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Using Azure Pipelines with C++ Projects

This guide describes how to use Azure Pipelines to build and test C++ projects.
It uses a pipeline `azure-pipeline.yml` and a template `build-template.yml` for a comprehensive CI/CD pipeline.

## Prerequisites

- Access to an Azure DevOps service or server.
- Follow the [documentation](../README.md) starting with the [initial general configuration](../README.md#initial-general-configuration).

## Setting Up Your Pipeline

1. Fork the repository in GitHub or import it into Azure DevOps.
2. In Azure DevOps, navigate to Pipelines and create a new pipeline.
3. Select GitHub or Azure Repos as the code source, and select your forked/imported repository.
4. When prompted for a configuration, select "Existing Azure Pipelines YAML file" and enter the path to `azure-pipeline.yml`.

## Configuring Build Parameters

Customize the build parameters in `azure-pipeline.yml` to meet the needs of your project.
- Choose between *Deploy*, which also publishes the build artifacts, or *Build* only.
- Enable or disable builds for Windows or Linux altogether. Note that if build is enabled but no matrix is generated, the pipeline will fail.

## Accessing private resources

In `build/build-template.yml' look for something like this:
```yaml
${{ if eq(parameters.agentType, 'containerized') }}:
pool:
vmImage: 'ubuntu-latest'
container:
image: $(container_image)
options: -v /etc/localtime:/etc/localtime:ro
# endpoint: Dockerhub # If you need access to a private container registry
${{ else }}:
pool:
vmImage: $(azure_vmImage)
```

### Using a Private Docker Registry

- Add a *Docker Registry* service connection where you can specify your credentials.
- Specify the new service connection in the container settings with the key `endpoint`, for example:
```yaml
container:
image: $(container_image)
options: -v /etc/localtime:/etc/localtime:ro
endpoint: myDockerhubAccount # If you need access to a private container registry
```

### Using self-hosted agents

Instead of specifying the `vmImage', specify the pool directly by name, e.g:
```yaml
${{ if eq(parameters.agentType, 'containerized') }}:
pool: 'container-enabled-agents'
container:
image: $(container_image)
options: -v /etc/localtime:/etc/localtime:ro
${{ else }}:
pool: 'Win_vs2022_pool'
```

## Limitations

- Conan is not available on Microsoft-hosted agents, installation via `pip3` is done each time conan is needed and takes about 30 seconds.
- Caching of artifacts (such as conan dependencies) is not yet implemented.

## Customizing the build environment

- Modify the `build-template.yml` file to include any additional build steps or customizations required for your project.

For a detailed walkthrough and additional configuration options, refer to the [Azure Pipiles documentation](https://docs.microsoft.com/en-us/azure/devops/pipelines/?view=azure-devops).
File renamed without changes.
114 changes: 60 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,55 @@
# C++ Multi Builder

This GitHub repository provides a ready-to-use GitHub Action to build C++ projects.
It is designed to lower the entry barrier for developers and allow easy building, unit testing, and packaging of C++ projects for multiple combinations of OS using a single C++ source code.
This GitHub repository provides an out-of-the-box GitHub Action and [Azure Pipeline](.docs/AZURE.md) for building C++ projects.
It is designed to lower the barrier to entry for developers, allowing them to easily build, unit test, and package C++ projects for multiple OS combinations using a single C++ source code.

## Features

- **Ease of Use**: Set up with minimal configuration required.
- **Multiple OS Support**: Build your C++ projects for various combinations of operating systems.
- **Ease of use**: Set up with minimal configuration required.
- **Multiple OS Support**: Build your C++ projects for different combinations of operating systems.
- **C++ Package Manager Support**: Conan package manager is supported out of the box for managing C++ dependencies.
- **Automated Testing and Packaging**: Includes support for unit testing and packaging of your projects.
- **Debug files available**: PDB and unstripped files are kept beside the build artifacts.
- **Caching Support**: Conan packages are cached automatically
- **Automated testing and packaging**: Includes support for unit testing and packaging your projects.
- **Debug files available**: PDB and unstripped files are kept alongside build artifacts.
- **Caching support**: Conan packages are automatically cached in GitHub actions.
- **Multiple CI Platforms**: Use GitHub Actions or Azure Pipelines. Also works on-premises or with self-hosted runners/agents.

## Getting Started

### Prerequisites

- A GitHub account
- Basic knowledge of C++ and CMake
- Familiarity with GitHub Actions
- Basic C++ and CMake skills
- Familiarity with GitHub actions

### Fork the Repository
### Fork the repository

To get started, fork this repository to your own GitHub account. This will be the home for your C++ CMake project.
To get started, fork this repository into your own GitHub account. This will be the home for your C++ CMake project.

### Initial general configuration

The default configuration is saved in `pipeline/createMatrix/mergekeys.yml`.
The default configuration is stored in `pipeline/createMatrix/mergekeys.yml`.

In this file the used Docker images and various other settings are stored.
This file stores the Docker images used and various other settings.

#### Linux

Linux builds rely on Docker images.

Those docker images need to have the following tools installed:
- compiler
These docker images must have the following tools installed:
- compilers
- ninja
- conan

### Add Your C++ CMake Project
### Adding your C++ CMake project

Place your C++ source code anywhere in the repository alongside a `CMakeLists.txt` file.
Place your C++ source code anywhere in the repository, along with a `CMakeLists.txt` file.
This is where you'll define your project and its dependencies.

### Configuration

Create a `build-config.yml` file in your repository alongside the `CMakeLists.txt`.
This file specifies the build configurations for different OS.
Here's an example based on the provided demo in the `demo`directory:
Create a `build-config.yml` file in your repository along with the `CMakeLists.txt` file.
This file specifies the build configurations for different operating systems.
Here's an example based on the demo provided in the `demo` directory:

```yaml
demo:
Expand All @@ -63,9 +64,9 @@ demo:
<<: *_debian_bullseye_relwithdebinfo
```

For C++ package management, create a `conanfile.txt` or `conanfile.py` file alongside your `CMakeLists.txt`.
For C++ package management, create a `conanfile.txt` or `conanfile.py` file in addition to your `CMakeLists.txt` file.

### Utilize Packaging and Testing
### Using packaging and testing

To use unit testing and/or packaging, include the necessary CMake files for packaging and testing as follows:
```cmake
Expand All @@ -78,65 +79,67 @@ include(../cmake/packaging.cmake)
include(../cmake/testing.cmake)
```

These includes will enable the GitHub Action pipeline to perform automated testing and packaging of your project.
These includes will enable the GitHub actions pipeline to perform automated testing and packaging of your project.

Testing also requires the [googletest](https://github.com/google/googletest) framework, just merge the following line into your `conanfile.py`:
Testing also requires the [googletest](https://github.com/google/googletest) framework, just merge the following line to your `conanfile.py`:
```python
def requirements(self):
self.requires("gtest/1.14.0")
```

A full example of a `conanfile.py` can be found [here](BUILD.md#conan).
A complete example of a `conanfile.py` can be found [here](.docs/BUILD.md#conan).

### Details about packaging
### Packaging details

#### Key Features

Automatically selects packaging format based on the target OS.
Automatically selects the packaging format based on the target OS.
- **Windows**: Packages are generated as ZIP files.
- **Debian-based Linux**: Packages are generated as DEB files.
- **Red Hat-based Linux**: Packages are generated as RPM files.

#### Customization

Beside the mentioned [Key features](#key-features) CPack default features are used.
Besides the mentioned [Key Features](#key-features) CPack standard settings are used.

For Linux it is recommended to set the `CPACK_PACKAGING_INSTALL_PREFIX` to whatever is desired. E.g.:
It is recommended to set `CPACK_PACKAGE_CONTACT`, otherwise it is automatically set to `undefined`.

For Linux it is recommended to set the `CPACK_PACKAGING_INSTALL_PREFIX` to whatever is desired. For example:
```cmake
set(CPACK_PACKAGE_CONTACT "Your name or company")
set(CPACK_PACKAGING_INSTALL_PREFIX "/usr/local/bin/")
```

For additional customization, such as including additional files in the package or changing package metadata, refer to the [CPack documentation](https://cmake.org/cmake/help/latest/module/CPack.html).
For further customization, such as including additional files in the package or changing package metadata, see the [CPack documentation](https://cmake.org/cmake/help/latest/module/CPack.html).

### How to Add a New Test
### To add a new test

1. **Define Test Sources:**
List all source files associated with your test.
For a comprehensive test suite, you might separate your test sources from your main application sources.
1. **Define test sources**:
List all the source files associated with your test.
For a large test suite, you may want to separate your test sources from your main application sources.

2. **Use the `add_gtest_with_xml` Macro:**
This macro is used to compile the test sources into an executable, link it against Google Test and any necessary project libraries, and set up XML output for test results.
2. **Use the `add_gtest_with_xml` Macro**:
This macro is used to compile the test sources into an executable, link it with Google Test and any necessary project libraries, and set up XML output for the test results.
The basic syntax is:

```cmake
add_gtest_with_xml(TARGET_NAME TARGET_LIBRARY TEST_SOURCES)
```

- `TARGET_NAME`: A unique name for your test executable.
- `TARGET_LIBRARY`: The library against which your test executable should be linked. This usually includes your project's main library.
- `TARGET_LIBRARY`: The library your test executable should be linked against. This is usually your project's main library.
- `TEST_SOURCES`: The source files for your test.

3. **Example:**
For a hypothetical binary named `demo` that tests functionality in `demoLib`, you might write:
3. **Example**:
For a hypothetical binary named `demo` that tests the functionality in `demoLib`, you might write:

```cmake
set(TEST_SOURCES demoTest.cxx)
add_gtest_with_xml(demo demoLib ${TEST_SOURCES})
```

4. **Integration with CMakeLists.txt:**
Add your test configuration to a `CMakeLists.txt` within your project's test directory.
4. **Integration with CMakeLists.txt**:
Add your test configuration to a `CMakeLists.txt` in your project's test directory.
If your project structure does not already include a test directory, create one as shown:

```cmake
Expand All @@ -145,21 +148,24 @@ If your project structure does not already include a test directory, create one

### Build Pipeline

The `build.yml` GitHub Action workflow file orchestrates the build process.
It prepares the build environment, installs necessary dependencies, and runs the build according to configurations specified in `build-config.yml`.
This process is triggered by push or pull request events to the main branch, or can be manually dispatched.
The `build.yml` GitHub action workflow file orchestrates the build process.
It prepares the build environment, installs the necessary dependencies, and executes the build according to the configurations specified in `build-config.yml`.

When running the build, certain directories are set automatically:
- **build directory:** is set set to `build/make`
- **install dir:** is set to `build/install` via `CMAKE_INSTALL_PREFIX` cache variable
- **packaging dir:** is set to `build/deploy` via `CPACK_OUTPUT_FILE_PREFIX` cache variable
Its use in Azure DevOps is described [here](.docs/AZURE.md).

**Note:** The automation searchs in these paths for the build artifacts, like test results or the generated binaries.
When doing modifications, please make sure those directories are still be set correctly by the automation.
This process is triggered by push or pull request events to the main branch, or can be triggered manually.

#### Docker login
When the build is run, certain directories are automatically set:
- **build directory**: is set set to `build/make`
- **install dir**: is set to `build/install` via the `CMAKE_INSTALL_PREFIX` cache variable
- **packaging dir**: is set to `build/deploy` via the `CPACK_OUTPUT_FILE_PREFIX` cache variable

If you use private container images, uncomment the following lines in `build.yml` and provide the referenced secrets.
**Note:** The automation looks in these paths for the build artifacts, such as test results or generated binaries.
If you make changes, make sure these directories are still set correctly by the automation.

#### Docker Login

If you are using private container images, uncomment the following lines in `build.yml` and provide the referenced secrets.

```yaml
# credentials:
Expand All @@ -169,9 +175,9 @@ If you use private container images, uncomment the following lines in `build.yml

## Local Build Environment Setup

For detailed instructions on setting up your local build environment, including configuring Conan and CMake for various build types, please see the [Build Environment Setup Guide](BUILD.md).
For detailed instructions on setting up your local build environment, including configuring Conan and CMake for different build types, see the [Build Environment Setup Guide](.docs/BUILD.md).
This guide provides step-by-step instructions to help you get started quickly and efficiently.

## Support

For any questions or support, consider opening an issue in the repository. Contributions to improve the build process or add new features are welcome.
If you have any questions or need support, please consider opening an issue in the repository. Contributions to improve the build process or add new features are welcome.
64 changes: 64 additions & 0 deletions pipeline/azure-pipeline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
trigger:
- main

parameters:
- name: stepsToPerform
displayName: Which steps to perform
type: string
default: Deploy
values:
- Deploy
- Build

- name: buildWindows
type: boolean
default: true

- name: buildLinux
type: boolean
default: true

variables:
- name: System.Debug
value: true

stages:

- stage: Eval
displayName: "Prepare Pipeline"
condition: succeeded()
dependsOn: [] #removes implicit dependency on previous stage, can run parallel to static ana
pool:
vmImage: 'ubuntu-latest'
jobs:
- job: SetVariables
displayName: "Set variables for pipeline"
steps:
- checkout: self
lfs: false
clean: true
fetchDepth: 1 # Fetch only one commit to improve checkout speed, we don't need history
displayName: "Checkout Repository"

- task: PowerShell@2
inputs:
targetType: 'inline'
script: |
Install-Module -Name PowerShell-yaml -Scope CurrentUser -Force
$(Build.SourcesDirectory)\pipeline\createMatrix\createMatrix.ps1 -basedir "$(Build.SourcesDirectory)" -verbose -azpMatrix -mergeKeyFile pipeline\createMatrix\mergekeys.yml
displayName: 'Set build configs'
name: Matrix

- ${{ if eq(parameters.buildWindows, true) }}:
- template: build-template.yml
parameters:
stepsToPerform: ${{ parameters.stepsToPerform }}
agentType: native
matrixName: 'Matrix.WindowsBuildConfigs'

- ${{ if eq(parameters.buildLinux, true) }}:
- template: build-template.yml
parameters:
stepsToPerform: ${{ parameters.stepsToPerform }}
agentType: containerized
matrixName: 'Matrix.LinuxBuildConfigs'
Loading