Introduction
So far our project is rather simple. A real project would be more
complicated than the one we’ve created. Let’s add subdirectories, libraries,
and proper unit tests to make our project more realistic.
In this chapter we will split up our project to have a library which we can
put in a subdirectory. Then we will use
Google Test and
Google Mock to add a more realistic unit test.
The Library in a Subdirectory
We will make the ToDo class its own library, and put it in a subdirectory. Even
though it is a single source file making it a library actually has one
significant advantage. CMake will compile source files once for each target
that includes them. So if the ToDo class is used by our command line tool, a
unit test, and perhaps a GUI App it would be compiled three times. Imagine
if we had a collection of classes instead of just one. This results in a
lot of unnecessary compilation.
There were some minor changes to the C++, grab the files here:
Source
(CMakeLists.txt
listed below)
CMakeLists.txt
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
set(CMAKE_LEGACY_CYGWIN_WIN32 0)
project("To Do List")
enable_testing()
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR
"${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(warnings "-Wall -Wextra -Werror")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(warnings "/W4 /WX /EHsc")
endif()
if (NOT CONFIGURED_ONCE)
set(CMAKE_CXX_FLAGS "${warnings}"
CACHE STRING "Flags used by the compiler during all build types." FORCE)
set(CMAKE_C_FLAGS "${warnings}"
CACHE STRING "Flags used by the compiler during all build types." FORCE)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_subdirectory(ToDoCore)
add_executable(toDo main.cc)
target_link_libraries(toDo toDoCore)
add_test(toDoTest toDo)
set(CONFIGURED_ONCE TRUE CACHE INTERNAL
"A flag showing that CMake has configured at least once.")
So now our executable “toDo” only depends on the file “main.cc” and the new
library “toDoCore”. Our project also has a new subdirectory “ToDoCore”.
- include_directories(directories)
-
Add
directories
to the end of this directory’s
include paths. We didn’t need this before because all of our files were in
the same directory. -
include_directories()
documentation - CMAKE_CURRENT_SOURCE_DIR
- The full path to the source directory that CMake is currently processing.
-
CMAKE_CURRENT_SOURCE_DIR
documentation - add_subdirectory(source_dir)
-
Include the directory
source_dir
in your
project. This directory must contain a
CMakeLists.txt
file. -
Note: We’re omitting the optional second
parameter. This only works with subdirectories of the current directory.
We will see how to add external directories later. -
add_subdirectory
documentation -
target_link_libraries(target
library…) -
Specify that
target
needs to be linked against
one or more libraries. If a library name matches another target
dependencies are setup automatically so that the libraries will be built
first andtarget
will be updated whenever any of
the libraries are. -
If the
target
is an executable then it will be
linked against the listed libraries. -
If the target is a library then its dependency on these libraries will
be recorded. Then when something else links against
target
it will also link against
target
‘s dependencies. This makes it much easier
to handle a library’s dependencies since you only have to define them once
when you define library itself. -
For the moment we are using the simplest form of this command. For more
information see the
documentation .
When describing add_subdirectory()
I stated that the
subdirectory must contain a CMakeLists.txt
file. So here’s the
new file.
ToDoCore/CMakeLists.txt
Conveniently this file is rather simple.
-
add_library(target
STATIC | SHARED | MODULE
sources…) -
This command creates a new library
target
built
fromsources
. As you may have noticed
this command is very similar toadd_executable
. -
With
STATIC
,SHARED
, andMODULE
you
can specify what kind of library to build.STATIC
libraries
are archives of object files that are linked directly into other targets.
SHARED
libraries are linked dynamically and loaded at
runtime.MODULE
libraries are plug-ins that aren’t linked
against but can be loaded dynamically at runtime. -
If the library type is not specified it will be either
STATIC
orSHARED
. The default type is controlled by the
BUILD_SHARED_LIBS
variable. By default static libraries are created. -
add_library()
documentation
Testing – for Real
We have a rudimentary test but if we were really developing software we’d
write a real test using a real testing framework. As mentioned earlier we
will use
Google Test 1.6.0 and Google Mock 1.6.0. Conveniently they include their own
CMakeLists.txt
files, which makes them easy for us to use.
First the test:
ToDoCore/unit_test/ToDoTest.cc
#include "ToDoCore/ToDo.h"
#include <string>
using std::string;
#include <gmock/gmock.h>
using ::testing::Eq;
#include <gtest/gtest.h>
using ::testing::Test;
namespace ToDoCore
{
namespace testing
{
class ToDoTest : public Test
{
protected:
ToDoTest(){}
~ToDoTest(){}
virtual void SetUp(){}
virtual void TearDown(){}
ToDo list;
static const size_t taskCount = 3;
static const string tasks[taskCount];
};
const string ToDoTest::tasks[taskCount] = {"write code",
"compile",
"test"};
TEST_F(ToDoTest, constructor_createsEmptyList)
{
EXPECT_THAT(list.size(), Eq(size_t(0)));
}
TEST_F(ToDoTest, addTask_threeTimes_sizeIsThree)
{
list.addTask(tasks[0]);
list.addTask(tasks[1]);
list.addTask(tasks[2]);
EXPECT_THAT(list.size(), Eq(taskCount));
}
TEST_F(ToDoTest, getTask_withOneTask_returnsCorrectString)
{
list.addTask(tasks[0]);
ASSERT_THAT(list.size(), Eq(size_t(1)));
EXPECT_THAT(list.getTask(0), Eq(tasks[0]));
}
TEST_F(ToDoTest, getTask_withThreeTasts_returnsCorrectStringForEachIndex)
{
list.addTask(tasks[0]);
list.addTask(tasks[1]);
list.addTask(tasks[2]);
ASSERT_THAT(list.size(), Eq(taskCount));
EXPECT_THAT(list.getTask(0), Eq(tasks[0]));
EXPECT_THAT(list.getTask(1), Eq(tasks[1]));
EXPECT_THAT(list.getTask(2), Eq(tasks[2]));
}
} // namespace testing
} // namespace ToDoCore
This is a rather simple test, but ToDo
is still a rather simple
class. It may look strange if you are unfamiliar with Google Test, taking a
look at
Google Test Primer may be helpful. I also use a little functionality from Google Mock so
Google Mock for Dummies may also be useful.
Now we need to build the test:
ToDoCore/CMakeLists.txt
ToDoCore/unit_test/CMakeLists.txt
set(GMOCK_DIR "../../../../../gmock/gmock-1.6.0"
CACHE PATH "The path to the GoogleMock test framework.")
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# force this option to ON so that Google Test will use /MD instead of /MT
# /MD is now the default for Visual Studio, so it should be our default, too
option(gtest_force_shared_crt
"Use shared (DLL) run-time lib even when Google Test is built as static lib."
ON)
elseif (APPLE)
add_definitions(-DGTEST_USE_OWN_TR1_TUPLE=1)
endif()
add_subdirectory(${GMOCK_DIR} ${CMAKE_BINARY_DIR}/gmock)
include_directories(SYSTEM ${GMOCK_DIR}/gtest/include
${GMOCK_DIR}/include)
add_executable(ToDoTest ToDoTest.cc)
target_link_libraries(ToDoTest toDoCore
gmock_main)
add_test(ToDoTest ToDoTest)
First we add the Google Mock directory to our project then we add our
test. The path to Google Mock is stored in a cached variable so that you can
easily set it to the correct value either from the command line or via one
of the GUIs. There are several potential problems with that line but we will
worry about those later, for now it’s good enough. Okay I oversimplified a
little. We don’t just add the Google Mock directory, we also work around
some OS-specific problems.
When using Visual Studio to build our test we would run into a problem. Even
when building static libraries, CMake’s default, MSVC defaults to linking
against the multi-threaded, DLL-specific version of the standard library. By
default Google Test overrides this so that the non-DLL version of the
multi-threaded standard library is used. Then when our test links against
both toDoCore
and gmock_main
the linker will
output a large number of errors since we would be linking against two
different copies of the standard library. To avoid this problem we force
Google Test to use the DLL-specific version to match Visual Studio’s default
by setting the gtest_force_shared_crt
option to
ON
. See
Microsoft C/C++ Compiler Run-Time Library.
The second problem occurs on newer version of Mac OS X which default to
using a different standard library that fully supports C++11. GTest uses the
tuple
class from the draft TR1 standard and therefore looks for
it in the std::tr1
namespace. The tr1
namespace is
not present in the C++11 standard library that Apple uses so GTest cannot
find it and won’t compile. We fix this by telling GTest to use its own
tuple
implementation.
-
add_subdirectory(source_dir
binary_dir) -
Add the directory
source_dir
to the current
project withbinary_dir
as its corresponding
binary output directory. When adding a directory that is a subdirectory of
the current directory CMake will automatically determine what the binary
output directory should be, making the second argument optional. However
if you add a directory that isn’t a subdirectory you need to specify the
binary output directory. -
add_subdirectory
documentation - CMAKE_BINARY_DIR
-
This variable holds the path to the top level binary output directory,
i.e. the directory in which you ran the cmake command or the
path you chose for “Where to build the binaries” in the GUI. -
CMAKE_BINARY_DIR
documentation -
include_directories(AFTER|BEFORE
SYSTEM
directory…) -
- AFTER|BEFORE
-
Specify whether or not these include directories should be appended or
prepended to the list of include directories. If omitted then the
default behavior is used. -
By default directories are appended to the list. This behavior can be
changed by settingCMAKE_INCLUDE_DIRECTORIES_BEFORE
to
TRUE
. - SYSTEM
-
Specify that these directories are system include directories. This
only has an affect on compilers that support the distinction. This can
change the order in which the compiler searches include directories or
the handling of warnings from headers found in these directories. - directory…
- The directories to be added to the list of include directories.
-
include_directories()
documentation -
option(name
docstring
initialValue) -
Provide a boolean option to the user. This will be displayed in the GUI as
a checkbox. Once created the value of the option can be accessed as the
variablename
. The
docstring
will be displayed in the GUI to tell
the user what this option does. If no initial value is provided it
defaults to OFF. -
While this boolean option is stored in the cache and accessible as a
variable you cannot override theinitialValue
by
setting a variable of the same name beforehand, not even by passing a
-D command line option to CMake. Which is why we have to define
the option ourselves before Google Test does. -
option()
documentation - add_definitions(flags…)
-
Add preprocessor definitions to the compiler command line for targets in
the current directory and those below it. While this command is intended
for adding definitions you still need to precede them with
-D
. -
Because this command modifies the
COMPILE_DEFINITIONS
directory property it affects all targets in the directory, even
those that were defined before this command was used. If
this is not the desired effect then modifying the
COMPILE_DEFINITIONS
property of particular targets or source
files will work better. (Properties are introduced below.) -
add_definitions()
documentation -
COMPILE_DEFINITIONS
directory property documentation -
COMPILE_DEFINITIONS
target property documentation -
COMPILE_DEFINITIONS
source file property documentation
Let’s go ahead and try out our new test!
Source
> mkdir build > cd build > cmake -G "Unix Makefiles" .. -- The C compiler identification is Clang 4.2.0 -- The CXX compiler identification is Clang 4.2.0 -- Check for working C compiler: /usr/bin/cc -- Check for working C compiler: /usr/bin/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ -- Check for working CXX compiler: /usr/bin/c++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Found PythonInterp: /usr/local/bin/python (found version "2.7.3") -- Looking for include file pthread.h -- Looking for include file pthread.h - found -- Looking for pthread_create -- Looking for pthread_create - found -- Found Threads: TRUE -- Configuring done -- Generating done -- Build files have been written to: /Documents/Programming/C++/CMake Tutorial/flavors/part4_step2/build > make Scanning dependencies of target toDoCore [ 14%] Building CXX object ToDoCore/CMakeFiles/toDoCore.dir/ToDo.cc.o Linking CXX static library libtoDoCore.a [ 14%] Built target toDoCore Scanning dependencies of target toDo [ 28%] Building CXX object CMakeFiles/toDo.dir/main.cc.o Linking CXX executable toDo [ 28%] Built target toDo Scanning dependencies of target gtest [ 42%] Building CXX object gmock/gtest/CMakeFiles/gtest.dir/src/gtest-all.cc.o In file included from /Documents/Programming/C++/gmock/gmock-1.6.0/gtest/src/gtest-all.cc:42: In file included from /Documents/Programming/C++/gmock/gmock-1.6.0/gtest/src/gtest.cc:132: /Documents/Programming/C++/gmock/gmock-1.6.0/gtest/src/gtest-internal-inl.h:206:8: error: private field 'pretty_' is not used [-Werror,-Wunused-private-field] bool pretty_; ^ 1 error generated. make[2]: *** [gmock/gtest/CMakeFiles/gtest.dir/src/gtest-all.cc.o] Error 1 make[1]: *** [gmock/gtest/CMakeFiles/gtest.dir/all] Error 2 make: *** [all] Error 2
Oh noes! Newer versions of Clang have some pretty strict warnings and we
have just run afoul of one. So we have a problem: we want to use strict
compiler settings to ensure we write good code but we also don’t want to go
changing Google Test. As it turns out CMake actually provides us the
flexibility we need to disable warnings for just the gtest
target.
This is a capability that can easily be abused. In the case of Google Test
we didn’t write it and we know, or at least assume, that it works
fine. Because of that we don’t care about any warnings we might find in
Google Test’s code. We need to be careful not to use this feature to allow
ourselves to write poor code.
ToDoCore/unit_test/CMakeLists.txt
set(GMOCK_DIR "../../../../../gmock/gmock-1.6.0"
CACHE PATH "The path to the GoogleMock test framework.")
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# force this option to ON so that Google Test will use /MD instead of /MT
# /MD is now the default for Visual Studio, so it should be our default, too
option(gtest_force_shared_crt
"Use shared (DLL) run-time lib even when Google Test is built as static lib."
ON)
elseif (APPLE)
add_definitions(-DGTEST_USE_OWN_TR1_TUPLE=1)
endif()
add_subdirectory(${GMOCK_DIR} ${CMAKE_BINARY_DIR}/gmock)
set_property(TARGET gtest APPEND_STRING PROPERTY COMPILE_FLAGS " -w")
include_directories(SYSTEM ${GMOCK_DIR}/gtest/include
${GMOCK_DIR}/include)
add_executable(ToDoTest ToDoTest.cc)
target_link_libraries(ToDoTest toDoCore
gmock_main)
add_test(ToDoTest ToDoTest)
- set_property(TARGET gtest APPEND_STRING PROPERTY COMPILE_FLAGS ” -w”)
-
There are a variety of things that have properties in CMake, in this case
we are interested in a target’s properties. Each target can have it’s own
compiler flags in addition the ones set in
CMAKE_<LANG>_FLAGS
. Here we append
“-w
” togtest
‘s
COMPILE_FLAGS
. The flag “-w
” disables all
warnings for both GCC and Clang. When compiling with MSVC the
“-w
” will be automatically converted to
“/w
” which has the same function.
(Although it will warn that
“/w
” is overriding
“/W4
“) -
COMPILE_FLAGS
documentation - GCC Warning Options , currently these work for Clang too.
- Microsoft C/C++ Compiler Warning Level
-
set_property(TARGET
target_name…
APPEND|APPEND_STRING
PROPERTY name value…) -
- TARGET
-
Specify that we want to set the property of a target. Several other
types of things have properties you can set. For the moment we are
only going to deal with targets, but the concept is the same for the
rest. - target_name…
-
The name of the target whose property you want to set. You can list
multiple targets and all will have the property set the same way for
each. - APPEND | APPEND_STRING
-
Append to the property’s existing value instead of setting
it.APPEND
appends to the property as a
list.APPEND_STRING
appends to the property as a string. -
Note: Do not provide a multiple values when
usingAPPEND_STRING
as the results will not be what you
expect. -
Don’t worry about lists we will cover them in the next
chapter. - PROPERTY
- name
-
The name of the property you want to set. See
Properties on Targets. - value…
-
The value to set for the property. If multiple values are provided
they are treated as a list. Only provide one value if also using
APPEND_STRING
. -
Don’t worry about
lists yet.
-
set_property()
documentation
Let’s give this version a try.
Source
> mkdir build > cd build > cmake -G "Unix Makefiles" .. -- The C compiler identification is Clang 4.2.0 -- The CXX compiler identification is Clang 4.2.0 -- Check for working C compiler: /usr/bin/cc -- Check for working C compiler: /usr/bin/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ -- Check for working CXX compiler: /usr/bin/c++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Found PythonInterp: /usr/local/bin/python (found version "2.7.3") -- Looking for include file pthread.h -- Looking for include file pthread.h - found -- Looking for pthread_create -- Looking for pthread_create - found -- Found Threads: TRUE -- Configuring done -- Generating done -- Build files have been written to: /Documents/Programming/C++/CMake Tutorial/flavors/part4_step3/build > make Scanning dependencies of target toDoCore [ 14%] Building CXX object ToDoCore/CMakeFiles/toDoCore.dir/ToDo.cc.o Linking CXX static library libtoDoCore.a [ 14%] Built target toDoCore Scanning dependencies of target toDo [ 28%] Building CXX object CMakeFiles/toDo.dir/main.cc.o Linking CXX executable toDo [ 28%] Built target toDo Scanning dependencies of target gtest [ 42%] Building CXX object gmock/gtest/CMakeFiles/gtest.dir/src/gtest-all.cc.o Linking CXX static library libgtest.a [ 42%] Built target gtest Scanning dependencies of target gmock [ 57%] Building CXX object gmock/CMakeFiles/gmock.dir/src/gmock-all.cc.o Linking CXX static library libgmock.a [ 57%] Built target gmock Scanning dependencies of target gmock_main [ 71%] Building CXX object gmock/CMakeFiles/gmock_main.dir/src/gmock_main.cc.o Linking CXX static library libgmock_main.a [ 71%] Built target gmock_main Scanning dependencies of target ToDoTest [ 85%] Building CXX object ToDoCore/unit_test/CMakeFiles/ToDoTest.dir/ToDoTest.cc.o Linking CXX executable ToDoTest [ 85%] Built target ToDoTest Scanning dependencies of target gtest_main [100%] Building CXX object gmock/gtest/CMakeFiles/gtest_main.dir/src/gtest_main.cc.o Linking CXX static library libgtest_main.a [100%] Built target gtest_main > make test Running tests... Test project /Documents/Programming/C++/CMake Tutorial/flavors/part4_step3/build Start 1: ToDoTest 1/1 Test #1: ToDoTest ......................... Passed 0.00 sec 100% tests passed, 0 tests failed out of 1 Total Test time (real) = 0.01 sec > ToDoCore/unit_test/ToDoTest Running main() from gmock_main.cc [==========] Running 4 tests from 1 test case. [----------] Global test environment set-up. [----------] 4 tests from ToDoTest [ RUN ] ToDoTest.constructior_createsEmptyList [ OK ] ToDoTest.constructior_createsEmptyList (0 ms) [ RUN ] ToDoTest.addTask_threeTimes_sizeIsThree [ OK ] ToDoTest.addTask_threeTimes_sizeIsThree (0 ms) [ RUN ] ToDoTest.getTask_withOneTask_returnsCorrectString [ OK ] ToDoTest.getTask_withOneTask_returnsCorrectString (0 ms) [ RUN ] ToDoTest.getTask_withThreeTasts_returnsCorrectStringForEachIndex [ OK ] ToDoTest.getTask_withThreeTasts_returnsCorrectStringForEachIndex (1 ms) [----------] 4 tests from ToDoTest (1 ms total) [----------] Global test environment tear-down [==========] 4 tests from 1 test case ran. (1 ms total) [ PASSED ] 4 tests.
Yay! Everything works now and our test passes, too.
Next we will focus on how we could add more unit tests
(if we had more units) without duplicating the
work we’ve done here. Also we will make it so that our unit tests are
automatically run as needed whenever we build.
Version | Date | Comment |
1 | 2013-05-05 | Original version. |
2 | 2013-07-14 | Added line numbers and indication of changes to code samples. Added a link to the section on lists. |
3 | 2014-10-01 | Added the work around for a problem with Google Test and newer versions of Mac OS X along with an explanation and a description of add_definitions() |
This is a great tutorial. Unfortunately, gmock 1.6 doesn’t build on my Mac.
Gmock 1.7.0 does, but produces the error output listed in this gist:
https://gist.github.com/acgetchell/004242400a17d8bd72fc
The source files I am working with is listed here:
https://github.com/acgetchell/cmake-tutorial
Thanks for any suggestions!
Which version of OS X are you using?
Regardless this was written on OS X 10.8 and with 10.9 Apple switched the default standard library to one that fully supports C++11. This causes issues with GTest/GMock 1.6 because it was designed before C++11 was commonly available. Oddly enough the solution is to tell GTest to use its own tuple implementation. Simply add the following before you add the GMock directory.
add_definitions(-DGTEST_USE_OWN_TR1_TUPLE=1)
I will update this page to add that. As to your issue with GTest/GMock 1.7 I’m not sure off the top of my head but I will look into it.
As for the problem with GMock 1.7.0 they are related to the above line
set_property(TARGET gtest APPEND_STRING PROPERTY COMPILE_FLAGS " -w")
and a fix to GMock that allows you to link against it as a DLL. To fix a very peculiar linking problem on Windows when building
gmock
as a DLLgmock
andgmock_main
no longer link againstgtest
instead they compile GTest in directly. However this means the problem ingtest
we sidestepped now appears ingmock
andgmock_main
. So if we modify our workaround to beset_property(TARGET gtest gmock gmock_main APPEND_STRING PROPERTY COMPILE_FLAGS " -w")
it should all build again!
Thanks John for the update, once I updated the TARGET to include gmock and gmock_main the compilation worked fine.
Hi, I had to update the TARGET too and it’s fine now, anyone knows why?
Thanks for commenting about this issue, I have update the post with the fix.
Hi John!
Thanks for the suggestion!
I reverted from using Yosemite to using OS X 10.9.5.
I believe I made the changes you suggested (feel free to check my source files):
https://github.com/acgetchell/cmake-tutorial
Here are my results:
https://gist.github.com/acgetchell/12abdc4681c700543d2a
Thanks again for your comments, this is the closest I’ve come to getting GMock to work.
Regards,
Adam
Works now!
Thanks to this tutorial, David Alfonso’s GMock/CMake skeleton project:
https://github.com/davidag/gtestmock-cmake-template
And Jeff Langr’s “Modern C++ Programming with Test-Driven Development”, in particular the errata:
https://pragprog.com/titles/lotdd/errata
I’ve got a working CMake/GMock project:
https://github.com/acgetchell
Hi John, thx for this tuto realy nice (and better than the official documentation ^^).
I have a question about the first example. It should be include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ToDoCore) instead of include_directories(${CMAKE_CURRENT_SOURCE_DIR}) ?
Forget what I said, it is because you set the full path to the header into your main.cc, and not in my own file.
This is one hell of a great tutorial. Although to be honest it would have been easier to first show how to include all the libraries and then add a separate chapter dedicated to testing only. Imho that’s a good way of separating the two and making it easier to follow. Anyways thanks a lot!
Amazing tutorial, thank you so much for this. Keep it up!
Following this on Windows, I downloaded the latest version of googletest (which now includes googlemock) and when generating the solution for Visual Studio, it generated new projects for gmock, gmock_main, gtest, and gtest_main — none of which do anything when I run them. And I’m pretty sure that the RUN_TESTS project is still doing the old tests. At least, it doesn’t say anything specific about doing google tests, and the output looks nothing like what is in the example output.
Am I doing something wrong (I mean, aside from not following the tutorial exactly, but the tutorial tells me to use old versions and I’d rather learn the newer versions…)?
After sleeping on it and coming back, I figured out that I need to select the unit test project (ToDoTest), build it, and then running it shows up a command prompt briefly. But if I run that from the prompt itself, I see all the output as it should be.
Your article needs updating~
COMPILE_FLAGS is deprecated. see https://cmake.org/cmake/help/v3.6/prop_tgt/COMPILE_FLAGS.html
better to use these instead:
target_compile_options(gtest PRIVATE -w)
target_compile_options(gtest_main PRIVATE -w)
target_compile_options(gmock PRIVATE -w)
target_compile_options(gmock_main PRIVATE -w)
I found that I have to append to the Clang Compile Flags of all of these targets. maybe because I am using gtest1.7 and gmock1.7.
Ah, yes, CMake has been changing a lot since version 3 came out. I’ll admit I haven’t kept up with all of them, I suppose I should at least write up what needs to be fixed and continue (I should do that part anyway) with newer versions of CMake. Although some Linux distributions, e.g. RHEL, still ship with CMake 2.8: https://cmake.org/Wiki/CMake_Life_Cycle_Considerations. I suppose the best move is to update to be compatible (no warnings) with new versions of CMake while still supporting CMake 2.8 for compatibility.
As for needing to update all four gtest/gmock targets that is because of a change in version 1.7. Rather than having the other targets link against
gtest
they all compile it in directly. That change works around a problem when building them a DLLs on Windows.This is a great tutorial. I’ve learnt a lot about CMake from here and it is also the first I heard of Google Test and Google Mock which look fantastic. Thanks for this incredible resource!
I’d just like to point out that strictly speaking you don’t need Google Mock for the code you’ve shown, but only Google Test. They’ve been merged into one project now (https://github.com/google/googletest), but they are separate entities. Your CMakeLists.txt causes both gmock and gtest to compile and link to the code even though gmock doesn’t actually do anything. I modified my CMakeLists.txt to link only to Google Test instead of Mock and it works. This way it doesn’t have to compile and link to the unnecessary gmock. I guess in the future I’d like it compile and link to both once I start using gmock functionality, but I prefer to keep them separate at this point just to have it clear in my head which functionality comes from gtest and which comes from gmock.
Also, you seem to be using outdated syntax for the tests. According to the current primer (https://github.com/google/googletest/blob/master/googletest/docs/Primer.md) you should be using tests like
EXPECT_EQ(list.size(), size_t(0));
instead of
EXPECT_THAT(list.size(), Eq(size_t(0)));
Also, your Google Test and Google Mock documentation links are out of date and they redirect. The Primer I used it is at https://github.com/google/googletest/blob/master/googletest/docs/Primer.md and the Google Mock for Dummies is at https://github.com/google/googletest/blob/master/googlemock/docs/ForDummies.md
PS One error I had a problem with when compiling is that once I updated the tests that refer to the variable taskCount to
EXPECT_EQ(list.size(), taskCount);
the final linking stage would fail saying there is an undefined reference to taskCount. The easiest fix I found was to enclose it in size_t() like
EXPECT_EQ(list.size(), size_t(taskCount));
which I suspect is due to some properties of C++ macros that I am unaware of.
You are correct that Google Mock isn’t actually needed. I also suppose it is small consolation that my links were correct when I wrote this, I should probably update them. I just went ahead and included Google Mock as it might be useful on same projects, although I haven’t really used it myself.
As for
EXPECT_EQ()
versusEXPECT_THAT()
I have to disagree a little. You are correct that Google Test specifiesEXPECT_EQ()
, but if you read the documentation for Google Mock it providesEXPECT_THAT()
, which uses a Google Mock matcher for the comparison. I preferEXPECT_THAT()
overEXPECT_EQ()
, etc., because I find the order of the arguments to be clearer and I like the messages it produces when the values don’t match.So yes, Google Mock is not needed, but I actually am using it.
Your issue with
taskCount
and the linker is interesting; I would guess the compiler is optimizing outtaskCount
and then whatever theEXPECT_EQ()
macro resolved to probably tries to get its address.This is a bit of a confusing statement: “non-DLL version of the multi-threaded standard library”. Rather than calling the library “non-DLL”, just call it the “static version of the run-time library (.lib)” since on Windows static libraries have the file extension of “.lib” and dynamic libraries have “.dll”.
Keep on truckin’
Good point. I don’t use, or develop for, Windows much. I probably got confused by the fact that building dynamic libraries creates for .dll and .lib files.
Such a Great Tutorial my friends….
Now that GoogleTest and GoogleMock are in the same repository, the includes and
ToDoCore/CMakeLists.txt
needs to updated.Your includes should now be this for your
ToDoTest.cxx
:And for the
ToDoCore/unit_test/CMakeLists.txt
:That should do it!
Thanks! In the meantime there have been a bunch of changes that require updates. Than you for the updates for Google Test and Google Mock.
I have no idea how to modify this for the newest google test version. Thanks for your write-ups and effort for the past 4 posts. I’ve read three “how to cmake” tutorials and this was was the most comprehensible of them all.
Can anyone explain how to execute this project?Please help me..
https://github.com/rpclib/rpclib this project