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

2

2

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
Jezreel answered 4/5, 2022 at 5:30 Comment(9)
Note to @273K and others: I had the c tag too because technically 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. But, removing the c tag is probably not a big deal either.Jezreel
You may test ASM code with google test framework. Why have you not used the tag [assembly]? Your question is "how to build gtest?", not "Is Google Test OK for testing C code?". The question is about C++.Tollhouse
@273K, sounds fine, that's why I didn't revert the edit. That's a good link you provided there. I think people will find it useful. Thanks.Jezreel
1.) You don't need to use the static libs at all. You also can simply include the needed header files and pick the needed c++ files and everything is fine. That is what I do. 2.) You should decide if you want to write your own main or use the delivered one. That is whats the difference is in the delivered .a files. So simply include your needed headers and link against the libs as needed. For me it is quite unclear what is unanswered in the docu here.Hydranth
@Klaus, I address not using the static libraries at all, here, under "Option 2: rebuild your unit test and the entire gtest/gmock library all at once". The downside is it takes 11 sec to build instead of 1.5 sec. That's a lot of unnecessary thumb-twiddling time when I'm trying to rapidly test.Jezreel
There is something totally wrong I believe. First: If templates are in use to do something special with your part of the code, it can't be removed by static libs at all. The templates needed from googletest itself did not need a second to compile. I full test project, not only the google libs are compiled on my very cheep discounter PC within: real 0m0,955s user 0m0,614s sys 0m0,266s. I believe you did something wrong, but not related to gtest...Hydranth
I run another test, modified a common used header of my project which recompiles more or less my whole project and use ccache in background: real 0m0,471s user 0m0,360s sys 0m0,105s. No idea how you need 11 sec at all...Hydranth
@Klaus, will you clone my repo and run my "Option 1" and "Option 2" instructions, exactly as I gave them? I see ~1.5 sec and ~11 sec, as I explain in my instructions, here: github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/…. I'd like to see if you get similar results with my exact instructions. I am curious why there is such a big difference between us.Jezreel
Let us continue this discussion in chat.Hydranth
J
4

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.

Jezreel answered 4/5, 2022 at 5:30 Comment(11)
Why do you need this instruction when you can build GTest with 2 cmake commands?Vale
@Vale Even after you build with the 2 cmake commands, one still may not know how to use the .a files which are produced by those commands. I still spent 4 hrs trying to figure out how to use the .a files in my build commands. Not only that, but it seems you should build the libraries with the same exact build commands you use on your tests or else you may have problems. Having this manual control allows quickly and easily tweaking the exact build options you use to make the .a files so that they match the build options you use on your unit tests.Jezreel
Lastly, it's a good exercise to learn how to make and use static library .a files.Jezreel
There's learning value, I agree, but I wouldn't recommend others to do it. Or at least reframe the question as a generic "how do I create static libraries with GCC". "easily tweaking the exact build" That can be done with -DCMAKE_{C,CXX,LINKER}_FLAGS. I can understand not liking CMake enough to use it for your own projects, but I can't understand not using it for projects where it's the intended build system.Swipple
"spent 4 hrs trying to figure out how to use the .a files" Then the question should've been "how do I create and use .a files". Then someone with the same problem would be much more likely to be able to find your post.Swipple
@HolyBlackCat, where it's the intended build system....actually, googletest explicitly has a disclaiimer that it's not the intended build system for gtest. Bazel is. Cmake is only community-supported for gtest, and I'm not sure how well it's kept up. I also find both bazel and cmake too big and bulky for tiny < 10 file projects.Jezreel
Ah well, at least it's supported. :) I can understand avoiding CMake for your tiny project, but not for dependencies of any size. Someday you might have a dependency so big you wouldn't be able to build it manually. A more sustainable approach is to use a package manager (which I frankly dislike for small projects...) or at least some kind of scripts to invoke CMake (and/or something else) to build your dependencies.Swipple
@HolyBlackCat, I'll get there someday. I'm not a build expert. Meanwhile, I'm happy I at least got it working so I can run basic gtest unit tests in my hello world repo. Off to the next piece. Just trying to share what I know to help the next person.Jezreel
@ixSci, I don't know what disclaimer I'd possibly write. On personal code outside of work, I know of no other way to use gtest--meaning: to get it to compile with my unit test code. This is my first and only time ever getting gtest to build outside of work (and at work someone else manages the build system). I have never seen another person build or link gtest. I have never seen another way to install or use gtest. I have never seen another code example nor tutorial showing how to build nor run gtest.Jezreel
So...I'm thrilled to see the RUN and OK output above. gtest ran. That's a big deal for me...no, a huge deal. I've been wanting to know how to do that for years, and I just figured it out. If you have better ways, please show them so I can learn what you know too.Jezreel
But you already know the better way, it's called CMake. The only problem you mentioned is the vague lack of "granular control".Swipple
J
0

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 the more manual approach, see my other answer here.

The "easy" way: install gtest's headers and .a static library files system-wide into /usr/local/include and /usr/local/lib, respectively

Tested in Linux Ubuntu.

With another year's worth of effort, for a total of about 5 years trying to learn how to do this, I finally figured out the "easy" way.

I initially literally just wanted to know what g++ command to run to build my own unit test files. Here is the answer:

  1. Install gtest and gmock system-wide as static, .a shared libraries in /usr/local/lib/. Also, install their header files system-wide into /usr/local/include/.

    sudo apt update
    sudo apt install cmake
    
    # You can find some of these instructions, here: 
    # https://github.com/google/googletest/tree/main/googletest
    time 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."
                            # Takes ~2 seconds.
    time make            # Run those makefiles just autogenerated by cmake above.
                            # Takes ~10 seconds.
    sudo make install    # Install the .a library files, and headers, into 
                            # /user/local/.
    
  2. Use the -pthread, -lgtest, -lgtest_main, -lgmock, and -lgmock_main linker flags, passed directly to g++, as necessary.

    Example:

    # Build and run an example googletest unit test that comes in the repo:
    # - required in this case: `-pthread`, `-lgtest`, and `-lgtest_main`
    
    mkdir -p bin
    
    time g++ -Wall -Wextra -Werror -O3 -std=c++17 -pthread \
        googletest/googletest/samples/sample1_unittest.cc \
        googletest/googletest/samples/sample1.cc \
        -lgtest -lgtest_main -o bin/a && time bin/a
    

For a ton more details, longer explanations, and more info., see my full answer here: How to install Google Test (gtest) and Google Mock (gmock) as shared, static .a libraries, system-wide, on Linux/Unix!

For more information on the -l flags, see also my other answer here: Meaning of -l (lowercase "L") flags in gcc/g++

If you don't want to install the latest "daily" gtest code, just get the latest release here instead: https://github.com/google/googletest/releases

Jezreel answered 13/3, 2023 at 7:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.