Git Product home page Git Product logo

template-project-cpp's Introduction

Template C++ Project

codecov Build Status Build status

Overview

This repository is a template to help get you set up quickly when starting a new C++ project. We have tried to conform to common software engineering 'best practices', and to that end this repository features the following:

  • C++14
  • CMake build script for cross-platform configuration (see here for more info)
  • Catch unit testing framework (see here)
  • Travis integration for automated testing on Linux and macOS (see here)
  • AppVeyor integration for automated testing on Windows (see here)
  • Codecov integration for automated coverage testing (see here)
  • ClangFormat for automated source code formatting (see here)
  • Clang-Tidy for static analysis to catch coding errors (see here)
  • AddressSanitizer for catching memory-related issues (see here)

In addition, the project is set up to use the boost libraries, and we will hopefully add other common libraries to the configuration soon.

Getting started

We strongly recommend that you use git to keep your copy of this project under version control.

Feel free to:

Note: if you just Fork this repository then it will not be independent of the original repo (i.e. no separate GitHub issues)

Where does it run?

We expect this project to be usable on all modern systems It is regularly tested on the following operating systems:

  • Linux: Ubuntu 14.04
  • masOS: High Sierra
  • Windows: Windows Server 2012

and with the following C++ compilers/toolchains:

  • GCC 5.x, 6.x, 7.x
  • Clang 4.x, 5.x
  • Xcode 9.3
  • Visual Studio 2015

First run

Linux

  • Install CMake and a C++ compiler. E.g. for Ubuntu you can use the command-line and type:
$ sudo apt install build-essential cmake
  • Make a build directory and configure the project. E.g. Assuming you are in a directory containing the template source code:
$ mkdir build
$ cd build
$ cmake ..
  • Compile the project
$ make
  • Run all the tests using CTest (this is bundled with CMake)
$ ctest --output-on-failure

macOS

Windows

First, install the following software:

Next, we assume the use of Microsoft's C++ package manager, vcpkg, for installing dependencies. The following instructions assume you install vcpkg to C:\vcpkg:

  • Install and configure vcpkg
  • Ensure you have run vcpkg integrate install
  • Install boost for 64 bit targets: vcpkg install boost:x64-windows

From Visual Studio, configure the project to use the vcpkg toolchain file:

  • Open the project with File -> Open -> Folder, and select this project
  • Edit the build configurations: CMake -> Change CMake Settings -> Template
    • We suggest removing both x86 targets; just keep both x64 targets
    • Add the following to both x64 targets:
"variables": [
                {
                    "name": "CMAKE_TOOLCHAIN_FILE",
                    "value": "C:\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake"
                }
            ],

Build the project and run the tests:

  • CMake -> Build All
  • CMake -> Tests -> Run Template CTests

Documentation

MyLibrary.{hpp,cpp}

This template C++ project implements a single function, get_nth_prime, within the namespace cpp_template.

  • Note1: It is good practice in C++ to put all your code within a namespace, so that definitions in separate projects do not conflict with each other.

  • Note2: get_nth_prime simply wraps the Boost prime number implementation

  • Note3: To start using this template in your own projects, simply replace these files with your own, and make sure to update the filenames in CMakeLists.txt.

Exception.h

The argument to get_nth_prime must be greater than zero, and less than boost::math::max_prime. If either of these conditions are not satisfied the function throws an exception, which is defined in this file.

  • Note1: Throwing an exception when an error is detected allows programs to react to run-time errors. This is in contrast asserts, which immediately halt program execution.

MyTests.cpp

Write the unit tests for your code here. Our example uses the Catch framework, and includes tests that check the accuracy of the get_nth_prime function, and check that the function throws the appropriate exceptions on invalid input.

  • Note1: You probably will want to change the filename, or add separate files containing more tests. In this case, make sure to update the filenames in CMakeLists.txt.
  • Note2: You probably want to use your C++ code to actually do something, for example running a simulation. One option is to run this through your testing framework (e.g. you might want to check that your simulation ran correctly, and you can use Catch's assertions to do this). Alternatively, it might be more suitable to write an entirely separate executable. You can easily do this by using the add_executable CMake function (in CMakeLists.txt), exactly like we have done for MyTests.cpp

CMakeLists.txt

CMake is a cross-platform build configuration tool, which generates compilation scripts (e.g. using Makefiles in linux, or Visual Studio projects for windows) that you can run to compile your C++ project.

Edit the CMakeTests.txt configuration file to do things like: - setup the overall structure of your project, creating libraries and executables and specifying the dependencies between these. - setup the flags you wish to pass to the compiler - search for any libraries on the current system, and link/include them in your project - setup testing using ctest - setup how to install your project on the current system

.travis.yml

This template uses Travis CI for automated testing. This is fully defined in the .travis.yml file and includes:

  • A matrix of build configurations:
    • MacOS X with XCode 9.3
    • Ubuntu 14.04 with GCC 5,6,7 & Clang 4,5
  • Test coverage data collection with lcov and reporting with codecov

The results of the automated testing are reported on the Travis CI project page

appveyor.yml

For windows testing we use AppVeyor, testing with just a single windows configuration:

  • Visual Studio 2017 with boost v1.64

codecov

Code coverage allow you to see how much of your code is actually covered by your test suite. That is, which lines of code are actually run during the tests.

To do this, the code must be compiled with compiler flags that allow the executable to collect information about which lines of code are called during execution. For GCC or Clang this means adding the --coverage flag, which is done in the CMakeLists.txt configuration file.

You can see the .travis.yml for an example of how to collect the coverage data in a readable format using lcov (see the "after_success:" section). This data is then sent to codecov for an even easier-to-read web interface.

.clang-format

Clang Format is a tool to automatically format your code according to a set style configuration. This is incredibly useful because it frees you up from having to worry about things like indenting, spacing out your code or breaking long lines of code, just type in your code and let Clang Format clean it up for you.

You can install Clang Format on Ubuntu using apt:

$ sudo apt install clang-format

You can set the particular style you wish to apply using the .clang-format configuration file. The clang-format configurator is a useful web app for generating this file.

Note that most IDEs will allow you to automatically run Clang Format when the file is saved, which even saves you from manually running the tool in the first place.

.clang-tidy

Clang Tidy is a clang-based C++ linter tool. A linter will analyzing your code to check for common programming bugs and stylistic errors. This might seem similar to the warnings often given by the compiler, but a linter will have a much more comprehensive set of tests that examines the structure of your code rather than the often line-by-line checking done by the compiler.

You can install Clang Tidy on Ubuntu using apt:

$ sudo apt install clang-tidy

The .clang-tidy configuration file allows you to set or turn off individual or sets of checks done by clang-tidy. We also setup the CMakeLists.txt file so that clang-tidy is run automatically during compile-time.

AddressSanitizer

There is an optional component enabled via CMake that can use the LLVM AddressSanitizer to detect memory errors. This is turned on by default for the clang builds on Travis, so you will see any errors on there if it's configured.

You can also run it yourself, provided you are using the clang compiler, by using the Template_MEMCHECK option when running CMake. Simply enable the option, then configure, build, and test:

cmake -DTemplate_MEMCHECK=TRUE /path/to/project
make
ctest

The test will fail at the first error. It is unlikely that you will encounter a false positive when using the address sanitizer, so if you do see an error, best not to ignore it!

Feedback and suggestions

If you have any feedback or suggestions about this project, please get in touch or open an issue.

template-project-cpp's People

Contributors

fcooper8472 avatar martinjrobins avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

template-project-cpp's Issues

documentation

The template project still needs plenty of documentation to explain what each bit is doing:

  • CMakeLists.txt
  • MyLibrary.{cpp,hpp}
  • MyTests.cpp
  • travis.yml
  • appveyor.yml
  • codecov
  • clang-format
  • clang-tidy

Travis not finding the correct compiler

Both the clang and gcc travis builds have the following snippet in the output:

Setting environment variables from .travis.yml
$ export CXX=g++-5
$ export BUILD_TYPE=Debug
$ export CXX=g++
$ export CC=gcc
$ g++ --version
g++ (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
Setting environment variables from .travis.yml
$ export CXX=clang++-5.0
$ export BUILD_TYPE=Debug
$ export CXX=g++
$ export CC=gcc
$ g++ --version
g++ (Ubuntu 4.8.5-4ubuntu8~14.04.2) 4.8.5

So we appear to be ending up with the same (old) gcc version, and I think this might be causing the spurious warnings we're getting related to #9.

Abseil support?

@martinjrobins what are your thoughts on Abseil support?

Would be different than other libraries such as Eigen and Boost they strongly recommend building it from your project tree.

We could add it as a submodule, and then simply

add_subdirectory(abseil-cpp)

and the abseil internals sort everything else out nicely.

I would be in favour of adding it. Besides a number of really cool features and utilities, it pre-supports a number of newer C++ features which is good from a "best practices" point of view.

The downside is that having a submodule is a little annoying in terms of keeping the project as simple as possible, and does (marginally) increase the compile time of the project, so would be happy to leave it out if you're not keen.

Header file extension names

At the moment we are using .h for headers and .cpp for implementations.

Catch is currently .hpp. I think it would be useful to have complete consistency within the project. My vote would be for changing all headers to .hpp (something about the filenames being the same length...), although I'm not strongly wedded to one or the other.

Your thoughts @martinjrobins?

Rework CMake coverage for consistency

See #8 for discussion about CMake consistency for the coverage option.

How about:

# Setup coverage testing for GCC or Clang
option(Template_ENABLE_COVERAGE "Enable coverage reporting for GCC or Clang" FALSE)
if (Template_ENABLE_COVERAGE)
    if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
        target_compile_options(mylib PUBLIC --coverage -O0)
        target_link_libraries(mylib PUBLIC --coverage)
    else()
        message(FATAL_ERROR "GCC or Clang required with Template_ENABLE_COVERAGE: found ${CMAKE_CXX_COMPILER_ID}")
    endif()
endif()

Is this what you had in mind, and would this mess up the Travis integration?

Codecov testing too many files?

I've not used Codecov before, so probably one for @martinjrobins:

This output looks as though codecov is checking a whole bunch of files including

File '/usr/include/boost/exception/exception.hpp'
File '/usr/include/boost/smart_ptr/detail/sp_counted_impl.hpp'
File '/usr/include/c++/5/bits/postypes.h'

Can we get it to analyse only our project files?

Travis configuration

Travis thinks it's running a build with gcc and clang, but because the script specifies CXX and CC I'm fairly sure it's doing the same identical build each time.

Can we get it actually building with both compilers?

Docker Images to build C/C++

For starters let me just say that this is a great template to start any C++ project with a very good foundation.

I would just like to make a suggestion, based on the only thing I had to add to this template, and maybe hear you thoughts on it.

What do you think about including a generic dockerfile with ubuntu or alpine with both the build tools and boost?

Investigate adding address sanitizer

This seems to be the current best practice for detecting memory errors in C++ code, and it seems very straightforward to use.

AddressSanitizer is a fast memory error detector. It consists of a compiler instrumentation module and a run-time library. The tool can detect the following types of bugs:

Out-of-bounds accesses to heap, stack and globals
Use-after-free
Use-after-return (runtime flag ASAN_OPTIONS=detect_stack_use_after_return=1)
Use-after-scope (clang flag -fsanitize-address-use-after-scope)
Double-free, invalid free
Memory leaks (experimental)
Typical slowdown introduced by AddressSanitizer is 2x.

@martinjrobins what's the modern-CMake-approved method of passing

-O1 -g -fsanitize=address -fno-omit-frame-pointer

to the (clang) compiler, and

-g -fsanitize=address

to the (clang) linker?

exception nothrow warning

travis says (for both gcc and clang):

/home/travis/build/OxfordRSE/template-project-cpp/src/MyLibrary.cpp:44:11: warning: thrown exception type is not nothrow copy constructible [cert-err60-cpp]
    throw std::out_of_range("non-negative argument required");

This doesn't seem like a valid warning, since we are just using a standard library exception! Not sure how to fix this

Add Eigen support?

@martinjrobins what do you think about adding in something from Eigen?

Another very short function that, perhaps, accepts an Eigen matrix and returns the largest (in magnitude) eigenvalue? Or some other trivial wrapping of some existing Eigen functionality, just to provide a minimal example?

Libraries, dependencies & integrations

From @martinjrobins original post.

Libraries:

  • Boost
  • OpenMP (this is linked, but I still want to setup a test that uses openmp)

Dependencies:

  • CMake
  • Catch2

Integrations:

  • travis-ci (with linux and mac)
  • codecov
  • appveyor

A few other suggestions:

  • clang-format
  • clang-tidy (put in a config file, but need to actually use it)

llvm leaksanitizer fatal error

tried to turn on leaksanitizer on travis clang setup, but got this error:

$ ctest -j2 --output-on-failure
Test project /home/travis/build/OxfordRSE/template-project-cpp
    Start 1: test1
1/1 Test #1: test1 ............................***Failed    0.01 sec
===============================================================================
All tests passed (6 assertions in 2 test cases)
==3894==LeakSanitizer has encountered a fatal error.
==3894==HINT: For debugging, try setting environment variable LSAN_OPTIONS=verbosity=1:log_threads=1
==3894==HINT: LeakSanitizer does not work under ptrace (strace, gdb, etc)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.