Ihave recently been sold on using CMake for compiling my C++ projects, and would now like to start writing some unit tests for my code. I have decided to use the Google Test utility to help with this, but require some help in getting started.
All day I have been reading various guides and examples include the Primer, an introduction at IBM and some questions on SO (here and here) as well as other sources I've lost track of. I realise there's plenty out there but somehow I am still having difficulties.
I'm currently trying to implement the most basic test, to confirm I've compiled/installed gtest right and it's not working. The only source file (testgtest.cpp) is taken almost exactly from this previous answer:
Having done some more digging, I think my issue is something to do with the type of library I am building gtest into. When building gtest with CMake, if BUILD_SHARED_LIBS is un-checked, and I link my program against these .lib files I get the errors mentioned above. However, if BUILD_SHARED_LIBS is checked then I produce a set of .lib and .dll files. When now linking against these .lib files the program compiles, but when run complains that it can't find gtest.dll.
Used in the normal way, ExternalProject won't do the download and unpacking at configure time (i.e. when CMake is run), but you can get it to do so with just a little bit of work. I've written a blog post on how to do this which also includes a generalised implementation which works for any external project which uses CMake as its build system, not just gtest. You can find them here:
Most likely, the difference in compiler options between your test binary and the Google Test library is to blame on such errors. That's why it's recommended to bring in Google Test in the source form and build it along with your tests. It's very easy to do in CMake. You just invoke ADD_SUBDIRECTORY with the path to the gtest root and then you can use public library targets (gtest and gtest_main) defined there. There is more background information in this CMake thread in the googletestframework group.
[edit]The BUILD_SHARED_LIBS option is only effective on Windows for now. It specifies the type of libraries that you want CMake to build. If you set it to ON, CMake will build them as DLLs as opposed to static libs. In that case you have to build your tests with -DGTEST_LINKED_AS_SHARED_LIBRARY=1 and copy the DLL files produced by the CMake to the directory with your test binary (CMake places them in a separate output directory by default). Unless gtest in static lib doesn't work for you, it's easier not to set that option.
I like the library but adding it to the project is a real pain. And you have no chance to do it right unless you dig (and hack) into the gtest cmake files. Shame. In particular I do not like the idea of adding gtest as a source. :)
I decided to throw something generic together real quick demonstrating a different way of doing it than the answers previously posted, in hope that it might help someone. The following worked for me on my mac. Firstly I ran setup commands for gtests. I just used a script I found to setup everything.
Both commands are intended to replace use of add_test() to register tests, and will create a separate CTest test for each Google Test test case. Note that this is in some cases less efficient, as common set-up and tear-down logic cannot be shared by multiple test cases executing in the same instance. However, it provides more fine-grained pass/fail information to CTest, which is usually considered as more beneficial. By default, the CTest test name is the same as the Google Test name (i.e. suite.testcase); see also TEST_PREFIX and TEST_SUFFIX.
This flag is in TORCH_CXX_FLAGS, however gtest uses its own CMakeLists.txt with its own set of flags. You should add it manually. The easiest way is probably with add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0) somewhere near the top of CMakeLists.txt.
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:
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?
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:
C++ build systems are a bit of a black art and the older the projectthe more weird stuff you can find so it is not surprising that a lotof 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 onlyessential if you are building a component that is supposed to be usedas a library as opposed to an actual application. Your headers are thebasis for users to interact with what you offer and must beinstalled. This means they have to be in a subdirectory (no-one wantslots of headers ending up in top-level /usr/include/) and yourheaders must be able to include themselves with such a setup.
Bundling dependencies: I think this largely depends on the ability ofthe build system to locate and configure dependencies and howdependent your code on a single version is. It also depends on howable your users are and how easy is the dependency to install on theirplatform. CMake comes with a find_package script for GoogleTest. This makes things a lot easier. I would go with bundling onlywhen necessary and avoid it otherwise.
I suppose you also want to use CTest to run tests for your system (italso comes with build-in support for GTest). An important decision fordirectory layout and test organization will be: Do you end up withsubprojects? If so, you need some more work when setting up CMakeListsand should split your subprojects into subdirectories, each with itsown include and src files. Maybe even their own doxygen runs andoutputs (combining multiple doxygen projects is possible, but not easyor pretty).
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.
Addendum At some point you will want to generate a config.hppfile that contains a version define and maybe a define to some versioncontrol identifier (a Git hash or SVN revision number). CMake hasmodules to automate finding that information and to generatefiles. You can use CMake's configure_file to replace variables in atemplate file with variables defined inside the CMakeLists.txt.
About splitting the header files and source files (cpp), both schemes are fairly common. However, I tend to prefer keeping them together, it is just more practical on day-to-day tasks to have the files together. Also, when all the code is under one top-level folder, i.e., the trunk/src/ folder, you can notice that all the other folders (bin, lib, include, doc, and maybe some test folder) at the top level, in addition to the "build" directory for an out-of-source build, are all folders that contain nothing more than files that are generated in the build process. And thus, only the src folder needs to be backed up, or much better, kept under a version control system / server (like Git or SVN).
And when it comes to installing your header files on the destination system (if you want to eventually distribute your library), well, CMake has a command for installing files (implicitly creates a "install" target, to do "make install") which you can use to put all the headers into the /usr/include/ directory. I just use the following cmake macro for this purpose:
Where SRCROOT is a cmake variable that I set to the src folder, and INCLUDEROOT is cmake variable that I configure to wherever to headers need to go. Of course, there are many other ways to do this, and I'm sure my way is not the best. The point is, there is no reason to split the headers and sources just because only the headers need to be installed on the target system, because it is very easy, especially with CMake (or CPack), to pick out and configure the headers to be installed without having to have them in a separate directory. And this is what I have seen in most libraries.
3a8082e126