diff --git a/.github/workflows/build-ios-mac.yml b/.github/workflows/build-ios-mac.yml index 7ca85012b..864326da8 100644 --- a/.github/workflows/build-ios-mac.yml +++ b/.github/workflows/build-ios-mac.yml @@ -55,9 +55,8 @@ jobs: run: | sudo chown -R $USER:staff /usr/local - uses: actions/checkout@v4 - with: - submodules: 'true' - continue-on-error: true + - name: Initialize googletest + run: git submodule update --init --depth=1 third_party/googletest - name: build run: | if [[ "${{ matrix.os }}" == "macos-14" ]]; then diff --git a/.github/workflows/build-posix-latest.yml b/.github/workflows/build-posix-latest.yml index 8f9320e57..797b605aa 100644 --- a/.github/workflows/build-posix-latest.yml +++ b/.github/workflows/build-posix-latest.yml @@ -44,7 +44,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - continue-on-error: true + - name: Initialize googletest + run: git submodule update --init --depth=1 third_party/googletest - name: Test ${{ matrix.os }} ${{ matrix.config }} run: ./build-tests.sh ${{ matrix.config }} diff --git a/.github/workflows/build-ubuntu-2204.yml b/.github/workflows/build-ubuntu-2204.yml index 1fbcc6404..55ba518ca 100644 --- a/.github/workflows/build-ubuntu-2204.yml +++ b/.github/workflows/build-ubuntu-2204.yml @@ -44,6 +44,7 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - continue-on-error: true + - name: Initialize googletest + run: git submodule update --init --depth=1 third_party/googletest - name: Test ${{ matrix.os }} ${{ matrix.config }} run: ./build-tests.sh ${{ matrix.config }} \ No newline at end of file diff --git a/.github/workflows/test-embedding.yml b/.github/workflows/test-embedding.yml new file mode 100644 index 000000000..0565a1c86 --- /dev/null +++ b/.github/workflows/test-embedding.yml @@ -0,0 +1,233 @@ +name: Source embedding matrix + +on: + push: + branches: + - main + - master + - dev + pull_request: + branches: + - main + - master + - dev + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + linux: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - dependencies: system + library-type: STATIC + shared: OFF + fetchcontent: OFF + preload-curl: ON + preload-storage: ON + - dependencies: system + library-type: SHARED + shared: ON + fetchcontent: ON + preload-curl: OFF + preload-storage: OFF + - dependencies: self-contained + library-type: STATIC + shared: OFF + fetchcontent: ON + preload-curl: OFF + preload-storage: OFF + steps: + - uses: actions/checkout@v4 + - name: Install system dependencies + if: matrix.dependencies == 'system' + run: sudo apt-get update && sudo apt-get install -y libcurl4-openssl-dev libsqlite3-dev ninja-build zlib1g-dev + - name: Configure + shell: bash + run: | + options=( + -G Ninja + -S tests/embedding + -B build-embedding + -DCMAKE_BUILD_TYPE=Release + -DMATSDK_EMBEDDING_USE_FETCHCONTENT=${{ matrix.fetchcontent }} + -DMATSDK_EMBEDDING_PRELOAD_CURL=${{ matrix.preload-curl }} + -DMATSDK_EMBEDDING_PRELOAD_STORAGE_DEPS=${{ matrix.preload-storage }} + -DBUILD_SHARED_LIBS=${{ matrix.shared }} + ) + if [[ "${{ matrix.dependencies }}" == "self-contained" ]]; then + options+=( + -DMATSDK_CURL_PROVIDER=FETCH + -DMATSDK_CURL_TLS_BACKEND=MBEDTLS + -DMATSDK_SQLITE_PROVIDER=MINIMAL + -DMATSDK_ZLIB_PROVIDER=VENDORED + ) + else + options+=( + -DMATSDK_SQLITE_PROVIDER=SYSTEM + -DMATSDK_ZLIB_PROVIDER=SYSTEM + ) + fi + cmake "${options[@]}" + - name: Build and run + run: | + cmake --build build-embedding --target embedding_test --parallel 4 + ./build-embedding/embedding_test + + windows: + runs-on: windows-2022 + steps: + - uses: actions/checkout@v4 + - name: Configure + run: > + cmake -S tests/embedding -B build-embedding -A x64 + -DMATSDK_EMBEDDING_USE_FETCHCONTENT=ON + -DMATSDK_SQLITE_PROVIDER=VENDORED + -DMATSDK_ZLIB_PROVIDER=VENDORED + - name: Build and run + shell: pwsh + run: | + cmake --build build-embedding --config Release --target embedding_test -- /m + & .\build-embedding\Release\embedding_test.exe + + installed-package-linux: + runs-on: ubuntu-latest + strategy: + matrix: + mode: [system, fetched] + steps: + - uses: actions/checkout@v4 + - name: Install system dependencies + if: matrix.mode == 'system' + run: sudo apt-get update && sudo apt-get install -y libcurl4-openssl-dev libsqlite3-dev zlib1g-dev + - name: Configure, install, and consume + shell: bash + run: | + options=( + -G Ninja + -S . + -B build-package + -DCMAKE_BUILD_TYPE=Release + -DBUILD_SHARED_LIBS=OFF + -DMATSDK_BUILD_UNIT_TESTS=OFF + -DMATSDK_BUILD_FUNC_TESTS=OFF + -DMATSDK_BUILD_PACKAGE=OFF + -DMATSDK_BUILD_OBJC_WRAPPER=OFF + -DMATSDK_BUILD_SWIFT_WRAPPER=OFF + -DCMAKE_INSTALL_PREFIX="${RUNNER_TEMP}/matsdk" + ) + if [[ "${{ matrix.mode }}" == "fetched" ]]; then + options+=( + -DMATSDK_CURL_PROVIDER=FETCH + -DMATSDK_CURL_TLS_BACKEND=MBEDTLS + -DMATSDK_SQLITE_PROVIDER=MINIMAL + -DMATSDK_ZLIB_PROVIDER=VENDORED + ) + else + options+=( + -DMATSDK_SQLITE_PROVIDER=SYSTEM + -DMATSDK_ZLIB_PROVIDER=SYSTEM + ) + fi + cmake "${options[@]}" + cmake --build build-package --target mat --parallel 4 + cmake --install build-package + cmake -G Ninja -S tests/vcpkg -B build-consumer \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH="${RUNNER_TEMP}/matsdk" + cmake --build build-consumer --parallel 4 + ./build-consumer/vcpkg_test + + installed-package-macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - name: Configure, install, and consume + run: | + cmake -G Ninja -S . -B build-package \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=OFF \ + -DMATSDK_BUILD_UNIT_TESTS=OFF \ + -DMATSDK_BUILD_FUNC_TESTS=OFF \ + -DMATSDK_BUILD_PACKAGE=OFF \ + -DMATSDK_BUILD_OBJC_WRAPPER=OFF \ + -DMATSDK_BUILD_SWIFT_WRAPPER=OFF \ + -DMATSDK_SQLITE_PROVIDER=SYSTEM \ + -DMATSDK_ZLIB_PROVIDER=SYSTEM \ + -DCMAKE_INSTALL_PREFIX="${RUNNER_TEMP}/matsdk" + cmake --build build-package --target mat --parallel 4 + cmake --install build-package + cmake -G Ninja -S tests/vcpkg -B build-consumer \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH="${RUNNER_TEMP}/matsdk" + cmake --build build-consumer --parallel 4 + ./build-consumer/vcpkg_test + + macos: + runs-on: macos-latest + strategy: + matrix: + architectures: [arm64, "arm64;x86_64"] + steps: + - uses: actions/checkout@v4 + - name: Configure + run: > + cmake -G Ninja -S tests/embedding -B build-embedding + -DCMAKE_BUILD_TYPE=Release + "-DCMAKE_OSX_ARCHITECTURES=${{ matrix.architectures }}" + -DMATSDK_EMBEDDING_USE_FETCHCONTENT=ON + -DMATSDK_SQLITE_PROVIDER=SYSTEM + -DMATSDK_ZLIB_PROVIDER=SYSTEM + - name: Build + run: cmake --build build-embedding --target embedding_test --parallel 4 + + ios: + runs-on: macos-latest + strategy: + matrix: + include: + - sdk: iphoneos + sqlite-provider: SYSTEM + zlib-provider: SYSTEM + - sdk: iphonesimulator + sqlite-provider: VENDORED + zlib-provider: VENDORED + steps: + - uses: actions/checkout@v4 + - name: Configure + run: > + cmake -G Xcode -S tests/embedding -B build-embedding + -DCMAKE_SYSTEM_NAME=iOS + -DCMAKE_OSX_SYSROOT=${{ matrix.sdk }} + -DCMAKE_OSX_ARCHITECTURES=arm64 + -DCMAKE_OSX_DEPLOYMENT_TARGET=13.0 + -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=NO + -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=NO + -DMATSDK_EMBEDDING_USE_FETCHCONTENT=ON + -DMATSDK_SQLITE_PROVIDER=${{ matrix.sqlite-provider }} + -DMATSDK_ZLIB_PROVIDER=${{ matrix.zlib-provider }} + - name: Build + run: cmake --build build-embedding --config Release --target embedding_test --parallel 4 + + android: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Configure + run: > + cmake -G Ninja -S tests/embedding -B build-embedding + -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_LATEST_HOME}/build/cmake/android.toolchain.cmake + -DANDROID_ABI=arm64-v8a + -DANDROID_PLATFORM=23 + -DCMAKE_BUILD_TYPE=Release + -DMATSDK_EMBEDDING_USE_FETCHCONTENT=ON + -DMATSDK_SQLITE_PROVIDER=VENDORED + -DMATSDK_ZLIB_PROVIDER=VENDORED + - name: Build + run: cmake --build build-embedding --target embedding_test --parallel 4 diff --git a/CMakeLists.txt b/CMakeLists.txt index cc36e9da3..a95e56fb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,25 +1,57 @@ cmake_minimum_required(VERSION 3.15...3.31) + +# Backward-compatible translation for legacy Apple build scripts. Standard +# CMAKE_OSX_* variables are the canonical interface and must be initialized +# before project() so CMake's compiler/platform detection sees them. +if(NOT DEFINED CMAKE_OSX_ARCHITECTURES) + if(DEFINED IOS_ARCH AND NOT IOS_ARCH STREQUAL "") + set(CMAKE_OSX_ARCHITECTURES "${IOS_ARCH}" CACHE STRING + "Apple target architectures" FORCE) + elseif(DEFINED MAC_ARCH AND NOT MAC_ARCH STREQUAL "") + if(MAC_ARCH STREQUAL "universal") + set(_matsdk_legacy_apple_architectures "arm64;x86_64") + else() + set(_matsdk_legacy_apple_architectures "${MAC_ARCH}") + endif() + set(CMAKE_OSX_ARCHITECTURES "${_matsdk_legacy_apple_architectures}" CACHE STRING + "Apple target architectures" FORCE) + endif() +endif() +if(NOT DEFINED CMAKE_OSX_SYSROOT AND DEFINED IOS_PLAT AND NOT IOS_PLAT STREQUAL "") + set(CMAKE_OSX_SYSROOT "${IOS_PLAT}" CACHE STRING "Apple SDK sysroot" FORCE) +endif() +if(NOT DEFINED CMAKE_OSX_DEPLOYMENT_TARGET + AND DEFINED IOS_DEPLOYMENT_TARGET + AND NOT IOS_DEPLOYMENT_TARGET STREQUAL "") + set(CMAKE_OSX_DEPLOYMENT_TARGET "${IOS_DEPLOYMENT_TARGET}" CACHE STRING + "Apple deployment target" FORCE) +endif() +if((DEFINED FORCE_RESET_OSX_DEPLOYMENT_TARGET AND FORCE_RESET_OSX_DEPLOYMENT_TARGET) + OR (DEFINED FORCE_RESET_DEPLOYMENT_TARGET AND FORCE_RESET_DEPLOYMENT_TARGET)) + message(DEPRECATION + "FORCE_RESET_OSX_DEPLOYMENT_TARGET/FORCE_RESET_DEPLOYMENT_TARGET are no " + "longer needed. CMAKE_OSX_DEPLOYMENT_TARGET (or legacy " + "IOS_DEPLOYMENT_TARGET) is honored directly without mutating global flags.") +endif() + project(MSTelemetry LANGUAGES C CXX) +if(APPLE) + set(MATSDK_BUILD_PLATFORM_APPLE TRUE) +else() + set(MATSDK_BUILD_PLATFORM_APPLE FALSE) +endif() ################################################################################################ -# Vcpkg dependency mode: detect early so it can guard platform-specific flag logic +# Package-manager detection (internal; dependency selection is target/provider based) ################################################################################################ +set(MATSDK_USING_VCPKG OFF) if(DEFINED VCPKG_TOOLCHAIN OR DEFINED VCPKG_TARGET_TRIPLET) - option(MATSDK_USE_VCPKG_DEPS "Use vcpkg-provided dependencies via find_package()" ON) -else() - option(MATSDK_USE_VCPKG_DEPS "Use vcpkg-provided dependencies via find_package()" OFF) + set(MATSDK_USING_VCPKG ON) endif() -message(STATUS "MATSDK_USE_VCPKG_DEPS: ${MATSDK_USE_VCPKG_DEPS}") - -# Build a private, feature-stripped copy of the vendored SQLite amalgamation -# instead of linking an external SQLite. The SDK uses SQLite only for its offline -# event-storage cache, so the minimal build (see lib/CMakeLists.txt -# MATSDK_SQLITE_MINIMAL_DEFS) omits every optional SQLite subsystem the SDK does -# not use, shrinking the SQLite code ~10% and removing the external sqlite3 -# dependency. Off by default to preserve the existing external/system-SQLite -# behavior; the Android NDK path always bundles SQLite regardless. -option(MATSDK_MINIMAL_SQLITE "Build a feature-stripped vendored SQLite instead of an external one" OFF) -message(STATUS "MATSDK_MINIMAL_SQLITE: ${MATSDK_MINIMAL_SQLITE}") +message(STATUS "MATSDK_USING_VCPKG: ${MATSDK_USING_VCPKG}") + +include(cmake/MatsdkOptions.cmake) +include(cmake/MatsdkAppleSystemDeps.cmake) # Begin Uncomment for i386 build #set(CMAKE_SYSTEM_PROCESSOR i386) @@ -34,104 +66,17 @@ if (NOT TARGET_ARCH) set(TARGET_ARCH ${CMAKE_SYSTEM_PROCESSOR}) endif() -# Enable ARC for obj-c on Apple -# Initialize platform options before conditional blocks (needed for config templates) -if(NOT DEFINED BUILD_IOS) - set(BUILD_IOS OFF) -endif() -if(NOT APPLE AND NOT DEFINED BUILD_APPLE_HTTP) - set(BUILD_APPLE_HTTP OFF) -endif() - if(APPLE) - message(STATUS "BUILD_IOS: ${BUILD_IOS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fobjc-arc") - - # iOS build options - option(BUILD_IOS "Build for iOS" NO) - option(FORCE_RESET_OSX_DEPLOYMENT_TARGET "Clear the OSX Deployment Target Set" YES) - if (DEFINED FORCE_RESET_DEPLOYMENT_TARGET) - set(FORCE_RESET_OSX_DEPLOYMENT_TARGET ${FORCE_RESET_DEPLOYMENT_TARGET}) - endif() - - # When building via vcpkg, the toolchain file handles architecture, sysroot, - # deployment target, and platform flags. Skip manual flag configuration. - if(NOT MATSDK_USE_VCPKG_DEPS) - if(BUILD_IOS) - set(TARGET_ARCH "APPLE") - set(IOS True) - set(APPLE True) - - if(FORCE_RESET_OSX_DEPLOYMENT_TARGET) - set(CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE) - if (${IOS_PLAT} STREQUAL "iphonesimulator") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mios-simulator-version-min=${IOS_DEPLOYMENT_TARGET}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mios-simulator-version-min=${IOS_DEPLOYMENT_TARGET}") - else() - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -miphoneos-version-min=${IOS_DEPLOYMENT_TARGET}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -miphoneos-version-min=${IOS_DEPLOYMENT_TARGET}") - endif() - endif() - - if((${IOS_PLAT} STREQUAL "iphoneos") OR (${IOS_PLAT} STREQUAL "iphonesimulator") OR (${IOS_PLAT} STREQUAL "xros") OR (${IOS_PLAT} STREQUAL "xrsimulator")) - set(IOS_PLATFORM "${IOS_PLAT}") - else() - message(FATAL_ERROR "Unrecognized iOS platform '${IOS_PLAT}'") - endif() - - if(${IOS_ARCH} STREQUAL "x86_64") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -arch x86_64") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -arch x86_64") - set(CMAKE_SYSTEM_PROCESSOR x86_64) - elseif(${IOS_ARCH} STREQUAL "arm64") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -arch arm64") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -arch arm64") - set(CMAKE_SYSTEM_PROCESSOR arm64) - elseif(${IOS_ARCH} STREQUAL "arm64e") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -arch arm64e") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -arch arm64e") - set(CMAKE_SYSTEM_PROCESSOR arm64e) - else() - message(FATAL_ERROR "Unrecognized iOS architecture '${IOS_ARCH}'") - endif() - - execute_process(COMMAND xcodebuild -version -sdk ${IOS_PLATFORM} ONLY_ACTIVE_ARCH=NO Path - OUTPUT_VARIABLE CMAKE_OSX_SYSROOT - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - message(STATUS "CMAKE_OSX_SYSROOT ${CMAKE_OSX_SYSROOT}") - message(STATUS "ARCHITECTURE: ${CMAKE_SYSTEM_PROCESSOR}") - message(STATUS "PLATFORM: ${IOS_PLATFORM}") - else() - if("${MAC_ARCH}" STREQUAL "x86_64") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -arch x86_64") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -arch x86_64") - set(CMAKE_SYSTEM_PROCESSOR x86_64) - set(TARGET_ARCH ${CMAKE_SYSTEM_PROCESSOR}) - set(CMAKE_OSX_ARCHITECTURES ${MAC_ARCH}) - set(APPLE True) - elseif("${MAC_ARCH}" STREQUAL "arm64") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -arch arm64") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -arch arm64") - set(CMAKE_SYSTEM_PROCESSOR arm64) - set(TARGET_ARCH ${CMAKE_SYSTEM_PROCESSOR}) - set(CMAKE_OSX_ARCHITECTURES ${MAC_ARCH}) - set(APPLE True) - else() - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -arch x86_64 -arch arm64") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -arch x86_64 -arch arm64") - endif() - message(STATUS "MAC_ARCH: ${MAC_ARCH}") - endif() - else() - # vcpkg mode: just set internal flags from what the toolchain provides - if(BUILD_IOS OR CMAKE_SYSTEM_NAME STREQUAL "iOS") - set(BUILD_IOS ON) - set(TARGET_ARCH "APPLE") - set(IOS True) - endif() - message(STATUS "vcpkg toolchain managing architecture and platform flags") + if(MATSDK_PLATFORM_IOS) + set(TARGET_ARCH "APPLE") + set(IOS TRUE) + elseif(CMAKE_OSX_ARCHITECTURES) + set(TARGET_ARCH "${CMAKE_OSX_ARCHITECTURES}") endif() + message(STATUS "MATSDK_PLATFORM_IOS: ${MATSDK_PLATFORM_IOS}") + message(STATUS "CMAKE_OSX_ARCHITECTURES: ${CMAKE_OSX_ARCHITECTURES}") + message(STATUS "CMAKE_OSX_SYSROOT: ${CMAKE_OSX_SYSROOT}") + message(STATUS "CMAKE_OSX_DEPLOYMENT_TARGET: ${CMAKE_OSX_DEPLOYMENT_TARGET}") endif() message(STATUS "CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}") @@ -144,126 +89,41 @@ message(STATUS "CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}") include(tools/ParseOsRelease.cmake) -# When building via vcpkg, let the toolchain manage compiler flags. -# Only apply project-specific flags for non-vcpkg (legacy) builds. -if(NOT MATSDK_USE_VCPKG_DEPS) - -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - set(WARN_FLAGS "/W4 /WX") -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - # -Wno-unknown-warning-option is Clang-only, omitted here - set(WARN_FLAGS "-Wall -Werror -Wextra -Wno-unused-parameter -Wno-unused-but-set-variable") -else() - # Clang / AppleClang - set(WARN_FLAGS "-Wall -Werror -Wextra -Wno-unused-parameter -Wno-unknown-warning-option -Wno-unused-but-set-variable") -endif() - -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - # Using GCC with -s and -Wl linker flags. -ffunction-sections/-fdata-sections - # are set once for all dep modes by the global block further below. - set(REL_FLAGS "-s -Wl,--gc-sections -Os ${WARN_FLAGS} -fmerge-all-constants") -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - set(REL_FLAGS "${WARN_FLAGS}") -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") - set(REL_FLAGS "-Os ${WARN_FLAGS} -fmerge-all-constants") -else() - # Using clang - strip unsupported GCC options (-ffunction-sections is set by - # the global block further below). - set(REL_FLAGS "-Os ${WARN_FLAGS} -fmerge-all-constants") -endif() - -## Uncomment this to reduce the volume of note warnings on RPi4 w/gcc-8 Ref. https://gcc.gnu.org/ml/gcc/2017-05/msg00073.html -#if (CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l") -# set(WARN_FLAGS "${WARN_FLAGS} -Wno-psabi" -#endif() - -# Use libtcmalloc for Debug builds memory leaks detection -set(DBG_FLAGS "-ggdb -gdwarf-2 -O0 ${WARN_FLAGS} -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free") - -if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") - #TODO: -fno-rtti - message(STATUS "Building Release ...") - set(CMAKE_C_FLAGS "$ENV{CFLAGS} ${CMAKE_C_FLAGS} -std=c11 ${REL_FLAGS}") - set(CMAKE_CXX_FLAGS "$ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS} -std=c++11 ${REL_FLAGS}") -else() - set(USE_TCMALLOC 1) - message(STATUS "Building Debug ...") - include(tools/FindTcmalloc.cmake) - set(CMAKE_C_FLAGS "$ENV{CFLAGS} ${CMAKE_C_FLAGS} -std=c11 ${DBG_FLAGS}") - set(CMAKE_CXX_FLAGS "$ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS} -std=c++11 ${DBG_FLAGS}") -endif() - -#Remove /Zi for Win32 debug compiler issue -if(MSVC) - string( TOLOWER "${CMAKE_VS_PLATFORM_NAME}" PLATFORM_NAME_LOWER ) - if (PLATFORM_NAME_LOWER STREQUAL "win32") - string(REGEX REPLACE "/Z[iI7]" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") - string(REGEX REPLACE "/Z[iI7]" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") - endif() -endif() - -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - # using Clang -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - # using GCC - # Prefer to generate position-independent code - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") - # using Intel C++ -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - # using Visual Studio C++ -endif() - -endif() # NOT MATSDK_USE_VCPKG_DEPS (compiler flags) - -# --- Dead-strip enablement (applies in BOTH vendored and vcpkg modes) --------- -# Deliberate exception to the "let the toolchain manage compiler flags" note -# above (the NOT MATSDK_USE_VCPKG_DEPS block): these flags are NOT optimization -# or dependency choices the vcpkg toolchain owns -- they only split functions and -# data into separate COMDATs/sections so a *consumer's* linker can drop -# unreferenced SDK code (MSVC /OPT:REF + /OPT:ICF, GNU/Clang --gc-sections, Apple -# ld -dead_strip). The toolchain does not set them, and the vcpkg-packaged -# library (and every MSVC build, which never gets /Gy from the block above) would -# otherwise link whole .obj files instead of individual functions. Applying them -# here in both modes closes that gap and matches the MSBuild Release projects, -# which already enable FunctionLevelLinking + OptimizeReferences + COMDATFolding. +# SDK-owned compiler policy. This interface target is linked PRIVATE by SDK +# targets, so add_subdirectory()/FetchContent consumers and vendored dependency +# targets never inherit the SDK's warning-as-error or optimization policy. +add_library(matsdk_build_options INTERFACE) if(MSVC) - # /Gy (function-level linking) is supported by both cl.exe and clang-cl. - add_compile_options(/Gy) - # /Gw (whole-program global data) is cl.exe-only; the ClangCL toolset (for - # which MSVC is also true) does not support it. - if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - add_compile_options(/Gw) - endif() -elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") - # On Mach-O, clang emits .subsections_via_symbols, so ld64's -dead_strip - # already removes unreferenced code at per-symbol (function) granularity - # without -ffunction-sections; we add it only for cross-toolchain - # consistency. -fdata-sections is omitted because it historically conflicted - # with bitcode on AppleClang. - add_compile_options(-ffunction-sections) + target_compile_options(matsdk_build_options INTERFACE + /W4 + $<$:/WX> + /Gy + $<$:/Gw>) else() - # GCC / Clang (Linux, Android, MinGW) - add_compile_options(-ffunction-sections -fdata-sections) -endif() - -# Hidden symbol visibility (non-Windows): export only the MATSDK_LIBABI-decorated -# public API (classes + the C API), hiding SDK internals and the bundled -# sqlite3/zlib. This shrinks the dynamic symbol table (faster dynamic -# linking/loading, smaller binaries) and enables more inlining + dead-code -# elimination -- the non-Windows analog of what /Gy plus the consumer's /OPT:REF -# achieve on MSVC. All Windows toolchains (MSVC, MinGW, ClangCL) restrict exports -# via __declspec(dllexport) on MATSDK_LIBABI (lib/include/public/ctmacros.hpp), -# so this is gated on NOT WIN32 (not NOT MSVC, which would also catch MinGW/ -# Clang-GNU Windows builds and apply ELF-style visibility that does not belong on -# a PE/COFF target). -if(NOT WIN32) - # -fvisibility=hidden applies to C and C++; -fvisibility-inlines-hidden is a - # C++-only option, so scope it to CXX. (Applying it to C sources -- e.g. the - # bundled sqlite3/zlib on the legacy Android path -- makes Clang emit an - # "unused argument" warning that becomes an error under the project's -Werror.) - add_compile_options(-fvisibility=hidden $<$:-fvisibility-inlines-hidden>) + target_compile_options(matsdk_build_options INTERFACE + -Wall + -Wextra + -Wno-unused-parameter + -Wno-unused-but-set-variable + $<$:-Werror> + $<$:-Wno-unknown-warning-option> + $<$:-Wno-unknown-warning-option> + $<$:-ggdb> + $<$:-gdwarf-2> + $<$:-O0> + $<$:-fno-builtin-malloc> + $<$:-fno-builtin-calloc> + $<$:-fno-builtin-realloc> + $<$:-fno-builtin-free> + $<$>:-Os> + $<$>:-fmerge-all-constants> + -ffunction-sections + $<$>:-fdata-sections>) + if(NOT WIN32) + target_compile_options(matsdk_build_options INTERFACE + -fvisibility=hidden + $<$:-fvisibility-inlines-hidden>) + endif() endif() include(tools/Utils.cmake) @@ -283,35 +143,38 @@ set(PAL_IMPLEMENTATION ${DEFAULT_PAL_IMPLEMENTATION}) message(STATUS "PAL implementation: ${PAL_IMPLEMENTATION}") string(TOUPPER ${PAL_IMPLEMENTATION} PAL_IMPLEMENTATION_UPPER) -add_definitions(-DMATSDK_PAL_${PAL_IMPLEMENTATION_UPPER}=1) +add_library(matsdk_internal_config INTERFACE) +target_compile_definitions(matsdk_internal_config INTERFACE + MATSDK_PAL_${PAL_IMPLEMENTATION_UPPER}=1 + NOMINMAX) option(GCC5_CXX11_ABI_WORKAROUND "Workaround: Use legacy C++11 ABI (for GCC 5 compatibility)" OFF) if(GCC5_CXX11_ABI_WORKAROUND) - add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) + target_compile_definitions(matsdk_internal_config INTERFACE + _GLIBCXX_USE_CXX11_ABI=0) endif() option(USE_ONEDS_BOUNDCHECK_METHODS "Use bound check methods for C99 functions" OFF) if (USE_ONEDS_BOUNDCHECK_METHODS) - add_definitions(-DHAVE_ONEDS_BOUNDCHECK_METHODS) + target_compile_definitions(matsdk_internal_config INTERFACE + HAVE_ONEDS_BOUNDCHECK_METHODS) endif() option(USE_ONEDS_SECURE_MEM_FUNCTIONS "Use secure memory functions for sqlite" OFF) -if(USE_ONEDS_SECURE_MEM_FUNCTIONS) - add_definitions(-DUSE_ONEDS_SECURE_MEM_FUNCTIONS) -endif() - -if(PAL_IMPLEMENTATION STREQUAL "WIN32" AND NOT MATSDK_USE_VCPKG_DEPS) - add_definitions(-DZLIB_WINAPI) -endif() - -add_definitions(-DNOMINMAX) - ################################################################################################ # Build prefix and version ################################################################################################ set(SDK_VERSION_PREFIX "EVT") -add_definitions("-DMATSDK_VERSION_PREFIX=\"${SDK_VERSION_PREFIX}\"") +target_compile_definitions(matsdk_internal_config INTERFACE + "MATSDK_VERSION_PREFIX=\"${SDK_VERSION_PREFIX}\"") +if(MATSDK_ANDROID_USE_ROOM) + target_compile_definitions(matsdk_internal_config INTERFACE USE_ROOM) +endif() +if(MATSDK_ENABLE_CAPI_HTTP_CLIENT) + target_compile_definitions(matsdk_internal_config INTERFACE + ENABLE_CAPI_HTTP_CLIENT) +endif() set(MATSDK_API_VERSION "3.10") string(TIMESTAMP DAYNUMBER "%j") @@ -332,74 +195,37 @@ endif() message(STATUS "SDK version: ${SDK_VERSION_PREFIX}-${MATSDK_BUILD_VERSION}") ################################################################################################ -# User options (must be before HTTP stack section for BUILD_APPLE_HTTP) +# Embedding/dependency options ################################################################################################ -option(BUILD_HEADERS "Build API headers" YES) -option(BUILD_LIBRARY "Build library" YES) -option(BUILD_TEST_TOOL "Build console test tool" YES) -# Default the test suites ON only when this repository is the top-level project -# (developer/CI build), and OFF when it is consumed via add_subdirectory()/ -# FetchContent, so downstream projects don't build the tests or require the -# third_party/googletest submodule. PROJECT_IS_TOP_LEVEL exists on CMake >= 3.21; -# fall back to comparing the source dirs on older CMake (floor is 3.15). -if(DEFINED PROJECT_IS_TOP_LEVEL) - set(MATSDK_TESTS_DEFAULT ${PROJECT_IS_TOP_LEVEL}) -elseif(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - set(MATSDK_TESTS_DEFAULT ON) -else() - set(MATSDK_TESTS_DEFAULT OFF) +set(MATSDK_CURL_PROVIDER "SYSTEM" CACHE STRING + "How builds resolve libcurl: SYSTEM (canonical target/find_package) or FETCH") +set_property(CACHE MATSDK_CURL_PROVIDER PROPERTY STRINGS SYSTEM FETCH) +set(MATSDK_CURL_TLS_BACKEND "MBEDTLS" CACHE STRING + "TLS backend for MATSDK_CURL_PROVIDER=FETCH: MBEDTLS or OPENSSL") +set_property(CACHE MATSDK_CURL_TLS_BACKEND PROPERTY STRINGS MBEDTLS OPENSSL) +set(MATSDK_CURL_URL "https://github.com/curl/curl/releases/download/curl-8_21_0/curl-8.21.0.tar.xz" CACHE STRING + "URL for MATSDK_CURL_PROVIDER=FETCH") +set(MATSDK_CURL_SHA256 "aa1b66a70eace83dc624508745646c08ae561de512ab403adffb93ac87fc72e6" CACHE STRING + "SHA256 for MATSDK_CURL_URL") +set(MATSDK_MBEDTLS_URL "https://github.com/Mbed-TLS/mbedtls/releases/download/mbedtls-3.6.7/mbedtls-3.6.7.tar.bz2" CACHE STRING + "URL for the mbedTLS dependency used by MATSDK_CURL_PROVIDER=FETCH and MATSDK_CURL_TLS_BACKEND=MBEDTLS") +set(MATSDK_MBEDTLS_SHA256 "a7e8bcbec0e6f761b4af24f25677626b35f762f68eef79c08677a363212d11f6" CACHE STRING + "SHA256 for MATSDK_MBEDTLS_URL") +string(TOUPPER "${MATSDK_CURL_PROVIDER}" MATSDK_CURL_PROVIDER_UPPER) +if(NOT MATSDK_CURL_PROVIDER_UPPER STREQUAL "SYSTEM" AND NOT MATSDK_CURL_PROVIDER_UPPER STREQUAL "FETCH") + message(FATAL_ERROR "MATSDK_CURL_PROVIDER must be SYSTEM or FETCH; got '${MATSDK_CURL_PROVIDER}'.") endif() -option(BUILD_UNIT_TESTS "Build unit tests" ${MATSDK_TESTS_DEFAULT}) -option(BUILD_FUNC_TESTS "Build functional tests" ${MATSDK_TESTS_DEFAULT}) -option(BUILD_JNI_WRAPPER "Build JNI wrapper" NO) -option(BUILD_OBJC_WRAPPER "Build Obj-C wrapper" YES) -option(BUILD_SWIFT_WRAPPER "Build Swift Wrappers" YES) -option(BUILD_PACKAGE "Build package" YES) -option(BUILD_PRIVACYGUARD "Build Privacy Guard" YES) -option(BUILD_CDS "Build CDS - Common Diagnostic Stack" YES) -option(BUILD_LIVEEVENTINSPECTOR "Build Live Event Inspector" YES) -option(BUILD_SIGNALS "Build Signals" YES) -option(BUILD_SANITIZER "Build Sanitizer" YES) -option(LINK_STATIC_DEPENDS "Link dependencies for static build" YES) - -set(MATSDK_ANDROID_HTTP_CLIENT "AUTO" CACHE STRING "Android HTTP client: AUTO, JAVA, or CURL") -set_property(CACHE MATSDK_ANDROID_HTTP_CLIENT PROPERTY STRINGS AUTO JAVA CURL) -string(TOUPPER "${MATSDK_ANDROID_HTTP_CLIENT}" MATSDK_ANDROID_HTTP_CLIENT_UPPER) -if(NOT MATSDK_ANDROID_HTTP_CLIENT_UPPER STREQUAL "AUTO" - AND NOT MATSDK_ANDROID_HTTP_CLIENT_UPPER STREQUAL "JAVA" - AND NOT MATSDK_ANDROID_HTTP_CLIENT_UPPER STREQUAL "CURL") - message(FATAL_ERROR - "MATSDK_ANDROID_HTTP_CLIENT must be AUTO, JAVA, or CURL; got " - "'${MATSDK_ANDROID_HTTP_CLIENT}'.") -endif() - -set(MATSDK_ANDROID_HTTP_CLIENT_RESOLVED "") -set(MATSDK_ANDROID_USES_CURL OFF) -set(MATSDK_ANDROID_USES_JAVA_HTTP OFF) -if(CMAKE_SYSTEM_NAME STREQUAL "Android") - if(MATSDK_ANDROID_HTTP_CLIENT_UPPER STREQUAL "AUTO") - set(MATSDK_ANDROID_HTTP_CLIENT_RESOLVED "JAVA") - else() - set(MATSDK_ANDROID_HTTP_CLIENT_RESOLVED "${MATSDK_ANDROID_HTTP_CLIENT_UPPER}") - endif() - - if(MATSDK_ANDROID_HTTP_CLIENT_RESOLVED STREQUAL "CURL") - set(MATSDK_ANDROID_USES_CURL ON) - elseif(MATSDK_ANDROID_HTTP_CLIENT_RESOLVED STREQUAL "JAVA") - set(MATSDK_ANDROID_USES_JAVA_HTTP ON) - endif() - message(STATUS "MATSDK_ANDROID_HTTP_CLIENT: ${MATSDK_ANDROID_HTTP_CLIENT} -> ${MATSDK_ANDROID_HTTP_CLIENT_RESOLVED}") +string(TOUPPER "${MATSDK_CURL_TLS_BACKEND}" MATSDK_CURL_TLS_BACKEND_UPPER) +if(NOT MATSDK_CURL_TLS_BACKEND_UPPER STREQUAL "MBEDTLS" AND NOT MATSDK_CURL_TLS_BACKEND_UPPER STREQUAL "OPENSSL") + message(FATAL_ERROR "MATSDK_CURL_TLS_BACKEND must be MBEDTLS or OPENSSL; got '${MATSDK_CURL_TLS_BACKEND}'.") endif() - -# Enable Azure Monitor / Application Insights end-point support -option(BUILD_AZMON "Build for Azure Monitor" YES) - -if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - option(BUILD_APPLE_HTTP "Build Apple HTTP client" YES) +if(MATSDK_USING_VCPKG AND MATSDK_CURL_PROVIDER_UPPER STREQUAL "FETCH") + message(FATAL_ERROR + "MATSDK_CURL_PROVIDER=FETCH is a non-vcpkg dependency mode. " + "Use the vcpkg curl-openssl/curl-mbedtls feature instead.") endif() - -if(BUILD_APPLE_HTTP) - add_definitions(-DAPPLE_HTTP=1) +if(MATSDK_BUILD_APPLE_HTTP) + target_compile_definitions(matsdk_internal_config INTERFACE APPLE_HTTP=1) endif() ################################################################################################ @@ -408,117 +234,123 @@ endif() # Only use custom curl if compiling with CPP11 PAL set(MATSDK_NEEDS_CURL OFF) +set(MATSDK_CURL_FETCHED OFF) +set(MATSDK_CURL_LINK_TARGET "") if(PAL_IMPLEMENTATION STREQUAL "CPP11" - AND NOT BUILD_IOS + AND NOT MATSDK_PLATFORM_IOS AND (NOT CMAKE_SYSTEM_NAME STREQUAL "Android" OR MATSDK_ANDROID_USES_CURL) - AND NOT BUILD_APPLE_HTTP) + AND NOT MATSDK_BUILD_APPLE_HTTP) set(MATSDK_NEEDS_CURL ON) - add_definitions(-DHAVE_MAT_CURL_HTTP_CLIENT) - if(MATSDK_USE_VCPKG_DEPS) - # The TLS backend (OpenSSL/mbedTLS) is selected by the vcpkg port's - # curl-openssl (default) / curl-mbedtls features; the SDK just links libcurl. - # Force CONFIG mode so the vcpkg-provided CURLConfig (which defines the - # CURL::libcurl imported target) is used rather than the module FindCURL, - # which on some CMake versions does not define that target. - find_package(CURL CONFIG QUIET) - if(NOT TARGET CURL::libcurl) - message(FATAL_ERROR - "libcurl was not found. The vcpkg port provides the curl HTTP client " - "through the curl-openssl (default) or curl-mbedtls feature. Install " - "cpp-client-telemetry with its default features, or, under the [core,...] " - "form (which drops the default curl-openssl and system-sqlite features), " - "re-select a curl backend and a SQLite backend together, e.g. " - "[core,curl-openssl,system-sqlite] or [core,curl-mbedtls,minimal-sqlite].") - endif() - list(APPEND LIBS CURL::libcurl) + target_compile_definitions(matsdk_internal_config INTERFACE + HAVE_MAT_CURL_HTTP_CLIENT) + if(TARGET CURL::libcurl) + set(MATSDK_CURL_LINK_TARGET CURL::libcurl) + elseif(MATSDK_CURL_PROVIDER_UPPER STREQUAL "FETCH") + include(cmake/MatsdkFetchCurl.cmake) + matsdk_fetch_curl(_matsdk_curl_target) + set(MATSDK_CURL_LINK_TARGET "${_matsdk_curl_target}") + set(MATSDK_CURL_FETCHED ON) else() find_package(CURL REQUIRED) - # Prefer the imported target, which carries curl's include dirs and link - # flags. Fall back to the find-module variables on CMake < 3.12, where - # find_package(CURL) does not define CURL::libcurl. - if(TARGET CURL::libcurl) - list(APPEND LIBS CURL::libcurl) - else() - include_directories(${CURL_INCLUDE_DIRS}) - list(APPEND LIBS "${CURL_LIBRARIES}") + if(NOT TARGET CURL::libcurl) + message(FATAL_ERROR + "find_package(CURL) did not create the required CURL::libcurl target.") endif() + set(MATSDK_CURL_LINK_TARGET CURL::libcurl) endif() endif() ################################################################################################ -# Dependency resolution (vcpkg mode vs vendored) +# Canonical dependency targets ################################################################################################ -if(MATSDK_USE_VCPKG_DEPS) - if(APPLE) - # macOS/iOS ship libsqlite3 and libz as system libraries (the SDK's SPM - # distribution links them the same way), so the vcpkg sqlite3/zlib packages are - # not pulled there -- find the system ones via CMake's standard find modules. - find_package(SQLite3 REQUIRED) - find_package(ZLIB REQUIRED) - find_package(nlohmann_json CONFIG REQUIRED) - set(MATSDK_APPLE_SYSTEM_DEPS ON) - message(STATUS "Apple: using system SQLite3 + zlib; vcpkg-provided nlohmann-json") +if(MATSDK_SQLITE_PROVIDER_RESOLVED STREQUAL "SYSTEM" AND NOT TARGET SQLite::SQLite3) + if(APPLE AND NOT MATSDK_USING_VCPKG) + matsdk_add_apple_system_library(SQLite::SQLite3 sqlite3) else() - set(MATSDK_APPLE_SYSTEM_DEPS OFF) - # SQLite is provided by the private minimal build when MATSDK_MINIMAL_SQLITE is - # ON, so only require the external vcpkg sqlite3 package otherwise. - if(NOT MATSDK_MINIMAL_SQLITE) - find_package(unofficial-sqlite3 CONFIG QUIET) - if(NOT unofficial-sqlite3_FOUND) - message(FATAL_ERROR - "SQLite was not found and the minimal SQLite is not enabled. The vcpkg " - "port provides SQLite through one of two features: 'system-sqlite' " - "(default, links the external sqlite3 package) or 'minimal-sqlite' " - "(builds a private feature-stripped SQLite). Install " - "cpp-client-telemetry with its default features, or with " - "[core,system-sqlite] or [core,minimal-sqlite]. For a direct CMake build, pass " - "-DMATSDK_MINIMAL_SQLITE=ON or ensure unofficial-sqlite3 is discoverable.") - endif() + find_package(SQLite3 QUIET) + if(NOT TARGET SQLite::SQLite3 AND MATSDK_USING_VCPKG) + find_package(unofficial-sqlite3 CONFIG REQUIRED) + add_library(SQLite::SQLite3 INTERFACE IMPORTED GLOBAL) + set_property(TARGET SQLite::SQLite3 PROPERTY + INTERFACE_LINK_LIBRARIES unofficial::sqlite3::sqlite3) endif() - find_package(ZLIB REQUIRED) - find_package(nlohmann_json CONFIG REQUIRED) - if(MATSDK_MINIMAL_SQLITE) - message(STATUS "Using vcpkg-provided zlib, nlohmann-json; private minimal SQLite") - else() - message(STATUS "Using vcpkg-provided sqlite3, zlib, nlohmann-json") + if(NOT TARGET SQLite::SQLite3) + message(FATAL_ERROR + "MATSDK_SQLITE_PROVIDER=SYSTEM requires SQLite::SQLite3. Install SQLite, " + "define the canonical target before adding 1DS, or choose MINIMAL/VENDORED.") endif() endif() -else() - # Include repo root to allow includes of vendored sqlite, zlib, and nlohmann. - # Use CMAKE_CURRENT_SOURCE_DIR (this repo's root) rather than CMAKE_SOURCE_DIR - # so the vendored headers still resolve when the SDK is consumed as a subproject - # (add_subdirectory/FetchContent), where CMAKE_SOURCE_DIR is the consumer's root. - include_directories(${CMAKE_CURRENT_SOURCE_DIR}) - message(STATUS "Using vendored sqlite3, zlib, nlohmann-json") endif() -if(BUILD_UNIT_TESTS OR BUILD_FUNC_TESTS) - message(STATUS "Adding gtest") - add_library(gtest STATIC IMPORTED GLOBAL) - message(STATUS "Adding gmock") - add_library(gmock STATIC IMPORTED GLOBAL) +if(MATSDK_ZLIB_PROVIDER_RESOLVED STREQUAL "SYSTEM" AND NOT TARGET ZLIB::ZLIB) + if(APPLE AND NOT MATSDK_USING_VCPKG) + matsdk_add_apple_system_library(ZLIB::ZLIB z) + else() + find_package(ZLIB REQUIRED) + endif() endif() -# Bond Lite subdirectories -include_directories(bondlite/include) - -include_directories(lib/pal) +set(MATSDK_USES_NLOHMANN_TARGET OFF) +if(TARGET nlohmann_json::nlohmann_json) + set(MATSDK_USES_NLOHMANN_TARGET ON) +elseif(MATSDK_USING_VCPKG) + find_package(nlohmann_json CONFIG REQUIRED) + set(MATSDK_USES_NLOHMANN_TARGET ON) +else() + # nlohmann JSON remains header-only and vendored for source embedding. + set(MATSDK_USES_VENDORED_NLOHMANN ON) +endif() +message(STATUS + "Dependencies: SQLite=${MATSDK_SQLITE_PROVIDER_RESOLVED}, " + "zlib=${MATSDK_ZLIB_PROVIDER_RESOLVED}, " + "nlohmann-target=${MATSDK_USES_NLOHMANN_TARGET}") + +if(MATSDK_BUILD_UNIT_TESTS OR MATSDK_BUILD_FUNC_TESTS) + if(NOT TARGET gtest OR NOT TARGET gmock) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/third_party/googletest/CMakeLists.txt") + set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) + set(BUILD_GMOCK ON CACHE BOOL "" FORCE) + if(MSVC) + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + endif() + set(_matsdk_saved_build_shared_libs "${BUILD_SHARED_LIBS}") + set(BUILD_SHARED_LIBS OFF) + add_subdirectory(third_party/googletest EXCLUDE_FROM_ALL) + set(BUILD_SHARED_LIBS "${_matsdk_saved_build_shared_libs}") + # Checked-in iOS test projects consume these archive paths directly. + set(_matsdk_gtest_archive_dir + "${CMAKE_CURRENT_SOURCE_DIR}/third_party/googletest/build/lib") + foreach(_matsdk_gtest_target IN ITEMS gtest gmock) + set_target_properties(${_matsdk_gtest_target} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${_matsdk_gtest_archive_dir}") + foreach(_matsdk_gtest_config IN ITEMS DEBUG RELEASE RELWITHDEBINFO MINSIZEREL) + set_target_properties(${_matsdk_gtest_target} PROPERTIES + "ARCHIVE_OUTPUT_DIRECTORY_${_matsdk_gtest_config}" + "${_matsdk_gtest_archive_dir}") + endforeach() + endforeach() + else() + message(FATAL_ERROR + "Tests require the third_party/googletest submodule. " + "Run git submodule update --init third_party/googletest.") + endif() + endif() +endif() #if(BUILD_UNIT_TESTS) # message("Adding bondlite tests") # enable_testing() # add_subdirectory(bondlite/tests) #endif() -if(BUILD_HEADERS) +if(MATSDK_BUILD_HEADERS) add_subdirectory(lib/include) endif() -include_directories(lib/include) -if(BUILD_LIBRARY) +if(MATSDK_BUILD_LIBRARY) add_subdirectory(lib) endif() -if(BUILD_UNIT_TESTS OR BUILD_FUNC_TESTS) +if(MATSDK_BUILD_UNIT_TESTS OR MATSDK_BUILD_FUNC_TESTS) message(STATUS "Building tests") enable_testing() add_subdirectory(tests) @@ -528,14 +360,19 @@ endif() # Packaging ################################################################################################ -if (BUILD_PACKAGE) - if ("${CMAKE_PACKAGE_TYPE}" STREQUAL "deb") +if(DEFINED CMAKE_PACKAGE_TYPE AND NOT DEFINED CPACK_GENERATOR) + string(TOUPPER "${CMAKE_PACKAGE_TYPE}" CPACK_GENERATOR) + message(DEPRECATION + "CMAKE_PACKAGE_TYPE is deprecated; use standard CPACK_GENERATOR.") +endif() +if(MATSDK_BUILD_PACKAGE) + if("DEB" IN_LIST CPACK_GENERATOR) include(tools/MakeDeb.cmake) endif() - if ("${CMAKE_PACKAGE_TYPE}" STREQUAL "rpm") + if("RPM" IN_LIST CPACK_GENERATOR) include(tools/MakeRpm.cmake) endif() - if ("${CMAKE_PACKAGE_TYPE}" STREQUAL "tgz") + if("TGZ" IN_LIST CPACK_GENERATOR) # TODO: [MG] - fix path... should we simply use /usr/local/lib without CPU? # TODO: [MG] - Windows path is not ideal -- C:/Program Files (x86)/MSTelemetry/* - what should we use instead? include(tools/MakeTgz.cmake) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 000000000..6a6110015 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,194 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 21, + "patch": 0 + }, + "configurePresets": [ + { + "name": "matsdk-common", + "hidden": true, + "cacheVariables": { + "BUILD_SHARED_LIBS": "OFF", + "CPACK_GENERATOR": "TGZ", + "MATSDK_BUILD_PACKAGE": "ON", + "MATSDK_BUILD_UNIT_TESTS": "OFF", + "MATSDK_BUILD_FUNC_TESTS": "OFF" + } + }, + { + "name": "matsdk-unix", + "hidden": true, + "inherits": "matsdk-common", + "generator": "Unix Makefiles", + "binaryDir": "${sourceDir}/out" + }, + { + "name": "matsdk-debug", + "inherits": "matsdk-unix", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "matsdk-release", + "inherits": "matsdk-unix", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "matsdk-macos-arm64", + "inherits": "matsdk-release", + "cacheVariables": { + "CMAKE_OSX_ARCHITECTURES": "arm64" + } + }, + { + "name": "matsdk-macos-universal", + "inherits": "matsdk-release", + "cacheVariables": { + "CMAKE_OSX_ARCHITECTURES": "arm64;x86_64" + } + }, + { + "name": "matsdk-windows", + "hidden": true, + "inherits": "matsdk-common", + "generator": "Ninja", + "binaryDir": "${sourceDir}/out/windows" + }, + { + "name": "matsdk-windows-debug", + "inherits": "matsdk-windows", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "matsdk-windows-release", + "inherits": "matsdk-windows", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "matsdk-ios", + "hidden": true, + "inherits": "matsdk-common", + "generator": "Unix Makefiles", + "binaryDir": "${sourceDir}/out", + "cacheVariables": { + "CMAKE_SYSTEM_NAME": "iOS", + "CMAKE_OSX_DEPLOYMENT_TARGET": "13.0" + } + }, + { + "name": "matsdk-ios-device-base", + "hidden": true, + "inherits": "matsdk-ios", + "cacheVariables": { + "CMAKE_OSX_SYSROOT": "iphoneos", + "CMAKE_OSX_ARCHITECTURES": "arm64" + } + }, + { + "name": "matsdk-ios-simulator-base", + "hidden": true, + "inherits": "matsdk-ios", + "cacheVariables": { + "CMAKE_OSX_SYSROOT": "iphonesimulator", + "CMAKE_OSX_ARCHITECTURES": "arm64" + } + }, + { + "name": "matsdk-ios-device-debug", + "inherits": "matsdk-ios-device-base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "matsdk-ios-device-release", + "inherits": "matsdk-ios-device-base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "matsdk-ios-simulator-debug", + "inherits": "matsdk-ios-simulator-base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "matsdk-ios-simulator-release", + "inherits": "matsdk-ios-simulator-base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "matsdk-android-arm64", + "inherits": "matsdk-common", + "generator": "Ninja", + "binaryDir": "${sourceDir}/out/android-arm64", + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": "$env{ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake", + "ANDROID_ABI": "arm64-v8a", + "ANDROID_PLATFORM": "android-23", + "CMAKE_BUILD_TYPE": "Release", + "MATSDK_SQLITE_PROVIDER": "VENDORED", + "MATSDK_ZLIB_PROVIDER": "VENDORED" + } + } + ], + "buildPresets": [ + { + "name": "matsdk-debug", + "configurePreset": "matsdk-debug" + }, + { + "name": "matsdk-release", + "configurePreset": "matsdk-release" + }, + { + "name": "matsdk-macos-arm64", + "configurePreset": "matsdk-macos-arm64" + }, + { + "name": "matsdk-macos-universal", + "configurePreset": "matsdk-macos-universal" + }, + { + "name": "matsdk-windows-debug", + "configurePreset": "matsdk-windows-debug" + }, + { + "name": "matsdk-windows-release", + "configurePreset": "matsdk-windows-release" + }, + { + "name": "matsdk-ios-device-debug", + "configurePreset": "matsdk-ios-device-debug" + }, + { + "name": "matsdk-ios-device-release", + "configurePreset": "matsdk-ios-device-release" + }, + { + "name": "matsdk-ios-simulator-debug", + "configurePreset": "matsdk-ios-simulator-debug" + }, + { + "name": "matsdk-ios-simulator-release", + "configurePreset": "matsdk-ios-simulator-release" + }, + { + "name": "matsdk-android-arm64", + "configurePreset": "matsdk-android-arm64" + } + ] +} diff --git a/README.md b/README.md index 3ddcbb580..181530a47 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,12 @@ Platform specific build instructions: * [Linux](docs/cpp-start-linux.md). [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10) or [Docker](https://www.docker.com/products/docker-desktop) can be used to build for various Linux distros. Please refer to [build-docker.cmd](build-docker.cmd) script and [the list of supported containers](docker/). Docker build script accepts the container name as first argument. * [iOS/iPadOS](docs/cpp-start-ios.md) * [Android](docs/cpp-start-android.md) +* [CMake source embedding / FetchContent](docs/embedding-with-cmake.md) + +Standard configure/build presets are listed with `cmake --list-presets`. +`build.sh`, `build-ios.sh`, and `build-cmake.ps1` are thin compatibility +wrappers around those presets. Presets require CMake 3.21+; direct CMake builds +retain the project's CMake 3.15 floor. Other resources to learn how to setup the build system: diff --git a/build-cmake.ps1 b/build-cmake.ps1 new file mode 100644 index 000000000..284920141 --- /dev/null +++ b/build-cmake.ps1 @@ -0,0 +1,61 @@ +param( + [ValidateSet("Debug", "Release")] + [string]$Configuration = "Release", + [switch]$Shared, + [switch]$Clean, + [switch]$Package, + [string[]]$CMakeArgs = @() +) + +$ErrorActionPreference = "Stop" +$RepoRoot = Split-Path -Parent $MyInvocation.MyCommand.Path +Set-Location $RepoRoot + +& cmake -P (Join-Path $RepoRoot "cmake\MatsdkRequirePresetSupport.cmake") +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +if (-not (Get-Command cl.exe -ErrorAction SilentlyContinue)) { + $vswhere = "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" + if (-not (Test-Path $vswhere)) { + throw "Visual Studio vswhere.exe was not found." + } + $vsInstall = & $vswhere -latest -property installationPath + if (-not $vsInstall) { + throw "Visual Studio was not found." + } + $vsDevCmd = Join-Path $vsInstall "Common7\Tools\VsDevCmd.bat" + & cmd /d /s /c "`"$vsDevCmd`" -no_logo && set" | ForEach-Object { + $name, $value = $_ -split "=", 2 + if ($name -and $null -ne $value) { + Set-Item -Path "Env:$name" -Value $value + } + } +} + +$Preset = "matsdk-windows-$($Configuration.ToLowerInvariant())" +$BuildDir = Join-Path $RepoRoot "out\windows" +if ($Clean -and (Test-Path $BuildDir)) { + Remove-Item -LiteralPath $BuildDir -Recurse -Force +} + +$configureArgs = @("--preset", $Preset) +$configureArgs += if ($Shared) { + "-DBUILD_SHARED_LIBS=ON" +} else { + "-DBUILD_SHARED_LIBS=OFF" +} +$configureArgs += $CMakeArgs +if ($Package) { + $configureArgs += "-DCPACK_GENERATOR=TGZ" +} + +& cmake @configureArgs +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +& cmake --build --preset $Preset +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +if ($Package) { + & cmake --build --preset $Preset --target package + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } +} diff --git a/build-ios.sh b/build-ios.sh index d316fe2fa..227eb4b7a 100755 --- a/build-ios.sh +++ b/build-ios.sh @@ -1,4 +1,9 @@ -#!/bin/sh +#!/bin/bash + +set -e + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$DIR" # The expected iOS build invocation is: # build-ios.sh [clean] [release|debug] ${ARCH} ${PLATFORM} @@ -49,7 +54,6 @@ fi echo "IOS_ARCH = $IOS_ARCH, IOS_PLAT = $IOS_PLAT, BUILD_TYPE = $BUILD_TYPE" -FORCE_RESET_DEPLOYMENT_TARGET=NO DEPLOYMENT_TARGET="" if [ "$IOS_PLAT" == "iphoneos" ] || [ "$IOS_PLAT" == "iphonesimulator" ]; then @@ -57,19 +61,16 @@ if [ "$IOS_PLAT" == "iphoneos" ] || [ "$IOS_PLAT" == "iphonesimulator" ]; then DEPLOYMENT_TARGET="$IOS_DEPLOYMENT_TARGET" if [ -z "$DEPLOYMENT_TARGET" ]; then DEPLOYMENT_TARGET="12.0" - FORCE_RESET_DEPLOYMENT_TARGET=YES fi elif [ "$IOS_PLAT" == "xros" ] || [ "$IOS_PLAT" == "xrsimulator" ]; then SYS_NAME="visionOS" DEPLOYMENT_TARGET="$XROS_DEPLOYMENT_TARGET" if [ -z "$DEPLOYMENT_TARGET" ]; then DEPLOYMENT_TARGET="1.0" - FORCE_RESET_DEPLOYMENT_TARGET=YES fi fi echo "deployment target = $DEPLOYMENT_TARGET" -echo "force reset deployment target = $FORCE_RESET_DEPLOYMENT_TARGET" # Install build tools and recent sqlite3 FILE=".buildtools" @@ -87,15 +88,31 @@ if [ -f /usr/bin/clang ]; then echo "clang version: `clang --version`" fi -mkdir -p out -cd out - -CMAKE_PACKAGE_TYPE=tgz - -cmake_cmd="cmake -DCMAKE_OSX_SYSROOT=$IOS_PLAT -DCMAKE_SYSTEM_NAME=$SYS_NAME -DCMAKE_IOS_ARCH_ABI=$IOS_ARCH -DCMAKE_OSX_DEPLOYMENT_TARGET=$DEPLOYMENT_TARGET -DBUILD_IOS=YES -DIOS_ARCH=$IOS_ARCH -DIOS_PLAT=$IOS_PLAT -DIOS_DEPLOYMENT_TARGET=$DEPLOYMENT_TARGET -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PACKAGE_TYPE=$CMAKE_PACKAGE_TYPE -DFORCE_RESET_DEPLOYMENT_TARGET=$FORCE_RESET_DEPLOYMENT_TARGET $CMAKE_OPTS .." -echo "${cmake_cmd}" -eval $cmake_cmd - -make +cmake -P "$DIR/cmake/MatsdkRequirePresetSupport.cmake" + +CPACK_GENERATOR=TGZ +case "$IOS_PLAT" in + *simulator) PLATFORM_PRESET="matsdk-ios-simulator" ;; + *) PLATFORM_PRESET="matsdk-ios-device" ;; +esac +PRESET="${PLATFORM_PRESET}-$(echo "$BUILD_TYPE" | tr '[:upper:]' '[:lower:]')" + +cmake_args=( + cmake --preset "$PRESET" + "-DCMAKE_SYSTEM_NAME=$SYS_NAME" + "-DCMAKE_OSX_SYSROOT=$IOS_PLAT" + "-DCMAKE_OSX_ARCHITECTURES=$IOS_ARCH" + "-DCMAKE_OSX_DEPLOYMENT_TARGET=$DEPLOYMENT_TARGET" + "-DCMAKE_BUILD_TYPE=$BUILD_TYPE" + "-DCPACK_GENERATOR=$CPACK_GENERATOR" +) +if [ -n "$CMAKE_OPTS" ]; then + eval "extra_cmake_args=($CMAKE_OPTS)" + cmake_args+=("${extra_cmake_args[@]}") +fi +printf ' %q' "${cmake_args[@]}" +printf '\n' +"${cmake_args[@]}" -make package +cmake --build --preset "$PRESET" +cmake --build --preset "$PRESET" --target package diff --git a/build-tests-ios.sh b/build-tests-ios.sh index 3e4a40f46..68f3366d3 100755 --- a/build-tests-ios.sh +++ b/build-tests-ios.sh @@ -5,7 +5,8 @@ SIMULATOR=${2:-iPhone 8} set -e -./build-ios.sh ${SKU} +CMAKE_OPTS="${CMAKE_OPTS} -DMATSDK_BUILD_UNIT_TESTS=ON -DMATSDK_BUILD_FUNC_TESTS=ON" \ + ./build-ios.sh ${SKU} cd tests/unittests diff --git a/build-tests.sh b/build-tests.sh index 15b07fed6..eecd7fd87 100755 --- a/build-tests.sh +++ b/build-tests.sh @@ -2,7 +2,8 @@ cd "${0%/*}" SKU=${1:-release} echo Building and running $SKU tests... -./build.sh ${SKU} +CMAKE_OPTS="${CMAKE_OPTS} -DMATSDK_BUILD_UNIT_TESTS=ON -DMATSDK_BUILD_FUNC_TESTS=ON" \ + ./build.sh ${SKU} # Fail on test errors set -e cd out diff --git a/build.sh b/build.sh index 52a5081b2..f16ee9f05 100755 --- a/build.sh +++ b/build.sh @@ -70,7 +70,7 @@ while [[ $# -gt 0 ]]; do echo "MAC_ARCH = $MAC_ARCH" ;; CUSTOM_BUILD_FLAGS*) - CUSTOM_CMAKE_CXX_FLAG="\"${ARG:19:999}\"" + CUSTOM_CMAKE_CXX_FLAG="${ARG:19:999}" echo "custom compiler flags = $CUSTOM_CMAKE_CXX_FLAG" ;; *) @@ -164,47 +164,54 @@ if [ -f /usr/bin/clang ]; then echo "clang version: `clang --version`" fi +cmake -P "$DIR/cmake/MatsdkRequirePresetSupport.cmake" + # Skip Version.hpp changes # git update-index --skip-worktree lib/include/public/Version.hpp -#rm -rf out -mkdir -p out -cd out - # .tgz package -CMAKE_PACKAGE_TYPE=tgz +CPACK_GENERATOR=TGZ if [ -f /usr/bin/dpkg ]; then # .deb package - export CMAKE_PACKAGE_TYPE=deb + export CPACK_GENERATOR=DEB elif [ -f /usr/bin/rpmbuild ]; then # .rpm package - export CMAKE_PACKAGE_TYPE=rpm + export CPACK_GENERATOR=RPM fi # Fail on error set -e -# TODO: should this be improved to verify if the platform is Apple? Right now we unconditionally pass -DMAC_ARCH even if building for Windows or Linux. -cmake_cmd="cmake -DMAC_ARCH=$MAC_ARCH -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PACKAGE_TYPE=$CMAKE_PACKAGE_TYPE -DCMAKE_CXX_FLAGS="${CUSTOM_CMAKE_CXX_FLAG}" $CMAKE_OPTS .." -echo $cmake_cmd -eval $cmake_cmd - -# TODO: strip symbols to minimize (release-only) - -# Build all -# TODO: what are the pros and cons of using 'make' vs 'cmake --build' ? -#make -cmake --build . - -# No fail on error -set +e +PRESET="matsdk-$(echo "$BUILD_TYPE" | tr '[:upper:]' '[:lower:]')" +cmake_args=(cmake --preset "$PRESET") +if [[ "$OS_NAME" == *Darwin* ]]; then + if [[ "$MAC_ARCH" == "universal" ]]; then + cmake_args+=("-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64") + else + cmake_args+=("-DCMAKE_OSX_ARCHITECTURES=$MAC_ARCH") + fi +fi +cmake_args+=( + "-DCPACK_GENERATOR=$CPACK_GENERATOR" +) +if [[ -n "$CUSTOM_CMAKE_CXX_FLAG" ]]; then + cmake_args+=("-DCMAKE_CXX_FLAGS=$CUSTOM_CMAKE_CXX_FLAG") +fi +if [[ -n "$CMAKE_OPTS" ]]; then + # Preserve existing support for callers passing multiple quoted -D arguments. + eval "extra_cmake_args=($CMAKE_OPTS)" + cmake_args+=("${extra_cmake_args[@]}") +fi +printf ' %q' "${cmake_args[@]}" +printf '\n' +"${cmake_args[@]}" -# Remove old package -rm -f *.deb *.rpm +cmake --build --preset "$PRESET" -# Build new package -make package +rm -f out/*.deb out/*.rpm +cmake --build --preset "$PRESET" --target package +cd out # Install newly generated package if [ -f /usr/bin/dpkg ]; then @@ -221,7 +228,7 @@ fi ## strip --strip-unneeded out/lib/libmat.so ## strip -S --strip-unneeded --remove-section=.note.gnu.gold-version --remove-section=.comment --remove-section=.note --remove-section=.note.gnu.build-id --remove-section=.note.ABI-tag out/lib/libmat.so -if [ "$CMAKE_PACKAGE_TYPE" == "tgz" ]; then +if [ "$CPACK_GENERATOR" == "TGZ" ]; then cd .. MATSDK_INSTALL_DIR="${MATSDK_INSTALL_DIR:-/usr/local}" echo "+-----------------------------------------------------------------------------------+" diff --git a/cmake/MSTelemetryConfig.cmake.in b/cmake/MSTelemetryConfig.cmake.in index 8d63ac1f0..6b6daee7c 100644 --- a/cmake/MSTelemetryConfig.cmake.in +++ b/cmake/MSTelemetryConfig.cmake.in @@ -2,30 +2,38 @@ include(CMakeFindDependencyMacro) -# Re-find dependencies that consumers need. -# On Apple the SDK links the system libsqlite3 (SQLite::SQLite3); elsewhere it uses -# the vcpkg sqlite3 package unless a private minimal SQLite is bundled. -if(@MATSDK_APPLE_SYSTEM_DEPS@) - find_dependency(SQLite3) -elseif(NOT @MATSDK_BUNDLE_SQLITE@) - find_dependency(unofficial-sqlite3 CONFIG) -endif() -find_dependency(ZLIB) -find_dependency(nlohmann_json CONFIG) - -# Curl is re-found only when the SDK was built with the curl HTTP client -# (Linux, explicit Android curl builds, and macOS built without Apple HTTP). -# Windows (WinInet), default Android Java/JNI HTTP, iOS, and -# macOS-with-Apple-HTTP do not link curl. -# We bake the build-time decision into a boolean rather than re-deriving it, -# because the macOS BUILD_APPLE_HTTP choice can't be inferred from -# CMAKE_SYSTEM_NAME alone. -if(@MATSDK_NEEDS_CURL@) - # Force CONFIG mode so the vcpkg-provided CURLConfig (which defines the - # CURL::libcurl imported target referenced by MSTelemetryTargets.cmake) is - # used, rather than module-mode FindCURL, which on some CMake versions does - # not define that target. - find_dependency(CURL CONFIG) +# Recreate dependencies only when a static package needs them at the final link. +if(@MATSDK_CONFIG_STATIC_PACKAGE@) + if("@MATSDK_SQLITE_PROVIDER_RESOLVED@" STREQUAL "SYSTEM") + if(@MATSDK_BUILD_PLATFORM_APPLE@) + include("${CMAKE_CURRENT_LIST_DIR}/MatsdkAppleSystemDeps.cmake") + matsdk_add_apple_system_library(SQLite::SQLite3 sqlite3) + else() + if(NOT TARGET SQLite::SQLite3) + find_dependency(SQLite3) + endif() + endif() + if(NOT TARGET MSTelemetry::sqlite_dependency) + add_library(MSTelemetry::sqlite_dependency INTERFACE IMPORTED GLOBAL) + set_property(TARGET MSTelemetry::sqlite_dependency PROPERTY + INTERFACE_LINK_LIBRARIES SQLite::SQLite3) + endif() + endif() + if("@MATSDK_ZLIB_PROVIDER_RESOLVED@" STREQUAL "SYSTEM") + if(@MATSDK_BUILD_PLATFORM_APPLE@) + include("${CMAKE_CURRENT_LIST_DIR}/MatsdkAppleSystemDeps.cmake") + matsdk_add_apple_system_library(ZLIB::ZLIB z) + else() + if(NOT TARGET ZLIB::ZLIB) + find_dependency(ZLIB) + endif() + endif() + if(NOT TARGET MSTelemetry::zlib_dependency) + add_library(MSTelemetry::zlib_dependency INTERFACE IMPORTED GLOBAL) + set_property(TARGET MSTelemetry::zlib_dependency PROPERTY + INTERFACE_LINK_LIBRARIES ZLIB::ZLIB) + endif() + endif() endif() if("@MATSDK_ANDROID_HTTP_CLIENT_RESOLVED@" STREQUAL "") @@ -45,6 +53,66 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android") find_dependency(Threads) endif() +if(@MATSDK_CONFIG_STATIC_PACKAGE@ AND @MATSDK_NEEDS_CURL@) + if(@MATSDK_CURL_FETCHED@) + function(_matsdk_import_static target_name archive_name) + if(NOT TARGET "${target_name}") + add_library("${target_name}" STATIC IMPORTED GLOBAL) + set_target_properties("${target_name}" PROPERTIES + IMPORTED_LOCATION + "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_LIBDIR@/${archive_name}") + endif() + endfunction() + + if("@MATSDK_CURL_TLS_BACKEND_UPPER@" STREQUAL "MBEDTLS") + set(_matsdk_mbedcrypto_support) + foreach(_matsdk_support_archive IN ITEMS everest p256m) + if(EXISTS + "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_LIBDIR@/lib${_matsdk_support_archive}.a") + _matsdk_import_static( + "MSTelemetry::${_matsdk_support_archive}" + "lib${_matsdk_support_archive}.a") + list(APPEND _matsdk_mbedcrypto_support + "MSTelemetry::${_matsdk_support_archive}") + endif() + endforeach() + _matsdk_import_static(MSTelemetry::mbedcrypto libmbedcrypto.a) + _matsdk_import_static(MSTelemetry::mbedx509 libmbedx509.a) + _matsdk_import_static(MSTelemetry::mbedtls libmbedtls.a) + set_property(TARGET MSTelemetry::mbedcrypto PROPERTY + INTERFACE_LINK_LIBRARIES "${_matsdk_mbedcrypto_support}") + set_property(TARGET MSTelemetry::mbedx509 PROPERTY + INTERFACE_LINK_LIBRARIES MSTelemetry::mbedcrypto) + set_property(TARGET MSTelemetry::mbedtls PROPERTY + INTERFACE_LINK_LIBRARIES + "MSTelemetry::mbedx509;MSTelemetry::mbedcrypto") + set(_matsdk_curl_tls_targets + "MSTelemetry::mbedtls;MSTelemetry::mbedx509;MSTelemetry::mbedcrypto") + else() + find_dependency(OpenSSL) + set(_matsdk_curl_tls_targets "OpenSSL::SSL;OpenSSL::Crypto") + endif() + + _matsdk_import_static(MSTelemetry::curl_archive libcurl.a) + set_property(TARGET MSTelemetry::curl_archive PROPERTY + INTERFACE_LINK_LIBRARIES "${_matsdk_curl_tls_targets}") + else() + if(NOT TARGET CURL::libcurl) + find_dependency(CURL) + endif() + endif() + if(NOT TARGET MSTelemetry::curl_dependency) + add_library(MSTelemetry::curl_dependency INTERFACE IMPORTED GLOBAL) + if(@MATSDK_CURL_FETCHED@) + set(_matsdk_curl_dependency_target MSTelemetry::curl_archive) + else() + set(_matsdk_curl_dependency_target CURL::libcurl) + endif() + set_property(TARGET MSTelemetry::curl_dependency PROPERTY + INTERFACE_LINK_LIBRARIES "${_matsdk_curl_dependency_target}") + endif() +endif() + include("${CMAKE_CURRENT_LIST_DIR}/MSTelemetryTargets.cmake") check_required_components(MSTelemetry) diff --git a/cmake/MatsdkAppleSystemDeps.cmake b/cmake/MatsdkAppleSystemDeps.cmake new file mode 100644 index 000000000..2fdb7d70c --- /dev/null +++ b/cmake/MatsdkAppleSystemDeps.cmake @@ -0,0 +1,18 @@ +# Apple ships system SQLite and zlib but no CMake package config for either, so +# there is no find_package() to call. This defines the canonical imported +# target as a thin wrapper around the raw linker library name (e.g. "sqlite3", +# "z"). +# +# This file is shared between the root CMakeLists.txt (build time) and the +# installed MSTelemetryConfig.cmake (consume time, via install(FILES...) in +# lib/CMakeLists.txt) so the two never drift out of sync -- in particular the +# GLOBAL keyword below, which is required so a consumer that calls +# find_package(MSTelemetry) in one directory can link MSTelemetry::mat from a +# sibling/non-descendant directory. +function(matsdk_add_apple_system_library target_name library_name) + if(NOT TARGET "${target_name}") + add_library("${target_name}" INTERFACE IMPORTED GLOBAL) + set_property(TARGET "${target_name}" PROPERTY + INTERFACE_LINK_LIBRARIES "${library_name}") + endif() +endfunction() diff --git a/cmake/MatsdkFetchCurl.cmake b/cmake/MatsdkFetchCurl.cmake new file mode 100644 index 000000000..85380fd0a --- /dev/null +++ b/cmake/MatsdkFetchCurl.cmake @@ -0,0 +1,137 @@ +include(FetchContent) + +function(matsdk_fetch_curl out_target) + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux") + message(FATAL_ERROR + "MATSDK_CURL_PROVIDER=FETCH is currently supported only on Linux. " + "Use MATSDK_CURL_PROVIDER=SYSTEM for this platform.") + endif() + if(TARGET CURL::libcurl) + message(FATAL_ERROR + "MATSDK_CURL_PROVIDER=FETCH requires owning the CURL::libcurl target, " + "but a target with that name already exists. Use MATSDK_CURL_PROVIDER=SYSTEM.") + endif() + + set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0126 NEW) + + foreach(option IN ITEMS + BUILD_SHARED_LIBS + BUILD_TESTING + ENABLE_PROGRAMS + ENABLE_TESTING + GEN_FILES + UNSAFE_BUILD + INSTALL_MBEDTLS_HEADERS + MBEDTLS_FATAL_WARNINGS + USE_SHARED_MBEDTLS_LIBRARY + LINK_WITH_PTHREAD + BUILD_CURL_EXE + BUILD_EXAMPLES + BUILD_LIBCURL_DOCS + BUILD_MISC_DOCS + ENABLE_CURL_MANUAL + CURL_ENABLE_EXPORT_TARGET + CURL_USE_OPENSSL + CURL_USE_PKGCONFIG + CURL_USE_CMAKECONFIG + CURL_ZLIB + CURL_BROTLI + CURL_ZSTD + USE_LIBIDN2 + CURL_USE_LIBPSL + CURL_USE_LIBSSH2 + CURL_USE_LIBSSH + CURL_USE_GSSAPI + CURL_USE_GSASL + USE_NGHTTP2 + USE_NGTCP2 + USE_QUICHE + ENABLE_ARES + ENABLE_UNIX_SOCKETS) + set(${option} OFF) + endforeach() + + foreach(option IN ITEMS + BUILD_STATIC_LIBS + DISABLE_PACKAGE_CONFIG_AND_INSTALL + CURL_DISABLE_INSTALL + HTTP_ONLY + CURL_DISABLE_ALTSVC + CURL_DISABLE_HSTS + CURL_DISABLE_COOKIES + CURL_DISABLE_NETRC + CURL_DISABLE_MIME + CURL_DISABLE_DOH + CURL_DISABLE_AWS + CURL_DISABLE_BEARER_AUTH + CURL_DISABLE_DIGEST_AUTH + CURL_DISABLE_KERBEROS_AUTH + CURL_DISABLE_NEGOTIATE_AUTH) + set(${option} ON) + endforeach() + + if(MATSDK_CURL_TLS_BACKEND_UPPER STREQUAL "MBEDTLS") + set(USE_STATIC_MBEDTLS_LIBRARY ON) + set(CURL_USE_MBEDTLS ON) + set(HAVE_MBEDTLS_DES_CRYPT_ECB ON) + set(MBEDTLS_CONFIG_FILE "") + set(MBEDTLS_USER_CONFIG_FILE "") + + FetchContent_Declare( + matsdk_mbedtls + URL ${MATSDK_MBEDTLS_URL} + URL_HASH SHA256=${MATSDK_MBEDTLS_SHA256}) + FetchContent_MakeAvailable(matsdk_mbedtls) + + foreach(target mbedtls mbedx509 mbedcrypto) + if(NOT TARGET ${target}) + message(FATAL_ERROR "Embedded mbedTLS dependency target not found: ${target}") + endif() + set_target_properties(${target} PROPERTIES + POSITION_INDEPENDENT_CODE ON + C_VISIBILITY_PRESET hidden) + target_compile_options(${target} PRIVATE + $<$:-ffunction-sections;-fdata-sections>) + endforeach() + + set(MBEDTLS_INCLUDE_DIR "${matsdk_mbedtls_SOURCE_DIR}/include") + set(MBEDTLS_LIBRARY MbedTLS::mbedtls) + set(MBEDX509_LIBRARY MbedTLS::mbedx509) + set(MBEDCRYPTO_LIBRARY MbedTLS::mbedcrypto) + set(MBEDTLS_USE_STATIC_LIBS ON) + elseif(MATSDK_CURL_TLS_BACKEND_UPPER STREQUAL "OPENSSL") + set(CURL_USE_OPENSSL ON) + find_package(OpenSSL REQUIRED) + endif() + + FetchContent_Declare( + matsdk_curl + URL ${MATSDK_CURL_URL} + URL_HASH SHA256=${MATSDK_CURL_SHA256}) + FetchContent_MakeAvailable(matsdk_curl) + + if(NOT TARGET CURL::libcurl OR NOT TARGET libcurl_static) + message(FATAL_ERROR "The embedded static CURL::libcurl target was not created.") + endif() + + set_target_properties(libcurl_static PROPERTIES + POSITION_INDEPENDENT_CODE ON + C_VISIBILITY_PRESET hidden) + target_compile_options(libcurl_static PRIVATE + $<$:-ffunction-sections;-fdata-sections>) + + set(_matsdk_fetched_curl_targets libcurl_static) + if(MATSDK_CURL_TLS_BACKEND_UPPER STREQUAL "MBEDTLS") + list(APPEND _matsdk_fetched_curl_targets mbedtls mbedx509 mbedcrypto) + foreach(_matsdk_mbedtls_support_target everest p256m) + if(TARGET ${_matsdk_mbedtls_support_target}) + list(APPEND _matsdk_fetched_curl_targets + ${_matsdk_mbedtls_support_target}) + endif() + endforeach() + endif() + set(MATSDK_FETCHED_CURL_TARGETS + "${_matsdk_fetched_curl_targets}" PARENT_SCOPE) + set(${out_target} CURL::libcurl PARENT_SCOPE) +endfunction() diff --git a/cmake/MatsdkOptions.cmake b/cmake/MatsdkOptions.cmake new file mode 100644 index 000000000..ec8ef409b --- /dev/null +++ b/cmake/MatsdkOptions.cmake @@ -0,0 +1,218 @@ +function(matsdk_bool_option canonical legacy description default_value) + set(initial_value "${default_value}") + set(canonical_predefined OFF) + if(DEFINED ${canonical}) + set(canonical_predefined ON) + endif() + set(legacy_defined OFF) + if(NOT "${legacy}" STREQUAL "") + if(DEFINED ${legacy}) + set(legacy_defined ON) + if(NOT canonical_predefined) + set(initial_value "${${legacy}}") + endif() + endif() + endif() + option(${canonical} "${description}" "${initial_value}") + if(canonical_predefined AND legacy_defined + AND NOT "${${legacy}}" STREQUAL "${${canonical}}") + message(DEPRECATION + "${legacy} is deprecated and conflicts with ${canonical}; " + "${canonical}=${${canonical}} takes precedence.") + endif() +endfunction() + +if(DEFINED PROJECT_IS_TOP_LEVEL) + set(MATSDK_PROJECT_IS_TOP_LEVEL "${PROJECT_IS_TOP_LEVEL}") +elseif(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + set(MATSDK_PROJECT_IS_TOP_LEVEL ON) +else() + set(MATSDK_PROJECT_IS_TOP_LEVEL OFF) +endif() + +matsdk_bool_option(MATSDK_BUILD_HEADERS BUILD_HEADERS + "Build API headers" ON) +matsdk_bool_option(MATSDK_BUILD_LIBRARY BUILD_LIBRARY + "Build the SDK library" ON) +matsdk_bool_option(MATSDK_BUILD_TEST_TOOL BUILD_TEST_TOOL + "Build the console test tool" "${MATSDK_PROJECT_IS_TOP_LEVEL}") +matsdk_bool_option(MATSDK_BUILD_UNIT_TESTS BUILD_UNIT_TESTS + "Build unit tests" "${MATSDK_PROJECT_IS_TOP_LEVEL}") +matsdk_bool_option(MATSDK_BUILD_FUNC_TESTS BUILD_FUNC_TESTS + "Build functional tests" "${MATSDK_PROJECT_IS_TOP_LEVEL}") +matsdk_bool_option(MATSDK_BUILD_JNI_WRAPPER BUILD_JNI_WRAPPER + "Build the JNI wrapper" OFF) +matsdk_bool_option(MATSDK_ANDROID_USE_ROOM USE_ROOM + "Use Android Room for offline storage" OFF) +matsdk_bool_option(MATSDK_ENABLE_CAPI_HTTP_CLIENT ENABLE_CAPI_HTTP_CLIENT + "Enable the C API HTTP client on Android" OFF) +matsdk_bool_option(MATSDK_BUILD_OBJC_WRAPPER BUILD_OBJC_WRAPPER + "Build the Objective-C wrapper" ON) +matsdk_bool_option(MATSDK_BUILD_SWIFT_WRAPPER BUILD_SWIFT_WRAPPER + "Build Swift wrappers" ON) +matsdk_bool_option(MATSDK_BUILD_PACKAGE BUILD_PACKAGE + "Build an SDK package" "${MATSDK_PROJECT_IS_TOP_LEVEL}") +matsdk_bool_option(MATSDK_BUILD_PRIVACYGUARD BUILD_PRIVACYGUARD + "Build Privacy Guard" ON) +matsdk_bool_option(MATSDK_BUILD_CDS BUILD_CDS + "Build Common Diagnostic Stack" ON) +matsdk_bool_option(MATSDK_BUILD_LIVEEVENTINSPECTOR BUILD_LIVEEVENTINSPECTOR + "Build Live Event Inspector" ON) +matsdk_bool_option(MATSDK_BUILD_SIGNALS BUILD_SIGNALS + "Build Signals" ON) +matsdk_bool_option(MATSDK_BUILD_SANITIZER BUILD_SANITIZER + "Build Sanitizer" ON) +matsdk_bool_option(MATSDK_BUILD_AZMON BUILD_AZMON + "Build Azure Monitor / Application Insights support" ON) +matsdk_bool_option(MATSDK_BUILD_APPLE_HTTP BUILD_APPLE_HTTP + "Build the Apple-native HTTP client" "${APPLE}") + +set(_matsdk_android_http_client_predefined OFF) +if(DEFINED MATSDK_ANDROID_HTTP_CLIENT) + set(_matsdk_android_http_client_predefined ON) +endif() +set(MATSDK_ANDROID_HTTP_CLIENT "AUTO" CACHE STRING + "Android HTTP client: AUTO, JAVA, or CURL") +set_property(CACHE MATSDK_ANDROID_HTTP_CLIENT PROPERTY STRINGS AUTO JAVA CURL) + +# Legacy alias: USE_CURL=ON selected the native curl transport on Android +# before MATSDK_ANDROID_HTTP_CLIENT existed. Translate it (once, unless the +# canonical option was already set explicitly) rather than dropping it, since +# it is a real behavioral switch for deliberate Android curl consumers, not +# just a renamed knob. +if(DEFINED USE_CURL AND USE_CURL) + if(_matsdk_android_http_client_predefined + AND NOT MATSDK_ANDROID_HTTP_CLIENT STREQUAL "CURL") + message(DEPRECATION + "USE_CURL is deprecated and conflicts with MATSDK_ANDROID_HTTP_CLIENT; " + "MATSDK_ANDROID_HTTP_CLIENT=${MATSDK_ANDROID_HTTP_CLIENT} takes precedence.") + elseif(NOT _matsdk_android_http_client_predefined) + set(MATSDK_ANDROID_HTTP_CLIENT "CURL" CACHE STRING + "Android HTTP client: AUTO, JAVA, or CURL" FORCE) + endif() +endif() + +string(TOUPPER "${MATSDK_ANDROID_HTTP_CLIENT}" MATSDK_ANDROID_HTTP_CLIENT_UPPER) +if(NOT MATSDK_ANDROID_HTTP_CLIENT_UPPER MATCHES "^(AUTO|JAVA|CURL)$") + message(FATAL_ERROR + "MATSDK_ANDROID_HTTP_CLIENT must be AUTO, JAVA, or CURL; got " + "'${MATSDK_ANDROID_HTTP_CLIENT}'.") +endif() + +set(MATSDK_ANDROID_HTTP_CLIENT_RESOLVED "") +set(MATSDK_ANDROID_USES_CURL OFF) +set(MATSDK_ANDROID_USES_JAVA_HTTP OFF) +if(CMAKE_SYSTEM_NAME STREQUAL "Android") + if(MATSDK_ANDROID_HTTP_CLIENT_UPPER STREQUAL "AUTO") + set(MATSDK_ANDROID_HTTP_CLIENT_RESOLVED "JAVA") + else() + set(MATSDK_ANDROID_HTTP_CLIENT_RESOLVED + "${MATSDK_ANDROID_HTTP_CLIENT_UPPER}") + endif() + + if(MATSDK_ANDROID_HTTP_CLIENT_RESOLVED STREQUAL "CURL") + set(MATSDK_ANDROID_USES_CURL ON) + else() + set(MATSDK_ANDROID_USES_JAVA_HTTP ON) + endif() + message(STATUS + "MATSDK_ANDROID_HTTP_CLIENT: ${MATSDK_ANDROID_HTTP_CLIENT} -> " + "${MATSDK_ANDROID_HTTP_CLIENT_RESOLVED}") +endif() + +option(BUILD_IOS "Deprecated: use CMAKE_SYSTEM_NAME=iOS or visionOS" OFF) +set(MATSDK_PLATFORM_IOS OFF) +if(BUILD_IOS + OR CMAKE_SYSTEM_NAME STREQUAL "iOS" + OR CMAKE_SYSTEM_NAME STREQUAL "visionOS") + set(MATSDK_PLATFORM_IOS ON) +endif() + +matsdk_bool_option(MATSDK_WARNINGS_AS_ERRORS "" + "Treat warnings in SDK-owned targets as errors" "${MATSDK_PROJECT_IS_TOP_LEVEL}") +option(LINK_STATIC_DEPENDS + "Deprecated no-op retained for compatibility with legacy build scripts" ON) + +option(BUILD_SHARED_LIBS "Build shared libraries" OFF) + +set(MATSDK_SQLITE_PROVIDER "AUTO" CACHE STRING + "SQLite dependency provider: AUTO, SYSTEM, MINIMAL, VENDORED, or NONE") +set_property(CACHE MATSDK_SQLITE_PROVIDER PROPERTY STRINGS + AUTO SYSTEM MINIMAL VENDORED NONE) +set(MATSDK_ZLIB_PROVIDER "AUTO" CACHE STRING + "zlib dependency provider: AUTO, SYSTEM, or VENDORED") +set_property(CACHE MATSDK_ZLIB_PROVIDER PROPERTY STRINGS AUTO SYSTEM VENDORED) + +string(TOUPPER "${MATSDK_SQLITE_PROVIDER}" MATSDK_SQLITE_PROVIDER_RESOLVED) +string(TOUPPER "${MATSDK_ZLIB_PROVIDER}" MATSDK_ZLIB_PROVIDER_RESOLVED) + +if(MATSDK_SQLITE_PROVIDER_RESOLVED STREQUAL "AUTO") + if(MATSDK_ANDROID_USE_ROOM AND CMAKE_SYSTEM_NAME STREQUAL "Android") + set(MATSDK_SQLITE_PROVIDER_RESOLVED NONE) + elseif(TARGET SQLite::SQLite3) + set(MATSDK_SQLITE_PROVIDER_RESOLVED SYSTEM) + elseif(NOT MATSDK_USING_VCPKG + AND (WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Android")) + set(MATSDK_SQLITE_PROVIDER_RESOLVED VENDORED) + else() + set(MATSDK_SQLITE_PROVIDER_RESOLVED SYSTEM) + endif() +endif() + +if(MATSDK_ZLIB_PROVIDER_RESOLVED STREQUAL "AUTO") + if(TARGET ZLIB::ZLIB) + set(MATSDK_ZLIB_PROVIDER_RESOLVED SYSTEM) + elseif(NOT MATSDK_USING_VCPKG + AND (WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Android")) + set(MATSDK_ZLIB_PROVIDER_RESOLVED VENDORED) + else() + set(MATSDK_ZLIB_PROVIDER_RESOLVED SYSTEM) + endif() +endif() + +if(NOT MATSDK_SQLITE_PROVIDER_RESOLVED MATCHES "^(SYSTEM|MINIMAL|VENDORED|NONE)$") + message(FATAL_ERROR + "MATSDK_SQLITE_PROVIDER must be AUTO, SYSTEM, MINIMAL, VENDORED, or NONE; " + "got '${MATSDK_SQLITE_PROVIDER}'.") +endif() +if(MATSDK_SQLITE_PROVIDER_RESOLVED STREQUAL "NONE" + AND NOT MATSDK_ANDROID_USE_ROOM) + message(FATAL_ERROR + "MATSDK_SQLITE_PROVIDER=NONE is valid only with MATSDK_ANDROID_USE_ROOM=ON.") +endif() +if(NOT MATSDK_ZLIB_PROVIDER_RESOLVED MATCHES "^(SYSTEM|VENDORED)$") + message(FATAL_ERROR + "MATSDK_ZLIB_PROVIDER must be AUTO, SYSTEM, or VENDORED; " + "got '${MATSDK_ZLIB_PROVIDER}'.") +endif() +set(MATSDK_BUNDLE_SQLITE OFF) +if(MATSDK_SQLITE_PROVIDER_RESOLVED STREQUAL "MINIMAL" + OR MATSDK_SQLITE_PROVIDER_RESOLVED STREQUAL "VENDORED") + set(MATSDK_BUNDLE_SQLITE ON) +endif() +set(MATSDK_BUNDLE_ZLIB OFF) +if(MATSDK_ZLIB_PROVIDER_RESOLVED STREQUAL "VENDORED") + set(MATSDK_BUNDLE_ZLIB ON) +endif() + +message(STATUS "BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}") +message(STATUS "MATSDK_SQLITE_PROVIDER: ${MATSDK_SQLITE_PROVIDER} -> ${MATSDK_SQLITE_PROVIDER_RESOLVED}") +message(STATUS "MATSDK_ZLIB_PROVIDER: ${MATSDK_ZLIB_PROVIDER} -> ${MATSDK_ZLIB_PROVIDER_RESOLVED}") + +################################################################################################ +# Removed inputs +################################################################################################ +# These predate canonical replacements by more than three months and have no +# clean behavioral mapping onto the new provider/layout model, so they are not +# translated -- only detected, so an old script gets an explicit message +# instead of a silent layout/linkage change. +if(DEFINED INSTALL_LIB_DIR) + message(DEPRECATION + "INSTALL_LIB_DIR no longer has any effect; installation layout is " + "controlled by GNUInstallDirs (CMAKE_INSTALL_LIBDIR, CMAKE_INSTALL_PREFIX).") +endif() +if(DEFINED BUILD_STATIC_SQLITE) + message(DEPRECATION + "BUILD_STATIC_SQLITE no longer has any effect; select the SQLite " + "dependency with MATSDK_SQLITE_PROVIDER=SYSTEM|MINIMAL|VENDORED instead.") +endif() diff --git a/cmake/MatsdkRequirePresetSupport.cmake b/cmake/MatsdkRequirePresetSupport.cmake new file mode 100644 index 000000000..18b682ad0 --- /dev/null +++ b/cmake/MatsdkRequirePresetSupport.cmake @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.15) + +if(CMAKE_VERSION VERSION_LESS 3.21) + message(FATAL_ERROR + "The 1DS build wrappers require CMake 3.21 or newer for CMakePresets.json " + "support. Direct CMake builds retain the CMake 3.15 minimum.") +endif() diff --git a/docs/building-with-vcpkg.md b/docs/building-with-vcpkg.md index fed2dbdcf..8cdb27c69 100644 --- a/docs/building-with-vcpkg.md +++ b/docs/building-with-vcpkg.md @@ -418,7 +418,7 @@ unused) but does not save the dependency. For a plain (non-vcpkg) CMake build, pass the option directly: ```bash -cmake -DMATSDK_MINIMAL_SQLITE=ON .. +cmake -DMATSDK_SQLITE_PROVIDER=MINIMAL .. ``` The strip is **amalgamation-safe**: it changes no SQLite grammar/parser, so no @@ -438,22 +438,13 @@ unchanged against the minimal build. > that case, prefer the default `system-sqlite` feature so the whole graph shares a > single SQLite. -## How It Works: MATSDK_USE_VCPKG_DEPS +## How It Works -When the SDK detects it is being built via vcpkg (by checking for -`VCPKG_TOOLCHAIN` or `VCPKG_TARGET_TRIPLET`), it automatically sets -`MATSDK_USE_VCPKG_DEPS=ON`. This switches dependency resolution from -vendored sources to vcpkg-provided packages via `find_package()`. Android HTTP -transport selection is controlled separately by `MATSDK_ANDROID_HTTP_CLIENT`, -which defaults to `JAVA` on Android. - -You can also set this explicitly for custom CMake workflows: - -```bash -cmake -DMATSDK_USE_VCPKG_DEPS=ON \ - -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake \ - .. -``` +The SDK consumes canonical CMake dependency targets. The vcpkg toolchain +provides those targets through normal `find_package()` discovery; no separate +SDK-specific dependency-mode switch is required. Android transport selection is +separate: `MATSDK_ANDROID_HTTP_CLIENT=AUTO` resolves to the Java/JNI transport, +while the explicit Android curl features select the native curl transport. ## Migrating from the older overlay port diff --git a/docs/cpp-start-ios.md b/docs/cpp-start-ios.md index ad80866e0..6adf7b5cc 100644 --- a/docs/cpp-start-ios.md +++ b/docs/cpp-start-ios.md @@ -37,6 +37,25 @@ If Xcode reports that the requested simulator runtime is missing, install it from Xcode > Settings > Components or run `xcodebuild -downloadPlatform iOS -architectureVariant arm64`. +For direct CMake integration, use the standard Apple variables rather than +SDK-specific architecture flags: + +```sh +cmake -S . -B out \ + -DCMAKE_SYSTEM_NAME=iOS \ + -DCMAKE_OSX_SYSROOT=iphonesimulator \ + -DCMAKE_OSX_ARCHITECTURES=arm64 \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=13.0 \ + -DCMAKE_BUILD_TYPE=Release \ + -DMATSDK_BUILD_UNIT_TESTS=OFF \ + -DMATSDK_BUILD_FUNC_TESTS=OFF \ + -DMATSDK_BUILD_OBJC_WRAPPER=OFF \ + -DMATSDK_BUILD_SWIFT_WRAPPER=OFF +``` + +Use `iphoneos` for a device build. Legacy `IOS_ARCH`/`IOS_PLAT` inputs remain +accepted temporarily, but new integrations should use `CMAKE_OSX_*`. + ## 3. Integrate the SDK into your C++ project SDK package contains headers and library installed at the following locations diff --git a/docs/cpp-start-macosx.md b/docs/cpp-start-macosx.md index ec9ef9f71..b0312507b 100644 --- a/docs/cpp-start-macosx.md +++ b/docs/cpp-start-macosx.md @@ -35,22 +35,18 @@ If you do not have those credentials, generate them and use the username and pas ### 2. Run the file build.sh to build the SDK, this will build the SDK along with Unit and Functional Tests -To disable building the tests go to the **CMakeLists.txt** file in the root of the SDK directory and change +To disable tests without editing SDK sources, pass the namespaced CMake options: -```console -option(BUILD_UNIT_TESTS "Build unit tests" YES) -option(BUILD_FUNC_TESTS "Build functional tests" YES) -``` - -to - -```console -option(BUILD_UNIT_TESTS "Build unit tests" NO) -option(BUILD_FUNC_TESTS "Build functional tests" NO) +```sh +CMAKE_OPTS="-DMATSDK_BUILD_UNIT_TESTS=OFF -DMATSDK_BUILD_FUNC_TESTS=OFF" ./build.sh ``` _**Note:** In order to build from scratch all dependencies along with the SDK you need to run: `./build.sh clean`_ +For direct CMake builds, use `CMAKE_OSX_ARCHITECTURES` (`arm64`, `x86_64`, or +`arm64;x86_64`) and `CMAKE_OSX_DEPLOYMENT_TARGET`. The SDK no longer injects +global `-arch` or deployment-target flags. + ### 3. The SDK will be installed under `usr/local/lib/libmat.a` ## **Instrument your code to send a telemetry event** diff --git a/docs/embedding-with-cmake.md b/docs/embedding-with-cmake.md new file mode 100644 index 000000000..3d9f1c591 --- /dev/null +++ b/docs/embedding-with-cmake.md @@ -0,0 +1,81 @@ +# Embedding 1DS with CMake + +Consumers that build the SDK from source with `add_subdirectory()` or +`FetchContent` can link the same target name used by installed/vcpkg builds: + +```cmake +set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) +set(MATSDK_BUILD_TEST_TOOL OFF CACHE BOOL "" FORCE) +set(MATSDK_BUILD_UNIT_TESTS OFF CACHE BOOL "" FORCE) +set(MATSDK_BUILD_FUNC_TESTS OFF CACHE BOOL "" FORCE) +set(MATSDK_BUILD_PACKAGE OFF CACHE BOOL "" FORCE) + +add_subdirectory(cpp_client_telemetry) +target_link_libraries(your_target PRIVATE MSTelemetry::mat) +``` + +For a static SDK build, CMake carries the SDK's link dependencies through the +`MSTelemetry::mat` target, so the consuming target should not need to name the +SDK's internal dependencies directly. + +Use standard `BUILD_SHARED_LIBS=OFF|ON` to select static or shared output. +SDK-specific behavior continues to use namespaced `MATSDK_*` options. + +`MATSDK_WARNINGS_AS_ERRORS` defaults to `ON` for standalone SDK builds and +`OFF` when the SDK is embedded. Its warning policy is private to SDK-owned +targets and never propagates to the parent consumer or vendored dependencies. +Set it explicitly to `ON` in consumer CI to test new toolchains strictly. + +## SQLite and zlib providers + +Source builds can select dependency modes without patching 1DS sources: + +```cmake +set(MATSDK_SQLITE_PROVIDER MINIMAL CACHE STRING "" FORCE) # SYSTEM, MINIMAL, VENDORED +set(MATSDK_ZLIB_PROVIDER VENDORED CACHE STRING "" FORCE) # SYSTEM or VENDORED +``` + +`MINIMAL` builds the feature-stripped SQLite amalgamation. `VENDORED` builds the +unstripped vendored dependency. `SYSTEM` consumes the canonical +`SQLite::SQLite3` / `ZLIB::ZLIB` targets or uses `find_package()`. `AUTO` +preserves platform defaults: system dependencies on desktop/Apple source builds +and vendored dependencies on Windows/Android source builds. + +## Non-vcpkg dependency selection + +When the CPP11 PAL uses the curl HTTP transport outside vcpkg, the SDK normally +calls `find_package(CURL)` and links `CURL::libcurl` when that imported target is +available. On Linux, set `MATSDK_CURL_PROVIDER=FETCH` to let the SDK download and +build a pinned static curl dependency instead: + +```cmake +set(MATSDK_CURL_PROVIDER FETCH CACHE STRING "" FORCE) +set(MATSDK_CURL_TLS_BACKEND MBEDTLS CACHE STRING "" FORCE) # or OPENSSL +add_subdirectory(cpp_client_telemetry) + +target_link_libraries(your_target PRIVATE MSTelemetry::mat) +``` + +The default fetched backend is mbedTLS and is fully self-contained. Selecting +`OPENSSL` builds curl from source but still requires the parent build environment +to provide OpenSSL through `find_package(OpenSSL)`. + +Non-vcpkg Linux builds similarly use `find_package()` for zlib and SQLite unless +an explicit vendored/minimal provider is selected. + +To make a superbuild choose dependency implementations without changing the +leaf consumer target, define the standard CMake targets before adding the SDK: + +```cmake +# These may be real targets or aliases to targets owned by your superbuild. +add_library(CURL::libcurl ALIAS my_curl_target) +add_library(ZLIB::ZLIB ALIAS my_zlib_target) +add_library(SQLite::SQLite3 ALIAS my_sqlite_target) +add_subdirectory(cpp_client_telemetry) + +target_link_libraries(your_target PRIVATE MSTelemetry::mat) +``` + +For a fully self-contained source build, use `MATSDK_SQLITE_PROVIDER=MINIMAL` +and `MATSDK_ZLIB_PROVIDER=VENDORED`; the vendored targets are PIC, hidden, and +compiled without inheriting the SDK's warnings-as-errors policy. diff --git a/install.sh b/install.sh index 4dcddc197..c8b1df24f 100755 --- a/install.sh +++ b/install.sh @@ -1,7 +1,11 @@ #!/bin/sh -MATSDK_INSTALL_DIR=$1 +set -e + +MATSDK_INSTALL_DIR=${1:-/usr/local} +if [ ! -f out/cmake_install.cmake ]; then + echo "ERROR: out/cmake_install.cmake not found; configure and build the SDK first." >&2 + exit 1 +fi + echo "Install SDK to $MATSDK_INSTALL_DIR" -mkdir -p $MATSDK_INSTALL_DIR/lib -cp out/lib/libmat.* $MATSDK_INSTALL_DIR/lib -mkdir -p $MATSDK_INSTALL_DIR/include/mat -cp lib/include/public/* $MATSDK_INSTALL_DIR/include/mat +cmake --install out --prefix "$MATSDK_INSTALL_DIR" diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 13b4d46d4..ed9328bf3 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,18 +1,6 @@ # Honor visibility properties for all target types cmake_policy(SET CMP0063 NEW) -# Legacy (non-target) include paths that apply globally within this directory and -# are used by build.sh / MSBuild / standalone CMake workflows. They do NOT propagate -# to downstream consumers via find_package() (see target_include_directories below). -include_directories( . ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include/public ${CMAKE_CURRENT_SOURCE_DIR}/include/mat ${CMAKE_CURRENT_SOURCE_DIR}/pal ${CMAKE_CURRENT_SOURCE_DIR}/utils ${CMAKE_CURRENT_SOURCE_DIR}/modules/exp ${CMAKE_CURRENT_SOURCE_DIR}/modules/dataviewer ${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard ${CMAKE_CURRENT_SOURCE_DIR}/modules/liveeventinspector ${CMAKE_CURRENT_SOURCE_DIR}/modules/cds ${CMAKE_CURRENT_SOURCE_DIR}/modules/signals ${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer ) - -# Legacy builds may need system-installed deps from /usr/local/include. Excluded on -# iOS: /usr/local/include is a host (macOS) path, and injecting it into an iOS -# cross-compile's search path can shadow the iOS SDK's own headers. -if(NOT MATSDK_USE_VCPKG_DEPS AND NOT CMAKE_SYSTEM_NAME STREQUAL "iOS") - include_directories(/usr/local/include) -endif() - set(SRCS decorators/BaseDecorator.cpp packager/BondSplicer.cpp packager/Packager.cpp @@ -55,7 +43,6 @@ set(SRCS decorators/BaseDecorator.cpp offline/StorageObserver.cpp offline/OfflineStorageFactory.cpp offline/MemoryStorage.cpp - offline/OfflineStorage_SQLite.cpp offline/OfflineStorageHandler.cpp offline/LogSessionDataProvider.cpp backoff/IBackoff.cpp @@ -65,8 +52,38 @@ set(SRCS decorators/BaseDecorator.cpp decoder/PayloadDecoder.cpp ) +if(MATSDK_ANDROID_USE_ROOM) + list(APPEND SRCS offline/OfflineStorage_Room.cpp) +else() + list(APPEND SRCS offline/OfflineStorage_SQLite.cpp) +endif() + +if(MATSDK_BUILD_JNI_WRAPPER) + list(APPEND SRCS + jni/JniConvertors.cpp + jni/LogManager_jni.cpp + jni/Logger_jni.cpp + jni/SemanticContext_jni.cpp + jni/Utils_jni.cpp) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/dataviewer/") + list(APPEND SRCS jni/LogManagerDDVController_jni.cpp) + endif() + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/" + AND MATSDK_BUILD_PRIVACYGUARD) + list(APPEND SRCS jni/PrivacyGuard_jni.cpp) + endif() + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/signals/" + AND MATSDK_BUILD_SIGNALS) + list(APPEND SRCS jni/Signals_jni.cpp) + endif() + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/" + AND MATSDK_BUILD_SANITIZER) + list(APPEND SRCS jni/Sanitizer_jni.cpp) + endif() +endif() + # Support for Azure Monitor / Application Insights -if(BUILD_AZMON) +if(MATSDK_BUILD_AZMON) include(modules/azmon/CMakeLists.txt OPTIONAL) endif() @@ -91,7 +108,7 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/dataviewer/") ) endif() -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/" AND BUILD_PRIVACYGUARD) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/" AND MATSDK_BUILD_PRIVACYGUARD) list(APPEND SRCS modules/privacyguard/PrivacyGuard.cpp modules/privacyguard/RegisteredFileTypes.cpp @@ -99,29 +116,29 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/" AND BUILD_PRIVACYG ) endif() -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/liveeventinspector/" AND BUILD_LIVEEVENTINSPECTOR) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/liveeventinspector/" AND MATSDK_BUILD_LIVEEVENTINSPECTOR) list(APPEND SRCS modules/liveeventinspector/LiveEventInspector.cpp modules/liveeventinspector/LiveEventInspector.hpp ) endif() -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/cds/" AND BUILD_CDS) - add_definitions(-DHAVE_MAT_CDS) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/cds/" AND MATSDK_BUILD_CDS) + target_compile_definitions(matsdk_internal_config INTERFACE HAVE_MAT_CDS) list(APPEND SRCS modules/cds/CdsFactory.hpp modules/cds/CdsFactory.cpp ) endif() -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/signals/" AND BUILD_SIGNALS) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/signals/" AND MATSDK_BUILD_SIGNALS) list(APPEND SRCS modules/signals/Signals.cpp modules/signals/SignalsEncoder.cpp ) endif() -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/" AND BUILD_SANITIZER) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/" AND MATSDK_BUILD_SANITIZER) list(APPEND SRCS modules/sanitizer/detectors/EmailAddressDetector.cpp modules/sanitizer/detectors/JwtDetector.cpp @@ -153,7 +170,7 @@ if(PAL_IMPLEMENTATION STREQUAL "CPP11") list(APPEND SRCS pal/posix/sysinfo_utils_apple.cpp ) - if(BUILD_IOS) + if(MATSDK_PLATFORM_IOS) list(APPEND SRCS pal/posix/sysinfo_utils_ios.mm ) @@ -178,7 +195,7 @@ if(PAL_IMPLEMENTATION STREQUAL "CPP11") endif() if(APPLE) - if(BUILD_APPLE_HTTP OR BUILD_IOS) + if(MATSDK_BUILD_APPLE_HTTP OR MATSDK_PLATFORM_IOS) list(APPEND SRCS http/HttpClient_Apple.mm ) @@ -216,7 +233,7 @@ if(PAL_IMPLEMENTATION STREQUAL "CPP11") ) endif() endif() - if(APPLE AND BUILD_OBJC_WRAPPER) + if(APPLE AND MATSDK_BUILD_OBJC_WRAPPER) message(STATUS "Include ObjC Wrappers") set(OBJC_WRAPPER_SRCS ../wrappers/obj-c/ODWLogger.mm @@ -233,13 +250,13 @@ if(PAL_IMPLEMENTATION STREQUAL "CPP11") ../wrappers/obj-c/ODWDiagnosticDataViewer.mm ) endif() - if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/" AND BUILD_PRIVACYGUARD) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard/" AND MATSDK_BUILD_PRIVACYGUARD) set(MATSDK_OBJC_PRIVACYGUARD_AVAILABLE ON) list(APPEND OBJC_WRAPPER_SRCS ../wrappers/obj-c/ODWPrivacyGuard.mm ) endif() - if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/" AND BUILD_SANITIZER) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer/" AND MATSDK_BUILD_SANITIZER) set(MATSDK_OBJC_SANITIZER_AVAILABLE ON) list(APPEND OBJC_WRAPPER_SRCS ../wrappers/obj-c/ODWSanitizer.mm @@ -248,7 +265,7 @@ if(PAL_IMPLEMENTATION STREQUAL "CPP11") list(APPEND SRCS ${OBJC_WRAPPER_SRCS}) endif() - if(APPLE AND BUILD_SWIFT_WRAPPER) + if(APPLE AND MATSDK_BUILD_SWIFT_WRAPPER) message(STATUS "Building Swift Wrappers") # Run swift build for the Swift Wrappers Package string(TOLOWER ${CMAKE_BUILD_TYPE} LOWER_BUILD_TYPE) @@ -271,11 +288,17 @@ if(PAL_IMPLEMENTATION STREQUAL "CPP11") elseif(PAL_IMPLEMENTATION STREQUAL "WIN32") # Win32 Desktop for now. # TODO: define a separate PAL for Win10 cmake build -if(NOT MATSDK_USE_VCPKG_DEPS) - include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../zlib ${CMAKE_CURRENT_SOURCE_DIR}/../sqlite) -endif() -add_definitions(-D_UNICODE -DUNICODE -DWIN32 -DMATSDK_PLATFORM_WINDOWS=1 -D_UTC_SDK -DUSE_BOND -D_WINDOWS -D_USRDLL -DWINVER=_WIN32_WINNT_WIN7) -remove_definitions(-D_MBCS) +target_compile_definitions(matsdk_internal_config INTERFACE + _UNICODE + UNICODE + WIN32 + MATSDK_PLATFORM_WINDOWS=1 + _UTC_SDK + USE_BOND + _WINDOWS + _USRDLL + WINVER=_WIN32_WINNT_WIN7) +target_compile_options(matsdk_internal_config INTERFACE /U_MBCS) list(APPEND SRCS http/HttpClient_WinInet.cpp http/HttpClient_WinInet.hpp @@ -310,6 +333,15 @@ endif() create_source_files_groups_per_folder(${SRCS}) +if(APPLE) + set(_matsdk_objcxx_sources ${SRCS}) + list(FILTER _matsdk_objcxx_sources INCLUDE REGEX "\\.mm$") + if(_matsdk_objcxx_sources) + set_source_files_properties(${_matsdk_objcxx_sources} + PROPERTIES COMPILE_OPTIONS "-fobjc-arc;-Wno-error=shorten-64-to-32") + endif() +endif() + # Linux and Android require pthreads if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android") find_package(Threads REQUIRED) @@ -325,6 +357,27 @@ else() message(STATUS "Building static SDK library") add_library(mat STATIC ${SRCS}) endif() +target_link_libraries(mat PRIVATE + $ + $) +set_target_properties(mat PROPERTIES POSITION_INDEPENDENT_CODE ON) +if(BUILD_SHARED_LIBS) + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_link_options(mat PRIVATE + $<$>:-s> + $<$>:-Wl,--gc-sections>) + elseif(APPLE) + target_link_options(mat PRIVATE + $<$>:-Wl,-dead_strip>) + endif() +endif() +if(APPLE) + target_compile_options(mat PRIVATE + $<$:-Wno-error=shorten-64-to-32>) +endif() +if(NOT TARGET MSTelemetry::mat) + add_library(MSTelemetry::mat ALIAS mat) +endif() # Public-API export decoration (MATSDK_LIBABI in lib/include/public/ctmacros.hpp). # The SDK has no .def file, so __declspec(dllexport)/(dllimport) on Windows and @@ -369,13 +422,25 @@ target_include_directories(mat ) target_include_directories(mat PRIVATE + ${PROJECT_SOURCE_DIR}/bondlite/include ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/include/mat ${CMAKE_CURRENT_SOURCE_DIR}/pal ${CMAKE_CURRENT_SOURCE_DIR}/utils + ${CMAKE_CURRENT_SOURCE_DIR}/modules/exp + ${CMAKE_CURRENT_SOURCE_DIR}/modules/dataviewer + ${CMAKE_CURRENT_SOURCE_DIR}/modules/privacyguard + ${CMAKE_CURRENT_SOURCE_DIR}/modules/liveeventinspector + ${CMAKE_CURRENT_SOURCE_DIR}/modules/cds + ${CMAKE_CURRENT_SOURCE_DIR}/modules/signals + ${CMAKE_CURRENT_SOURCE_DIR}/modules/sanitizer ) +if(NOT MATSDK_USES_NLOHMANN_TARGET) + target_include_directories(mat PRIVATE ${PROJECT_SOURCE_DIR}) +endif() -if(APPLE AND BUILD_OBJC_WRAPPER) +if(APPLE AND MATSDK_BUILD_OBJC_WRAPPER) if(BUILD_SHARED_LIBS AND OBJC_WRAPPER_SRCS) # The root CMakeLists.txt applies -fvisibility=hidden globally to shrink the # exported symbol table of the core C++ SDK. For Objective-C that also hides @@ -407,7 +472,7 @@ endif() # The SDK uses SQLite only for its offline event-storage cache: plain tables, # indexes, transactions, WAL, autovacuum/VACUUM, a handful of PRAGMAs, and one # custom UTF-8 SQL function. None of SQLite's optional subsystems are needed, so -# when MATSDK_MINIMAL_SQLITE is set the bundled SQLite is compiled with these +# when MATSDK_SQLITE_PROVIDER=MINIMAL the bundled SQLite is compiled with these # options to strip out everything the SDK does not use (~10% smaller SQLite code). # They are all amalgamation-safe (no grammar/parser regeneration) and validated # against the offline-storage unit tests. @@ -447,22 +512,6 @@ set(MATSDK_SQLITE_MINIMAL_DEFS SQLITE_UNTESTABLE ) -# Bundle a vendored SQLite (built from sqlite/sqlite3.c) when MATSDK_MINIMAL_SQLITE -# is requested, or on the Android NDK legacy path (which has no system SQLite and -# has always built the vendored amalgamation). Otherwise an external/system SQLite -# is used. The feature-strip definitions above are applied ONLY when -# MATSDK_MINIMAL_SQLITE is ON, so the default Android legacy build keeps its -# existing (unstripped) bundled SQLite behavior. -set(MATSDK_BUNDLE_SQLITE OFF) -if(MATSDK_MINIMAL_SQLITE AND NOT APPLE) - # On Apple the SDK links the system libsqlite3/libz (see the Apple branch below), - # so MATSDK_MINIMAL_SQLITE has no effect there. - set(MATSDK_BUNDLE_SQLITE ON) -elseif(NOT MATSDK_USE_VCPKG_DEPS AND CMAKE_SYSTEM_NAME STREQUAL "Android") - # Android NDK ships no system SQLite, so the vendored amalgamation is always bundled. - set(MATSDK_BUNDLE_SQLITE ON) -endif() - if(MATSDK_BUNDLE_SQLITE AND NOT TARGET sqlite3_bundled) add_library(sqlite3_bundled STATIC "${CMAKE_CURRENT_SOURCE_DIR}/../sqlite/sqlite3.c") # Consumers of MSTelemetry::mat never include sqlite3.h (it is an internal @@ -470,137 +519,152 @@ if(MATSDK_BUNDLE_SQLITE AND NOT TARGET sqlite3_bundled) # SDK itself -- wrap it in BUILD_INTERFACE so install(EXPORT) stays valid. target_include_directories(sqlite3_bundled PUBLIC "$") - set_target_properties(sqlite3_bundled PROPERTIES POSITION_INDEPENDENT_CODE ON) - if(MATSDK_MINIMAL_SQLITE) + set_target_properties(sqlite3_bundled PROPERTIES + POSITION_INDEPENDENT_CODE ON + C_VISIBILITY_PRESET hidden) + if(MATSDK_SQLITE_PROVIDER_RESOLVED STREQUAL "MINIMAL") # Feature-stripped build: apply the minimal definitions. target_compile_definitions(sqlite3_bundled PRIVATE ${MATSDK_SQLITE_MINIMAL_DEFS}) endif() + if(USE_ONEDS_SECURE_MEM_FUNCTIONS) + target_compile_definitions(sqlite3_bundled PRIVATE + USE_ONEDS_SECURE_MEM_FUNCTIONS) + endif() + if(APPLE AND MATSDK_PLATFORM_IOS) + # SQLite already resolves this to false on Apple mobile platforms. Define it + # explicitly so the amalgamation does not emit its gethostuuid warning under + # consumer-provided warnings-as-errors. + target_compile_definitions(sqlite3_bundled PRIVATE HAVE_GETHOSTUUID=0) + endif() if(MSVC) # Silence the vendored amalgamation's warnings (/w) and turn off # warning-as-error (/WX-) for this third-party translation unit, so the SDK's # /WX does not promote any amalgamation warning that survives /w to an error. - target_compile_options(sqlite3_bundled PRIVATE /w /WX-) - elseif(MATSDK_MINIMAL_SQLITE) + target_compile_options(sqlite3_bundled PRIVATE + /w /WX- /Gy + $<$:/Gw>) + elseif(MATSDK_SQLITE_PROVIDER_RESOLVED STREQUAL "MINIMAL") # -w disables all warnings for this vendored translation unit so the SDK's # -Werror does not fire on amalgamation code (the OMIT_* options leave some # debug-build macros expanding to empty/unused statements). -fno-finite-math-only: # the amalgamation relies on the INFINITY macro, which -ffast-math / # -ffinite-math-only would break. - target_compile_options(sqlite3_bundled PRIVATE -w -fno-finite-math-only) + target_compile_options(sqlite3_bundled PRIVATE + -w -fno-finite-math-only -ffunction-sections + $<$>:-fdata-sections>) else() # Unstripped vendored build (Android legacy): keep the existing narrower # warning suppression. -fno-finite-math-only guards the INFINITY macro. - target_compile_options(sqlite3_bundled PRIVATE -fno-finite-math-only -Wno-unused-function) + target_compile_options(sqlite3_bundled PRIVATE + -fno-finite-math-only -Wno-unused-function -ffunction-sections + $<$>:-fdata-sections>) endif() endif() +if(MATSDK_BUNDLE_SQLITE AND NOT TARGET SQLite::SQLite3) + add_library(SQLite::SQLite3 ALIAS sqlite3_bundled) +endif() -# TODO: allow adding "${Tcmalloc_LIBRARIES}" to target_link_libraries for memory leak debugging -# (USE_TCMALLOC / FindTcmalloc.cmake are configured for Debug builds in the root CMakeLists.txt, -# but the library is not yet linked here). -if(MATSDK_USE_VCPKG_DEPS) - # vcpkg mode: all deps resolved via find_package() in root CMakeLists.txt - # These are PUBLIC so static-library consumers get the transitive link set - # through the exported MSTelemetry::mat target. - if(APPLE) - # macOS/iOS link the system libsqlite3 + libz (SQLite::SQLite3 / ZLIB::ZLIB - # resolve to the OS libraries via CMake's find modules), so the vcpkg - # sqlite3/zlib packages are neither pulled nor linked here. - target_link_libraries(mat - PUBLIC - SQLite::SQLite3 - ZLIB::ZLIB - nlohmann_json::nlohmann_json - ${LIBS} - ) +if(MATSDK_BUNDLE_ZLIB AND NOT TARGET zlib_bundled) + add_library(zlib_bundled STATIC + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/adler32.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/compress.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/crc32.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/deflate.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/gzclose.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/gzlib.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/gzread.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/gzwrite.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/infback.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/inffast.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/inflate.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/inftrees.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/trees.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/uncompr.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/zutil.c" + ) + target_include_directories(zlib_bundled PUBLIC + "$") + set_target_properties(zlib_bundled PROPERTIES + POSITION_INDEPENDENT_CODE ON + C_VISIBILITY_PRESET hidden) + if(NOT WIN32) + target_compile_definitions(zlib_bundled PRIVATE Z_HAVE_UNISTD_H) else() - if(MATSDK_BUNDLE_SQLITE) - # Private minimal SQLite instead of the vcpkg sqlite3 package. PRIVATE so its - # include dirs / compile definitions are not propagated as a public usage - # requirement. A static mat still propagates the archive itself for linking - # (via $), so it is added to the export set for static builds - # below; a shared mat absorbs it and propagates nothing. - target_link_libraries(mat PRIVATE sqlite3_bundled) - else() - target_link_libraries(mat PUBLIC unofficial::sqlite3::sqlite3) - endif() - target_link_libraries(mat - PUBLIC - ZLIB::ZLIB - nlohmann_json::nlohmann_json - ${LIBS} - ) + target_compile_definitions(zlib_bundled PRIVATE ZLIB_WINAPI) + target_compile_definitions(zlib_bundled INTERFACE + $) endif() -else() - # Legacy mode: use vendored or system-installed deps - if(CMAKE_SYSTEM_NAME STREQUAL "Android") - # Build zlib from bundled source: the Android NDK ships no system zlib, and the - # vendored zlib renames its exports to act_z_* (via zlib/names.h). SQLite is - # provided by sqlite3_bundled, created above (MATSDK_BUNDLE_SQLITE is ON for - # the Android NDK path). - add_library(zlib_bundled STATIC - "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/adler32.c" - "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/compress.c" - "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/crc32.c" - "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/deflate.c" - "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/gzclose.c" - "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/gzlib.c" - "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/gzread.c" - "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/gzwrite.c" - "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/infback.c" - "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/inffast.c" - "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/inflate.c" - "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/inftrees.c" - "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/trees.c" - "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/uncompr.c" - "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/zutil.c" - ) - target_include_directories(zlib_bundled PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../zlib") - set_target_properties(zlib_bundled PROPERTIES POSITION_INDEPENDENT_CODE ON) - # Bundled zlib compiles the pristine sources without zlib's configure step, - # so tell it is available (Android is POSIX). This gives gz*.c the - # real POSIX declarations for read/write/lseek/close instead of relying on - # implicit (int-returning) declarations. - target_compile_definitions(zlib_bundled PRIVATE Z_HAVE_UNISTD_H) - - target_link_libraries(mat PRIVATE sqlite3_bundled zlib_bundled ${LIBS}) - elseif(PAL_IMPLEMENTATION STREQUAL "WIN32") - # Windows legacy: vendored sqlite/zlib headers are included via - # include_directories in the PAL section above; link only ${LIBS} - # (e.g. CURL if needed — sqlite/zlib come from .vcxproj references), plus the - # private minimal SQLite when MATSDK_MINIMAL_SQLITE is enabled. - if(MATSDK_BUNDLE_SQLITE) - target_link_libraries(mat PRIVATE sqlite3_bundled ${LIBS}) - else() - target_link_libraries(mat PRIVATE ${LIBS}) - endif() - elseif(APPLE) - # macOS and iOS both ship system libsqlite3 and libz. Link them by portable - # names -- matching the SDK's own iOS Xcode projects (libsqlite3.tbd + libz.tbd - # from the SDKROOT), Package.swift (.linkedLibrary sqlite3/z), and the vcpkg - # Apple path -- so nothing is bundled and exported static packages stay - # relocatable. On Apple, #include / resolve from the SDK - # sysroot, so no explicit include dir or find_package is needed. - target_link_libraries(mat PRIVATE sqlite3 z ${LIBS}) + if(MSVC) + target_compile_options(zlib_bundled PRIVATE + /w /WX- /Gy + $<$:/Gw>) else() - # Linux legacy: system zlib + system (or private minimal) sqlite3. ZLIB::ZLIB - # and SQLite::SQLite3 are imported targets that carry their own include dirs. - find_package(ZLIB REQUIRED) - if(MATSDK_BUNDLE_SQLITE) - target_link_libraries(mat PRIVATE sqlite3_bundled ZLIB::ZLIB ${LIBS}) - else() - # find_package(SQLite3) needs CMake >= 3.14, guaranteed by the project floor; - # SQLite::SQLite3 is an imported target carrying its own include dirs. - find_package(SQLite3 REQUIRED) - target_link_libraries(mat PRIVATE SQLite::SQLite3 ZLIB::ZLIB ${LIBS}) - endif() + target_compile_options(zlib_bundled PRIVATE + -w -ffunction-sections + $<$>:-fdata-sections>) endif() endif() +if(MATSDK_BUNDLE_ZLIB AND NOT TARGET ZLIB::ZLIB) + add_library(ZLIB::ZLIB ALIAS zlib_bundled) +endif() + +if(NOT MATSDK_SQLITE_PROVIDER_RESOLVED STREQUAL "NONE" + AND NOT TARGET SQLite::SQLite3) + message(FATAL_ERROR + "SQLite::SQLite3 was not resolved for provider ${MATSDK_SQLITE_PROVIDER_RESOLVED}.") +endif() +if(NOT TARGET ZLIB::ZLIB) + message(FATAL_ERROR + "ZLIB::ZLIB was not resolved for provider ${MATSDK_ZLIB_PROVIDER_RESOLVED}.") +endif() + +if(MATSDK_SQLITE_PROVIDER_RESOLVED STREQUAL "NONE") + # Room provides Android offline storage; no SQLite dependency is needed. +elseif(MATSDK_BUNDLE_SQLITE) + target_link_libraries(mat PRIVATE sqlite3_bundled) +else() + add_library(matsdk_sqlite_dependency INTERFACE IMPORTED GLOBAL) + set_property(TARGET matsdk_sqlite_dependency PROPERTY + INTERFACE_LINK_LIBRARIES SQLite::SQLite3) + target_link_libraries(mat PRIVATE + "$" + "$") +endif() +if(MATSDK_BUNDLE_ZLIB) + target_link_libraries(mat PRIVATE zlib_bundled) +else() + add_library(matsdk_zlib_dependency INTERFACE IMPORTED GLOBAL) + set_property(TARGET matsdk_zlib_dependency PROPERTY + INTERFACE_LINK_LIBRARIES ZLIB::ZLIB) + target_link_libraries(mat PRIVATE + "$" + "$") +endif() +if(MATSDK_CURL_LINK_TARGET) + add_library(matsdk_curl_dependency INTERFACE IMPORTED GLOBAL) + set_property(TARGET matsdk_curl_dependency PROPERTY + INTERFACE_LINK_LIBRARIES ${MATSDK_CURL_LINK_TARGET}) + target_link_libraries(mat PRIVATE + "$" + "$") +endif() +if(MATSDK_USES_NLOHMANN_TARGET) + add_library(matsdk_nlohmann_dependency INTERFACE IMPORTED GLOBAL) + set_property(TARGET matsdk_nlohmann_dependency PROPERTY + INTERFACE_LINK_LIBRARIES nlohmann_json::nlohmann_json) + target_link_libraries(mat PRIVATE + "$") +endif() + +# TODO: allow adding "${Tcmalloc_LIBRARIES}" to target_link_libraries for memory leak debugging +# (USE_TCMALLOC / FindTcmalloc.cmake are configured for Debug builds in the root CMakeLists.txt, +# but the library is not yet linked here). # Platform-specific link dependencies if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android") - target_link_libraries(mat PUBLIC "${CMAKE_THREAD_LIBS_INIT}" "${CMAKE_DL_LIBS}") - if(THREADS_HAVE_PTHREAD_ARG) - target_compile_options(mat PUBLIC "-pthread") + target_link_libraries(mat PUBLIC Threads::Threads "${CMAKE_DL_LIBS}") + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l") + target_link_libraries(mat PUBLIC atomic) endif() if(CMAKE_SYSTEM_NAME STREQUAL "Android") target_link_libraries(mat PUBLIC log) @@ -615,7 +679,7 @@ elseif(APPLE) "-framework Network" "-framework SystemConfiguration" ) - if(BUILD_IOS OR CMAKE_SYSTEM_NAME STREQUAL "iOS") + if(MATSDK_PLATFORM_IOS) target_link_libraries(mat PUBLIC "-framework UIKit") else() target_link_libraries(mat PUBLIC "-framework IOKit") @@ -625,75 +689,81 @@ endif() ################################################################################################ # Installation ################################################################################################ -# The CMake package config / export workflow is used by vcpkg and any CMake-based -# consumer that does find_package(MSTelemetry). Legacy (non-vcpkg) builds install -# via install.sh or MSBuild output directories and don't need this. -if(MATSDK_USE_VCPKG_DEPS) - # A static libmat propagates its PRIVATE static dependencies through its link - # interface (as $), so the bundled SQLite must be part of the same - # export set and installed alongside mat for downstream find_package() consumers - # to link. A shared libmat absorbs sqlite3_bundled into the .so/.dylib/.dll and - # does not propagate the PRIVATE dep, so exporting the archive there is - # unnecessary (and risks a consumer linking a second SQLite copy) -- only export - # it for a static mat. - set(MATSDK_INSTALL_TARGETS mat) +# A static libmat propagates its private static dependencies at the final link, +# so install bundled archives beside it in both source and vcpkg workflows. +set(MATSDK_EXPORT_TARGETS mat) +set(MATSDK_AUX_INSTALL_TARGETS) +get_target_property(_mat_type mat TYPE) +if(_mat_type STREQUAL "STATIC_LIBRARY") if(MATSDK_BUNDLE_SQLITE AND TARGET sqlite3_bundled) - get_target_property(_mat_type mat TYPE) - if(_mat_type STREQUAL "STATIC_LIBRARY") - list(APPEND MATSDK_INSTALL_TARGETS sqlite3_bundled) - endif() + list(APPEND MATSDK_EXPORT_TARGETS sqlite3_bundled) + endif() + if(MATSDK_BUNDLE_ZLIB AND TARGET zlib_bundled) + list(APPEND MATSDK_EXPORT_TARGETS zlib_bundled) endif() - install(TARGETS ${MATSDK_INSTALL_TARGETS} - EXPORT MSTelemetryTargets + foreach(_matsdk_fetched_target IN LISTS MATSDK_FETCHED_CURL_TARGETS) + if(TARGET ${_matsdk_fetched_target}) + list(APPEND MATSDK_AUX_INSTALL_TARGETS ${_matsdk_fetched_target}) + endif() + endforeach() +endif() + +set(MATSDK_CONFIG_STATIC_PACKAGE FALSE) +if(_mat_type STREQUAL "STATIC_LIBRARY") + set(MATSDK_CONFIG_STATIC_PACKAGE TRUE) +endif() + +install(TARGETS ${MATSDK_EXPORT_TARGETS} + EXPORT MSTelemetryTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) +if(MATSDK_AUX_INSTALL_TARGETS) + install(TARGETS ${MATSDK_AUX_INSTALL_TARGETS} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) +endif() - message(STATUS "Library will be installed to ${CMAKE_INSTALL_LIBDIR}") +message(STATUS "Library will be installed to ${CMAKE_INSTALL_LIBDIR}") - # Generate and install CMake package config files - install(EXPORT MSTelemetryTargets - FILE MSTelemetryTargets.cmake - NAMESPACE MSTelemetry:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MSTelemetry - ) +# Generate and install CMake package config files for every CMake build. +install(EXPORT MSTelemetryTargets + FILE MSTelemetryTargets.cmake + NAMESPACE MSTelemetry:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MSTelemetry +) - configure_package_config_file( - "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/MSTelemetryConfig.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/MSTelemetryConfig.cmake" - INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MSTelemetry - ) +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/MSTelemetryConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/MSTelemetryConfig.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MSTelemetry +) - if(NOT DEFINED MATSDK_BUILD_VERSION OR MATSDK_BUILD_VERSION STREQUAL "") - message(FATAL_ERROR "MATSDK_BUILD_VERSION is not set. Cannot generate package version file.") - endif() +if(NOT DEFINED MATSDK_BUILD_VERSION OR MATSDK_BUILD_VERSION STREQUAL "") + message(FATAL_ERROR "MATSDK_BUILD_VERSION is not set. Cannot generate package version file.") +endif() - write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/MSTelemetryConfigVersion.cmake" - VERSION ${MATSDK_BUILD_VERSION} - COMPATIBILITY AnyNewerVersion - ) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/MSTelemetryConfigVersion.cmake" + VERSION ${MATSDK_BUILD_VERSION} + COMPATIBILITY AnyNewerVersion +) - install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/MSTelemetryConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/MSTelemetryConfigVersion.cmake" - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MSTelemetry - ) +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/MSTelemetryConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/MSTelemetryConfigVersion.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/MatsdkAppleSystemDeps.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MSTelemetry +) - if(CMAKE_SYSTEM_NAME STREQUAL "Android" AND MATSDK_ANDROID_USES_JAVA_HTTP) - install(FILES - "${CMAKE_CURRENT_SOURCE_DIR}/android_build/maesdk/src/main/java/com/microsoft/applications/events/HttpClient.java" - "${CMAKE_CURRENT_SOURCE_DIR}/android_build/maesdk/src/main/java/com/microsoft/applications/events/HttpClientRequest.java" - DESTINATION "${CMAKE_INSTALL_DATADIR}/cpp-client-telemetry/android/java/com/microsoft/applications/events" - ) - endif() -else() - # Legacy install: just put the library and headers in standard locations - install(TARGETS mat - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +if(CMAKE_SYSTEM_NAME STREQUAL "Android" AND MATSDK_ANDROID_USES_JAVA_HTTP) + install(FILES + "${CMAKE_CURRENT_SOURCE_DIR}/android_build/maesdk/src/main/java/com/microsoft/applications/events/HttpClient.java" + "${CMAKE_CURRENT_SOURCE_DIR}/android_build/maesdk/src/main/java/com/microsoft/applications/events/HttpClientRequest.java" + DESTINATION + "${CMAKE_INSTALL_DATADIR}/cpp-client-telemetry/android/java/com/microsoft/applications/events" ) - message(STATUS "Library will be installed to ${CMAKE_INSTALL_LIBDIR}") endif() diff --git a/lib/android_build/app/build.gradle b/lib/android_build/app/build.gradle index 28417a2c5..544239e58 100644 --- a/lib/android_build/app/build.gradle +++ b/lib/android_build/app/build.gradle @@ -11,7 +11,9 @@ android { externalNativeBuild { cmake { // Passes optional arguments to CMake. - arguments "-DANDROID_STL=c++_shared", "-DUSE_ROOM=1" + arguments "-DANDROID_STL=c++_shared", + "-DBUILD_SHARED_LIBS=OFF", + "-DMATSDK_ANDROID_USE_ROOM=ON" } } } diff --git a/lib/android_build/app/src/main/cpp/CMakeLists.txt b/lib/android_build/app/src/main/cpp/CMakeLists.txt index c8c397ea8..feb165ec7 100644 --- a/lib/android_build/app/src/main/cpp/CMakeLists.txt +++ b/lib/android_build/app/src/main/cpp/CMakeLists.txt @@ -4,6 +4,7 @@ # Sets the minimum version of CMake required to build the native library. cmake_minimum_required(VERSION 3.15...3.31) +project(MaesdkAndroidTests LANGUAGES C CXX) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -13,21 +14,6 @@ string(REPLACE "/lib/android_build/app/src/main/cpp" "" SDK_ROOT ${CMAKE_SOURCE_ set (gmock_dir ${SDK_ROOT}/third_party/googletest/googlemock) set (gtest_dir ${SDK_ROOT}/third_party/googletest/googletest) -include_directories(AFTER - ${SDK_ROOT}/lib - ${SDK_ROOT}/lib/include/public - ${SDK_ROOT}/lib/include - ${SDK_ROOT}/lib/include/mat - ${SDK_ROOT}/sqlite - ${SDK_ROOT}lib/pal - ${SDK_ROOT} - "${gmock_dir}/include" - "${gmock_dir}" - "${gtest_dir}/include" - # This directory is needed to build directly from Google - # Test sources. - "${gtest_dir}") - set(TESTS_COMMON_SRCS ${SDK_ROOT}/tests/common/Common.cpp ${SDK_ROOT}/tests/common/Mocks.cpp @@ -75,13 +61,8 @@ set(TESTS_SRCS ${SDK_ROOT}/tests/unittests/UtilsTests.cpp ) -find_package( ZLIB REQUIRED ) -include_directories( - ${ZLIB_INCLUDE_DIRS} - ${SDK_ROOT}/tests -) - -find_library(zlib-path z) +# The test app builds SQLite storage alongside the Room-backed SDK. +set(MATSDK_SQLITE_PROVIDER VENDORED CACHE STRING "" FORCE) #Add maesdk as a dependency add_subdirectory(../../../../maesdk/src/main/cpp maesdk) @@ -89,10 +70,9 @@ add_subdirectory(../../../../maesdk/src/main/cpp maesdk) # include the other flavor of database: if maesdk builds with Room include sqlite # if maesdk builds with native sqlite, include Room -if (USE_ROOM) +if (MATSDK_ANDROID_USE_ROOM) set(OTHER_OFFLINE_SRCS ${SDK_ROOT}/lib/offline/OfflineStorage_SQLite.cpp - ${SDK_ROOT}/sqlite/sqlite3.c ) else() set(OTHER_OFFLINE_SRCS @@ -128,6 +108,20 @@ add_library( # Sets the name of the library. ${TESTS_SRCS} ) +target_include_directories(native-lib PRIVATE + ${SDK_ROOT} + ${SDK_ROOT}/lib + ${SDK_ROOT}/lib/include/public + ${SDK_ROOT}/lib/include + ${SDK_ROOT}/lib/include/mat + ${SDK_ROOT}/lib/pal + ${SDK_ROOT}/sqlite + ${SDK_ROOT}/tests + "${gmock_dir}/include" + "${gmock_dir}" + "${gtest_dir}/include" + "${gtest_dir}") + # Specifies libraries CMake should link to your target library. You # can link multiple libraries, such as libraries you define in this @@ -135,10 +129,12 @@ add_library( # Sets the name of the library. target_link_libraries( # Specifies the target library. native-lib - maesdk + mat + matsdk_internal_config + SQLite::SQLite3 + ZLIB::ZLIB # Links the target library to the log library # included in the NDK. ${log-lib} - ${zlib-path} ) diff --git a/lib/android_build/maesdk/build.gradle b/lib/android_build/maesdk/build.gradle index 714dac0df..5569c0373 100644 --- a/lib/android_build/maesdk/build.gradle +++ b/lib/android_build/maesdk/build.gradle @@ -18,8 +18,9 @@ android { String cxxFlag = project.findProperty("CXXFLAGS") ?: System.getenv("CXXFLAGS") ?: "" ArrayList args = new ArrayList() args.add("-DANDROID_STL=c++_shared") - args.add("-DBUILD_SHARED_LIBS=1") - args.add("-DUSE_ROOM=1") + args.add("-DBUILD_SHARED_LIBS=ON") + args.add("-DMATSDK_ANDROID_USE_ROOM=ON") + args.add("-DMATSDK_BUILD_JNI_WRAPPER=ON") args.add("-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON") String linkerFlag = project.findProperty("CMAKE_SHARED_LINKER_FLAGS") ?: "" linkerFlag = "-DCMAKE_SHARED_LINKER_FLAGS=" + linkerFlag diff --git a/lib/android_build/maesdk/src/main/cpp/CMakeLists.txt b/lib/android_build/maesdk/src/main/cpp/CMakeLists.txt index fc2dad035..6712289dd 100644 --- a/lib/android_build/maesdk/src/main/cpp/CMakeLists.txt +++ b/lib/android_build/maesdk/src/main/cpp/CMakeLists.txt @@ -1,203 +1,17 @@ -# For more information about using CMake with Android Studio, read the -# documentation: https://d.android.com/studio/projects/add-native-code.html - -# Sets the minimum version of CMake required to build the native library. - cmake_minimum_required(VERSION 3.15...3.31) -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -# Enable Azure Monitor / Application Insights end-point support -option(BUILD_AZMON "Build for Azure Monitor" YES) -option(BUILD_PRIVACYGUARD "Build Privacy Guard" YES) -option(BUILD_SIGNALS "Build Signals" YES) -option(BUILD_SANITIZER "Build Sanitizer" YES) - -if(ENABLE_CAPI_HTTP_CLIENT) - add_definitions(-DENABLE_CAPI_HTTP_CLIENT) -endif() - -string(REPLACE "/lib/android_build/maesdk/src/main/cpp" "" SDK_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) - -if (USE_CURL) - add_definitions(-DHAVE_MAT_CURL_HTTP_CLIENT) - find_package(CURL REQUIRED) -endif() - -set(TARGETNAME maesdk) - -set(SRCS - ${SDK_ROOT}/lib/api/AllowedLevelsCollection.cpp - ${SDK_ROOT}/lib/api/AuthTokensController.cpp - ${SDK_ROOT}/lib/api/ContextFieldsProvider.cpp - ${SDK_ROOT}/lib/api/CorrelationVector.cpp - ${SDK_ROOT}/lib/api/DataViewerCollection.cpp - ${SDK_ROOT}/lib/api/ILogConfiguration.cpp - ${SDK_ROOT}/lib/api/LogConfiguration.cpp - ${SDK_ROOT}/lib/api/LogManager.cpp - ${SDK_ROOT}/lib/api/LogManagerFactory.cpp - ${SDK_ROOT}/lib/api/LogManagerImpl.cpp - ${SDK_ROOT}/lib/api/LogManagerProvider.cpp - ${SDK_ROOT}/lib/api/LogSessionData.cpp - ${SDK_ROOT}/lib/api/Logger.cpp - ${SDK_ROOT}/lib/api/capi.cpp - ${SDK_ROOT}/lib/backoff/IBackoff.cpp - ${SDK_ROOT}/lib/bond/BondSerializer.cpp - ${SDK_ROOT}/lib/callbacks/DebugSource.cpp - ${SDK_ROOT}/lib/compression/HttpDeflateCompression.cpp - ${SDK_ROOT}/lib/decoder/PayloadDecoder.cpp - ${SDK_ROOT}/lib/decorators/BaseDecorator.cpp - ${SDK_ROOT}/lib/filter/EventFilterCollection.cpp - ${SDK_ROOT}/lib/http/HttpClientFactory.cpp - ${SDK_ROOT}/lib/http/HttpClientManager.cpp - ${SDK_ROOT}/lib/http/HttpRequestEncoder.cpp - ${SDK_ROOT}/lib/http/HttpResponseDecoder.cpp - ${SDK_ROOT}/lib/jni/JniConvertors.cpp - ${SDK_ROOT}/lib/jni/LogManager_jni.cpp - ${SDK_ROOT}/lib/jni/Logger_jni.cpp - ${SDK_ROOT}/lib/jni/SemanticContext_jni.cpp - ${SDK_ROOT}/lib/jni/Utils_jni.cpp - ${SDK_ROOT}/lib/offline/MemoryStorage.cpp - ${SDK_ROOT}/lib/offline/LogSessionDataProvider.cpp - ${SDK_ROOT}/lib/offline/OfflineStorageFactory.cpp - ${SDK_ROOT}/lib/offline/OfflineStorageHandler.cpp - ${SDK_ROOT}/lib/offline/StorageObserver.cpp - ${SDK_ROOT}/lib/packager/BondSplicer.cpp - ${SDK_ROOT}/lib/packager/Packager.cpp - ${SDK_ROOT}/lib/pal/InformationProviderImpl.cpp - ${SDK_ROOT}/lib/pal/PAL.cpp - ${SDK_ROOT}/lib/pal/TaskDispatcher_CAPI.cpp - ${SDK_ROOT}/lib/pal/WorkerThread.cpp - ${SDK_ROOT}/lib/pal/posix/DeviceInformationImpl_Android.cpp - ${SDK_ROOT}/lib/pal/posix/NetworkInformationImpl_Android.cpp - ${SDK_ROOT}/lib/pal/posix/SystemInformationImpl_Android.cpp - ${SDK_ROOT}/lib/pal/posix/sysinfo_sources.cpp - ${SDK_ROOT}/lib/stats/MetaStats.cpp - ${SDK_ROOT}/lib/stats/Statistics.cpp - ${SDK_ROOT}/lib/system/EventProperties.cpp - ${SDK_ROOT}/lib/system/EventProperty.cpp - ${SDK_ROOT}/lib/system/TelemetrySystem.cpp - ${SDK_ROOT}/lib/tpm/DeviceStateHandler.cpp - ${SDK_ROOT}/lib/tpm/TransmissionPolicyManager.cpp - ${SDK_ROOT}/lib/tpm/TransmitProfiles.cpp - ${SDK_ROOT}/lib/utils/FileUtils.cpp - ${SDK_ROOT}/lib/utils/StringUtils.cpp - ${SDK_ROOT}/lib/utils/ZlibUtils.cpp - ${SDK_ROOT}/lib/utils/Utils.cpp -) - -# Support for Azure Monitor / Application Insights -if (BUILD_AZMON) - include(${SDK_ROOT}/lib/modules/azmon/CMakeLists.txt OPTIONAL) -endif() - -if(EXISTS ${SDK_ROOT}/lib/modules/dataviewer/) - list(APPEND SRCS - ${SDK_ROOT}/lib/jni/LogManagerDDVController_jni.cpp - ${SDK_ROOT}/lib/modules/dataviewer/DefaultDataViewer.cpp - ${SDK_ROOT}/lib/modules/dataviewer/OnDisableNotificationCollection.cpp - ) -endif() - -if(EXISTS ${SDK_ROOT}/lib/modules/privacyguard/ AND BUILD_PRIVACYGUARD) - list(APPEND SRCS - ${SDK_ROOT}/lib/jni/PrivacyGuard_jni.cpp - ${SDK_ROOT}/lib/modules/privacyguard/SummaryStatistics.cpp - ${SDK_ROOT}/lib/modules/privacyguard/PrivacyGuard.cpp - ${SDK_ROOT}/lib/modules/privacyguard/RegisteredFileTypes.cpp - ) -endif() - -if (EXISTS ${SDK_ROOT}/lib/modules/signals/ AND BUILD_SIGNALS) - list(APPEND SRCS - ${SDK_ROOT}/lib/jni/Signals_jni.cpp - ${SDK_ROOT}/lib/modules/signals/Signals.cpp - ${SDK_ROOT}/lib/modules/signals/SignalsEncoder.cpp - ) -endif() - -if (EXISTS ${SDK_ROOT}/lib/modules/sanitizer/ AND BUILD_SANITIZER) - list(APPEND SRCS - ${SDK_ROOT}/lib/jni/Sanitizer_jni.cpp - ${SDK_ROOT}/lib/modules/sanitizer/detectors/EmailAddressDetector.cpp - ${SDK_ROOT}/lib/modules/sanitizer/detectors/JwtDetector.cpp - ${SDK_ROOT}/lib/modules/sanitizer/detectors/SPOPassword.cpp - ${SDK_ROOT}/lib/modules/sanitizer/detectors/UrlDetector.cpp - ${SDK_ROOT}/lib/modules/sanitizer/Sanitizer.cpp - ${SDK_ROOT}/lib/modules/sanitizer/SanitizerProvider.cpp - ${SDK_ROOT}/lib/modules/sanitizer/SanitizerStringUtils.cpp - ${SDK_ROOT}/lib/modules/sanitizer/SanitizerTargets.cpp - ${SDK_ROOT}/lib/modules/sanitizer/SanitizerTrie.cpp - ${SDK_ROOT}/lib/modules/sanitizer/SanitizerTrieNode.cpp - ) -endif() - -if (USE_ROOM) - add_definitions("-DUSE_ROOM") - list(APPEND SRCS ${SDK_ROOT}/lib/offline/OfflineStorage_Room.cpp) -else() - list(APPEND SRCS - ${SDK_ROOT}/lib/offline/OfflineStorage_SQLite.cpp - ${SDK_ROOT}/sqlite/sqlite3.c - ) -endif() - -if (USE_CURL) - list(APPEND SRCS ${SDK_ROOT}/lib/http/HttpClient_Curl.cpp) -else() - list(APPEND SRCS ${SDK_ROOT}/lib/http/HttpClient_Android.cpp) -endif() - -if (ENABLE_CAPI_HTTP_CLIENT) - list(APPEND SRCS ${SDK_ROOT}/lib/http/HttpClient_CAPI.cpp) -endif() - -add_library(${TARGETNAME} ${SRCS}) - -target_include_directories(${TARGETNAME} PUBLIC - ${SDK_ROOT}/lib - ${SDK_ROOT}/lib/include/public - ${SDK_ROOT}/lib/include - ${SDK_ROOT}/lib/include/mat - ${SDK_ROOT}/sqlite - ${SDK_ROOT}lib/pal - ${SDK_ROOT} - ${SDK_ROOT}/lib/modules/sanitizer/detectors - ${SDK_ROOT}/lib/modules/sanitizer - ${CURL_INCLUDE_DIRS}) - - -# Creates and names a library, sets it as either STATIC -# or SHARED, and provides the relative paths to its source code. -# You can define multiple libraries, and CMake builds them for you. -# Gradle automatically packages shared libraries with your APK. - -# Searches for a specified prebuilt library and stores the path as a -# variable. Because CMake includes system libraries in the search path by -# default, you only need to specify the name of the public NDK library -# you want to add. CMake verifies that the library exists before -# completing its build. - -find_library( # Sets the name of the path variable. - log-lib +project(MaesdkAndroid LANGUAGES C CXX) - # Specifies the name of the NDK library that - # you want CMake to locate. - log ) +get_filename_component(SDK_ROOT + "${CMAKE_CURRENT_LIST_DIR}/../../../../../.." ABSOLUTE) -find_library( - zlib - z -) +set(BUILD_SHARED_LIBS ON CACHE BOOL "") +set(MATSDK_BUILD_JNI_WRAPPER ON CACHE BOOL "" FORCE) +set(MATSDK_ANDROID_USE_ROOM ON CACHE BOOL "" FORCE) +set(MATSDK_BUILD_PACKAGE OFF CACHE BOOL "" FORCE) +set(MATSDK_BUILD_UNIT_TESTS OFF CACHE BOOL "" FORCE) +set(MATSDK_BUILD_FUNC_TESTS OFF CACHE BOOL "" FORCE) -# Specifies libraries CMake should link to your target library. You -# can link multiple libraries, such as libraries you define in this -# build script, prebuilt third-party libraries, or system libraries. +add_subdirectory("${SDK_ROOT}" "${CMAKE_CURRENT_BINARY_DIR}/matsdk") -target_link_libraries(maesdk PUBLIC - # Links the target library to the log library - # included in the NDK. - ${log-lib} - ${zlib} - ${CURL_LIBRARIES} - ) +# Preserve the Java/AAR runtime name: System.loadLibrary("maesdk"). +set_target_properties(mat PROPERTIES OUTPUT_NAME maesdk) diff --git a/lib/http/HttpClient_Curl.hpp b/lib/http/HttpClient_Curl.hpp index 533c522e3..7d599dec9 100644 --- a/lib/http/HttpClient_Curl.hpp +++ b/lib/http/HttpClient_Curl.hpp @@ -71,6 +71,13 @@ class HttpClient_Curl : public IHttpClient { class CurlHttpOperation { public: + static long GetPreferredHttpVersion() + { + const curl_version_info_data* versionInfo = curl_version_info(CURLVERSION_NOW); + return (versionInfo != nullptr && (versionInfo->features & CURL_VERSION_HTTP2) != 0) + ? CURL_HTTP_VERSION_2_0 + : CURL_HTTP_VERSION_1_1; + } void DispatchEvent(HttpStateEvent type) { @@ -134,21 +141,35 @@ class CurlHttpOperation { #if 0 // Be verbose - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + if (!SetOption(CURLOPT_VERBOSE, 1L)) #else - curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); + if (!SetOption(CURLOPT_VERBOSE, 0L)) #endif + { + DispatchEvent(OnCreateFailed); + return; + } // Specify target URL - curl_easy_setopt(curl, CURLOPT_URL, m_url.c_str()); + if (!SetOption(CURLOPT_URL, m_url.c_str()) + || !SetOption(CURLOPT_SSL_VERIFYPEER, sslVerify ? 1L : 0L) + || !SetOption(CURLOPT_SSL_VERIFYHOST, sslVerify ? 2L : 0L)) + { + DispatchEvent(OnCreateFailed); + return; + } + + if (!m_sslCaInfo.empty() && !SetOption(CURLOPT_CAINFO, m_sslCaInfo.c_str())) + { + DispatchEvent(OnCreateFailed); + return; + } - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, sslVerify ? 1L : 0L); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, sslVerify ? 2L : 0L); - if (!m_sslCaInfo.empty()) { - curl_easy_setopt(curl, CURLOPT_CAINFO, m_sslCaInfo.c_str()); + if (!SetOption(CURLOPT_HTTP_VERSION, GetPreferredHttpVersion())) + { + DispatchEvent(OnCreateFailed); + return; } - // HTTP/2 please, fallback to HTTP/1.1 if not supported - curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); // Headers are copied into m_headersChunk during construction and the // curl_slist is kept alive until destruction, so the original map does @@ -156,15 +177,24 @@ class CurlHttpOperation { for (const auto& kv : requestHeaders) { std::string header = kv.first + ": " + kv.second; - m_headersChunk = curl_slist_append(m_headersChunk, header.c_str()); + curl_slist* appended = curl_slist_append(m_headersChunk, header.c_str()); + if (appended == nullptr) + { + res = CURLE_OUT_OF_MEMORY; + DispatchEvent(OnCreateFailed); + return; + } + m_headersChunk = appended; } - if(m_headersChunk != nullptr) + if(m_headersChunk != nullptr && !SetOption(CURLOPT_HTTPHEADER, m_headersChunk)) { - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, m_headersChunk); + DispatchEvent(OnCreateFailed); + return; } TRACE("method=%s, url=%s\n", this->m_method.c_str(), this->m_url.c_str()); + m_isConfigured = true; DispatchEvent(OnCreated); } @@ -181,7 +211,10 @@ class CurlHttpOperation { } DispatchEvent(OnDestroy); res = CURLE_OK; - curl_easy_cleanup(curl); + if (curl != nullptr) + { + curl_easy_cleanup(curl); + } curl_slist_free_all(m_headersChunk); ReleaseResponse(); } @@ -197,10 +230,14 @@ class CurlHttpOperation { // Request buffer const void *request = requestBody.empty() ? nullptr : requestBody.data(); const size_t reqSize = requestBody.size(); + int socketWaitResult = 0; - if(!curl) + if(!curl || !m_isConfigured) { - res = CURLE_FAILED_INIT; + if (res == CURLE_OK) + { + res = CURLE_FAILED_INIT; + } DispatchEvent(OnSendFailed); goto cleanup; } @@ -209,37 +246,49 @@ class CurlHttpOperation { // curl_easy_setopt(curl, CURLOPT_LOCALPORT, dcf_port); // Perform initial connect, handling the timeout if needed - curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L); - DispatchEvent(OnConnecting); - res = curl_easy_perform(curl); - if(CURLE_OK != res) + if (!SetOption(CURLOPT_CONNECT_ONLY, 1L)) { - DispatchEvent(OnConnectFailed); // couldn't connect - stage 1 - TRACE("Error #1: %s\n", curl_easy_strerror(res)); + DispatchEvent(OnConnectFailed); goto cleanup; } + DispatchEvent(OnConnecting); + { + const CURLcode curlResult = curl_easy_perform(curl); + res = static_cast(curlResult); + if(CURLE_OK != curlResult) + { + DispatchEvent(OnConnectFailed); // couldn't connect - stage 1 + TRACE("Error #1: %s\n", curl_easy_strerror(curlResult)); + goto cleanup; + } + } - /* Extract the socket from the curl handle - we'll need it for waiting. - * Note that this API takes a pointer to a 'long' while we use - * curl_socket_t for sockets otherwise. - */ - + { + CURLcode infoResult; #if LIBCURL_VERSION_NUM >= 0x072D00 // Version 7.45.00 - res = curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sockextr); + infoResult = curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sockextr); #else - res = curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, &sockextr); + long lastSocket = -1; + infoResult = curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, &lastSocket); + if (infoResult == CURLE_OK) + { + sockextr = static_cast(lastSocket); + } #endif - - if(CURLE_OK != res) - { - DispatchEvent(OnConnectFailed); // couldn't connect - stage 2 - TRACE("Error #2: %s\n", curl_easy_strerror(res)); - goto cleanup; + if(CURLE_OK != infoResult || sockextr == CURL_SOCKET_BAD) + { + res = static_cast( + infoResult != CURLE_OK ? infoResult : CURLE_COULDNT_CONNECT); + DispatchEvent(OnConnectFailed); // couldn't connect - stage 2 + TRACE("Error #2: %s\n", curl_easy_strerror(static_cast(res))); + goto cleanup; + } } /* wait for the socket to become ready for sending */ sockfd = sockextr; - if( !WaitOnSocket(sockfd, 0, HTTP_CONN_TIMEOUT * 1000L) || isAborted) + socketWaitResult = WaitOnSocket(sockfd, 0, HTTP_CONN_TIMEOUT * 1000L); + if(socketWaitResult <= 0 || isAborted) { TRACE("Error #3: timeout, aborted=%u\n", isAborted.load() ); res = CURLE_OPERATION_TIMEDOUT; @@ -248,27 +297,46 @@ class CurlHttpOperation { } // once connection is there - switch back to easy perform for HTTP post - curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 0); + if (!SetOption(CURLOPT_CONNECT_ONLY, 0L)) + { + DispatchEvent(OnSendFailed); + goto cleanup; + } // send all data to our callback function if (rawResponse) { - curl_easy_setopt(curl, CURLOPT_HEADER, true); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (void *)&WriteMemoryCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response); - } else { - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (void *)&WriteVectorCallback); - curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void *)&respHeaders); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&respBody); + if (!SetOption(CURLOPT_HEADER, 1L) + || !SetOption(CURLOPT_WRITEFUNCTION, + static_cast(&WriteMemoryCallback)) + || !SetOption(CURLOPT_WRITEDATA, static_cast(&response))) + { + DispatchEvent(OnSendFailed); + goto cleanup; + } + } + else if (!SetOption(CURLOPT_WRITEFUNCTION, + static_cast(&WriteVectorCallback)) + || !SetOption(CURLOPT_HEADERFUNCTION, + static_cast(&WriteVectorCallback)) + || !SetOption(CURLOPT_HEADERDATA, static_cast(&respHeaders)) + || !SetOption(CURLOPT_WRITEDATA, static_cast(&respBody))) + { + DispatchEvent(OnSendFailed); + goto cleanup; } // TODO: only two methods supported for now - POST and GET if (m_method.compare("POST") == 0) { // POST - curl_easy_setopt(curl, CURLOPT_POST, true); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, static_cast(request)); - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, reqSize); + if (!SetOption(CURLOPT_POST, 1L) + || !SetOption(CURLOPT_POSTFIELDS, static_cast(request)) + || !SetOption(CURLOPT_POSTFIELDSIZE_LARGE, static_cast(reqSize))) + { + DispatchEvent(OnSendFailed); + goto cleanup; + } } else if (m_method.compare("GET") == 0) { @@ -280,16 +348,23 @@ class CurlHttpOperation { goto cleanup; } - curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 30L); - curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 4096); - DispatchEvent(OnSending); - res = curl_easy_perform(curl); - if(CURLE_OK != res) + if (!SetOption(CURLOPT_LOW_SPEED_TIME, 30L) + || !SetOption(CURLOPT_LOW_SPEED_LIMIT, 4096L)) { DispatchEvent(OnSendFailed); - TRACE("Error: %s\n", curl_easy_strerror(res)); goto cleanup; } + DispatchEvent(OnSending); + { + const CURLcode curlResult = curl_easy_perform(curl); + res = static_cast(curlResult); + if(CURLE_OK != curlResult) + { + DispatchEvent(OnSendFailed); + TRACE("Error: %s\n", curl_easy_strerror(curlResult)); + goto cleanup; + } + } /* Code snippet to parse raw HTTP response. This might come in handy * if we ever consider to handle the raw upload instead of curl_easy_perform @@ -303,7 +378,17 @@ class CurlHttpOperation { */ /* libcurl is nice enough to parse the response code itself: */ - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res); + { + long responseCode = 0; + const CURLcode infoResult = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode); + if (infoResult != CURLE_OK) + { + res = static_cast(infoResult); + DispatchEvent(OnSendFailed); + goto cleanup; + } + res = responseCode; + } // We got some response from server. Dump the contents. TRACE("HTTP response code %d\n", res); DispatchEvent(OnResponse); @@ -436,7 +521,7 @@ class CurlHttpOperation { const size_t httpConnTimeout; // Timeout for connect. Default: 5s CURL *curl; // Local curl instance - CURLcode res = CURLE_OK; // Curl result OR HTTP status code if successful + long res = CURLE_OK; // Curl result OR HTTP status code if successful IHttpResponseCallback* m_callback = nullptr; @@ -444,6 +529,7 @@ class CurlHttpOperation { std::string m_method; std::string m_url; std::string m_sslCaInfo; + bool m_isConfigured = false; // The SDK upload path keeps the owning IHttpRequest alive through the // callback context until Send() completes; copying this body would duplicate // every upload payload. Unlike CURLOPT_CAINFO, the body pointer is set and @@ -458,7 +544,7 @@ class CurlHttpOperation { // Socket parameters curl_socket_t sockfd = 0; - long sockextr = 0; + curl_socket_t sockextr = CURL_SOCKET_BAD; curl_off_t nread = 0; size_t sendlen = 0; // # bytes sent by client @@ -466,6 +552,20 @@ class CurlHttpOperation { std::future result; + template + bool SetOption(CURLoption option, TValue value) + { + const CURLcode optionResult = curl_easy_setopt(curl, option, value); + if (optionResult != CURLE_OK) + { + res = static_cast(optionResult); + TRACE("curl_easy_setopt(%d) failed: %s\n", + static_cast(option), curl_easy_strerror(optionResult)); + return false; + } + return true; + } + /** * Helper routine to wait for data on socket * @@ -507,7 +607,7 @@ class CurlHttpOperation { * @param userp * @return */ - static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) + static size_t WriteMemoryCallback(char *contents, size_t size, size_t nmemb, void *userp) { // Guard the size * nmemb product against size_t overflow before using it. if (nmemb != 0 && size > static_cast(-1) / nmemb) { @@ -551,14 +651,15 @@ class CurlHttpOperation { * @param data * @return */ - static size_t WriteVectorCallback(void *ptr, size_t size, size_t nmemb, std::vector* data) + static size_t WriteVectorCallback(char *ptr, size_t size, size_t nmemb, void* userp) { // Guard the size * nmemb product against size_t overflow before using it. if (nmemb != 0 && size > static_cast(-1) / nmemb) { return 0; } + size_t realsize = size * nmemb; + auto* data = static_cast*>(userp); if (data != nullptr) { - size_t realsize = size * nmemb; // SECURITY: bound the buffered response (see kMaxResponseBytes). Compare // overflow-safely (data->size() is always <= kMaxResponseBytes here). // Returning a short count aborts the transfer with CURLE_WRITE_ERROR. @@ -566,11 +667,11 @@ class CurlHttpOperation { TRACE("Response exceeds max buffered size (%zu bytes); aborting transfer\n", kMaxResponseBytes); return 0; } - const auto* begin = static_cast(ptr); + const auto* begin = reinterpret_cast(ptr); const auto* end = begin + realsize; data->insert( data->end(), begin, end); } - return size * nmemb; + return realsize; } }; diff --git a/lib/include/CMakeLists.txt b/lib/include/CMakeLists.txt index c5a0eb9f6..029c3ded0 100644 --- a/lib/include/CMakeLists.txt +++ b/lib/include/CMakeLists.txt @@ -11,22 +11,24 @@ set(MATSDK_PUBLIC_HEADER_INSTALL_EXCLUDES PATTERN "*.template" EXCLUDE ) -if(MATSDK_USE_VCPKG_DEPS) - # GitHub source archives used by the public vcpkg port do not include the - # private lib/modules submodule, so do not install public headers whose - # exported factories/functions are implemented only by those modules. +if(NOT EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/filter") + list(APPEND MATSDK_PUBLIC_HEADER_INSTALL_EXCLUDES + PATTERN "CompliantByDefaultFilterApi.hpp" EXCLUDE) +endif() +if(NOT EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/exp") list(APPEND MATSDK_PUBLIC_HEADER_INSTALL_EXCLUDES - PATTERN "CompliantByDefaultFilterApi.hpp" EXCLUDE PATTERN "IAFDClient.hpp" EXCLUDE - PATTERN "ICdsFactory.hpp" EXCLUDE - PATTERN "IECSClient.hpp" EXCLUDE - ) + PATTERN "IECSClient.hpp" EXCLUDE) +endif() +if(NOT EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/cds") + list(APPEND MATSDK_PUBLIC_HEADER_INSTALL_EXCLUDES + PATTERN "ICdsFactory.hpp" EXCLUDE) endif() install( DIRECTORY public/ DESTINATION - include/mat + ${CMAKE_INSTALL_INCLUDEDIR}/mat ${MATSDK_PUBLIC_HEADER_INSTALL_EXCLUDES} ) diff --git a/lib/pal/posix/NetworkInformationImpl_Android.cpp b/lib/pal/posix/NetworkInformationImpl_Android.cpp index 04f1960f5..15e2d646d 100644 --- a/lib/pal/posix/NetworkInformationImpl_Android.cpp +++ b/lib/pal/posix/NetworkInformationImpl_Android.cpp @@ -46,7 +46,7 @@ namespace PAL_NS_BEGIN { m_cost(NetworkCost_Unknown), m_info_helper(), m_registeredCount(0), - m_isNetDetectEnabled(configuration[CFG_BOOL_ENABLE_NET_DETECT]){}; + m_isNetDetectEnabled(configuration[CFG_BOOL_ENABLE_NET_DETECT]){} NetworkInformationImpl::~NetworkInformationImpl() {}; diff --git a/lib/system/EventProperties.cpp b/lib/system/EventProperties.cpp index 2ade77741..71d5f4c5b 100644 --- a/lib/system/EventProperties.cpp +++ b/lib/system/EventProperties.cpp @@ -474,7 +474,7 @@ namespace MAT_NS_BEGIN { evt_prop* EventProperties::pack() { size_t size = m_storage->properties.size() + m_storage->propertiesPartB.size() + 1; - evt_prop * result = static_cast(calloc(sizeof(evt_prop), size)); + evt_prop * result = static_cast(calloc(size, sizeof(evt_prop))); if (result==nullptr) { LOG_ERROR("Unable to allocate memory to pack EventProperties"); @@ -620,4 +620,3 @@ namespace MAT_NS_BEGIN { } MAT_NS_END - diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a1d0a1351..216590ebd 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,11 +1,24 @@ -include_directories(. ${CMAKE_CURRENT_SOURCE_DIR}/../lib/include/public ${CMAKE_CURRENT_SOURCE_DIR}/../lib/include/mat ${CMAKE_CURRENT_SOURCE_DIR}/../lib/decoder ${CMAKE_CURRENT_SOURCE_DIR}/../sqlite ) - -include_directories( +add_library(matsdk_test_config INTERFACE) +target_link_libraries(matsdk_test_config INTERFACE matsdk_internal_config) +target_include_directories(matsdk_test_config INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../lib + ${CMAKE_CURRENT_SOURCE_DIR}/../lib/include + ${CMAKE_CURRENT_SOURCE_DIR}/../lib/include/public + ${CMAKE_CURRENT_SOURCE_DIR}/../lib/include/mat + ${CMAKE_CURRENT_SOURCE_DIR}/../lib/decoder + ${CMAKE_CURRENT_SOURCE_DIR}/../lib/pal + ${CMAKE_CURRENT_SOURCE_DIR}/../lib/utils + ${CMAKE_CURRENT_SOURCE_DIR}/../sqlite ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/googletest/googletest/include - ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/googletest/googlemock/include -) + ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/googletest/googlemock/include) +if(NOT MATSDK_USES_NLOHMANN_TARGET) + target_include_directories(matsdk_test_config INTERFACE ${PROJECT_SOURCE_DIR}) +endif() -include_directories(../lib) +if(NOT TARGET gtest OR NOT TARGET gmock) + message(FATAL_ERROR "gtest/gmock targets were not configured.") +endif() set(TESTS_COMMON_SRCS ../common/Common.cpp @@ -14,11 +27,12 @@ set(TESTS_COMMON_SRCS ../../lib/decoder/PayloadDecoder.cpp ) -if(BUILD_FUNC_TESTS) +if(MATSDK_BUILD_FUNC_TESTS) add_subdirectory(functests) endif() -if(BUILD_UNIT_TESTS) - include_directories(${CMAKE_CURRENT_SOURCE_DIR}/unittests) +if(MATSDK_BUILD_UNIT_TESTS) + target_include_directories(matsdk_test_config INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/unittests) add_subdirectory(unittests) endif() diff --git a/tests/embedding/CMakeLists.txt b/tests/embedding/CMakeLists.txt new file mode 100644 index 000000000..d1bde3138 --- /dev/null +++ b/tests/embedding/CMakeLists.txt @@ -0,0 +1,80 @@ +cmake_minimum_required(VERSION 3.15...3.31) +project(cpp-client-telemetry_embedding_test LANGUAGES C CXX) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(BUILD_SHARED_LIBS OFF CACHE BOOL "") +set(MATSDK_BUILD_HEADERS ON CACHE BOOL "" FORCE) +set(MATSDK_BUILD_LIBRARY ON CACHE BOOL "" FORCE) +set(MATSDK_BUILD_TEST_TOOL OFF CACHE BOOL "" FORCE) +set(MATSDK_BUILD_UNIT_TESTS OFF CACHE BOOL "" FORCE) +set(MATSDK_BUILD_FUNC_TESTS OFF CACHE BOOL "" FORCE) +set(MATSDK_BUILD_PACKAGE OFF CACHE BOOL "" FORCE) +set(MATSDK_BUILD_OBJC_WRAPPER OFF CACHE BOOL "" FORCE) +set(MATSDK_BUILD_SWIFT_WRAPPER OFF CACHE BOOL "" FORCE) +set(MATSDK_WARNINGS_AS_ERRORS ON CACHE BOOL "" FORCE) + +option(MATSDK_EMBEDDING_PRELOAD_CURL + "Pre-create CURL::libcurl and disable subsequent package discovery" OFF) +if(MATSDK_EMBEDDING_PRELOAD_CURL) + find_path(MATSDK_TEST_CURL_INCLUDE_DIR curl/curl.h) + find_library(MATSDK_TEST_CURL_LIBRARY NAMES curl) + if(NOT MATSDK_TEST_CURL_INCLUDE_DIR OR NOT MATSDK_TEST_CURL_LIBRARY) + message(FATAL_ERROR "System curl headers/library were not found.") + endif() + add_library(matsdk_test_curl INTERFACE) + target_include_directories(matsdk_test_curl INTERFACE + "${MATSDK_TEST_CURL_INCLUDE_DIR}") + target_link_libraries(matsdk_test_curl INTERFACE + "${MATSDK_TEST_CURL_LIBRARY}") + add_library(CURL::libcurl ALIAS matsdk_test_curl) + set(CMAKE_DISABLE_FIND_PACKAGE_CURL ON CACHE BOOL "" FORCE) +endif() + +option(MATSDK_EMBEDDING_PRELOAD_STORAGE_DEPS + "Pre-create SQLite::SQLite3/ZLIB::ZLIB and disable later discovery" OFF) +if(MATSDK_EMBEDDING_PRELOAD_STORAGE_DEPS) + find_path(MATSDK_TEST_SQLITE_INCLUDE_DIR sqlite3.h) + find_library(MATSDK_TEST_SQLITE_LIBRARY NAMES sqlite3) + find_path(MATSDK_TEST_ZLIB_INCLUDE_DIR zlib.h) + find_library(MATSDK_TEST_ZLIB_LIBRARY NAMES z zlib) + if(NOT MATSDK_TEST_SQLITE_INCLUDE_DIR OR NOT MATSDK_TEST_SQLITE_LIBRARY + OR NOT MATSDK_TEST_ZLIB_INCLUDE_DIR OR NOT MATSDK_TEST_ZLIB_LIBRARY) + message(FATAL_ERROR "System SQLite/zlib headers or libraries were not found.") + endif() + add_library(matsdk_test_sqlite INTERFACE) + target_include_directories(matsdk_test_sqlite INTERFACE + "${MATSDK_TEST_SQLITE_INCLUDE_DIR}") + target_link_libraries(matsdk_test_sqlite INTERFACE + "${MATSDK_TEST_SQLITE_LIBRARY}") + add_library(SQLite::SQLite3 ALIAS matsdk_test_sqlite) + add_library(matsdk_test_zlib INTERFACE) + target_include_directories(matsdk_test_zlib INTERFACE + "${MATSDK_TEST_ZLIB_INCLUDE_DIR}") + target_link_libraries(matsdk_test_zlib INTERFACE + "${MATSDK_TEST_ZLIB_LIBRARY}") + add_library(ZLIB::ZLIB ALIAS matsdk_test_zlib) + set(CMAKE_DISABLE_FIND_PACKAGE_SQLite3 ON CACHE BOOL "" FORCE) + set(CMAKE_DISABLE_FIND_PACKAGE_ZLIB ON CACHE BOOL "" FORCE) +endif() + +option(MATSDK_EMBEDDING_USE_FETCHCONTENT + "Exercise local-source FetchContent instead of add_subdirectory" OFF) +if(MATSDK_EMBEDDING_USE_FETCHCONTENT) + include(FetchContent) + FetchContent_Declare(cpp_client_telemetry + SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../..") + FetchContent_MakeAvailable(cpp_client_telemetry) +else() + add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../.." cpp_client_telemetry) +endif() + +add_executable(embedding_test "${CMAKE_CURRENT_LIST_DIR}/../vcpkg/main.cpp") +target_link_libraries(embedding_test PRIVATE MSTelemetry::mat) +if(MSVC) + target_compile_options(embedding_test PRIVATE /W4 /WX) +else() + target_compile_options(embedding_test PRIVATE -Wall -Wextra -Werror) +endif() diff --git a/tests/functests/CMakeLists.txt b/tests/functests/CMakeLists.txt index d09e31f62..90727d5cd 100644 --- a/tests/functests/CMakeLists.txt +++ b/tests/functests/CMakeLists.txt @@ -7,15 +7,16 @@ set(SRCS Main.cpp MultipleLogManagersTests.cpp ) +set(MATSDK_FUNC_TEST_DEFINITIONS) -if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/privacyguard/" AND BUILD_PRIVACYGUARD) - add_definitions(-DHAVE_MAT_PRIVACYGUARD) +if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/privacyguard/" AND MATSDK_BUILD_PRIVACYGUARD) + list(APPEND MATSDK_FUNC_TEST_DEFINITIONS HAVE_MAT_PRIVACYGUARD) list(APPEND SRCS "${PROJECT_SOURCE_DIR}/lib/modules/privacyguard/tests/functests/PrivacyGuardFuncTests.cpp" ) endif() -if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/sanitizer/" AND BUILD_SANITIZER) +if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/sanitizer/" AND MATSDK_BUILD_SANITIZER) list(APPEND SRCS "${PROJECT_SOURCE_DIR}/lib/modules/sanitizer/tests/functests/SanitizerFuncTests.cpp" ) @@ -27,8 +28,8 @@ if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/dataviewer/") ) endif() -if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/liveeventinspector/" AND BUILD_LIVEEVENTINSPECTOR) - add_definitions(-DHAVE_MAT_LIVEEVENTINSPECTOR) +if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/liveeventinspector/" AND MATSDK_BUILD_LIVEEVENTINSPECTOR) + list(APPEND MATSDK_FUNC_TEST_DEFINITIONS HAVE_MAT_LIVEEVENTINSPECTOR) list(APPEND SRCS "${PROJECT_SOURCE_DIR}/lib/modules/liveeventinspector/tests/functests/LiveEventInspectorFuncTests.cpp" ) @@ -48,110 +49,24 @@ endif() source_group(" " REGULAR_EXPRESSION "") source_group("common" REGULAR_EXPRESSION "/tests/common/") -if(BUILD_IOS) +if(MATSDK_PLATFORM_IOS) add_library(FuncTests ${SRCS} ${TESTS_COMMON_SRCS}) else() add_executable(FuncTests ${SRCS} ${TESTS_COMMON_SRCS}) endif() +target_link_libraries(FuncTests PRIVATE matsdk_test_config) +if(MATSDK_FUNC_TEST_DEFINITIONS) + target_compile_definitions(FuncTests PRIVATE ${MATSDK_FUNC_TEST_DEFINITIONS}) +endif() -if(PAL_IMPLEMENTATION STREQUAL "WIN32") - # Link against prebuilt libraries on Windows - message(STATUS "WIN32: Linking against prebuilt libraries") - message(STATUS "WIN32: ... ${PROJECT_BINARY_DIR}/gtest") - message(STATUS "WIN32: ... ${PROJECT_BINARY_DIR}/gmock") - message(STATUS "WIN32: ... ${PROJECT_BINARY_DIR}/zlib") - message(STATUS "WIN32: ... ${PROJECT_BINARY_DIR}/sqlite") - # link_directories(${PROJECT_BINARY_DIR}/gtest/ ${PROJECT_BINARY_DIR}/gmock/ ${PROJECT_BINARY_DIR}/zlib/ ${PROJECT_BINARY_DIR}/sqlite/) - include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../../zlib ) - target_link_libraries(FuncTests - mat - wininet.lib - ${PROJECT_BINARY_DIR}/gtest/gtest.lib - ${PROJECT_BINARY_DIR}/gmock/gmock.lib - ${PROJECT_BINARY_DIR}/zlib/zlib.lib - ${PROJECT_BINARY_DIR}/sqlite/sqlite.lib - ) -else() - - # Prefer the SDK's bundled sqlite3 when present (e.g. the Android legacy - # build, where the NDK has no system sqlite3), then a more recent local - # sqlite3, otherwise the system library. - if(TARGET sqlite3_bundled) - set (SQLITE3_LIB sqlite3_bundled) - elseif(EXISTS "/usr/local/lib/libsqlite3.a") - set (SQLITE3_LIB "/usr/local/lib/libsqlite3.a") - elseif(EXISTS "/usr/local/opt/sqlite/lib/libsqlite3.a") - set (SQLITE3_LIB "/usr/local/opt/sqlite/lib/libsqlite3.a") - else() - find_package(SQLite3 REQUIRED) - set (SQLITE3_LIB SQLite::SQLite3) - endif() - - if(TARGET zlib_bundled) - set(MATSDK_TEST_ZLIB zlib_bundled) - else() - find_package( ZLIB REQUIRED ) - set(MATSDK_TEST_ZLIB ZLIB::ZLIB) - include_directories( ${ZLIB_INCLUDE_DIRS} ) - endif() - - set (PLATFORM_LIBS "") - # Add flags for obtaining system UUID via IOKit - if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") - set (PLATFORM_LIBS "-framework CoreFoundation -framework Foundation") - if(BUILD_IOS) - set (PLATFORM_LIBS "${PLATFORM_LIBS} -framework UIKit -framework Network -framework SystemConfiguration") - else() - set (PLATFORM_LIBS "${PLATFORM_LIBS} -framework IOKit -framework Network -framework SystemConfiguration") - endif() - endif() - - # Raspberry Pi 4 with gcc-8 on ARMv7l requires -latomic - if (CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l") - set (PLATFORM_LIBS "atomic") - endif() - - message(STATUS "Linking libraries") - message(STATUS "Current Dir: ${CMAKE_CURRENT_SOURCE_DIR}") - message(STATUS "Binary Dir: ${PROJECT_BINARY_DIR}") - - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) - - find_file(LIBGTEST - NAMES libgtest.a - PATHS - ${CMAKE_CURRENT_SOURCE_DIR}/../../third_party/googletest/build/lib/ - ) - - find_file(LIBGMOCK - NAMES libgmock.a - PATHS - ${CMAKE_CURRENT_SOURCE_DIR}/../../third_party/googletest/build/lib/ - ) - - target_link_libraries(FuncTests - ${LIBGTEST} - ${LIBGMOCK} - mat - ${MATSDK_TEST_ZLIB} - ${SQLITE3_LIB} - ${PLATFORM_LIBS} - dl) - - # Link curl only when the SDK actually uses the curl HTTP client (Linux, and - # macOS without Apple HTTP). The tests don't use curl directly, and on the - # Android legacy path mat uses HttpClient_Android (no system curl in the NDK). - # MATSDK_NEEDS_CURL already excludes iOS/Apple-HTTP. Prefer the CURL::libcurl - # imported target (correct under vcpkg, matches ZLIB::ZLIB above) and fall back - # to the find-module variables on CMake < 3.12, which does not define it. - if(MATSDK_NEEDS_CURL) - if(TARGET CURL::libcurl) - target_link_libraries(FuncTests CURL::libcurl) - else() - target_link_libraries(FuncTests ${CURL_LIBRARIES}) - endif() - endif() - +target_link_libraries(FuncTests PRIVATE + mat + SQLite::SQLite3 + ZLIB::ZLIB + gtest + gmock) +if(TARGET nlohmann_json::nlohmann_json) + target_link_libraries(FuncTests PRIVATE nlohmann_json::nlohmann_json) endif() add_test(FuncTests FuncTests "--gtest_output=xml:${PROJECT_BINARY_DIR}/test-reports/FuncTests.xml") diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt index 7233d2920..3eb112941 100644 --- a/tests/unittests/CMakeLists.txt +++ b/tests/unittests/CMakeLists.txt @@ -51,17 +51,18 @@ set(SRCS UtilsTests.cpp ZlibUtilsTests.cpp ) +set(MATSDK_UNIT_TEST_DEFINITIONS) set_source_files_properties(${SRCS} PROPERTIES COMPILE_FLAGS -Wno-deprecated-declarations) # Enable Azure Monitor unit tests when the module is present. # The AIJsonSerializer test sources are guarded by HAVE_MAT_AI. if (EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/azmon/AIJsonSerializer.hpp") - add_definitions(-DHAVE_MAT_AI) + list(APPEND MATSDK_UNIT_TEST_DEFINITIONS HAVE_MAT_AI) endif() if (APPLE) - if (BUILD_IOS) + if (MATSDK_PLATFORM_IOS) list(APPEND SRCS SysInfoUtilsTests_iOS.cpp) else() list(APPEND SRCS SysInfoUtilsTests_Mac.cpp) @@ -76,8 +77,8 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/exp/tests") ) endif() -if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/privacyguard/" AND BUILD_PRIVACYGUARD) - add_definitions(-DHAVE_MAT_PRIVACYGUARD) +if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/privacyguard/" AND MATSDK_BUILD_PRIVACYGUARD) + list(APPEND MATSDK_UNIT_TEST_DEFINITIONS HAVE_MAT_PRIVACYGUARD) list(APPEND SRCS "${PROJECT_SOURCE_DIR}/lib/modules/privacyguard/tests/unittests/InitializationConfigurationTests.cpp" "${PROJECT_SOURCE_DIR}/lib/modules/privacyguard/tests/unittests/PrivacyConcernEventTests.cpp" @@ -87,7 +88,7 @@ if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/privacyguard/" AND BUILD_PRIVACYGUA ) endif() -if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/sanitizer/" AND BUILD_SANITIZER) +if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/sanitizer/" AND MATSDK_BUILD_SANITIZER) list(APPEND SRCS "${PROJECT_SOURCE_DIR}/lib/modules/sanitizer/tests/unittests/SanitizerJwtTests.cpp" "${PROJECT_SOURCE_DIR}/lib/modules/sanitizer/tests/unittests/SanitizerProviderTests.cpp" @@ -109,116 +110,24 @@ endif() source_group(" " REGULAR_EXPRESSION "") source_group("common" REGULAR_EXPRESSION "/tests/common/") -if(BUILD_IOS) +if(MATSDK_PLATFORM_IOS) add_library(UnitTests STATIC ${SRCS} ${TESTS_COMMON_SRCS}) else() add_executable(UnitTests ${SRCS} ${TESTS_COMMON_SRCS}) endif() +target_link_libraries(UnitTests PRIVATE matsdk_test_config) +if(MATSDK_UNIT_TEST_DEFINITIONS) + target_compile_definitions(UnitTests PRIVATE ${MATSDK_UNIT_TEST_DEFINITIONS}) +endif() -if(PAL_IMPLEMENTATION STREQUAL "WIN32") - # Link against prebuilt libraries on Windows - message(STATUS "WIN32: Linking against prebuilt libraries") - message(STATUS "WIN32: ... ${PROJECT_BINARY_DIR}/gtest") - message(STATUS "WIN32: ... ${PROJECT_BINARY_DIR}/gmock") - message(STATUS "WIN32: ... ${PROJECT_BINARY_DIR}/zlib") - message(STATUS "WIN32: ... ${PROJECT_BINARY_DIR}/sqlite") - # link_directories(${PROJECT_BINARY_DIR}/gtest/ ${PROJECT_BINARY_DIR}/gmock/ ${PROJECT_BINARY_DIR}/zlib/ ${PROJECT_BINARY_DIR}/sqlite/) - include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../../zlib ) - target_link_libraries(UnitTests - mat - wininet.lib - ${PROJECT_BINARY_DIR}/gtest/gtest.lib - ${PROJECT_BINARY_DIR}/gmock/gmock.lib - ${PROJECT_BINARY_DIR}/zlib/zlib.lib - ${PROJECT_BINARY_DIR}/sqlite/sqlite.lib - ) -else() - - # Prefer the SDK's bundled sqlite3 when present (e.g. the Android legacy - # build, where the NDK has no system sqlite3), then a more recent local - # sqlite3, otherwise the system library. - if(TARGET sqlite3_bundled) - set (SQLITE3_LIB sqlite3_bundled) - elseif(EXISTS "/usr/local/lib/libsqlite3.a") - set (SQLITE3_LIB "/usr/local/lib/libsqlite3.a") - elseif(EXISTS "/usr/local/opt/sqlite/lib/libsqlite3.a") - set (SQLITE3_LIB "/usr/local/opt/sqlite/lib/libsqlite3.a") - elseif(EXISTS "/opt/homebrew/opt/sqlite/lib/libsqlite3.a") - # Apple Silicon homebrew installs to /opt/homebrew instead of /usr/local - set (SQLITE3_LIB "/opt/homebrew/opt/sqlite/lib/libsqlite3.a") - else() - find_package(SQLite3 REQUIRED) - set (SQLITE3_LIB SQLite::SQLite3) - endif() - - if(TARGET zlib_bundled) - set(MATSDK_TEST_ZLIB zlib_bundled) - else() - find_package( ZLIB REQUIRED ) - set(MATSDK_TEST_ZLIB ZLIB::ZLIB) - include_directories( ${ZLIB_INCLUDE_DIRS} ) - endif() - - set (PLATFORM_LIBS "") - # Add flags for obtaining system UUID via IOKit - if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") - set (PLATFORM_LIBS "-framework CoreFoundation -framework IOKit -framework SystemConfiguration -framework Foundation -framework Network") - if(BUILD_IOS) - set (PLATFORM_LIBS "${PLATFORM_LIBS} -framework UIKit") - endif() - endif() - - # Raspberry Pi 4 with gcc-8 on ARMv7l requires -latomic - if (CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l") - set (PLATFORM_LIBS "atomic") - endif() - - message(STATUS "Linking libraries") - message(STATUS "Current Dir: ${CMAKE_CURRENT_SOURCE_DIR}") - message(STATUS "Binary Dir: ${PROJECT_BINARY_DIR}") - - include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../../lib/ ) - - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) - - find_file(LIBGTEST - NAMES libgtest.a - PATHS - ${CMAKE_CURRENT_SOURCE_DIR}/../../third_party/googletest/build/lib/ - ) - - find_file(LIBGMOCK - NAMES libgmock.a - PATHS - ${CMAKE_CURRENT_SOURCE_DIR}/../../third_party/googletest/build/lib/ - ) - - message(STATUS "GTEST: ${LIBGTEST}") - message(STATUS "GMOCK: ${LIBGMOCK}") - - target_link_libraries(UnitTests - ${LIBGTEST} - ${LIBGMOCK} - mat - ${MATSDK_TEST_ZLIB} - ${SQLITE3_LIB} - ${PLATFORM_LIBS} - dl) - - # Link curl only when the SDK actually uses the curl HTTP client (Linux, and - # macOS without Apple HTTP). The tests don't use curl directly, and on the - # Android legacy path mat uses HttpClient_Android (no system curl in the NDK). - # MATSDK_NEEDS_CURL already excludes iOS/Apple-HTTP. Prefer the CURL::libcurl - # imported target (correct under vcpkg, matches ZLIB::ZLIB above) and fall back - # to the find-module variables on CMake < 3.12, which does not define it. - if(MATSDK_NEEDS_CURL) - if(TARGET CURL::libcurl) - target_link_libraries(UnitTests CURL::libcurl) - else() - target_link_libraries(UnitTests ${CURL_LIBRARIES}) - endif() - endif() - +target_link_libraries(UnitTests PRIVATE + mat + SQLite::SQLite3 + ZLIB::ZLIB + gtest + gmock) +if(TARGET nlohmann_json::nlohmann_json) + target_link_libraries(UnitTests PRIVATE nlohmann_json::nlohmann_json) endif() add_test(UnitTests UnitTests "--gtest_output=xml:${PROJECT_BINARY_DIR}/test-reports/UnitTests.xml") diff --git a/tests/unittests/HttpClientCurlTests.cpp b/tests/unittests/HttpClientCurlTests.cpp index d494ba2fc..00556471d 100644 --- a/tests/unittests/HttpClientCurlTests.cpp +++ b/tests/unittests/HttpClientCurlTests.cpp @@ -57,6 +57,15 @@ TEST_F(HttpClientCurlTests, CurlHttpOperation_ConstructsWithCaInfo) ASSERT_NE(op.GetHandle(), nullptr); } +TEST(HttpClientCurlOperationTests, SelectsHttp2OnlyWhenRuntimeSupportsIt) +{ + const curl_version_info_data* versionInfo = curl_version_info(CURLVERSION_NOW); + const long expected = (versionInfo != nullptr && (versionInfo->features & CURL_VERSION_HTTP2) != 0) + ? CURL_HTTP_VERSION_2_0 + : CURL_HTTP_VERSION_1_1; + EXPECT_EQ(CurlHttpOperation::GetPreferredHttpVersion(), expected); +} + // --- ILogConfiguration integration --- TEST(HttpClientCurlConfigTests, LogConfiguration_SslVerify_DefaultIsTrue) diff --git a/tests/vcpkg/test-vcpkg-windows.ps1 b/tests/vcpkg/test-vcpkg-windows.ps1 index b1390425a..5073daa56 100644 --- a/tests/vcpkg/test-vcpkg-windows.ps1 +++ b/tests/vcpkg/test-vcpkg-windows.ps1 @@ -11,7 +11,6 @@ $ErrorActionPreference = "Stop" $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $RepoRoot = (Resolve-Path (Join-Path $ScriptDir "..\..")).Path -$BuildDir = Join-Path $ScriptDir "build-windows" $OverlayPorts = Join-Path $RepoRoot "tools\ports" # Build the working tree under review (not a pinned release) so this test @@ -56,6 +55,7 @@ if ([string]::IsNullOrEmpty($Triplet)) { $Triplet = "x64-windows-static" } } +$BuildDir = Join-Path $ScriptDir "build-windows-$Triplet" # Map triplet to vcvarsall architecture $VcvarsArch = switch -Regex ($Triplet) { diff --git a/tools/ports/cpp-client-telemetry/portfile.cmake b/tools/ports/cpp-client-telemetry/portfile.cmake index b2fdab830..6b0995242 100644 --- a/tools/ports/cpp-client-telemetry/portfile.cmake +++ b/tools/ports/cpp-client-telemetry/portfile.cmake @@ -33,7 +33,7 @@ if(NOT DEFINED SOURCE_PATH) endif() # Determine if Apple HTTP should be used (no curl needed). -# Note: BUILD_APPLE_HTTP must remain ON for macOS/iOS because the vcpkg.json +# Note: MATSDK_BUILD_APPLE_HTTP must remain ON for macOS/iOS because the vcpkg.json # curl dependency is excluded on these platforms. set(MATSDK_BUILD_APPLE_HTTP OFF) if(VCPKG_TARGET_IS_OSX OR VCPKG_TARGET_IS_IOS) @@ -41,15 +41,22 @@ if(VCPKG_TARGET_IS_OSX OR VCPKG_TARGET_IS_IOS) endif() # iOS build options -set(MATSDK_BUILD_IOS OFF) +set(MATSDK_BUILD_IOS_LEGACY OFF) if(VCPKG_TARGET_IS_IOS) - set(MATSDK_BUILD_IOS ON) + set(MATSDK_BUILD_IOS_LEGACY ON) endif() set(MATSDK_ANDROID_HTTP_CLIENT AUTO) if(VCPKG_TARGET_IS_ANDROID) file(READ "${SOURCE_PATH}/CMakeLists.txt" _matsdk_root_cmake) - if(NOT _matsdk_root_cmake MATCHES "MATSDK_ANDROID_HTTP_CLIENT") + set(_matsdk_android_option_source "${_matsdk_root_cmake}") + if(EXISTS "${SOURCE_PATH}/cmake/MatsdkOptions.cmake") + file(READ "${SOURCE_PATH}/cmake/MatsdkOptions.cmake" + _matsdk_options_cmake) + string(APPEND _matsdk_android_option_source + "\n${_matsdk_options_cmake}") + endif() + if(NOT _matsdk_android_option_source MATCHES "MATSDK_ANDROID_HTTP_CLIENT") message(FATAL_ERROR "Android vcpkg builds require a cpp-client-telemetry source revision that " "supports MATSDK_ANDROID_HTTP_CLIENT. Update this port's REF/SHA512 to a " @@ -106,19 +113,47 @@ if(VCPKG_TARGET_IS_LINUX OR MATSDK_ANDROID_HTTP_CLIENT STREQUAL "CURL") endif() endif() -# minimal-sqlite -> -DMATSDK_MINIMAL_SQLITE=ON (private feature-stripped SQLite). -vcpkg_check_features( - OUT_FEATURE_OPTIONS FEATURE_OPTIONS - FEATURES - minimal-sqlite MATSDK_MINIMAL_SQLITE -) +set(MATSDK_VCPKG_SQLITE_PROVIDER SYSTEM) +if("minimal-sqlite" IN_LIST FEATURES) + set(MATSDK_VCPKG_SQLITE_PROVIDER MINIMAL) +endif() + +if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic") + set(MATSDK_VCPKG_BUILD_SHARED_LIBS ON) +else() + set(MATSDK_VCPKG_BUILD_SHARED_LIBS OFF) +endif() + +file(READ "${SOURCE_PATH}/CMakeLists.txt" MATSDK_ROOT_CMAKE) +set(MATSDK_PINNED_SOURCE_OPTIONS) +if(MATSDK_ROOT_CMAKE MATCHES "MATSDK_USE_VCPKG_DEPS") + list(APPEND MATSDK_PINNED_SOURCE_OPTIONS -DMATSDK_USE_VCPKG_DEPS=ON) +endif() +if(MATSDK_ROOT_CMAKE MATCHES "MATSDK_MINIMAL_SQLITE" + AND "minimal-sqlite" IN_LIST FEATURES) + list(APPEND MATSDK_PINNED_SOURCE_OPTIONS -DMATSDK_MINIMAL_SQLITE=ON) +endif() vcpkg_cmake_configure( SOURCE_PATH "${SOURCE_PATH}" OPTIONS - ${FEATURE_OPTIONS} - -DMATSDK_USE_VCPKG_DEPS=ON + ${MATSDK_PINNED_SOURCE_OPTIONS} + -DMATSDK_SQLITE_PROVIDER=${MATSDK_VCPKG_SQLITE_PROVIDER} + -DBUILD_SHARED_LIBS=${MATSDK_VCPKG_BUILD_SHARED_LIBS} -DMATSDK_ANDROID_HTTP_CLIENT=${MATSDK_ANDROID_HTTP_CLIENT} + -DMATSDK_BUILD_HEADERS=ON + -DMATSDK_BUILD_LIBRARY=ON + -DMATSDK_BUILD_TEST_TOOL=OFF + -DMATSDK_BUILD_UNIT_TESTS=OFF + -DMATSDK_BUILD_FUNC_TESTS=OFF + -DMATSDK_BUILD_JNI_WRAPPER=OFF + -DMATSDK_BUILD_OBJC_WRAPPER=OFF + -DMATSDK_BUILD_SWIFT_WRAPPER=OFF + -DMATSDK_BUILD_PACKAGE=OFF + -DBUILD_VERSION=${VERSION} + -DMATSDK_BUILD_APPLE_HTTP=${MATSDK_BUILD_APPLE_HTTP} + # Legacy aliases keep the pinned release fallback buildable until the + # next release contains the canonical MATSDK_* options. -DBUILD_HEADERS=ON -DBUILD_LIBRARY=ON -DBUILD_TEST_TOOL=OFF @@ -128,9 +163,8 @@ vcpkg_cmake_configure( -DBUILD_OBJC_WRAPPER=OFF -DBUILD_SWIFT_WRAPPER=OFF -DBUILD_PACKAGE=OFF - -DBUILD_VERSION=${VERSION} -DBUILD_APPLE_HTTP=${MATSDK_BUILD_APPLE_HTTP} - -DBUILD_IOS=${MATSDK_BUILD_IOS} + -DBUILD_IOS=${MATSDK_BUILD_IOS_LEGACY} ) vcpkg_cmake_install() diff --git a/tools/setup-buildtools-apple.sh b/tools/setup-buildtools-apple.sh index 83b75f091..489cf28da 100755 --- a/tools/setup-buildtools-apple.sh +++ b/tools/setup-buildtools-apple.sh @@ -57,7 +57,4 @@ cd $SQLITE_PKG ./configure && make && make install cd .. -## Build Google Test framework -./build-gtest.sh $1 - ## Install dotnet for test server diff --git a/tools/setup-buildtools.sh b/tools/setup-buildtools.sh index a5f001664..fa023f6c4 100755 --- a/tools/setup-buildtools.sh +++ b/tools/setup-buildtools.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash if [ -f /bin/yum ]; then if [ `cat /etc/redhat-release | tr -dc '0-9.'|cut -d \. -f1` == "7" ]; then @@ -30,11 +30,12 @@ echo "*********************************************************" exit 3 fi -if [ `cmake --version | grep 3` == "" ]; then +if ! command -v cmake >/dev/null 2>&1 || \ + [ "$(printf '%s\n' 3.21.7 "$(cmake --version | head -1 | awk '{print $3}')" | sort -V | head -1)" != "3.21.7" ]; then yum -y remove cmake -wget https://cmake.org/files/v3.6/cmake-3.6.2.tar.gz -tar -zxvf cmake-3.6.2.tar.gz -cd cmake-3.6.2 +wget https://cmake.org/files/v3.21/cmake-3.21.7.tar.gz +tar -zxvf cmake-3.21.7.tar.gz +cd cmake-3.21.7 ./bootstrap --prefix=/usr/local make make install @@ -72,8 +73,5 @@ cd $SQLITE_PKG ./configure && make && make install cd .. -## Build Google Test framework -./build-gtest.sh - ## Change owner from root to current dir owner chown -R `stat . -c %u:%g` *