This is a demo project to demonstrate a reasonable structure for CMake based projects, that use CTest to run unit tests via Catch.
This project was developed as a teaching aid for UCL's "Research Computing with C++" course developed by Dr. James Hetherington and Dr. Matt Clarkson.
The main idea of this project is to try and help a C++ algorithm developer write their algorithm in a C++ library and then deploy the C++ library in a variety of scenarios.
The main features provided are:
make docs
or DOCS task in Visual Studio.boost::python
.The feature list above is quite diverse, and in reality most developers won't want all of the above features. So, while you could attempt all of these, within the same project, we envisage the following project types:
So, the aim for the C++ developer would be to write a small algorithm library, and get the code out there into the hands of their users. This project can accommodate all of the above, and there are CMake options to switch these options OFF/ON.
Furthermore, once you have a successful build for your use-case, you could delete the bits of code that you don't need. We could have made a different repository for each of the use-cases, but then there would be a lot of code duplication and overlap. So, for now, its all one repository. If you want to streamline your project, you could:
Take a look in the Code
sub-folder. Remove the directories you do not need,
and change Code/CMakeLists.txt
accordingly.
Search the top level CMakeLists.txt for code that looks like
mpAddSomething
and mpIncludeSomething
and easily chop out 3rd party libraries
you do not need.
We believe its easier to remove code you don't need than it is to build up a lot of CMake code, based on hours of searching the internet. At least the CMake code here has been tested ... to some degree.
This project itself can be built if you just want to evaluate it. In Linux terms that would be:
git clone --recursive https://github.com/MattClarkson/CMakeCatchTemplate
mkdir CMakeCatchTemplate-Build
cd CMakeCatchTemplate-Build
ccmake ../CMakeCatchTemplate
make
But ideally, you should use this project as a template to create your own project. To do so, please refer to the CMakeTemplateRenamer which will show you how to clone this repository, and rename all the variables to names of your choice. Then you would simply build your new project, using cmake, as shown above.
This project can be configured, using CMake, to build against Eigen, Boost, OpenCV, glog, gflags, VTK, PCL and ArrayFire. These were chosen as examples of how to use CMake, and some common C++ projects. These dependencies are optional, and this project will compile without them.
Furthermore, these dependencies can be downloaded and built, or the user can specify directories of previously compiled libraries.
To download and build dependencies, use CMake to ensure:
where ON
is the default. Then to build any of Eigen, Boost or OpenCV etc., use CMake to set:
and so on. If you set BUILD_SUPERBUILD=OFF, and these BUILD_whatever variables are on, then CMake will just try finding locally installed versions rather then downloading them.
To switch between static/dynamic linking, use CMake to set:
To switch between Debug and Release mode, use CMake to set:
Note: Only Debug and Release are supported.
Note: your host system is very likely to have a version of Boost that is different to the one provided here. So if you want to use Boost, you should probably try and use the one provided by this SuperBuild.
With all of those above build options, it is worth stressing:
So, once more: This project is just to provide an example. Its a template from which you can draw your own inspiration from.
If you build the project with shared libraries (BUILD_SHARED_LIBS:BOOL=ON)
then after the SuperBuild has successfully completed, you should look for the batch file
StartVS_Debug.bat
or StartVS_Release.bat
in the MYPROJECT-build
folder.
This sets the path before launching Visual Studio, so that when you come to run your
application or unit tests within Visual Studio, the dynamically
loaded libraries are found at run time.
This project can be used to build Python extensions, using either Boost.Python or PyBind11.
--recursive
.PYTHONPATH
to the directory containing your C++ Python extension.Code examples are in Code/PythonBoost
or Code/PythonPybind
.
So using the Code/PythonBoost
as an example, once PYTHONPATH
is set so
that you can pick up your compiled module, you would then be able to:
import CMakeCatchTemplatePython as mp
mp.my_first_add_function(1,6)
Deploying wheels is a difficult process. To help here, we have been inspired and assisted by Matthew Brett's multibuild, so you would configure .travis.yml and appveyor.yml to generate your own Python Wheels. This project itself is deployed to PyPi but obviously only includes the above function for illustrative purposes.
Minimum CMake version is 3.5. If you turn GUI options on, then the minimum Qt is version 5. Qt4 is not supported and not planned to be supported. If you are using VTK you should try a Qt version >= 5.5.0 to take advantage of the new OpenGL2 backend. If you need PyBind11, you need at least C++11, so on Windows you should have at least VS2015.
There are many different issues and combinations to test when packaging an application. For example:
make install
to install it in a specific directory, linked against known libraries, in known locations.make package
to make a relocatable and distributable bundle so that another user can install it anywhere on their system.It would take too long to document all of them and all of the issues involved. So, this project suggests some simple starting points, and recommendations.
Use Case | Important CMake settings | Workflow |
---|---|---|
Command Line Apps | leave GUIs OFF, BUILD_SHARED_LIBS=OFF, CMAKE_INSTALL_PREFIX=/path/to/install/to | make, make install |
C++ Gui Apps | Learn to build Qt5 first, BUILD_SHARED_LIBS=ON, build against your compiled Qt | make, make package |
Python Modules | must clone repo with --recursive, leave GUIs OFF, BUILD_SHARED_LIBS=OFF | make, test locally by setting PYTHONPATH, configure CI builds (see appveyor.yml and .travis.yml) to make wheels, upload to PyPi |
Unity Modules | leave GUIs OFF, BUILD_SHARED_LIBS=ON | make, then point Unity at the module. |
If you change your use-case, you must do a full clean build. That means completely delete the build folder, not just do a make clean
.
We welcome contributions to this project. Please use the following workflow.
<issue-number>-<some-short-description>
replacing <issue-number>
with the Github issue number
and <some-short-description>
with your description of the thing you are implementing.