yaobin.wen

Yaobin's Blog

View on GitHub
11 May 2022

Why does CMake report the missing of `libgmock.a`?

by yaobin.wen

A few weeks ago, I ran into the following CMake error when building our code:

CMake Error at /usr/lib/x86_64-linux-gnu/cmake/GTest/GTestTargets.cmake:110 (message):
  The imported target "GTest::gmock" references the file

     "/usr/lib/x86_64-linux-gnu/libgmock.a"

  but this file does not exist.  Possible reasons include:

  * The file was deleted, renamed, or moved to another location.

  * An install or uninstall procedure did not complete successfully.

  * The installation package was faulty and contained

     "/usr/lib/x86_64-linux-gnu/cmake/GTest/GTestTargets.cmake"

  but not all the files it references.

Call Stack (most recent call first):
  /usr/lib/x86_64-linux-gnu/cmake/GTest/GTestConfig.cmake:42 (include)
  /usr/share/cmake-3.22/Modules/FindGTest.cmake:187 (find_package)
  /opt/ros/melodic/share/catkin/cmake/test/gtest.cmake:340 (find_package)
  /opt/ros/melodic/share/catkin/cmake/all.cmake:164 (include)
  /opt/ros/melodic/share/catkin/cmake/catkinConfig.cmake:20 (include)
  CMakeLists.txt:58 (find_package)

-- Configuring incomplete, errors occurred!

However, we didn’t encounter this error when we were using CMake 3.15. This error happened when we switched to CMake 3.21+.

After some investigation, I figured out the general reason why the error didn’t happen on 3.15 but on a newer version:

However, as I read more about GoogleTest’s CMake code, it gave me the feeling that the way GoogleTest should be used depends on whether the code is built with only gtest enabled, or with gtest and gmock both enabled.

According to GoogleTest’s CMake file, line 25:

option(BUILD_GMOCK "Builds the googlemock subproject" ON)

by default, both gtest and gmock are enabled (because building gmock implies building gtest). Therefore, after the code is built, the generated googletest/CMakeFiles/Export/lib/cmake/GTest/GTestTargets.cmake has all the CMake Target instances:

In contrast, when I disabled the build of gmock, the generated GTestTargets.cmake only contains the Target instances of gtest and gtest_main. That all these Target instances are contained in the same GTestTargets.cmake seems to suggest that the package GoogleTest also expects that the users need to install both gtest and gmock on the system.

However, the package gtest only installs gtest-related Target instances (gtest, gtest_main); the package gmock, however, installs both gtest- and gmock-related Target instances. Therefore, if one consuming package depends on gtest only, it should install the gtest Debian packages that were built with gmock disabled so the GTestTargets.cmake wouldn’t contain anything about gmock. If the consuming package depends on gmock, it will need to install gmock Debian package. Because gmock always includes gtest, so all the four Target instances mentioned above will be installed, too, and that wouldn’t cause any error.

In my case, my project builds GoogleTest by ourselves and we are using the default build options, which means we build GoogleTest with both gtest and gmock enabled. Therefore, the generated GTestTargets.cmake will need all the four Target instances be present on the system. However, because the code that I built above only depends on gtest, the Debian build tools only install gtest Debian packages, so the gmock part is missing, hence the gmock-related build errors.

I feel the root cause of the issue is somewhere in GoogleTest: I think they should have split GTestTargets.cmake into two parts, one for gtest and one for gmock, so no matter if the source code is built with one or both enabled, the users can always install and use only the part(s) they really need, and not “tethered” to all of them if the package was built with both gtest and gmock enabled.

Tags: Tech - CMake - GoogleTest