Skip to content
This repository has been archived by the owner on Dec 8, 2021. It is now read-only.

feat: Add build info #278

Merged
merged 19 commits into from
Aug 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions bazel/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@
licenses(["notice"]) # Apache v2

package(default_visibility = ["//:__subpackages__"])

exports_files([
"compiler_id.sh",
"compiler_version.sh",
])
48 changes: 48 additions & 0 deletions bazel/compiler_id.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash
#
# Copyright 2019 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
#
# http://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.
#
# Given an argument that is the path to a compiler, tries to determine an
# identification string for the compiler according to the CMake-defined IDs:
# https://cmake.org/cmake/help/v3.5/variable/CMAKE_LANG_COMPILER_ID.html

if [[ $# -ne 1 ]]; then
echo "Usage: $0 <path-to-compiler>"
exit 1
fi

version="$("${1}" --version 2> /dev/null \
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're going to support multiple compilers, the script will probably grow larger as we detect the executable and use the appropriate switch/flags. Just spitballing, but what do you think about adopting an approach similar to this? TL;DR, compile a program in Bazel that uses compiler-specific version macros then spits out the information.

| head -1 \
| tr '[:upper:]' '[:lower:]')"

case "${version}" in
*gcc* | *g++*)
echo "GNU"
;;

*clang*)
echo "Clang"
;;

*msvc* | *microsoft*)
# I don't think "--version" above will actually work on Windows, so we
# should figure out how to do that correctly. See #281.
echo "MSVC"
;;

*)
echo "unknown"
;;
esac
34 changes: 34 additions & 0 deletions bazel/compiler_version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/bin/bash
#
# Copyright 2019 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
#
# http://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.
#
# Given an argument that is the path to a compiler, tries to determine
# the compiler's version by looking for the first string that looks like
# X.Y with more optional numbers, '.', '-', and '+'.

if [[ $# -ne 1 ]]; then
echo "Usage: $0 <path-to-compiler>"
exit 1
fi

version="$("${1}" --version 2> /dev/null \
| grep -Eo "[0-9]+\.[0-9.+-]+" \
| head -1)"

if [[ -n "${version}" ]]; then
echo "${version}"
else
echo unknown
fi
6 changes: 1 addition & 5 deletions ci/kokoro/docker/build-in-docker-cmake.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,11 @@ if [[ "${GOOGLE_CLOUD_CPP_CXX_STANDARD:-}" != "" ]]; then
"-DGOOGLE_CLOUD_CPP_CXX_STANDARD=${GOOGLE_CLOUD_CPP_CXX_STANDARD}")
fi

if [[ "${CODE_COVERAGE:-}" == "yes" ]]; then
cmake_flags+=(
"-DCMAKE_BUILD_TYPE=Coverage")
fi

# We disable the shellcheck warning because we want ${CMAKE_FLAGS} to expand as
# separate arguments.
# shellcheck disable=SC2086
cmake "-DCMAKE_INSTALL_PREFIX=$HOME/staging" \
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
${CMAKE_FLAGS:-} \
"-H${SOURCE_DIR}" "-B${BINARY_DIR}" "${cmake_flags[@]}"
cmake --build "${BINARY_DIR}" -- -j "$(nproc)"
Expand Down
10 changes: 5 additions & 5 deletions ci/kokoro/docker/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ if [[ "${BUILD_NAME}" = "clang-tidy" ]]; then
export DISTRO_VERSION=30
export CC=clang
export CXX=clang++
export BUILD_TYPE=Debug
export CHECK_STYLE=yes
export GENERATE_DOCS=yes
export CLANG_TIDY=yes
Expand Down Expand Up @@ -118,7 +119,7 @@ elif [[ "${BUILD_NAME}" = "cxx17" ]]; then
export CXX=g++
in_docker_script="ci/kokoro/docker/build-in-docker-cmake.sh"
elif [[ "${BUILD_NAME}" = "coverage" ]]; then
export CODE_COVERAGE=yes
export BUILD_TYPE=Coverage
export RUN_INTEGRATION_TESTS=yes
export DISTRO=fedora-install
export DISTRO_VERSION=30
Expand Down Expand Up @@ -227,13 +228,12 @@ docker_flags=(
# installations.
"--env" "TEST_INSTALL=${TEST_INSTALL:-}"

# If set to 'yes', run compile with code coverage flags. Currently only the
# CMake builds use this flag.
"--env" "CODE_COVERAGE=${CODE_COVERAGE:-}"

# If set, pass -DGOOGLE_CLOUD_CPP_CXX_STANDARD=<value> to CMake.
"--env" "GOOGLE_CLOUD_CPP_CXX_STANDARD=${GOOGLE_CLOUD_CPP_CXX_STANDARD:-}"

# The type of the build for CMake
"--env" "BUILD_TYPE=${BUILD_TYPE:-Release}"

# Additional flags to enable CMake features.
"--env" "CMAKE_FLAGS=${CMAKE_FLAGS:-}"

Expand Down
2 changes: 1 addition & 1 deletion ci/kokoro/docker/upload-coverage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fi
source "${PROJECT_ROOT}/ci/kokoro/define-docker-variables.sh"
source "${PROJECT_ROOT}/ci/define-dump-log.sh"

if [[ "${CODE_COVERAGE:-}" != "yes" ]]; then
if [[ "${BUILD_NAME:-}" != "coverage" ]]; then
# Not a code coverage build, exit silently.
exit 0
fi
Expand Down
32 changes: 31 additions & 1 deletion google/cloud/spanner/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,42 @@ package(default_visibility = ["//visibility:public"])

licenses(["notice"]) # Apache 2.0

load(":spanner_client_version.bzl", "GOOGLE_CLOUD_CPP_SPANNER_IS_RELEASE")

genrule(
name = "generate_build_info",
srcs = ["internal/build_info.cc.in"],
outs = ["internal/build_info.cc"],
cmd = """
V="unknown";
CC_VERSION=$$($(location //bazel:compiler_version.sh) $(CC));
CC_ID=$$($(location //bazel:compiler_id.sh) $(CC));
sed -e "s;@CMAKE_CXX_COMPILER_ID@;$${CC_ID};" \
-e "s;@CMAKE_CXX_COMPILER_VERSION@;$${CC_VERSION};" \
-e "s;@CMAKE_CXX_FLAGS@;$(CC_FLAGS);" \
-e "s;\\$${CMAKE_CXX_FLAGS_.*};-c $(COMPILATION_MODE);" \
-e "s;@GOOGLE_CLOUD_CPP_SPANNER_IS_RELEASE@;%s;" \
-e "s;@GOOGLE_CLOUD_CPP_SPANNER_BUILD_METADATA@;$${V};" < $< > $@
""" % (GOOGLE_CLOUD_CPP_SPANNER_IS_RELEASE),
toolchains = [
"@bazel_tools//tools/cpp:current_cc_toolchain",
"@bazel_tools//tools/cpp:cc_flags",
],
tools = [
"//bazel:compiler_id.sh",
"//bazel:compiler_version.sh",
],
)

load(":spanner_client.bzl", "spanner_client_hdrs", "spanner_client_srcs")

cc_library(
name = "spanner_client",
srcs = spanner_client_srcs,
srcs = spanner_client_srcs + ["internal/build_info.cc"],
hdrs = spanner_client_hdrs,
data = [
":generate_build_info",
],
deps = [
"@com_github_googleapis_google_cloud_cpp//google/cloud:google_cloud_cpp_common",
"@com_github_googleapis_google_cloud_cpp//google/cloud/grpc_utils:google_cloud_cpp_grpc_utils",
Expand Down
63 changes: 63 additions & 0 deletions google/cloud/spanner/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,66 @@ set(DOXYGEN_PROJECT_NUMBER "${SPANNER_VERSION}")
set(DOXYGEN_EXAMPLE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/samples)
include(EnableDoxygen)

# Define a function to fetch the current git revision. Using a function creates
# a new scope, so the CMake variables do not leak to the global namespace.
function (google_cloud_cpp_spanner_initialize_git_head var)
set(result "unknown")
# If we cannot find a `.git` directory do not even try to guess the git
# revision.
if (IS_DIRECTORY ${PROJECT_SOURCE_DIR}/.git)
# We need `git` to find the revision.
find_program(GOOGLE_CLOUD_CPP_SPANNER_GIT_PROGRAM NAMES git)
mark_as_advanced(GOOGLE_CLOUD_CPP_SPANNER_GIT_PROGRAM)
if (GOOGLE_CLOUD_CPP_SPANNER_GIT_PROGRAM)
# Run `git rev-parse --short HEAD` and capture the output in a
# variable.
execute_process(COMMAND "${GOOGLE_CLOUD_CPP_SPANNER_GIT_PROGRAM}"
rev-parse --short HEAD
OUTPUT_VARIABLE GIT_HEAD_LOG
ERROR_VARIABLE GIT_HEAD_LOG)
string(REPLACE "\n"
""
result
"${GIT_HEAD_LOG}")
endif ()
endif ()
set(${var} "${result}" PARENT_SCOPE)
endfunction ()

# Capture the compiler version and the git revision into variables, then
# generate a config file with the values.
if (NOT "${GOOGLE_CLOUD_CPP_SPANNER_BUILD_METADATA}" STREQUAL "")
# The build metadata flag is already defined, do not re-compute the
# initialization value. This works both when the user supplies
# -DGOOGLE_CLOUD_CPP_SPANNER_METADATA=value in the command line, and when
# GOOGLE_CLOUD_CPP_SPANNER_METADATA has a cached value
set(GOOGLE_CLOUD_CPP_SPANNER_GIT_HEAD "unused")
else ()
google_cloud_cpp_spanner_initialize_git_head(
GOOGLE_CLOUD_CPP_SPANNER_GIT_HEAD)
endif ()

# Define a CMake configuration option to set the build metadata. By default this
# is initialized from `git rev-parse --short HEAD`, but the developer (or the
# script building via CMake) can override the value.
set(GOOGLE_CLOUD_CPP_SPANNER_BUILD_METADATA
"${GOOGLE_CLOUD_CPP_SPANNER_GIT_HEAD}"
CACHE STRING "Append build metadata to the library version number")
# This option is rarely needed. Mark it as "advanced" to remove it from the
# default CMake UIs.
mark_as_advanced(GOOGLE_CLOUD_CPP_SPANNER_BUILD_METADATA)

message(STATUS "google-cloud-cpp-spanner build metadata set to"
" ${GOOGLE_CLOUD_CPP_SPANNER_BUILD_METADATA}")

# Create the file that captures build information. Having access to the compiler
# and build flags at runtime allows us to print better benchmark results.
string(TOUPPER "${CMAKE_BUILD_TYPE}" GOOGLE_CLOUD_CPP_SPANNER_BUILD_TYPE_UPPER)
configure_file(internal/build_info.cc.in internal/build_info.cc)

configure_file(version_info.h.in ${CMAKE_CURRENT_SOURCE_DIR}/version_info.h)
add_library(spanner_client
${CMAKE_CURRENT_BINARY_DIR}/internal/build_info.cc
backoff_policy.h
client.cc
client.h
Expand All @@ -38,6 +96,7 @@ add_library(spanner_client
date.h
internal/base64.cc
internal/base64.h
internal/build_info.h
internal/database_admin_retry.cc
internal/database_admin_retry.h
internal/database_admin_stub.cc
Expand Down Expand Up @@ -102,6 +161,9 @@ add_library(googleapis-c++::spanner_client ALIAS spanner_client)
include(CreateBazelConfig)
create_bazel_config(spanner_client)

export_variables_to_bazel("spanner_client_version.bzl"
GOOGLE_CLOUD_CPP_SPANNER_IS_RELEASE)

# Define the tests in a function so we have a new scope for variable names.
function (spanner_client_define_tests)
# The tests require googletest to be installed. Force CMake to use the
Expand Down Expand Up @@ -133,6 +195,7 @@ function (spanner_client_define_tests)
database_admin_client_test.cc
date_test.cc
internal/base64_test.cc
internal/build_info_test.cc
internal/date_test.cc
internal/merge_chunk_test.cc
internal/polling_loop_test.cc
Expand Down
94 changes: 94 additions & 0 deletions google/cloud/spanner/internal/build_info.cc.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright 2017 Google Inc.
//
// 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
//
// http://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/spanner/internal/build_info.h"
#include "google/cloud/internal/port_platform.h"
#include <algorithm>
#include <cctype>
#include <iterator>

namespace google {
namespace cloud {
namespace spanner {
inline namespace SPANNER_CLIENT_NS {
namespace internal {

std::string CompilerId() { return R"""(@CMAKE_CXX_COMPILER_ID@)"""; }

std::string CompilerVersion() { return R"""(@CMAKE_CXX_COMPILER_VERSION@)"""; }

std::string BuildFlags() {
static auto const* const kFlags = [] {
auto* flags = new std::string(R"""(@CMAKE_CXX_FLAGS@)""");
if (!flags->empty()) *flags += ' ';
*flags +=
R"""(${CMAKE_CXX_FLAGS_${GOOGLE_CLOUD_CPP_SPANNER_BUILD_TYPE_UPPER}})""";
return flags;
}();
return *kFlags;
}

std::string CompilerFeatures() {
#if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS
return "ex";
#else
return "noex";
#endif // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS
}

std::string LanguageVersion() {
static auto const* const kLanguageVersion = [] {
auto* s = new std::string;
switch (__cplusplus) {
case 199711L:
*s += "98";
break;
case 201103L:
*s += "2011";
break;
case 201402L:
*s += "2014";
break;
case 201703L:
*s += "2017";
break;
default:
*s += "unknown";
}
return s;
}();
return *kLanguageVersion;
}

bool IsRelease() {
static bool const kIsRelease = []() -> bool {
// NOLINTNEXTLINE(readability-redundant-string-init)
std::string value = R"""(@GOOGLE_CLOUD_CPP_SPANNER_IS_RELEASE@)""";
for (char& c : value) {
c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
}
return value == "yes" || value == "1" || value == "true";
}();
return kIsRelease;
}

std::string BuildMetadata() {
return R"""(@GOOGLE_CLOUD_CPP_SPANNER_BUILD_METADATA@)""";
}

} // namespace internal
} // namespace GOOGLE_CLOUD_CPP_NS
} // namespace spanner
} // namespace cloud
} // namespace google
Loading