# ============================================================================
# Copyright 2017-2024, Schlumberger
#
# 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.
# ============================================================================

cmake_minimum_required(VERSION 3.3)
cmake_policy(SET CMP0057 NEW) # IN_LIST

# main project name
project(sdapi)

# cmake modules
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/modules)

if(WIN32)
    set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/modules/version_info_win32)

else()
    # cmake config packages.
    # adapt to third party container sdk?
    list(APPEND CMAKE_PREFIX_PATH /usr/local/share)
    list(APPEND CMAKE_PREFIX_PATH /usr/local/lib/cmake)
    list(APPEND CMAKE_PREFIX_PATH /usr/local/lib64/cmake)

    # when cmake attempts to use pkgconfig from dependencies
    # aka libxml2 may be troublesome on centos / static builds
    set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig:/usr/local/lib64/pkgconfig")

endif()

message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}")
message(STATUS "CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}")
message(STATUS "CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}")

# Build Types
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}
    CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel tsan asan lsan ubsan Coverage Veracode"
    FORCE)

# ThreadSanitizer
set(CMAKE_C_FLAGS_TSAN
    "-fsanitize=thread -g -O1"
    CACHE STRING "Flags used by the C compiler during ThreadSanitizer builds."
    FORCE)
set(CMAKE_CXX_FLAGS_TSAN
    "-fsanitize=thread -g -O1"
    CACHE STRING "Flags used by the C++ compiler during ThreadSanitizer builds."
    FORCE)

# AddressSanitize
set(CMAKE_C_FLAGS_ASAN
    "-fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer -g -O1"
    CACHE STRING "Flags used by the C compiler during AddressSanitizer builds."
    FORCE)
set(CMAKE_CXX_FLAGS_ASAN
    "-fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer -g -O1"
    CACHE STRING "Flags used by the C++ compiler during AddressSanitizer builds."
    FORCE)

# LeakSanitizer
set(CMAKE_C_FLAGS_LSAN
    "-fsanitize=leak -fno-omit-frame-pointer -g -O1"
    CACHE STRING "Flags used by the C compiler during LeakSanitizer builds."
    FORCE)
set(CMAKE_CXX_FLAGS_LSAN
    "-fsanitize=leak -fno-omit-frame-pointer -g -O1"
    CACHE STRING "Flags used by the C++ compiler during LeakSanitizer builds."
    FORCE)

# UndefinedBehavior
set(CMAKE_C_FLAGS_UBSAN
    "-fsanitize=undefined"
    CACHE STRING "Flags used by the C compiler during UndefinedBehaviourSanitizer builds."
    FORCE)
set(CMAKE_CXX_FLAGS_UBSAN
    "-fsanitize=undefined"
    CACHE STRING "Flags used by the C++ compiler during UndefinedBehaviourSanitizer builds."
    FORCE)

# set compilers flags
set(CMAKE_CXX_STANDARD 14 CACHE STRING "C++ standard to be used")
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

if(NOT WIN32)
    set(CMAKE_CXX_FLAGS "-pthread ${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Wno-deprecated-declarations -Werror")

    if(CMAKE_BUILD_TYPE STREQUAL "Coverage" OR CMAKE_BUILD_TYPE STREQUAL "Debug")
        set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -g3 -Og ")
    elseif(CMAKE_BUILD_TYPE STREQUAL "Veracode")
        set(CMAKE_CXX_FLAGS_VERACODE "${CMAKE_CXX_FLAGS} -gdwarf-2 -g3 -O0 -fno-builtin ")
    elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
        set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O3 ")
    endif()

    # enforce no undefined symbols in shared libraries produced by the linker
    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined")

    # enforce no undefined symbols in shared libraries consumed by the linker
    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-allow-shlib-undefined")

else()
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHa /W4")
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi /W4")
    set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")
endif()

# set compiler flags for coverage
if(NOT WIN32 AND CMAKE_BUILD_TYPE STREQUAL "Coverage")
    include(coverage)
    set(CMAKE_CXX_FLAGS "-fprofile-arcs -ftest-coverage ${CMAKE_CXX_FLAGS}")
    set(CMAKE_EXE_LINKER_FLAGS "--coverage ${CMAKE_EXE_LINKER_FLAGS}")
    setup_target_for_coverage(${PROJECT_NAME}_coverage ctest coverage)
endif()

option(AZURE_PROVIDER_ENABLED OFF)
option(AZURE_CURL_PROVIDER_ENABLED OFF)
option(AWS_PROVIDER_ENABLED OFF)
option(ANTHOS_PROVIDER_ENABLED OFF)
option(IBM_PROVIDER_ENABLED OFF)
option(GCS_PROVIDER_ENABLED OFF)

set(OPTIONAL_STORAGE_PROVIDERS_ENABLED "" CACHE STRING
    "semi-colon separated list of optional cloud storage providers sdk to enable. azure;gcs;aws for example.")

if("azure" IN_LIST OPTIONAL_STORAGE_PROVIDERS_ENABLED)
    set(AZURE_PROVIDER_ENABLED ON)
    add_definitions(-DHAS_AZURE_BLOB_STORAGE_PROVIDER)
else()
    message(STATUS "NOT BUILDING AZURE PROVIDER")
endif()

if("azure-curl" IN_LIST OPTIONAL_STORAGE_PROVIDERS_ENABLED)
    set(AZURE_CURL_PROVIDER_ENABLED ON)
    add_definitions(-DHAS_AZURE_BLOB_STORAGE_PROVIDER_CURL)
else()
    message(STATUS "NOT BUILDING AZURE PROVIDER CURL")
endif()

if("gcs" IN_LIST OPTIONAL_STORAGE_PROVIDERS_ENABLED)
    set(GCS_PROVIDER_ENABLED ON)
    add_definitions(-DHAS_GCS_STORAGE_PROVIDER)
else()
    message(STATUS "NOT BUILDING GCS PROVIDER")
endif()

if("aws" IN_LIST OPTIONAL_STORAGE_PROVIDERS_ENABLED)
    set(AWS_PROVIDER_ENABLED ON)
    add_definitions(-DHAS_AWS_S3_STORAGE_PROVIDER)
else()
    message(STATUS "NOT BUILDING AWS PROVIDER")
endif()

if("anthos" IN_LIST OPTIONAL_STORAGE_PROVIDERS_ENABLED)
    set(ANTHOS_PROVIDER_ENABLED ON)
    add_definitions(-DHAS_ANTHOS_STORAGE_PROVIDER)
else()
    message(STATUS "NOT BUILDING ANTHOS PROVIDER")
endif()

if("ibm" IN_LIST OPTIONAL_STORAGE_PROVIDERS_ENABLED)
    set(IBM_PROVIDER_ENABLED ON)
    add_definitions(-DHAS_IBM_STORAGE_PROVIDER)
else()
    message(STATUS "NOT BUILDING IBM PROVIDER")
endif()

message(STATUS "AZURE_PROVIDER_ENABLED=${AZURE_PROVIDER_ENABLED}")
message(STATUS "AZURE_CURL_PROVIDER_ENABLED=${AZURE_CURL_PROVIDER_ENABLED}")
message(STATUS "AWS_PROVIDER_ENABLED=${AWS_PROVIDER_ENABLED}")
message(STATUS "IBM_PROVIDER_ENABLED=${IBM_PROVIDER_ENABLED}")
message(STATUS "ANTHOS_PROVIDER_ENABLED=${ANTHOS_PROVIDER_ENABLED}")
message(STATUS "GCS_PROVIDER_ENABLED=${GCS_PROVIDER_ENABLED}")

option(ENABLE_STATIC "produce libsdapi_static.a" OFF)

if(ENABLE_STATIC)
    # Use crc32c from VCPKG when static library is needed
    # Eventually, unify to use only VCPKG
    find_package(Crc32c CONFIG REQUIRED)
    set(CRC32C_LIBRARY Crc32c::crc32c)
    set(CRC32C_FROM_VCPKG ON)
else()
    include(crc32c)
endif()

# includes
include_directories(${sdapi_SOURCE_DIR}/src/core)
include_directories(${sdapi_SOURCE_DIR}/src/lib)
include_directories(${sdapi_SOURCE_DIR}/src/lib/cloud)
include_directories(${sdapi_SOURCE_DIR}/src/lib/cloud/providers)
include_directories(${sdapi_SOURCE_DIR}/src/lib/cloud/providers/gcs-accessor)

# retrieve sources
file(GLOB SRC_CORE ${sdapi_SOURCE_DIR}/src/core/*.cc)
file(GLOB SRC_LIB_PROVIDERS ${sdapi_SOURCE_DIR}/src/lib/cloud/*.cc ${sdapi_SOURCE_DIR}/src/lib/cloud/providers/gcs-accessor/*.cc)

if(AZURE_PROVIDER_ENABLED)
    file(GLOB SRC_LIB_PROVIDERS_AZURE ${sdapi_SOURCE_DIR}/src/lib/cloud/providers/azure/cpprest/*.cc)
endif()
if(AZURE_CURL_PROVIDER_ENABLED)
    file(GLOB SRC_LIB_PROVIDERS_AZURE_NEW ${sdapi_SOURCE_DIR}/src/lib/cloud/providers/azure/curl/*.cc)
endif()
if(AWS_PROVIDER_ENABLED)
    file(GLOB SRC_LIB_PROVIDERS_AWS ${sdapi_SOURCE_DIR}/src/lib/cloud/providers/aws/*.cc)
endif()
if(IBM_PROVIDER_ENABLED)
    file(GLOB SRC_LIB_PROVIDERS_IBM ${sdapi_SOURCE_DIR}/src/lib/cloud/providers/ibm/*.cc)
    if(NOT AWS_PROVIDER_ENABLED)
        file(GLOB SRC_LIB_PROVIDERS_IBM_EXTRA ${sdapi_SOURCE_DIR}/src/lib/cloud/providers/aws/*.cc)
        list(APPEND SRC_LIB_PROVIDERS_IBM "${SRC_LIB_PROVIDERS_IBM_EXTRA}")
    endif()
endif()
if(ANTHOS_PROVIDER_ENABLED)
    file(GLOB SRC_LIB_PROVIDERS_ANTHOS ${sdapi_SOURCE_DIR}/src/lib/cloud/providers/anthos/*.cc)
    if(NOT AWS_PROVIDER_ENABLED)
        file(GLOB SRC_LIB_PROVIDERS_ANTHOS_EXTRA ${sdapi_SOURCE_DIR}/src/lib/cloud/providers/aws/*.cc)
        list(APPEND SRC_LIB_PROVIDERS_ANTHOS "${SRC_LIB_PROVIDERS_ANTHOS_EXTRA}")
    endif()
endif()
if(GCS_PROVIDER_ENABLED)
    file(GLOB SRC_LIB_PROVIDERS_GCS ${sdapi_SOURCE_DIR}/src/lib/cloud/providers/gcs/*.cc)
endif()

file(GLOB SRC_LIB_HTTP ${sdapi_SOURCE_DIR}/src/lib/http/*.cc)
file(GLOB SRC_LIB_JSON ${sdapi_SOURCE_DIR}/src/lib/json/*.cpp)
file(GLOB SRC_LIB_AUTH ${sdapi_SOURCE_DIR}/src/lib/auth/*.cc)
file(GLOB SRC_LIB_SHARED ${sdapi_SOURCE_DIR}/src/lib/shared/*.cc)

set(SOURCES ${SRC_CORE} ${SRC_LIB_PROVIDERS} ${SRC_LIB_HTTP} ${SRC_LIB_JSON} ${SRC_LIB_AUTH} ${SRC_LIB_SHARED})

if(AZURE_PROVIDER_ENABLED)
    file(GLOB SRC_AZS_SHARED ${sdapi_SOURCE_DIR}/src/lib/cloud/providers/azure/*.cc)
    set(SOURCES ${SOURCES} ${SRC_LIB_PROVIDERS_AZURE} ${SRC_AZS_SHARED})
endif()

if(AZURE_CURL_PROVIDER_ENABLED)
    file(GLOB SRC_AZS_SHARED ${sdapi_SOURCE_DIR}/src/lib/cloud/providers/azure/*.cc)
    set(SOURCES ${SOURCES} ${SRC_LIB_PROVIDERS_AZURE_NEW} ${SRC_AZS_SHARED})
endif()

if(ENABLE_STATIC)
    # Use curl from VCPKG when static library is needed
    # Eventually, unify to use only VCPKG
    find_package(CURL CONFIG REQUIRED)
    set(CURL_LIBRARY CURL::libcurl)
else()
    # import curl module
    if(NOT LIBCURL_VERSION)
        set(LIBCURL_VERSION "7.73.0")
    endif()
    include(curl)
endif()
# import openssl module for linux
if(NOT WIN32)
    find_package(OpenSSL REQUIRED)
    set(OPENSSL_LIBRARY ${OPENSSL_CRYPTO_LIBRARY})
    include_directories(SYSTEM ${OPENSSL_INCLUDE_DIR})
else()
    set(OPENSSL_LIBRARY "")
endif()

if(AZURE_CURL_PROVIDER_ENABLED)

    if(NOT WIN32)

        # cmake configs :
        # there may be issues with LibXml2 ... and libxml2 built in container

        find_library(XML2_LIBRARY xml2)
        find_library(LZMA_LIBRARY lzma)
        find_library(Z_LIBRARY z)

        find_package(libxml2 CONFIG REQUIRED)
        set(LIBXML2_LIBRARY ${XML2_LIBRARY} CACHE FILEPATH "path to libxml2 library")

        find_package(LibXml2 CONFIG REQUIRED)

        if(LibXml2_FOUND AND NOT TARGET LibXml2::LibXml2)
            message(STATUS "manually constructing LibXml2::LibXml2")

            add_library(LibXml2::LibXml2 UNKNOWN IMPORTED)
            set_target_properties(LibXml2::LibXml2 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LIBXML2_INCLUDE_DIRS}")
            set_target_properties(LibXml2::LibXml2 PROPERTIES INTERFACE_COMPILE_OPTIONS "${LIBXML2_DEFINITIONS}")
            set_property(TARGET LibXml2::LibXml2 APPEND PROPERTY IMPORTED_LOCATION "${LIBXML2_LIBRARY}")

            # the magic line that makes statically linked libxml2 with lzma and lz work is here...
            set_property(TARGET LibXml2::LibXml2 PROPERTY IMPORTED_LINK_INTERFACE_LIBRARIES "${LZMA_LIBRARY};${Z_LIBRARY}")

        else()
            # for libxml2 2.9.11+
            # work around bug in find_package(azure-storage-blobs-cpp CONFIG REQUIRED ) 5 lines down
            # by adding LIBXML2_INCLUDE_DIR to cache.
            set(LIBXML2_INCLUDE_DIR "${LIBXML2_INCLUDE_DIR}" CACHE INTERNAL "attempt to work around errors in find_package(azure-storage-blobs-cpp CONFIG REQURED)")
        endif()
    endif()

    find_package(azure-core-cpp CONFIG REQUIRED)
    find_package(azure-storage-common-cpp CONFIG REQUIRED)
    find_package(azure-storage-blobs-cpp CONFIG REQUIRED)

endif()

if(AZURE_PROVIDER_ENABLED)
    # import azure storage cpp module
    # for now that does not get bundled into the static library bundle because it's not a cmake package
    # and its dependencies are not declared.
    find_path(WASTORAGE_INCLUDE_DIR was/blob.h)
    include_directories(${WASTORAGE_INCLUDE_DIR})

    if(NOT WIN32)
        find_library(WASTORAGE_LIBRARY azurestorage)
        find_library(CPPREST_LIBRARY cpprest)
        find_library(BOOST_LOG_LIBRARY boost_log)
        find_library(BOOST_THREAD_LIBRARY boost_thread)
        find_library(SSL_LIBRARY ssl)
        find_library(XML2_LIBRARY xml2)
        find_library(LZMA_LIBRARY lzma)
        find_library(UUID_LIBRARY uuid)
        find_library(Z_LIBRARY z)
        find_library(CRYPTO_LIBRARY crypto)

        find_package(cpprestsdk REQUIRED)
        if(cpprestsdk_FOUND)
            message(STATUS "Found cpprestsdk as a CMake package")
        else()
            message(STATUS "Did not find cpprestsdk as a CMake package : library will be added manually without dependencies declared")
        endif()

    else()
        find_library(WASTORAGE_LIBRARY wastorage)
        if(CMAKE_BUILD_TYPE STREQUAL "Debug")
            find_library(CPPREST_LIBRARY NAMES cpprest cpprest_2_10d)
        else()
            find_library(CPPREST_LIBRARY NAMES cpprest cpprest_2_10)
        endif()
    endif()
endif()

if(AWS_PROVIDER_ENABLED)
    # Amazon S3 and security token service ( sts )?
    # as an example to try and build.
    find_package(AWSSDK REQUIRED COMPONENTS s3 transfer)
    if(AWSSDK_FOUND)
        set(SOURCES ${SOURCES} ${SRC_LIB_PROVIDERS_AWS})
    endif()
endif()

if(IBM_PROVIDER_ENABLED)
    find_package(AWSSDK REQUIRED COMPONENTS s3 transfer)
    if(AWSSDK_FOUND)
        set(SOURCES ${SOURCES} ${SRC_LIB_PROVIDERS_IBM})
    endif()
endif()

if(ANTHOS_PROVIDER_ENABLED)
    find_package(AWSSDK REQUIRED COMPONENTS s3 transfer)
    if(AWSSDK_FOUND)
        set(SOURCES ${SOURCES} ${SRC_LIB_PROVIDERS_ANTHOS})
    endif()
endif()

if(GCS_PROVIDER_ENABLED)
    # Google Cloud Storage C++ Client Library
    find_package(google_cloud_cpp_storage REQUIRED)
    set(SOURCES ${SOURCES} ${SRC_LIB_PROVIDERS_GCS})
endif()

# set major library versions
if(NOT DEFINED LIB_VERSION_MAJOR)
    set(LIB_VERSION_MAJOR 0)
endif()

# set minor library versions
if(NOT DEFINED LIB_VERSION_MINOR)
    set(LIB_VERSION_MINOR 0)
endif()

# set patch library versions
if(NOT DEFINED LIB_VERSION_PATCH)
    if(DEFINED LIBVERSION) # backward compatibility (old naming convention for patch)
        set(LIB_VERSION_PATCH ${LIBVERSION})
    elseif(DEFINED SDAPI_WIN_VERSION) # backward compatibility (old naming convention for patch)
        set(LIB_VERSION_PATCH ${SDAPI_WIN_VERSION})
    else()
        set(LIB_VERSION_PATCH 0)
    endif()
endif()

# set the versioninfo file for win32
if(WIN32)
    include(generate_product_version)
    generate_product_version(
        VersionFilesOutputVariable
        NAME "sdapi"
        VERSION_MAJOR ${LIB_VERSION_MAJOR}
        VERSION_MINOR ${LIB_VERSION_MINOR}
        VERSION_PATCH ${LIB_VERSION_PATCH}
        COMPANY_NAME "Schlumberger"
    )
endif()

# build shared library
add_library(sdapi SHARED ${SOURCES} ${VersionFilesOutputVariable})
target_include_directories(sdapi PRIVATE ${CMAKE_SOURCE_DIR})
if(NOT CRC32C_FROM_VCPKG)
    add_dependencies(sdapi crc32c)
endif()
if(NOT WIN32)
    target_link_libraries(sdapi PRIVATE
        ${CURL_LIBRARY}
        ${OPENSSL_LIBRARY}
        ${CRC32C_LIBRARY}
    )

    if(AZURE_CURL_PROVIDER_ENABLED)
        target_link_libraries(sdapi PRIVATE Azure::azure-storage-blobs LibXml2::LibXml2)
    endif(AZURE_CURL_PROVIDER_ENABLED)

    if(AZURE_PROVIDER_ENABLED)
        # stuff with no proper targets defined in CMake module or package?
        # we will have to reap all the libraries at some point though.
        target_link_libraries(sdapi PRIVATE
            ${WASTORAGE_LIBRARY}
            ${BOOST_LOG_LIBRARY}
            ${BOOST_THREAD_LIBRARY}
            ${SSL_LIBRARY}
            ${XML2_LIBRARY}
            ${LZMA_LIBRARY}
            ${UUID_LIBRARY}
            ${Z_LIBRARY}
            ${CRYPTO_LIBRARY}
        )

        if(cpprestsdk_FOUND)
            target_include_directories(sdapi PRIVATE cpprestsdk::cpprest)
            target_link_libraries(sdapi PRIVATE cpprestsdk::cpprest)
        else()
            target_link_libraries(sdapi PRIVATE ${CPPREST_LIBRARY})
        endif()
    endif(AZURE_PROVIDER_ENABLED)

    if(AWS_PROVIDER_ENABLED)
        target_include_directories(sdapi PRIVATE ${AWSSDK_INCLUDE_DIR})
        target_link_libraries(sdapi PRIVATE ${AWSSDK_LINK_LIBRARIES} ${AWSSDK_PLATFORM_DEPS})
    endif()

    if(IBM_PROVIDER_ENABLED)
        target_include_directories(sdapi PRIVATE ${AWSSDK_INCLUDE_DIR})
        target_link_libraries(sdapi PRIVATE ${AWSSDK_LINK_LIBRARIES} ${AWSSDK_PLATFORM_DEPS})
    endif()

    if(ANTHOS_PROVIDER_ENABLED)
        target_include_directories(sdapi PRIVATE ${AWSSDK_INCLUDE_DIR})
        target_link_libraries(sdapi PRIVATE ${AWSSDK_LINK_LIBRARIES} ${AWSSDK_PLATFORM_DEPS})
    endif()

    if(GCS_PROVIDER_ENABLED)
        target_link_libraries(sdapi PRIVATE google-cloud-cpp::storage)
    endif()

else() # WIN32 static lib

    target_link_libraries(sdapi PRIVATE
        ${CURL_LIBRARY}
        ${CRC32C_LIBRARY}
    )

    if(AZURE_CURL_PROVIDER_ENABLED)
        target_link_libraries(sdapi PRIVATE Azure::azure-storage-blobs)
    endif()

    if(AZURE_PROVIDER_ENABLED)
        target_link_libraries(sdapi PRIVATE
            ${WASTORAGE_LIBRARY}
            ${CPPREST_LIBRARY}
        )
    endif()

    if(AWS_PROVIDER_ENABLED)
        target_include_directories(sdapi PRIVATE ${AWSSDK_INCLUDE_DIR})
        target_link_libraries(sdapi PRIVATE ${AWSSDK_LINK_LIBRARIES} ${AWSSDK_PLATFORM_DEPS})
    endif()

    if(GCS_PROVIDER_ENABLED)
        target_include_directories(sdapi PRIVATE storage_client)
        target_link_libraries(sdapi PRIVATE google-cloud-cpp::storage)
    endif()

    if(IBM_PROVIDER_ENABLED)
        target_include_directories(sdapi PRIVATE ${AWSSDK_INCLUDE_DIR})
        target_link_libraries(sdapi PRIVATE ${AWSSDK_LINK_LIBRARIES} ${AWSSDK_PLATFORM_DEPS})
        message(STATUS "[IBM Test] - WIN32 flow:target_include_directories:target_link_libraries")
    endif()

    if(ANTHOS_PROVIDER_ENABLED)
        target_include_directories(sdapi PRIVATE ${AWSSDK_INCLUDE_DIR})
        target_link_libraries(sdapi PRIVATE ${AWSSDK_LINK_LIBRARIES} ${AWSSDK_PLATFORM_DEPS})
        message(STATUS "[ANTHOS Test] - WIN32 flow:target_include_directories:target_link_libraries")
    endif()

endif()

if(NOT WIN32)

    message(STATUS "setting SOVERSION to ${LIB_VERSION_MAJOR}")
    message(STATUS "setting VERSION to ${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH}")

    set_target_properties(sdapi PROPERTIES
        SOVERSION ${LIB_VERSION_MAJOR}
        VERSION ${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH}
        CXX_VISIBILITY_PRESET hidden
        OUTPUT_NAME "sdapi"
        POSITION_INDEPENDENT_CODE ON)

    # add legacy symlink for LIB_VERSION_MAJOR SOVERSION
    if(APPLE)
        set(LN_FLAGS "-sf")
    else()
        set(LN_FLAGS "-sfT")

        file(GLOB version_script src/Version.txt)
        set_target_properties(sdapi PROPERTIES LINK_FLAGS "-Wl,--version-script=${version_script}")

        # if the linker version script changes. I want to link again.
        set_target_properties(sdapi PROPERTIES LINK_DEPENDS ${version_script})

    endif()

    add_custom_command(TARGET sdapi
        POST_BUILD
        COMMAND ln ARGS ${LN_FLAGS} $<TARGET_FILE_NAME:sdapi> $<TARGET_LINKER_FILE:sdapi>.${LIB_VERSION_MAJOR}
    )

    set_target_properties(sdapi PROPERTIES
        EXTRA_LIBRARY_FILES "${CMAKE_BINARY_DIR}/libsdapi.so.${LIB_VERSION_MAJOR}"
    )

else()
    SET(S "sdapi")
    if(DEFINED LIB_VERSION_ON_NAME)
        SET(V "_${LIB_VERSION_MAJOR}")
    endif()
    if(CMAKE_BUILD_TYPE STREQUAL "Debug")
        SET(D "_d")
    endif()
    set_target_properties(sdapi PROPERTIES
        OUTPUT_NAME "${S}${V}${D}"
        POSITION_INDEPENDENT_CODE ON)
endif()

# build static library
add_library(sdapi_static STATIC ${SOURCES})
target_include_directories(sdapi_static PRIVATE ${CMAKE_SOURCE_DIR})
if(NOT CRC32C_FROM_VCPKG)
    add_dependencies(sdapi_static crc32c)
endif()
if(NOT WIN32)
    set_target_properties(sdapi_static PROPERTIES
        POSITION_INDEPENDENT_CODE ON)

    target_link_libraries(sdapi_static PRIVATE
        ${CURL_LIBRARY}
        ${OPENSSL_LIBRARY}
        ${CRC32C_LIBRARY}
    )

    if(AZURE_CURL_PROVIDER_ENABLED)
        target_link_libraries(sdapi_static PRIVATE Azure::azure-storage-blobs LibXml2::LibXml2)
    endif()

    if(AZURE_PROVIDER_ENABLED)
        target_link_libraries(sdapi_static PRIVATE
            ${WASTORAGE_LIBRARY}
            ${BOOST_LOG_LIBRARY}
            ${BOOST_THREAD_LIBRARY}
            ${SSL_LIBRARY}
            ${XML2_LIBRARY}
            ${LZMA_LIBRARY}
            ${UUID_LIBRARY}
            ${Z_LIBRARY}
            ${CRYPTO_LIBRARY}
            ${CMAKE_DL_LIBS}
        )
        find_package(cpprestsdk)
        if(cpprestsdk_FOUND)
            target_include_directories(sdapi_static PRIVATE cpprestsdk::cpprest)
            target_link_libraries(sdapi_static PRIVATE cpprestsdk::cpprest)
        else()
            target_link_libraries(sdapi_static PRIVATE ${CPPREST_LIBRARY})
        endif()
    endif()

    if(AWS_PROVIDER_ENABLED)
        target_include_directories(sdapi_static PRIVATE ${AWSSDK_INCLUDE_DIR})
        target_link_libraries(sdapi_static PRIVATE ${AWSSDK_LINK_LIBRARIES} ${AWSSDK_PLATFORM_DEPS})
    endif()

    if(IBM_PROVIDER_ENABLED)
        target_include_directories(sdapi_static PRIVATE ${AWSSDK_INCLUDE_DIR})
        target_link_libraries(sdapi_static PRIVATE ${AWSSDK_LINK_LIBRARIES} ${AWSSDK_PLATFORM_DEPS})
    endif()

    if(ANTHOS_PROVIDER_ENABLED)
        target_include_directories(sdapi_static PRIVATE ${AWSSDK_INCLUDE_DIR})
        target_link_libraries(sdapi_static PRIVATE ${AWSSDK_LINK_LIBRARIES} ${AWSSDK_PLATFORM_DEPS})
    endif()

    if(GCS_PROVIDER_ENABLED)
        target_link_libraries(sdapi_static PRIVATE google-cloud-cpp::storage)
    endif()

else() # WIN32 static lib
    target_link_libraries(sdapi_static PRIVATE
        ${CURL_LIBRARY}
        ${CRC32C_LIBRARY}
    )

    if(AZURE_CURL_PROVIDER_ENABLED)
        target_link_libraries(sdapi_static PRIVATE Azure::azure-storage-blobs)
    endif()

    if(AZURE_PROVIDER_ENABLED)
        target_link_libraries(sdapi_static PRIVATE
            ${WASTORAGE_LIBRARY}
            ${CPPREST_LIBRARY}
        )
    endif()

    if(GCS_PROVIDER_ENABLED)
        target_include_directories(sdapi_static PRIVATE storage_client)
        target_link_libraries(sdapi_static PRIVATE google-cloud-cpp::storage)
    endif()

    if(IBM_PROVIDER_ENABLED)
        target_include_directories(sdapi_static PRIVATE ${AWSSDK_INCLUDE_DIR})
        target_link_libraries(sdapi_static PRIVATE ${AWSSDK_LINK_LIBRARIES} ${AWSSDK_PLATFORM_DEPS})
        message(STATUS "[IBM Test] - WIN32 flow:target_include_directories:target_link_libraries")
    endif()

    if(ANTHOS_PROVIDER_ENABLED)
        target_include_directories(sdapi_static PRIVATE ${AWSSDK_INCLUDE_DIR})
        target_link_libraries(sdapi_static PRIVATE ${AWSSDK_LINK_LIBRARIES} ${AWSSDK_PLATFORM_DEPS})
        message(STATUS "[Anthos Test] - WIN32 flow:target_include_directories:target_link_libraries")
    endif()

    SET(S "sdapi")
    if(DEFINED LIB_VERSION_ON_NAME)
        SET(V "_${LIB_VERSION_MAJOR}")
    endif()
    if(CMAKE_BUILD_TYPE STREQUAL "Debug")
        SET(D "_d")
    endif()
    set_target_properties(sdapi PROPERTIES
        OUTPUT_NAME "${S}${V}${D}"
        POSITION_INDEPENDENT_CODE ON)
endif()

if(ENABLE_STATIC)
    include(bundle_static_library)
    bundle_static_library(sdapi_static sdapi_static_bundled)
    # eventually only distribute the bundled library.
endif(ENABLE_STATIC)

# import install module
include(install)
include(installJsonCpp)

# =========================================
# Build Examples
# =========================================
option(BUILD_EXAMPLES "Build examples" OFF)
if(BUILD_EXAMPLES)
    set(CMAKE_RUNTIME_OUTPUT_PARENT_DIRECTORY "/examples")
    add_subdirectory(examples)
endif()

# ===============================================================
# Build Seismic Store Functional Tests
# ===============================================================
option(BUILD_FTEST "Build the seismic store functional tests" OFF)
if(BUILD_FTEST)
    add_subdirectory(test/seismic-store)
    add_subdirectory(test/seismic-store-lib)
    add_subdirectory(test/gcloud-storage)
endif()

# ===============================================================
# Build e2e functional tests
# ===============================================================
option(BUILD_E2ETEST "Build the sdapi e2e tests" OFF)
if(BUILD_E2ETEST)
    add_subdirectory(test/e2e)
endif()

# ===============================================================
# Build performance tests
# ===============================================================
option(BUILD_PERFORMANCETEST "Build the sdapi performance tests" OFF)
if(BUILD_PERFORMANCETEST)
    add_subdirectory(test/performance)
endif()

# ===============================================================
# Build Seismic Store Unit Tests
# ===============================================================
option(BUILD_UTEST "Build the seismic store unit tests" OFF)
if(BUILD_UTEST)
    enable_testing()
    add_subdirectory(test/utest)
    include(CTest)
    add_subdirectory(src/lib/cloud/test)
    add_subdirectory(src/core/test)
endif()

# ===============================================================
# Build Seismic Store Benchmarks
# ===============================================================
option(BUILD_BENCHMARKS "Build the seismic store benchmarks" OFF)
if(BUILD_BENCHMARKS)
    add_subdirectory(benchmarks)

    add_custom_target(run_benchmarks
        COMMAND gcs_perf --benchmark_repetitions=5 --benchmark_out=results_gcs.json --benchmark_out_format=json
        COMMAND sd_perf --benchmark_repetitions=5 --benchmark_out=results_sd.json --benchmark_out_format=json
        WORKING_DIRECTORY benchmarks
        DEPENDS gcs_perf sd_perf
        COMMENT "Running Performance Benchmarks"
    )

endif()
