# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you 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.

PROTOBUF_GENERATE_CPP(
  CLIENT_PROTO_SRCS CLIENT_PROTO_HDRS CLIENT_PROTO_TGTS
  SOURCE_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..
  BINARY_ROOT ${CMAKE_CURRENT_BINARY_DIR}/../..
  PROTO_FILES client.proto)
set(CLIENT_PROTO_LIBS
  consensus_metadata_proto
  kudu_common_proto
  token_proto)
ADD_EXPORTABLE_LIBRARY(client_proto
  SRCS ${CLIENT_PROTO_SRCS}
  DEPS ${CLIENT_PROTO_LIBS}
  NONLINK_DEPS ${CLIENT_PROTO_TGTS})

set(CLIENT_SRCS
  authz_token_cache.cc
  batcher.cc
  client.cc
  client_builder-internal.cc
  client-internal.cc
  columnar_scan_batch.cc
  error_collector.cc
  error-internal.cc
  hash.cc
  master_rpc.cc
  master_proxy_rpc.cc
  meta_cache.cc
  partitioner-internal.cc
  scan_batch.cc
  scan_configuration.cc
  scan_predicate.cc
  scan_token-internal.cc
  scanner-internal.cc
  replica-internal.cc
  replica_controller-internal.cc
  tablet_info_provider-internal.cc
  resource_metrics.cc
  schema.cc
  session-internal.cc
  table-internal.cc
  table_alterer-internal.cc
  table_creator-internal.cc
  tablet-internal.cc
  tablet_server-internal.cc
  transaction-internal.cc
  txn_manager_proxy_rpc.cc
  value.cc
  write_op.cc
)

set(CLIENT_LIBS
  client_proto
  gutil
  krpc
  kudu_common
  kudu_util
  master_proto
  tserver_proto
  tserver_service_proto
  txn_manager_proto)

# Make sure we exclude tcmalloc from the exported library; we want the library
# code to use the linking application's malloc implementation.
set(EXPORTED_CLIENT_LIBS
  ${CLIENT_LIBS}
  ${KUDU_BASE_LIBS})
list(REMOVE_ITEM EXPORTED_CLIENT_LIBS tcmalloc profiler)

# We customize the output name/directory of the exported library so that we can
# call it "kudu_client" without it colliding with the regular library.
#
# Unfortunately, this doesn't extend to the autogenerated cmake files that ship
# with the exported library; they still hew to the original target name of
# "kudu_client_exported".
ADD_EXPORTABLE_LIBRARY(kudu_client
  SRCS ${CLIENT_SRCS}
  DEPS ${CLIENT_LIBS}
  EXPORTED_SHARED
  EXPORTED_OUTPUT_NAME kudu_client
  EXPORTED_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/exported"
  EXPORTED_DEPS ${EXPORTED_CLIENT_LIBS})

################################################################################
# LIBRARY VERSIONS
################################################################################
#
# The external version of the exported Kudu client library. It is a separate
# entity from the main Kudu version so that the library and backends can evolve
# independently.
#
# Library versions affect packaging and control how the runtime linker finds the
# actual library file. The library's SOVERSION (i.e. major version) is typically
# appended to its package name and to the library filename, which means:
#
# 1. Multiple packages of the different major versions may be installed.
# 2. An application must link against a specific major version of the library.
#
# The minor and patch versions are purely informational; changes to them have no
# effect on runtime linking or on packages.
#
# The major version should only be incremented when an incompatible change is
# made to the library's ABI (i.e. interface to the application). It is not to be
# taken lightly because it has far reaching effects. Besides forcing an
# application to recompile (or worse, rewrite some code), it also affects
# packages. For example, package names typically change after a major version
# bump (e.g. libkuduclient0 becomes libkuduclient1).
#
# The minor and patch versions can be incremented freely, and should be
# incremented when significant (but not incompatible) or insignificant changes
# are made respectively.
#
# For a detailed explanation of the kinds of C++ changes that would break ABI
# compatibility, see:
#
#   https://community.kde.org/Policies/Binary_Compatibility_Issues_With_C++
#
# For more background on library versions, see:
#
#   https://autotools.io/libtool/version.html
set(CLIENT_VERSION_MAJOR 0)
set(CLIENT_VERSION_MINOR 1)
set(CLIENT_VERSION_PATCH 0)

if(NOT APPLE)
  # Localize thirdparty symbols using a linker version script. This hides them
  # from the client application. Also, completely remove libprotobuf symbols
  # (see KUDU-3334 for details). The --version-script and --exclude-libs
  # GNU ld linker's options are not supported by the OS X linker.
  set(LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/symbols.map")
  set(LINK_FLAGS "${LINK_FLAGS} -Wl,--exclude-libs=libprotobuf")
endif()

set_target_properties(kudu_client_exported
  PROPERTIES
  LINK_FLAGS "${LINK_FLAGS}"
  # This version is appended to the filename.
  #
  # For example: libkudu_client.so.1.2.3
  VERSION "${CLIENT_VERSION_MAJOR}.${CLIENT_VERSION_MINOR}.${CLIENT_VERSION_PATCH}"
  # This version is used to create two library symlinks.
  #
  # For example: libkudu_client.so -> libkudu_client.so.1
  #              libkudu_client.so.1 -> libkudu_client.so.1.2.3
  #
  # The runtime linker is expected to look up a library by name and SOVERSION.
  # In the previous example, that means it'll look up a file with name
  # libkudu_client.so.1. If the library is installed, that file should be a
  # symlink to the actual library file libkudu_client.so.1.2.3.
  SOVERSION "${CLIENT_VERSION_MAJOR}")

# Generate kudu_export.h.
generate_export_header(kudu_client_exported
  BASE_NAME kudu
  EXPORT_FILE_NAME ${CMAKE_BINARY_DIR}/src/kudu/util/kudu_export.h)

# "make install" invocations to generate a directory tree containing the
# exported client library and all of its headers.

# For CMAKE_INSTALL_<dir> variables.
include(GNUInstallDirs)

# Shared library.
install(TARGETS kudu_client_exported
  EXPORT kudu_client_export_set
  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})

# Headers: client
install(FILES
  callbacks.h
  client.h
  columnar_scan_batch.h
  hash.h
  resource_metrics.h
  row_result.h
  scan_batch.h
  scan_predicate.h
  schema.h
  shared_ptr.h
  stubs.h
  value.h
  write_op.h
  DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/kudu/client)

# Headers: common
install(FILES
  ../common/partial_row.h
  DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/kudu/common)

# Headers: util
install(FILES
  ${CMAKE_CURRENT_BINARY_DIR}/../util/kudu_export.h
  ../util/int128.h
  ../util/monotime.h
  ../util/slice.h
  ../util/status.h
  DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/kudu/util)

# Client example code.
#
# Can't use CMAKE_INSTALL_DOCDIR because we don't ever call project().
install(FILES
  ../../../examples/cpp/CMakeLists.txt
  ../../../examples/cpp/example.cc
  ../../../examples/cpp/non_unique_primary_key.cc
  DESTINATION ${CMAKE_INSTALL_DATADIR}/doc/kuduClient/examples)

# Exported cmake file for just the library's targets.
#
# Should not be included directly by users.
install(EXPORT kudu_client_export_set
  FILE kuduClientTargets.cmake
  DESTINATION ${CMAKE_INSTALL_DATADIR}/kuduClient/cmake)

# Exported cmake file for the library.
#
# This is the main cmake entry point and should be included directly.
include(CMakePackageConfigHelpers)
configure_package_config_file(clientConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/clientConfig.cmake
  INSTALL_DESTINATION ${CMAKE_INSTALL_DATADIR}/kuduClient/cmake
  PATH_VARS CMAKE_INSTALL_INCLUDEDIR)
install(FILES
  ${CMAKE_CURRENT_BINARY_DIR}/clientConfig.cmake
  DESTINATION ${CMAKE_INSTALL_DATADIR}/kuduClient/cmake
  RENAME kuduClientConfig.cmake)

# There's no way to rename a logical cmake exported target, so we use this
# script to forcefully change the kudu_client_exported target to kudu_client.
install(SCRIPT MungeExportedInstallTargets.cmake)

#######################################
# Test utility library
#######################################
if(NOT NO_TESTS)
  # This code is useful for other tests which use the client, but isn't
  # part of the client itself (ie we don't want to ship it to customers,
  # and therefore don't need to worry about export strictness)
  add_library(kudu_client_test_util
    client-test-util.cc)
  target_link_libraries(kudu_client_test_util
    gmock
    gtest
    kudu_client)
endif()

#######################################
# Unit tests
#######################################

# The OS X system compiler does not support source symbol maps, so the client
# leaks internal symbols globally.
#
# Coverage builds insert gcov-related symbols into the client library. We
# don't ship such builds, so there's no point in checking symbol visibility.
if (NOT APPLE AND NOT "${KUDU_GENERATE_COVERAGE}")
  ADD_KUDU_TEST(client_symbol-test.sh LABELS no_dist_test)
endif()

# The examples are never built with ASAN/TSAN.
if(NOT "${KUDU_USE_ASAN}" AND NOT "${KUDU_USE_TSAN}")
  ADD_KUDU_TEST(client_examples-test.sh RUN_SERIAL true LABELS no_dist_test)
endif()

SET_KUDU_TEST_LINK_LIBS(
  itest_util
  kudu_client
  mini_cluster)
if(NOT NO_ROCKSDB)
  ADD_KUDU_TEST_LINK_LIBS(
    rocksdb)
endif()
ADD_KUDU_TEST(client-test NUM_SHARDS 8 PROCESSORS 2
                          DATA_FILES ../scripts/first_argument.sh)
ADD_KUDU_TEST(client-unittest)
ADD_KUDU_TEST(flex_partitioning_client-test)
ADD_KUDU_TEST(predicate-test NUM_SHARDS 4)
ADD_KUDU_TEST(scan_token-test PROCESSORS 2)
