Search code examples
c++unit-testinggccgoogletest

How do I build and use googletest (gtest) and googlemock (gmock) with gcc/g++ or clang?


Googletest (gtest) seems to be an immensely popular unit test framework and I'd like to learn how to build it stand-alone on the g++ compiler, simply and easily, so I can test small libraries and one-off files with it.

I've read the official documentation and readmes here:

  1. https://github.com/google/googletest
  2. and here: https://github.com/google/googletest/tree/main/googletest

...but I still can't figure it out.

How can I just build and test with gtest using the gcc/g++ compiler, or the g++-compatible LLVM clang compiler?


I know I can do the following to use cmake, but it doesn't give me the level of granular control I desire, and it still doesn't answer the mystical question of "how do I use these .a static library files when done?".

From: https://github.com/google/googletest/tree/main/googletest#generic-build-instructions

git clone https://github.com/google/googletest.git
cd googletest        # Main directory of the cloned repository.
mkdir build          # Create a directory to hold the build output.
cd build
time cmake ..        # Generate native make build scripts for GoogleTest.

time make            # Run those makefiles just autogenerated by cmake above.

You'll now have the following 4 library files built with whatever build settings were pre-specified for you in the cmake files, but I still don't know how to use them:

googletest/build/lib/libgmock.a
googletest/build/lib/libgmock_main.a
googletest/build/lib/libgtest.a
googletest/build/lib/libgtest_main.a

Solution

  • If you're on Windows, you can run Bash and gcc and g++ build commands inside an MSYS2 terminal. See my full setup and installation instructions here: Installing & setting up MSYS2 from scratch, including adding all 7 profiles to Windows Terminal. git commands, however, should still be run inside the Git Bash terminal in Windows which comes with Git for Windows.

    For Linux, just use your regular Bash-based terminal for everything.


    For my brand-new answer 1 year later, see here: The "easy" way: install gtest's headers and .a static library files system-wide into /usr/local/include and /usr/local/lib, respectively


    The "hard" way: manually build everything from scratch, using g++ directly without a build system

    I finally figured it out! The key reference is this one, which has some excellent build command examples I studied to figure it all out: https://ethz-adrl.github.io/ct/ct_core/doc/html/md__home_adrl_code_src_control-toolbox_ct_core_build_test_googletest-src_googletest_README.html

    Here are the steps:

    Tested on Linux Ubuntu.

    I first documented this entire process, and more, in my eRCaGuy_hello_world repo in my main C++ readme file here: cpp/README.md.

    1. Build all of gtest and gmock as static library archive *.a files

    # Clone the repo
    git clone https://github.com/google/googletest.git
    
    # Build all of gtest and gmock as static library archive `*.a` files
    
    time g++ -Wall -Wextra -Werror -O3 -std=c++17 -pthread -c \
        -I"googletest/googletest/include" -I"googletest/googletest" \
        -I"googletest/googlemock/include" -I"googletest/googlemock" \
        googletest/googletest/src/gtest-all.cc \
        googletest/googletest/src/gtest_main.cc \
        googletest/googlemock/src/gmock-all.cc \
        googletest/googlemock/src/gmock_main.cc
    
    # move all of the object files just created to a "bin" dir
    mkdir -p bin
    mv -t bin gtest-all.o gtest_main.o gmock-all.o gmock_main.o
    
    # Use the `ar` "archive" utility to create the *.a static library archive files
    # from the 4 object files above
    time ar -rv bin/libgtest.a bin/gtest-all.o
    time ar -rv bin/libgtest_main.a bin/gtest_main.o
    time ar -rv bin/libgmock.a bin/gmock-all.o
    time ar -rv bin/libgmock_main.a bin/gmock_main.o
    

    You now have:

    bin/libgtest.a
    bin/libgtest_main.a
    bin/libgmock.a
    bin/libgmock_main.a
    

    2. Build and run some of the samples which come with googletest

    See these sample tests here: https://github.com/google/googletest/tree/main/googletest/samples.

    1. For googletest/googletest/samples/sample1_unittest.cc:
      time ( \
          time g++ -Wall -Wextra -Werror -O3 -std=c++17 -pthread \
          -I"googletest/googletest/include" -I"googletest/googlemock/include" \
          googletest/googletest/samples/sample1_unittest.cc \
          googletest/googletest/samples/sample1.cc \
          bin/libgtest.a bin/libgtest_main.a \
          -o bin/a \
          && time bin/a \
      )
      
    2. For googletest/googletest/samples/sample2_unittest.cc:
      time ( \
          time g++ -Wall -Wextra -Werror -O3 -std=c++17 -pthread \
          -I"googletest/googletest/include" -I"googletest/googlemock/include" \
          googletest/googletest/samples/sample2_unittest.cc \
          googletest/googletest/samples/sample2.cc \
          bin/libgtest.a bin/libgtest_main.a \
          -o bin/a \
          && time bin/a \
      )
      

    etc.

    Sample build and run command and output of building sample1_unittest.cc above:

    eRCaGuy_hello_world/cpp$ time ( \
    >     time g++ -Wall -Wextra -Werror -O3 -std=c++17 -pthread \
    >     -I"googletest/googletest/include" -I"googletest/googlemock/include" \
    >     googletest/googletest/samples/sample1_unittest.cc \
    >     googletest/googletest/samples/sample1.cc \
    >     bin/libgtest.a bin/libgtest_main.a \
    >     -o bin/a \
    >     && time bin/a \
    > )
    
    real    0m1.787s
    user    0m1.375s
    sys 0m0.165s
    Running main() from googletest/googletest/src/gtest_main.cc
    [==========] Running 6 tests from 2 test suites.
    [----------] Global test environment set-up.
    [----------] 3 tests from FactorialTest
    [ RUN      ] FactorialTest.Negative
    [       OK ] FactorialTest.Negative (0 ms)
    [ RUN      ] FactorialTest.Zero
    [       OK ] FactorialTest.Zero (0 ms)
    [ RUN      ] FactorialTest.Positive
    [       OK ] FactorialTest.Positive (0 ms)
    [----------] 3 tests from FactorialTest (0 ms total)
    
    [----------] 3 tests from IsPrimeTest
    [ RUN      ] IsPrimeTest.Negative
    [       OK ] IsPrimeTest.Negative (0 ms)
    [ RUN      ] IsPrimeTest.Trivial
    [       OK ] IsPrimeTest.Trivial (0 ms)
    [ RUN      ] IsPrimeTest.Positive
    [       OK ] IsPrimeTest.Positive (0 ms)
    [----------] 3 tests from IsPrimeTest (0 ms total)
    
    [----------] Global test environment tear-down
    [==========] 6 tests from 2 test suites ran. (0 ms total)
    [  PASSED  ] 6 tests.
    
    real    0m0.003s
    user    0m0.000s
    sys 0m0.002s
    
    real    0m1.790s
    user    0m1.375s
    sys 0m0.166s
    

    Notes

    1. Q: Why is the include dir -I"googletest/googletest" required when building the googletest library?
      1. A: Because googletest/googletest/src/gtest-all.cc includes all other source files as src/name_of_file.cc, here: https://github.com/google/googletest/blob/main/googletest/src/gtest-all.cc#L41-L49. That means that the parent dir which contains the src dir must be an "include folder". That parent dir is googletest/googletest, so we mark it as an include dir with -I"googletest/googletest".
    2. You can test C code with gtest too, using the extern "C" { } trick when including C headers in C++ to prevent name-mangling. You then link to the C-built object *.o files, while including the non-name-mangled headers in the C++ googletest unit tests.

    Happy building! Now I/we can finally use gtest easily in our own personal projects!

    Other references

    1. my own answer where I figured out the time cmd wrapper things to time sub-components of a larger multi-line command, as well as the entire multi-line command: How to run time on multiple commands AND write the time output to file?

    See also

    1. My Q&A: Meaning of -l (lowercase "L") flags in gcc/g++
      1. And the answer by @KamilCuk
    2. My answer: How to install Google Test (gtest) and Google Mock (gmock) as shared, static .a libraries, system-wide, on Linux/Unix:

      This includes a lot about gcc/g++ libraries, installing libraries, naming .a statically-linked library files, where g++ searches for includes, etc.