Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gmock and gtest targets are required even with BUILD_TESTING OFF #13621

Closed
anthonyalayo opened this issue Feb 16, 2024 · 9 comments
Closed

gmock and gtest targets are required even with BUILD_TESTING OFF #13621

anthonyalayo opened this issue Feb 16, 2024 · 9 comments
Assignees
Labels
priority: p2 Moderately-important priority. Fix may not be included in next release. type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns.

Comments

@anthonyalayo
Copy link

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

@anthonyalayo anthonyalayo added priority: p2 Moderately-important priority. Fix may not be included in next release. type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns. labels Feb 16, 2024
@dbolduc
Copy link
Member

dbolduc commented Feb 16, 2024

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

@anthonyalayo
Copy link
Author

@dbolduc giving it a shot, let me see

@anthonyalayo
Copy link
Author

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.

@anthonyalayo
Copy link
Author

anthonyalayo commented Feb 17, 2024

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.

@dbolduc
Copy link
Member

dbolduc commented Feb 27, 2024

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.

@anthonyalayo
Copy link
Author

Agreed, and sounds fair to me. Thanks!

@dbolduc
Copy link
Member

dbolduc commented Feb 29, 2024

@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 😅. 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.

@anthonyalayo
Copy link
Author

@dbolduc I should be able to get a reproduction, let me try and get back to you on it

@dbolduc
Copy link
Member

dbolduc commented Mar 6, 2024

We released this, closing.

@anthonyalayo - no worries on the repro

@dbolduc dbolduc closed this as completed Mar 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority: p2 Moderately-important priority. Fix may not be included in next release. type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns.
Projects
None yet
Development

No branches or pull requests

2 participants