I am new to programming in general so I decided that I would start by making a simple vector class in C++. However I would like to get in to good habits from the start rather than trying to modify my workflow later on.
I currently have only two files vector3.hpp and vector3.cpp. This project will slowly start to grow (making it much more of a general linear algebra library) as I become more familiar with everything, so I would like to adopt a “standard” project layout to make life easier later on. So after looking around I have found two ways to go about organizing hpp and cpp files, the first being:
project
└── src
├── vector3.hpp
└── vector3.cpp
and the second being:
project
├── inc
│ └── project
│ └── vector3.hpp
└── src
└── vector3.cpp
Which would you recommend and why?
Secondly I would like to use the Google C++ Testing Framework for unit testing my code as it seems fairly easy to use. Do you suggest bundling this with my code, for example in a inc/gtest or contrib/gtest folder? If bundled, do you suggest using the fuse_gtest_files.py script to reduce the number or files, or leaving it as is? If not bundled how is this dependency handled?
When it comes to writing tests, how are these generally organized? I was thinking to have one cpp file for each class (test_vector3.cpp for example) but all compiled in to one binary so that they can all be run together easily?
Since the gtest library is generally build using cmake and make, I was thinking that it would make sense for my project to also be built like this? If I decided to use the following project layout:
├── CMakeLists.txt
├── contrib
│ └── gtest
│ ├── gtest-all.cc
│ └── gtest.h
├── docs
│ └── Doxyfile
├── inc
│ └── project
│ └── vector3.cpp
├── src
│ └── vector3.cpp
└── test
└── test_vector3.cpp
How would the CMakeLists.txt have to look so that it can either build just the library or the library and the tests? Also I have seen quite a few projects that have a build and a bin directory. Does the build happen in the build directory and then the binaries moved out in to the bin directory? Would the binaries for the tests and the library live in the same place? Or would it make more sense to structure it as follows:
test
├── bin
├── build
└── src
└── test_vector3.cpp
I would also like to use doxygen to document my code. Is it possible to get this to automatically run with cmake and make?
Sorry for so many questions, but I have not found a book on C++ that satisfactorily answers these type of questions.
C++ build systems are a bit of a black art and the older the project
the more weird stuff you can find so it is not surprising that a lot
of questions come up. I’ll try to walk through the questions one by one and mention some general things regarding building C++ libraries.
Separating headers and cpp files in directories. This is only
essential if you are building a component that is supposed to be used
as a library as opposed to an actual application. Your headers are the
basis for users to interact with what you offer and must be
installed. This means they have to be in a subdirectory (no-one wants
lots of headers ending up in top-level
/usr/include/) and yourheaders must be able to include themselves with such a setup.
works well, because include paths work out and you can use easy
globbing for install targets.
Bundling dependencies: I think this largely depends on the ability of
the build system to locate and configure dependencies and how
dependent your code on a single version is. It also depends on how
able your users are and how easy is the dependency to install on their
platform. CMake comes with a
find_packagescript for GoogleTest. This makes things a lot easier. I would go with bundling only
when necessary and avoid it otherwise.
How to build: Avoid in-source builds. CMake makes out of source-builds
easy and it makes life a lot easier.
I suppose you also want to use CTest to run tests for your system (it
also comes with build-in support for GTest). An important decision for
directory layout and test organization will be: Do you end up with
subprojects? If so, you need some more work when setting up CMakeLists
and should split your subprojects into subdirectories, each with its
own
includeandsrcfiles. Maybe even their own doxygen runs andoutputs (combining multiple doxygen projects is possible, but not easy
or pretty).
You will end up with something like this:
where
In case you have sub-components I would suggest adding another hierarchy and use the tree above for each sub-project. Then things get tricky, because you need to decide if sub-components search and configure their dependencies or if you do that in the top-level. This should be decided on a case-by-case basis.
Doxygen: After you managed to go through the configuration dance of
doxygen, it is trivial to use CMake
add_custom_commandto add adoc target.
This is how my projects end up and I have seen some very similar projects, but of course this is no cure all.
Addendum At some point you will want to generate a
config.hppfile that contains a version define and maybe a define to some version
control identifier (a Git hash or SVN revision number). CMake has
modules to automate finding that information and to generate
files. You can use CMake’s
configure_fileto replace variables in atemplate file with variables defined inside the
CMakeLists.txt.If you are building libraries you will also need an export define to
get the difference between compilers right, e.g.
__declspecon MSVCand
visibilityattributes on GCC/clang.