An automated framework for executing these tools should be established very early in the development process. It should not take more than 2-3 commands to checkout the source code, build, and execute the tests. Once the tests are done executing, you should have an almost complete picture of the state and quality of the code.
Source control is an absolute necessity for any software development project. If you are not using one yet, start using one.
- GitHub - allows for unlimited public repositories, and unlimited private repositories with up to 3 collaborators.
- Bitbucket - allows for unlimited private repositories with up to 5 collaborators, for free.
- SourceForge - open source hosting only.
- GitLab - allows for unlimited public and private repositories, unlimited CI Runners included, for free.
- Visual Studio Online (http://www.visualstudio.com/what-is-visual-studio-online-vs) - allows for unlimited public repositories, must pay for private repository. Repositories can be git or TFVC. Additionally: Issue tracking, project planning (multiple Agile templates, such as SCRUM), integrated hosted builds, integration of all this into Microsoft Visual Studio. Windows only.
Use an industry standard widely accepted build tool. This prevents you from reinventing the wheel whenever you discover / link to a new library / package your product / etc. Examples include:
- Autotools - The traditional GNU build system.
- CMake
- Consider: https://github.com/sakra/cotire/ for build performance
- Consider: https://github.com/toeb/cmakepp for enhanced usability
- Utilize: https://cmake.org/cmake/help/v3.6/command/target_compile_features.html for C++ standard flags
- Consider: https://github.com/cheshirekow/cmake_format for automatic formatting of your CMakeLists.txt
- See the Further Reading section for CMake specific best practices
cmake --build
provides a common interface for compiling your project regardless of platform
- Waf
- FASTBuild
- Ninja - Can greatly improve the incremental build time of your larger projects. Can be used as a target for CMake.
- Bazel - Fast incremental builds using network artifact caching and remote execution.
- Buck - Similar to Bazel, with very good support for iOS and Android.
- gyp - Google's build tool for chromium.
- maiken - Crossplatform build tool with Maven-esque configuration style.
- Qt Build Suite - Crossplatform build tool From Qt.
- meson - Open source build system meant to be both extremely fast, and, even more importantly, as user-friendly as possible.
- premake
- xmake - A cross-platform build utility based on Lua. Modern C/C++ build tools, Support multi-language hybrid compilation
- build2 - A cargo-like complete toolchain (build system, package manager, project manager)
Remember, it's not just a build tool, it's also a programming language. Try to maintain good clean build scripts and follow the recommended practices for the tool you are using.
Package management is an important topic in C++, with currently no clear winner. Consider using a package manager to help you keep track of the dependencies for your project and make it easier for new people to get started with the project.
- Conan - a crossplatform dependency manager for C++
- hunter - CMake driven cross-platform package manager for C/C++
- C++ Archive Network (CPPAN) - a crossplatform dependency manager for C++
- qpm - Package manager for Qt
- build2 - A cargo-like complete toolchain (build system, package manager, project manager)
- Buckaroo - Truly decentralized cross-platform dependency manager for C/C++ and more
- Vcpkg - Microsoft C++ Library Manager for Windows, Linux, and macOS - description
- CPM - CMake package manager for modern CMake
Once you have picked your build tool, set up a continuous integration environment.
Continuous Integration (CI) tools automatically build the source code as changes are pushed to the repository. These can be hosted privately or with a CI host.
- Travis CI
- works well with C++
- designed for use with GitHub
- free for public repositories on GitHub
- AppVeyor
- supports Windows, MSVC and MinGW
- free for public repositories on GitHub
- Hudson CI / Jenkins CI
- Java Application Server is required
- supports Windows, OS X, and Linux
- extendable with a lot of plugins
- TeamCity
- has a free option for open source projects
- Decent CI
- simple ad-hoc continuous integration that posts results to GitHub
- supports Windows, OS X, and Linux
- used by ChaiScript
- Visual Studio Online (http://www.visualstudio.com/what-is-visual-studio-online-vs)
- Tightly integrated with the source repositories from Visual Studio Online
- Uses MSBuild (Visual Studio's build engine), which is available on Windows, OS X and Linux
- Provides hosted build agents and also allows for user-provided build agents
- Can be controlled and monitored from within Microsoft Visual Studio
- On-Premise installation via Microsoft Team Foundation Server
- GitLab
- use custom Docker images, so can be used for C++
- has free shared runners
- has trivial processing of result of coverage analyze
If you have an open source, publicly-hosted project on GitHub:
- go enable github actions. A template for this can be found in the C++ Boilerplate Template
- enable one of the coverage tools listed below (Codecov or Coveralls)
- enable Coverity Scan
These tools are all free and relatively easy to set up. Once they are set up you are getting continuous building, testing, analysis and reporting of your project. For free.
Use every available and reasonable set of warning options. Some warning options only work with optimizations enabled, or work better the higher the chosen level of optimization is, for example -Wnull-dereference
with GCC.
You should use as many compilers as you can for your platform(s). Each compiler implements the standard slightly differently and supporting multiple will help ensure the most portable, most reliable code.
-Wall -Wextra -Wshadow -Wnon-virtual-dtor -pedantic
- use these and consider the following (see descriptions below)
-pedantic
- Warn on language extensions-Wall -Wextra
reasonable and standard-Wshadow
warn the user if a variable declaration shadows one from a parent context-Wnon-virtual-dtor
warn the user if a class with virtual functions has a non-virtual destructor. This helps catch hard to track down memory errors-Wold-style-cast
warn for c-style casts-Wcast-align
warn for potential performance problem casts-Wunused
warn on anything being unused-Woverloaded-virtual
warn if you overload (not override) a virtual function-Wpedantic
(all versions of GCC, Clang >= 3.2) warn if non-standard C++ is used-Wconversion
warn on type conversions that may lose data-Wsign-conversion
(Clang all versions, GCC >= 4.3) warn on sign conversions-Wmisleading-indentation
(only in GCC >= 6.0) warn if indentation implies blocks where blocks do not exist-Wduplicated-cond
(only in GCC >= 6.0) warn ifif
/else
chain has duplicated conditions-Wduplicated-branches
(only in GCC >= 7.0) warn ifif
/else
branches have duplicated code-Wlogical-op
(only in GCC) warn about logical operations being used where bitwise were probably wanted-Wnull-dereference
(only in GCC >= 6.0) warn if a null dereference is detected-Wuseless-cast
(only in GCC >= 4.8) warn if you perform a cast to the same type-Wdouble-promotion
(GCC >= 4.6, Clang >= 3.8) warn iffloat
is implicitly promoted todouble
-Wformat=2
warn on security issues around functions that format output (i.e.,printf
)-Wlifetime
(only special branch of Clang currently) shows object lifetime issues-Wimplicit-fallthrough
Warns when case statements fall-through. (Included with-Wextra
in GCC, not in clang)
Consider using -Weverything
and disabling the few warnings you need to on Clang
-Weffc++
warning mode can be too noisy, but if it works for your project, use it also.
/permissive-
- Enforces standards conformance.
/W4 /w14640
- use these and consider the following (see descriptions below)
/W4
All reasonable warnings/w14242
'identfier': conversion from 'type1' to 'type1', possible loss of data/w14254
'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data/w14263
'function': member function does not override any base class virtual member function/w14265
'classname': class has virtual functions, but destructor is not virtual instances of this class may not be destructed correctly/w14287
'operator': unsigned/negative constant mismatch/we4289
nonstandard extension used: 'variable': loop control variable declared in the for-loop is used outside the for-loop scope/w14296
'operator': expression is always 'boolean_value'/w14311
'variable': pointer truncation from 'type1' to 'type2'/w14545
expression before comma evaluates to a function which is missing an argument list/w14546
function call before comma missing argument list/w14547
'operator': operator before comma has no effect; expected operator with side-effect/w14549
'operator': operator before comma has no effect; did you intend 'operator'?/w14555
expression has no effect; expected expression with side-effect/w14619
pragma warning: there is no warning number 'number'/w14640
Enable warning on thread unsafe static member initialization/w14826
Conversion from 'type1' to 'type_2' is sign-extended. This may cause unexpected runtime behavior./w14905
wide string literal cast to 'LPSTR'/w14906
string literal cast to 'LPWSTR'/w14928
illegal copy-initialization; more than one user-defined conversion has been implicitly applied
Not recommended
/Wall
- Not recommended for normal builds because the MSVC standard library is not/Wall
"clean", but can be enabled to discover new warnings to enable.- Since VS2022,
/external:anglebrackets /external:W0
can be used to turn off warnings from all headers included with angle brackets, e.g.#include <utility>
.
- Since VS2022,
Start with very strict warning settings from the beginning. Trying to raise the warning level after the project is underway can be painful.
Consider using the treat warnings as errors setting. /WX
with MSVC, -Werror
with GCC / Clang
LLVM based tools work best with a build system (such as cmake) that can output a compile command database, for example:
$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .
If you are not using a build system like that, you can consider Build EAR which will hook into your build system and generate a compile command database for you.
CMake now also comes with built-in support for calling clang-tidy
during normal compilation.
The best bet is the static analyzer that you can run as part of your automated build system. Cppcheck and clang meet that requirement for free options.
SonarLint runs as a plug-in in all the main IDEs. The other two run as part of your build pipeline and can also gate PRs. SonarQube runs on your own infrastructure whereas SonarCloud runs in The Cloud, is free for public Open Source projects and supports Automatic Analysis for zero-config setup.
All three run the same set of analyzers (although SonarQube and SonarCloud have a handful of additional checks that are too heavyweight to run in-IDE) that catch code smells and best practice violations, as well as complex bugs.
Coverity has a free (for open source) static analysis toolkit that can work on every commit in integration with Travis CI and AppVeyor.
PVS-Studio is a tool for bug detection in the source code of programs, written in C, C++ and C#. It is free for personal academic projects, open source non-commercial projects and independent projects of individual developers. It works in Windows and Linux environment.
Cppcheck is free and open source. It strives for 0 false positives and does a good job at it. Therefore all warnings should be enabled: --enable=all
Notes:
- For correct work it requires well formed path for headers, so before usage don't forget to pass:
--check-config
. - Finding unused headers does not work with
-j
more than 1. - Remember to add
--force
for code with a lot number of#ifdef
if you need to check all of them.
cppclean - Open source static analyzer focused on finding problems in C++ source that slow development of large code bases.
CppDepend Simplifies managing a complex C/C++ code base by analyzing and visualizing code dependencies, by defining design rules, by doing impact analysis, and comparing different versions of the code. It's free for OSS contributors.
Clang's analyzer's default options are good for the respective platform. It can be used directly from CMake. They can also be called via clang-check and clang-tidy from the LLVM-based Tools.
Also, CodeChecker is available as a front-end to clang's static analysis.
clang-tidy
can be easily used with Visual Studio via the Clang Power Tools extension.
Can be enabled with the /analyze
command line option. For now we will stick with the default options.
Flint and Flint++ are linters that analyze C++ code against Facebook's coding standards.
OCLint is a free, libre and open source static code analysis tool for improving quality of C++ code in many different ways.
Both of these tools from JetBrains offer some level of static analysis and automated fixes for common things that can be done better. They have options available for free licenses for open source project leaders.
The Eclipse based Cevelop IDE has various static analysis and refactoring / code fix tools available. For example, you can replace macros with C++ constexprs
, refactor namespaces (extract/inline using
, qualify name), and refactor your code to C++11's uniform initialization syntax. Cevelop is free to use.
Qt Creator can plug into the clang static analyzer.
clazy is a clang based tool for analyzing Qt usage.
IKOS is an open source static analyzer, developed by NASA. It is based on the Abstract Interpretation. It is written in C++ and provides an analyzer for C and C++, using LLVM. The source code is available on GitHub.
codespell is a spell checker for your source code.
A coverage analysis tool shall be run when tests are executed to make sure the entire application is being tested. Unfortunately, coverage analysis requires that compiler optimizations be disabled. This can result in significantly longer test execution times.
- Codecov
- integrates with Travis CI and AppVeyor
- free for open source projects
- Coveralls
- integrates with Travis CI and AppVeyor
- free for open source projects
- LCOV
- very configurable
- Gcovr
- kcov
- integrates with codecov and coveralls
- performs code coverage reporting without needing special compiler flags, just by instrumenting debug symbols.
- OpenCppCoverage - open source coverage reporting tool for Windows.
- Valgrind
- Valgrind is a runtime code analyzer that can detect memory leaks, race conditions, and other associated problems. It is supported on various Unix platforms.
- Heaptrack
- A profiler created by a Valgrind's Massif developer. Quite similar to Massif with pros and cons over it, way more intuitive though.
- Dr Memory
- Memoro - A detailed heap profiler.
- Hotspot - An intuitive front-end to visualize datas produced by the perf CPU profiler.
- uftrace - Can be used to generating function call graphs of a program execution.
- Cutter - A front-end for Radare2. It provides tools such as decompiler, disassembly, graph visualizer, hex editor.
- Ghidra - Ghidra is a free and open source reverse engineering tool developed by the National Security Agency (NSA) of the United States.
These tools provide many of the same features as Valgrind, but built into the compiler. They are easy to use and provide a report of what went wrong.
- AddressSanitizer
- MemorySanitizer
- ThreadSanitizer
- UndefinedBehaviorSanitizer
Be aware of the sanitizer options available, including runtime options. https://kristerw.blogspot.com/2018/06/useful-gcc-address-sanitizer-checks-not.html
If your project accepts user defined input, considering running a fuzzy input tester.
Both of these tools use coverage reporting to find new code execution paths and try to breed novel inputs for your code. They can find crashes, hangs, and inputs you didn't know were considered valid.
- american fuzzy lop
- LibFuzzer
- KLEE - Can be used to fuzz individual functions
Continuous fuzzing tools exist to run fuzz tests for you with each commit.
These tools take code executed during unit test runs and mutate the executed code. If the test continues to pass with a mutation in place, then there is likely a flawed test in your suite.
MSVC's Control Flow Guard adds high performance runtime security checks.
_GLIBCXX_DEBUG
with GCC's implementation libstdc++ implementation. See Krister's blog article.
If it is determined by team consensus that the compiler or analyzer is warning on something that is either incorrect or unavoidable, the team will disable the specific error to as localized part of the code as possible.
Be sure to reenable the warning after disabling it for a section of code. You do not want your disabled warnings to leak into other code.
CMake, mentioned above, has a built-in framework for executing tests. Make sure whatever build system you use has a way to execute tests built in.
To further aid in executing tests, consider a library such as Google Test, Catch, CppUTest or Boost.Test to help you organize the tests.
Unit tests are for small chunks of code, individual functions which can be tested standalone.
There should be a test enabled for every feature or bug fix that is committed. See also Code Coverage Analysis. These are tests that are higher level than unit tests. They should still be limited in scope to individual features.
Don't forget to make sure that your error handling is being tested and works properly as well. This will become obvious if you aim for 100% code coverage.
GDB - The GNU debugger, powerful and widely used. Most IDEs implement an interface to use it.
rr is a free (open source) reverse debugger that supports C++.
- hdoc the modern documentation tool for C++
Lizard provides a very simple interface for running complexity analysis against a C++ codebase.
Metrix++ can identify and report on the most complex sections of your code. Reducing complex code helps you and the compiler understand it better and optimize it better.
ABI Compliance Checker (ACC) can analyze two library versions and generates a detailed compatibility report regarding API and C++ ABI changes. This can help a library developer spot unintentional breaking changes to ensure backward compatibility.
Customizable Naming Convention Checker can report on identifiers in your code that do not follow certain naming conventions.
ClangFormat can check and correct code formatting to match organizational conventions automatically. Multipart series on utilizing clang-format.
SourceMeter offers a free version which provides many different metrics for your code and can also call into cppcheck.
Bloaty McBloatface is a binary size analyzer/profiler for unix-like platforms
pahole generates data on holes in the packing of data structures and classes in compiled code. It can also the size of structures and how they fit within the system's cache lines.
BinSkim is a binary static analysis tool that provides security and correctness results for Windows Portable Executable and *nix ELF binary formats