gmock and gtest targets are required even with BUILD_TESTING OFF
Does this issue affect the google-cloud-cpp project? Yes.
What component of google-cloud-cpp is this related to?
The entire project, but I am testing with pubsub.
Describe the bug
When using CMake's FetchContent in order to fetch google-cloud-cpp, it attempts to export gmock and test targets even when building with BUILD_TESTING=OFF.
To Reproduce Steps to reproduce the behavior:
Add the following to your CMake project which has proper install commands already:
FetchContent_Declare(
google-cloud-sdk
URL https://github.com/googleapis/google-cloud-cpp/archive/${google_cloud_version}.tar.gz
)
set(BUILD_TESTING OFF)
set(GOOGLE_CLOUD_CPP_ENABLE_EXAMPLES OFF)
set(GOOGLE_CLOUD_CPP_ENABLE "pubsub")
FetchContent_MakeAvailable(google-cloud-sdk)
You will get the following errors:
CMake Error: install(EXPORT "google_cloud_cpp_mocks-targets" ...) includes target "google_cloud_cpp_mocks" which requires target "gmock_main" that is not in any export set.
CMake Error: install(EXPORT "google_cloud_cpp_mocks-targets" ...) includes target "google_cloud_cpp_mocks" which requires target "gmock" that is not in any export set.
CMake Error: install(EXPORT "google_cloud_cpp_mocks-targets" ...) includes target "google_cloud_cpp_mocks" which requires target "gtest" that is not in any export set.
CMake Error: install(EXPORT "google_cloud_cpp_iam_mocks-targets" ...) includes target "google_cloud_cpp_iam_mocks" which requires target "gmock_main" that is not in any export set.
CMake Error: install(EXPORT "google_cloud_cpp_iam_mocks-targets" ...) includes target "google_cloud_cpp_iam_mocks" which requires target "gmock" that is not in any export set.
CMake Error: install(EXPORT "google_cloud_cpp_iam_mocks-targets" ...) includes target "google_cloud_cpp_iam_mocks" which requires target "gtest" that is not in any export set.
CMake Error: install(EXPORT "pubsub_mocks-targets" ...) includes target "google_cloud_cpp_pubsub_mocks" which requires target "gmock_main" that is not in any export set.
CMake Error: install(EXPORT "pubsub_mocks-targets" ...) includes target "google_cloud_cpp_pubsub_mocks" which requires target "gmock" that is not in any export set.
CMake Error: install(EXPORT "pubsub_mocks-targets" ...) includes target "google_cloud_cpp_pubsub_mocks" which requires target "gtest" that is not in any export set.
Expected behavior
No errors. I expect BUILD_TESTING=OFF to not export any target related to testing.
Operating system: macOS Sonoma 14.1.2 (23B92)
What compiler and version are you using?
Apple clang version 15.0.0 (clang-1500.1.0.2.5)
Target: arm64-apple-darwin23.1.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
What version of google-cloud-cpp are you using?
v2.21.0
Hey, thanks for the detailed and concise bug report. I agree with your assessment of the problem. It is weird that we try to install mock libraries which depend on GoogleTest when -DBUILD_TESTING is off. This is discussed some in #13550. I think the fix will look like applications opting-in to installing the mocks.
Add the following to your CMake project which has proper install commands already:
I want to reproduce the error, so I can know if a fix actually works. But I am struggling. (FetchContent is new to me). Can you help point out where our builds differ? Probably in the CMakeLists.txt or in the cmake build commands...
I tried the following self-contained Dockerfile (that uses debian 12):
# syntax=docker/dockerfile:1.3-labs
# test using
# docker buildx build --progress plain -t repro - <Dockerfile
FROM debian:bookworm
RUN apt-get update && \
apt-get --no-install-recommends install -y apt-transport-https apt-utils \
automake build-essential ca-certificates cmake curl git \
gcc g++ m4 make ninja-build pkg-config tar wget zlib1g-dev
RUN apt-get update && \
apt-get --no-install-recommends install -y \
libabsl-dev \
libprotobuf-dev protobuf-compiler \
libgrpc++-dev libgrpc-dev protobuf-compiler-grpc \
libcurl4-openssl-dev libssl-dev nlohmann-json3-dev
WORKDIR /w
RUN cat >quickstart.cc <<_EOF_
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "google/cloud/pubsub/publisher.h"
#include <iostream>
int main(int argc, char* argv[]) try {
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " <project-id> <topic-id>\n";
return 1;
}
std::string const project_id = argv[1];
std::string const topic_id = argv[2];
// Create a namespace alias to make the code easier to read.
namespace pubsub = ::google::cloud::pubsub;
auto publisher = pubsub::Publisher(
pubsub::MakePublisherConnection(pubsub::Topic(project_id, topic_id)));
auto id =
publisher
.Publish(pubsub::MessageBuilder{}.SetData("Hello World!").Build())
.get();
if (!id) throw std::move(id).status();
std::cout << "Hello World published with id=" << *id << "\n";
return 0;
} catch (google::cloud::Status const& status) {
std::cerr << "google::cloud::Status thrown: " << status << "\n";
return 1;
}
_EOF_
RUN cat >CMakeLists.txt <<'_EOF_'
cmake_minimum_required(VERSION 3.10...3.24)
project(google-cloud-cpp-pubsub-quickstart CXX)
include(FetchContent)
set(google_cloud_version "v2.21.0")
FetchContent_Declare(
google-cloud-sdk
URL https://github.com/googleapis/google-cloud-cpp/archive/${google_cloud_version}.tar.gz
)
set(BUILD_TESTING OFF)
set(GOOGLE_CLOUD_CPP_ENABLE_EXAMPLES OFF)
set(GOOGLE_CLOUD_CPP_ENABLE "pubsub")
FetchContent_MakeAvailable(google-cloud-sdk)
add_executable(quickstart quickstart.cc)
target_link_libraries(quickstart google-cloud-cpp::pubsub)
_EOF_
RUN cmake -G Ninja -S . -B cmake-out && \
cmake --build cmake-out --target install
RUN cmake-out/quickstart || true
^ The above is in a file called Dockerfile. Then to test, I run: docker buildx build --progress plain -t repro - <Dockerfile
@dbolduc giving it a shot, let me see
It was a bit of a head scratcher but I think I know. I think abseil is also exporting the targets and that's why it's not erroring per say, but it is installing the gmock's into /usr/local/lib. I'll reproduce.
I think there's something deep in the dependency tree @dbolduc that causes it to not error, yet still show you that the mocks are being installed. I tried playing with this list:
RUN apt-get update && \
apt-get --no-install-recommends install -y \
libabsl-dev \
libprotobuf-dev protobuf-compiler \
libgrpc++-dev libgrpc-dev protobuf-compiler-grpc \
libcurl4-openssl-dev libssl-dev nlohmann-json3-dev
by removing abseil and also fetching it:
include(FetchContent)
# fetching abseil
set(abseil_version "20230802.1")
FetchContent_Declare(
absl
GIT_REPOSITORY https://github.com/abseil/abseil-cpp
GIT_TAG ${abseil_version}
OVERRIDE_FIND_PACKAGE
)
set(ABSL_PROPAGATE_CXX_STD ON)
set(ABSL_BUILD_TESTING OFF)
set(ABSL_ENABLE_INSTALL ON)
FetchContent_MakeAvailable(absl)
# fetching google cloud sdk
set(google_cloud_version "v2.21.0")
FetchContent_Declare(
google-cloud-sdk
URL https://github.com/googleapis/google-cloud-cpp/archive/${google_cloud_version}.tar.gz
)
set(BUILD_TESTING OFF)
set(GOOGLE_CLOUD_CPP_ENABLE_EXAMPLES OFF)
set(GOOGLE_CLOUD_CPP_ENABLE "pubsub")
FetchContent_MakeAvailable(google-cloud-sdk)
As well as adding install export statements:
# executable config
add_executable(quickstart quickstart.cc)
target_link_libraries(quickstart google-cloud-cpp::pubsub)
install(TARGETS quickstart EXPORT quickstart-targets)
install(EXPORT quickstart-targets
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_LIB_NAME}
NAMESPACE quickstart::
)
But that is still not showing me gtest/gmock libs being installed on your demo test. Yet the project I am working on (closed source) has the error I noted on the ticket, and you can see it does get installed:
~/git/Backend master ⇣ ❯ sudo cmake --install build | grep -E "gtest|gmock" 05:55:53 PM
Password:
-- Installing: /usr/local/lib/libgmockd.1.12.1.dylib
-- Installing: /usr/local/lib/libgmock_maind.1.12.1.dylib
-- Installing: /usr/local/lib/libgtestd.1.12.1.dylib
-- Installing: /usr/local/lib/libgtest_maind.1.12.1.dylib
Where they are being installed because I added that code in order to get around this:
CMake Error: install(EXPORT "google_cloud_cpp_mocks-targets" ...) includes target "google_cloud_cpp_mocks" which requires target "gmock_main" that is not in any export set.
CMake Error: install(EXPORT "google_cloud_cpp_mocks-targets" ...) includes target "google_cloud_cpp_mocks" which requires target "gmock" that is not in any export set.
CMake Error: install(EXPORT "google_cloud_cpp_mocks-targets" ...) includes target "google_cloud_cpp_mocks" which requires target "gtest" that is not in any export set.
CMake Error: install(EXPORT "google_cloud_cpp_iam_mocks-targets" ...) includes target "google_cloud_cpp_iam_mocks" which requires target "gmock_main" that is not in any export set.
CMake Error: install(EXPORT "google_cloud_cpp_iam_mocks-targets" ...) includes target "google_cloud_cpp_iam_mocks" which requires target "gmock" that is not in any export set.
CMake Error: install(EXPORT "google_cloud_cpp_iam_mocks-targets" ...) includes target "google_cloud_cpp_iam_mocks" which requires target "gtest" that is not in any export set.
CMake Error: install(EXPORT "pubsub_mocks-targets" ...) includes target "google_cloud_cpp_pubsub_mocks" which requires target "gmock_main" that is not in any export set.
CMake Error: install(EXPORT "pubsub_mocks-targets" ...) includes target "google_cloud_cpp_pubsub_mocks" which requires target "gmock" that is not in any export set.
CMake Error: install(EXPORT "pubsub_mocks-targets" ...) includes target "google_cloud_cpp_pubsub_mocks" which requires target "gtest" that is not in any export set.
My guess is that if the example above also adds fetch content for grpc and protobuf, which would match what I currently have, it would reproduce.
With that being said, the example you made does show that the mocks are being installed. By aiming for the goal of removing the mock installation when building with BUILD_TESTING=OFF, it'll achieve the same goal.
My guess is that if the example above also adds fetch content for grpc and protobuf
I tried, and I gave up trying to make google-cloud-cpp build with gRPC using FetchContent().
Aside 1: we recommend package managers like vcpkg over FetchContent() to avoid these sorts of problems. https://github.com/googleapis/google-cloud-cpp/blob/v2.21.0/doc/public-api.md#unsupported-use-cases
Aside 2: we use this CMake module internally to deal with GoogleTest. You might find it interesting: https://github.com/googleapis/google-cloud-cpp/blob/main/cmake/FindGMockWithTargets.cmake
Yet the project I am working on (closed source) has the error I noted on the ticket
I am sure, although I could not reproduce the error.
By aiming for the goal of removing the mock installation when building with
BUILD_TESTING=OFF, it'll achieve the same goal.
Right. I agree that that would fix your problem. I do not think google-cloud-cpp can change the default behavior of installing mocks, for backwards compatibility reasons, though.
I am thinking about adding another flag to explicitly turn off installation of the mocks. I opened #13673, but I want to get feedback from other maintainers before making any promises that it will get merged.
Agreed, and sounds fair to me. Thanks!
@anthonyalayo - Thanks again for the report. I think you saw #13673 go through. FYI, we are planning to release v2.22.0 of google-cloud-cpp which will contain the new flag on 2024-03-04.
The team discussed adding a build that uses FetchContent() so we can try to break your use case less in the future :sweat_smile:. I got about this far, before deciding that I must be doing something wrong:
include(FetchContent)
# Abseil
set(abseil_version "20230802.1")
FetchContent_Declare(
absl
GIT_REPOSITORY https://github.com/abseil/abseil-cpp
GIT_TAG ${abseil_version}
OVERRIDE_FIND_PACKAGE
)
set(ABSL_PROPAGATE_CXX_STD ON)
set(ABSL_BUILD_TESTING OFF)
set(ABSL_ENABLE_INSTALL ON)
FetchContent_MakeAvailable(absl)
# Protobuf
set(protobuf_version "v25.3")
FetchContent_Declare(
protobuf
GIT_REPOSITORY https://github.com/protocolbuffers/protobuf
GIT_TAG ${protobuf_version}
OVERRIDE_FIND_PACKAGE
)
set(protobuf_BUILD_TESTS OFF)
set(protobuf_INSTALL ON)
set(protobuf_ABSL_PROVIDER package)
FetchContent_MakeAvailable(protobuf)
# gRPC
set(grpc_version "v1.61.1")
FetchContent_Declare(
grpc
GIT_REPOSITORY https://github.com/grpc/grpc
GIT_TAG ${grpc_version}
OVERRIDE_FIND_PACKAGE
)
set(BUILD_SHARED_LIBS ON)
set(gRPC_BUILD_TESTS OFF)
set(gRPC_INSTALL ON)
set(gRPC_ABSL_PROVIDER package)
set(gRPC_CARES_PROVIDER package)
set(gRPC_PROTOBUF_PROVIDER package)
set(gRPC_RE2_PROVIDER package)
set(gRPC_SSL_PROVIDER package)
set(gRPC_ZLIB_PROVIDER package)
set(protobuf_BUILD_PROTOBUF_BINARIES OFF)
FetchContent_MakeAvailable(grpc)
add_library(gRPC::grpc++ ALIAS grpc++)
add_library(gRPC::grpc ALIAS grpc)
add_executable(gRPC::grpc_cpp_plugin ALIAS grpc_cpp_plugin)
# I must be doing something wrong...
# I thought these targets would get installed into gRPCTargets:
# https://github.com/grpc/grpc/blob/5174569c4d3352112848f1b86ba259425db939cf/CMakeLists.txt#L3591-L3598
# Maybe gRPC_INSTALL is OFF?
# https://github.com/grpc/grpc/blob/5174569c4d3352112848f1b86ba259425db939cf/CMakeLists.txt#L50-L56
install(TARGETS upb_json_lib upb_textformat_lib zlibstatic gpr ssl crypto address_sorting grpc++ grpc grpc_cpp_plugin EXPORT dbolduc-grpc-targets)
#install(TARGETS grpc++ grpc_cpp_plugin EXPORT dbolduc-grpc-targets)
# Cloud C++
find_package(Threads REQUIRED)
set(google_cloud_version "v2.21.0")
FetchContent_Declare(
google-cloud-sdk
URL https://github.com/googleapis/google-cloud-cpp/archive/${google_cloud_version}.tar.gz
)
set(BUILD_TESTING OFF)
set(GOOGLE_CLOUD_CPP_ENABLE_EXAMPLES OFF)
set(GOOGLE_CLOUD_CPP_ENABLE "pubsub")
FetchContent_MakeAvailable(google-cloud-sdk)
@anthonyalayo - I know you said your CMakeLists.txt was closed source, but do you have any pointers on what flags you are setting? or which targets you are defining/exporting? (in order to build google-cloud-cpp, absl, protobuf, grpc). It would help us create a FetchContent() build.
@dbolduc I should be able to get a reproduction, let me try and get back to you on it
We released this, closing.
@anthonyalayo - no worries on the repro