diff --git a/.github/workflows/build-ios-mac.yml b/.github/workflows/build-ios-mac.yml index 29b3dfc34..d7687200d 100644 --- a/.github/workflows/build-ios-mac.yml +++ b/.github/workflows/build-ios-mac.yml @@ -55,14 +55,13 @@ jobs: run: | sudo chown -R $USER:staff /usr/local - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - 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 - export IOS_DEPLOYMENT_TARGET=13.0; + export CMAKE_OSX_DEPLOYMENT_TARGET=13.0; elif [[ "${{ matrix.os }}" == "macos-15" ]]; then - export IOS_DEPLOYMENT_TARGET=15.0; + export CMAKE_OSX_DEPLOYMENT_TARGET=15.0; fi ./build-tests-ios.sh ${{ matrix.config }} ${{ matrix.simulator }} diff --git a/.github/workflows/build-posix-latest.yml b/.github/workflows/build-posix-latest.yml index 7a35c5a54..dc45fe14e 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@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - 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 6c779c8b5..ca21ad8c4 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@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - 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 94397381b..6d3a0c9c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,25 +1,26 @@ cmake_minimum_required(VERSION 3.15...3.31) + 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_USING_VCPKG: ${MATSDK_USING_VCPKG}") + +include(cmake/MatsdkOptions.cmake) +include(cmake/MatsdkDependencyTargets.cmake) +if(APPLE) + include(cmake/MatsdkAppleSystemDeps.cmake) 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}") # Begin Uncomment for i386 build #set(CMAKE_SYSTEM_PROCESSOR i386) @@ -34,104 +35,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 +58,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 +112,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 +164,39 @@ 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) -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}'.") +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() - -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(MATSDK_CURL_PROVIDER_UPPER STREQUAL "FETCH" + AND 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,120 +205,133 @@ 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) - if(NOT TARGET SQLite3::SQLite3) - add_library(SQLite3::SQLite3 ALIAS SQLite::SQLite3) - endif() - 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(TARGET SQLite3::SQLite3 AND NOT TARGET SQLite::SQLite3) + add_library(SQLite::SQLite3 ALIAS SQLite3::SQLite3) +endif() +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) + matsdk_add_interface_dependency( + SQLite::SQLite3 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(TARGET SQLite::SQLite3 AND NOT TARGET SQLite3::SQLite3) + get_target_property(_matsdk_sqlite_target SQLite::SQLite3 ALIASED_TARGET) + if(_matsdk_sqlite_target) + add_library(SQLite3::SQLite3 ALIAS ${_matsdk_sqlite_target}) + else() + add_library(SQLite3::SQLite3 ALIAS SQLite::SQLite3) + endif() endif() -# Bond Lite subdirectories -include_directories(bondlite/include) +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() -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) @@ -531,14 +341,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-gtest.sh b/build-gtest.sh index 4c73f3382..4dca08f06 100755 --- a/build-gtest.sh +++ b/build-gtest.sh @@ -39,9 +39,8 @@ if(BUILD_IOS) set(CMAKE_OSX_DEPLOYMENT_TARGET "12.2" CACHE STRING "Force set of the deployment target for iOS" FORCE) set(CMAKE_C_FLAGS "\${CMAKE_C_FLAGS} -miphoneos-version-min=10.0") set(CMAKE_CXX_FLAGS "\${CMAKE_CXX_FLAGS} -miphoneos-version-min=10.0 -std=c++11") - set(IOS_PLATFORM "iphonesimulator") set(CMAKE_SYSTEM_PROCESSOR x86_64) - execute_process(COMMAND xcodebuild -version -sdk \${IOS_PLATFORM} Path + execute_process(COMMAND xcodebuild -version -sdk iphonesimulator Path OUTPUT_VARIABLE CMAKE_OSX_SYSROOT_OUT ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) diff --git a/build-ios.sh b/build-ios.sh index d316fe2fa..1ee6326c7 100755 --- a/build-ios.sh +++ b/build-ios.sh @@ -1,4 +1,10 @@ -#!/bin/sh +#!/bin/bash + +set -e + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$DIR" +. "$DIR/tools/build-common.sh" # The expected iOS build invocation is: # build-ios.sh [clean] [release|debug] ${ARCH} ${PLATFORM} @@ -7,11 +13,7 @@ # PLATFORM = iphoneos|iphonesimulator|xros|xrsimulator if [ "$1" == "clean" ]; then - echo "build-ios.sh: cleaning previous build artifacts" - rm -f CMakeCache.txt *.cmake - rm -rf out - rm -rf .buildtools -# make clean + matsdk_clean_build_outputs "build-ios.sh" shift fi @@ -25,77 +27,72 @@ elif [ "$1" == "debug" ]; then fi # Set Architecture: arm64, arm64e or x86_64 -IOS_ARCH=$(/usr/bin/uname -m) +APPLE_ARCH=$(/usr/bin/uname -m) if [ "$1" == "arm64" ]; then - IOS_ARCH="arm64" + APPLE_ARCH="arm64" shift elif [ "$1" == "arm64e" ]; then - IOS_ARCH="arm64e" + APPLE_ARCH="arm64e" shift elif [ "$1" == "x86_64" ]; then - IOS_ARCH="x86_64" + APPLE_ARCH="x86_64" shift fi # the last param is expected to specify the platform name: iphoneos|iphonesimulator|xros|xrsimulator # so if it is non-empty and it is not "device", we take it as a valid platform name # otherwise we fall back to old iOS logic which only supported iphoneos|iphonesimulator -IOS_PLAT="iphonesimulator" +APPLE_PLATFORM="iphonesimulator" if [ -n "$1" ] && [ "$1" != "device" ]; then - IOS_PLAT="$1" + APPLE_PLATFORM="$1" elif [ "$1" == "device" ]; then - IOS_PLAT="iphoneos" + APPLE_PLATFORM="iphoneos" fi -echo "IOS_ARCH = $IOS_ARCH, IOS_PLAT = $IOS_PLAT, BUILD_TYPE = $BUILD_TYPE" +echo "architecture = $APPLE_ARCH, platform = $APPLE_PLATFORM, build type = $BUILD_TYPE" -FORCE_RESET_DEPLOYMENT_TARGET=NO DEPLOYMENT_TARGET="" -if [ "$IOS_PLAT" == "iphoneos" ] || [ "$IOS_PLAT" == "iphonesimulator" ]; then +if [ "$APPLE_PLATFORM" == "iphoneos" ] || [ "$APPLE_PLATFORM" == "iphonesimulator" ]; then SYS_NAME="iOS" - DEPLOYMENT_TARGET="$IOS_DEPLOYMENT_TARGET" + DEPLOYMENT_TARGET="$CMAKE_OSX_DEPLOYMENT_TARGET" if [ -z "$DEPLOYMENT_TARGET" ]; then - DEPLOYMENT_TARGET="12.0" - FORCE_RESET_DEPLOYMENT_TARGET=YES + DEPLOYMENT_TARGET="13.0" fi -elif [ "$IOS_PLAT" == "xros" ] || [ "$IOS_PLAT" == "xrsimulator" ]; then +elif [ "$APPLE_PLATFORM" == "xros" ] || [ "$APPLE_PLATFORM" == "xrsimulator" ]; then SYS_NAME="visionOS" - DEPLOYMENT_TARGET="$XROS_DEPLOYMENT_TARGET" + DEPLOYMENT_TARGET="$CMAKE_OSX_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" -if [ ! -f $FILE ]; then - tools/setup-buildtools-apple.sh ios - # Assume that the build tools have been successfully installed - echo > $FILE -fi - -if [ -f /usr/bin/gcc ]; then - echo "gcc version: `gcc --version`" -fi - -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 - -make package +BUILD_TOOLS_MARKER=".buildtools" +matsdk_install_buildtools_once "$BUILD_TOOLS_MARKER" tools/setup-buildtools-apple.sh ios + +matsdk_print_compiler_versions +matsdk_require_cmake_preset_support + +CPACK_GENERATOR=TGZ +case "$APPLE_PLATFORM" 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=$APPLE_PLATFORM" + "-DCMAKE_OSX_ARCHITECTURES=$APPLE_ARCH" + "-DCMAKE_OSX_DEPLOYMENT_TARGET=$DEPLOYMENT_TARGET" + "-DCMAKE_BUILD_TYPE=$BUILD_TYPE" + "-DCPACK_GENERATOR=$CPACK_GENERATOR" +) +matsdk_append_cmake_opts_to_cmake_args +matsdk_run_logged_command "${cmake_args[@]}" + +matsdk_build_and_package_preset "$PRESET" 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..f701610db 100755 --- a/build.sh +++ b/build.sh @@ -32,6 +32,7 @@ export PATH=/usr/local/bin:$PATH DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" echo "Current directory: $DIR" cd $DIR +. "$DIR/tools/build-common.sh" export NOROOT=$NOROOT @@ -61,16 +62,16 @@ while [[ $# -gt 0 ]]; do echo "BUILD_TYPE = $BUILD_TYPE" ;; arm64|x86_64|universal) - if [[ -n "$MAC_ARCH" ]]; then - echo "Error: MAC_ARCH is already set to '$MAC_ARCH'. Cannot overwrite with $ARG." 1>&2 + if [[ -n "$APPLE_ARCH" ]]; then + echo "Error: APPLE_ARCH is already set to '$APPLE_ARCH'. Cannot overwrite with $ARG." 1>&2 exit 1 else - MAC_ARCH="$ARG" + APPLE_ARCH="$ARG" fi - echo "MAC_ARCH = $MAC_ARCH" + echo "APPLE_ARCH = $APPLE_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" ;; *) @@ -91,9 +92,9 @@ if [[ -z "$BUILD_TYPE" ]]; then echo "Assuming default BUILD_TYPE = Debug" fi -if [[ -z "$MAC_ARCH" ]]; then - MAC_ARCH=$(/usr/bin/uname -m) - echo "Using current machine MAC_ARCH = $MAC_ARCH" +if [[ -z "$APPLE_ARCH" ]]; then + APPLE_ARCH=$(/usr/bin/uname -m) + echo "Using current machine APPLE_ARCH = $APPLE_ARCH" fi # Evaluate switches @@ -123,11 +124,7 @@ if [[ $# -gt 0 ]]; then fi if [[ "$CLEAN" == "true" ]]; then - echo "Cleaning previous build artifacts" - rm -f CMakeCache.txt *.cmake - rm -rf out - rm -rf .buildtools - # make clean + matsdk_clean_build_outputs "build.sh" fi echo "CMAKE_OPTS from caller: $CMAKE_OPTS" @@ -137,74 +134,77 @@ if [ "$LINK_TYPE" == "shared" ]; then fi # Set target MacOS minver -default_mac_os_target=$([ "$MAC_ARCH" == "arm64" ] && echo "11.10" || echo "10.10") +default_mac_os_target=$([ "$APPLE_ARCH" == "arm64" ] && echo "11.10" || echo "10.10") [ -z $MACOSX_DEPLOYMENT_TARGET ] && export MACOSX_DEPLOYMENT_TARGET=${default_mac_os_target} echo "macosx deployment target="$MACOSX_DEPLOYMENT_TARGET # Install build tools and recent sqlite3 -FILE=.buildtools +BUILD_TOOLS_MARKER=.buildtools OS_NAME=`uname -a` -if [ ! -f $FILE ]; then +if [ ! -f "$BUILD_TOOLS_MARKER" ]; then + buildtools_cmd=() case "$OS_NAME" in - *Darwin*) CMD="tools/setup-buildtools-apple.sh $MAC_ARCH" ;; - *Linux*) CMD="tools/setup-buildtools.sh" ;; - *) CMD=""; echo "WARNING: unsupported OS $OS_NAME, skipping build tools installation.." ;; + *Darwin*) buildtools_cmd=(tools/setup-buildtools-apple.sh "$APPLE_ARCH") ;; + *Linux*) buildtools_cmd=(tools/setup-buildtools.sh) ;; + *) echo "WARNING: unsupported OS $OS_NAME, skipping build tools installation.." ;; esac - [[ -n "$CMD" ]] && { [[ -z "$NOROOT" ]] && sudo $CMD || echo "No root: skipping build tools installation."; } - echo > $FILE + if [[ ${#buildtools_cmd[@]} -gt 0 ]]; then + if [[ -z "$NOROOT" ]]; then + matsdk_try_buildtools_once "$BUILD_TOOLS_MARKER" \ + "No root: skipping build tools installation." \ + sudo "${buildtools_cmd[@]}" + else + echo "No root: skipping build tools installation." + matsdk_mark_buildtools_checked "$BUILD_TOOLS_MARKER" + fi + else + matsdk_mark_buildtools_checked "$BUILD_TOOLS_MARKER" + fi fi -if [ -f /usr/bin/gcc ]; then - echo "gcc version: `gcc --version`" -fi - -if [ -f /usr/bin/clang ]; then - echo "clang version: `clang --version`" -fi +matsdk_print_compiler_versions +matsdk_require_cmake_preset_support # 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 - -# Remove old package -rm -f *.deb *.rpm +PRESET="matsdk-$(echo "$BUILD_TYPE" | tr '[:upper:]' '[:lower:]')" +cmake_args=(cmake --preset "$PRESET") +if [[ "$OS_NAME" == *Darwin* ]]; then + if [[ "$APPLE_ARCH" == "universal" ]]; then + cmake_args+=("-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64") + else + cmake_args+=("-DCMAKE_OSX_ARCHITECTURES=$APPLE_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 +matsdk_append_cmake_opts_to_cmake_args +matsdk_run_logged_command "${cmake_args[@]}" -# Build new package -make package +rm -f out/*.deb out/*.rpm +matsdk_build_and_package_preset "$PRESET" +cd out # Install newly generated package if [ -f /usr/bin/dpkg ]; then @@ -221,7 +221,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..41ba63c0a 100644 --- a/cmake/MSTelemetryConfig.cmake.in +++ b/cmake/MSTelemetryConfig.cmake.in @@ -1,31 +1,29 @@ @PACKAGE_INIT@ include(CMakeFindDependencyMacro) +include("${CMAKE_CURRENT_LIST_DIR}/MatsdkDependencyTargets.cmake") -# 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_BUILD_PLATFORM_APPLE@) + set(_matsdk_package_sqlite_args APPLE_SYSTEM APPLE_LIBRARY sqlite3) + set(_matsdk_package_zlib_args APPLE_SYSTEM APPLE_LIBRARY z) + else() + set(_matsdk_package_sqlite_args) + set(_matsdk_package_zlib_args) + endif() + matsdk_add_package_system_dependency( + MSTelemetry::sqlite_dependency + SQLite::SQLite3 + "@MATSDK_SQLITE_PROVIDER_RESOLVED@" + SQLite3 + ${_matsdk_package_sqlite_args}) + matsdk_add_package_system_dependency( + MSTelemetry::zlib_dependency + ZLIB::ZLIB + "@MATSDK_ZLIB_PROVIDER_RESOLVED@" + ZLIB + ${_matsdk_package_zlib_args}) endif() if("@MATSDK_ANDROID_HTTP_CLIENT_RESOLVED@" STREQUAL "") @@ -45,6 +43,63 @@ 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(@MATSDK_CURL_FETCHED@) + set(_matsdk_curl_dependency_target MSTelemetry::curl_archive) + else() + set(_matsdk_curl_dependency_target CURL::libcurl) + endif() + matsdk_add_interface_dependency( + MSTelemetry::curl_dependency "${_matsdk_curl_dependency_target}") +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/MatsdkDependencyTargets.cmake b/cmake/MatsdkDependencyTargets.cmake new file mode 100644 index 000000000..c21c338de --- /dev/null +++ b/cmake/MatsdkDependencyTargets.cmake @@ -0,0 +1,40 @@ +include_guard() +set(_MATSDK_DEPENDENCY_TARGETS_DIR "${CMAKE_CURRENT_LIST_DIR}") + +function(matsdk_add_interface_dependency target_name) + if(ARGC LESS 2) + message(FATAL_ERROR + "matsdk_add_interface_dependency requires a target and at least one link dependency.") + endif() + + if(NOT TARGET "${target_name}") + add_library("${target_name}" INTERFACE IMPORTED GLOBAL) + endif() + set_property(TARGET "${target_name}" APPEND PROPERTY + INTERFACE_LINK_LIBRARIES "${ARGN}") +endfunction() + +function(matsdk_add_package_system_dependency dependency_target canonical_target provider_value package_name) + if(NOT "${provider_value}" STREQUAL "SYSTEM") + return() + endif() + + set(options APPLE_SYSTEM) + set(one_value_args APPLE_LIBRARY) + cmake_parse_arguments(MATSDK_PACKAGE_DEP "${options}" "${one_value_args}" "" ${ARGN}) + + if(MATSDK_PACKAGE_DEP_APPLE_SYSTEM) + if(NOT DEFINED MATSDK_PACKAGE_DEP_APPLE_LIBRARY + OR MATSDK_PACKAGE_DEP_APPLE_LIBRARY STREQUAL "") + message(FATAL_ERROR + "APPLE_LIBRARY is required for Apple system dependencies.") + endif() + include("${_MATSDK_DEPENDENCY_TARGETS_DIR}/MatsdkAppleSystemDeps.cmake") + matsdk_add_apple_system_library( + "${canonical_target}" "${MATSDK_PACKAGE_DEP_APPLE_LIBRARY}") + elseif(NOT TARGET "${canonical_target}") + find_dependency(${package_name}) + endif() + + matsdk_add_interface_dependency("${dependency_target}" "${canonical_target}") +endfunction() diff --git a/cmake/MatsdkFetchCurl.cmake b/cmake/MatsdkFetchCurl.cmake new file mode 100644 index 000000000..ea10d86d7 --- /dev/null +++ b/cmake/MatsdkFetchCurl.cmake @@ -0,0 +1,143 @@ +include(FetchContent) + +function(matsdk_configure_fetched_static_target target_name) + if(NOT TARGET "${target_name}") + message(FATAL_ERROR "Fetched dependency target not found: ${target_name}") + endif() + set_target_properties("${target_name}" PROPERTIES + POSITION_INDEPENDENT_CODE ON + C_VISIBILITY_PRESET hidden) + target_compile_options("${target_name}" PRIVATE + $<$:-ffunction-sections;-fdata-sections>) +endfunction() + +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(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) + matsdk_configure_fetched_static_target("${target}") + endforeach() + + set(MBEDTLS_INCLUDE_DIR "${matsdk_mbedtls_SOURCE_DIR}/include") + set(MBEDTLS_LIBRARY mbedtls) + set(MBEDX509_LIBRARY mbedx509) + set(MBEDCRYPTO_LIBRARY mbedcrypto) + set(MBEDTLS_USE_STATIC_LIBS ON) + foreach(_matsdk_mbedtls_target mbedtls mbedx509 mbedcrypto) + if(TARGET ${_matsdk_mbedtls_target} + AND NOT TARGET MbedTLS::${_matsdk_mbedtls_target}) + add_library(MbedTLS::${_matsdk_mbedtls_target} + ALIAS ${_matsdk_mbedtls_target}) + endif() + endforeach() + 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() + + matsdk_configure_fetched_static_target(libcurl_static) + + 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..a56e468c6 --- /dev/null +++ b/cmake/MatsdkOptions.cmake @@ -0,0 +1,181 @@ +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() + +option(MATSDK_BUILD_HEADERS + "Build API headers" ON) +option(MATSDK_BUILD_LIBRARY + "Build the SDK library" ON) +option(MATSDK_BUILD_TEST_TOOL + "Build the console test tool" "${MATSDK_PROJECT_IS_TOP_LEVEL}") +option(MATSDK_BUILD_UNIT_TESTS + "Build unit tests" "${MATSDK_PROJECT_IS_TOP_LEVEL}") +option(MATSDK_BUILD_FUNC_TESTS + "Build functional tests" "${MATSDK_PROJECT_IS_TOP_LEVEL}") +option(MATSDK_BUILD_JNI_WRAPPER + "Build the JNI wrapper" OFF) +option(MATSDK_ANDROID_USE_ROOM + "Use Android Room for offline storage" OFF) +option(MATSDK_ENABLE_CAPI_HTTP_CLIENT + "Enable the C API HTTP client on Android" OFF) +option(MATSDK_BUILD_OBJC_WRAPPER + "Build the Objective-C wrapper" ON) +option(MATSDK_BUILD_SWIFT_WRAPPER + "Build Swift wrappers" ON) +option(MATSDK_BUILD_PACKAGE + "Build an SDK package" "${MATSDK_PROJECT_IS_TOP_LEVEL}") +option(MATSDK_BUILD_PRIVACYGUARD + "Build Privacy Guard" ON) +option(MATSDK_BUILD_CDS + "Build Common Diagnostic Stack" ON) +option(MATSDK_BUILD_LIVEEVENTINSPECTOR + "Build Live Event Inspector" ON) +option(MATSDK_BUILD_SIGNALS + "Build Signals" ON) +option(MATSDK_BUILD_SANITIZER + "Build Sanitizer" ON) +option(MATSDK_BUILD_AZMON + "Build Azure Monitor / Application Insights support" ON) +option(MATSDK_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() + +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 OR TARGET SQLite3::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(MATSDK_ANDROID_USE_ROOM AND NOT CMAKE_SYSTEM_NAME STREQUAL "Android") + message(FATAL_ERROR + "MATSDK_ANDROID_USE_ROOM is supported only when CMAKE_SYSTEM_NAME is Android.") +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}") 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-android.md b/docs/cpp-start-android.md index 2281a5e31..8f02b05e7 100644 --- a/docs/cpp-start-android.md +++ b/docs/cpp-start-android.md @@ -12,7 +12,7 @@ You will ideally build the SDK using the same versions of the Android SDK, NDK, The Gradle wrapper in ```android_build``` builds two modules, ```app``` and ```maesdk```. The ```maesdk``` module is the SDK packaged as an AAR, with both the Java and C++ components included. The AAR includes C++ shared libraries for four ABIs (two ARM ABIs for devices and two Intel ABIs for the emulator). Android Gradle (as usual) supports debug and release builds, and the Gradle task ```maesdk:assemble``` should build both flavors of AAR. -On Android, there are two database implementations to choose from. By default (the main branch on Github), the SDK will use the Android-supported androidx.Room database package. This reduces APK size because we don't need to compile and link in a copy of SQLite in native code (SQLite is hundreds of kB per ABI of APK file size). Room does have a slight CPU performance disadvantage since database transactions cross the JNI boundary when native code uses it. If you wish to change from Room to the native SQLite implementation, you should change the two module ```build.gradle``` files (app and maesdk). In those files, you will see an argument to CMake to select Room: ```"-DUSE_ROOM=1"```. Change this to ```"-DUSE_ROOM=0``` to select the native SQLite. +On Android, there are two database implementations to choose from. By default (the main branch on Github), the SDK will use the Android-supported androidx.Room database package. This reduces APK size because we don't need to compile and link in a copy of SQLite in native code (SQLite is hundreds of kB per ABI of APK file size). Room does have a slight CPU performance disadvantage since database transactions cross the JNI boundary when native code uses it. If you wish to change from Room to the native SQLite implementation, you should change the two module ```build.gradle``` files (app and maesdk). In those files, you will see an argument to CMake to select Room: ```"-DMATSDK_ANDROID_USE_ROOM=ON"```. Change this to ```"-DMATSDK_ANDROID_USE_ROOM=OFF``` to select the native SQLite. When using the Room implementation, the ```maesdk``` AAR brings ```androidx.room``` as a transitive dependency, pinned in ```lib/android_build/maesdk/build.gradle``` (currently ```2.8.4```). The SDK's native (JNI) code is compiled and tested against this version and the Room-generated schema. Because Gradle resolves a single ```androidx.room``` version for the entire app, if your app (or one of its dependencies) selects a different version, the SDK's native code runs against it. **Do not force ```androidx.room``` below the version the SDK is built against**, and prefer aligning your app on the bundled version (or a compatible newer one). A significantly different Room version can change the shape of query results that cross the JNI boundary and has historically caused native crashes in record retrieval (issue #1227); the SDK now guards against null results defensively, but version alignment avoids subtle behavior differences. 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 ce2df9b89..b08fd4537 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,141 +519,148 @@ 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 (SQLite3::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 - SQLite3::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 SQLite3::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; - # SQLite3::SQLite3 is the canonical imported target. CMake < 4.3 only - # provides the deprecated SQLite::SQLite3 spelling. - find_package(SQLite3 REQUIRED) - if(NOT TARGET SQLite3::SQLite3) - add_library(SQLite3::SQLite3 ALIAS SQLite::SQLite3) - endif() - target_link_libraries(mat PRIVATE SQLite3::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() + matsdk_add_interface_dependency( + matsdk_sqlite_dependency SQLite::SQLite3) + target_link_libraries(mat PRIVATE + "$" + "$") +endif() +if(MATSDK_BUNDLE_ZLIB) + target_link_libraries(mat PRIVATE zlib_bundled) +else() + matsdk_add_interface_dependency( + matsdk_zlib_dependency ZLIB::ZLIB) + target_link_libraries(mat PRIVATE + "$" + "$") +endif() +if(MATSDK_CURL_LINK_TARGET) + matsdk_add_interface_dependency( + matsdk_curl_dependency ${MATSDK_CURL_LINK_TARGET}) + target_link_libraries(mat PRIVATE + "$" + "$") +endif() +if(MATSDK_USES_NLOHMANN_TARGET) + matsdk_add_interface_dependency( + matsdk_nlohmann_dependency 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) @@ -619,7 +675,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") @@ -629,75 +685,86 @@ 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 - ) +set(_matsdk_package_config_files + "${CMAKE_CURRENT_BINARY_DIR}/MSTelemetryConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/MSTelemetryConfigVersion.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/MatsdkDependencyTargets.cmake") +if(APPLE) + list(APPEND _matsdk_package_config_files + "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/MatsdkAppleSystemDeps.cmake") +endif() +install(FILES ${_matsdk_package_config_files} + 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_Apple.mm b/lib/http/HttpClient_Apple.mm index b7d6646a4..1a047f5d6 100644 --- a/lib/http/HttpClient_Apple.mm +++ b/lib/http/HttpClient_Apple.mm @@ -207,7 +207,7 @@ void HandleResponse(NSData* data, NSURLResponse* response, NSError* error) NSHTTPURLResponse *httpResp = static_cast(response); auto simpleResponse = new SimpleHttpResponse { NextRespId() }; - simpleResponse->m_statusCode = httpResp.statusCode; + simpleResponse->m_statusCode = static_cast(httpResp.statusCode); NSDictionary *responseHeaders = [httpResp allHeaderFields]; for (id key in responseHeaders) 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 785372186..216590ebd 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,25 +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 ) - -set(MATSDK_GTEST_INCLUDE_DIR - ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/googletest/googletest/include) -set(MATSDK_GMOCK_INCLUDE_DIR - ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/googletest/googlemock/include) -if(NOT EXISTS "${MATSDK_GTEST_INCLUDE_DIR}/gtest/gtest.h") - message(FATAL_ERROR - "Tests require the third_party/googletest submodule at " - "${CMAKE_CURRENT_SOURCE_DIR}/../third_party/googletest.") -endif() - -add_library(matsdk_test_includes INTERFACE) -target_include_directories(matsdk_test_includes INTERFACE +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 - ${MATSDK_GTEST_INCLUDE_DIR} - ${MATSDK_GMOCK_INCLUDE_DIR}) + ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/googletest/googletest/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() + +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 @@ -28,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 796623789..9c2a47919 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,115 +49,26 @@ 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() - -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) - if(NOT TARGET SQLite3::SQLite3) - add_library(SQLite3::SQLite3 ALIAS SQLite::SQLite3) - endif() - set (SQLITE3_LIB SQLite3::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 matsdk_test_config) +if(MATSDK_FUNC_TEST_DEFINITIONS) + target_compile_definitions(FuncTests PRIVATE ${MATSDK_FUNC_TEST_DEFINITIONS}) endif() -target_link_libraries(FuncTests matsdk_test_includes) +target_link_libraries(FuncTests PRIVATE + mat + ZLIB::ZLIB + gtest + gmock) +if(NOT MATSDK_SQLITE_PROVIDER_RESOLVED STREQUAL "NONE") + target_link_libraries(FuncTests PRIVATE SQLite::SQLite3) +endif() +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 a7efe90ae..05932e7b8 100644 --- a/tests/unittests/CMakeLists.txt +++ b/tests/unittests/CMakeLists.txt @@ -51,17 +51,24 @@ set(SRCS UtilsTests.cpp ZlibUtilsTests.cpp ) +if(MATSDK_SQLITE_PROVIDER_RESOLVED STREQUAL "NONE") + list(REMOVE_ITEM SRCS OfflineStorageTests_SQLite.cpp) +endif() +set(MATSDK_UNIT_TEST_DEFINITIONS) -set_source_files_properties(${SRCS} PROPERTIES COMPILE_FLAGS -Wno-deprecated-declarations) +if(NOT MSVC) + set_source_files_properties(${SRCS} + PROPERTIES COMPILE_FLAGS -Wno-deprecated-declarations) +endif() # 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 +83,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 +94,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,121 +116,26 @@ 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() - -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) - if(NOT TARGET SQLite3::SQLite3) - add_library(SQLite3::SQLite3 ALIAS SQLite::SQLite3) - endif() - set (SQLITE3_LIB SQLite3::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 matsdk_test_config) +if(MATSDK_UNIT_TEST_DEFINITIONS) + target_compile_definitions(UnitTests PRIVATE ${MATSDK_UNIT_TEST_DEFINITIONS}) endif() -target_link_libraries(UnitTests matsdk_test_includes) +target_link_libraries(UnitTests PRIVATE + mat + ZLIB::ZLIB + gtest + gmock) +if(NOT MATSDK_SQLITE_PROVIDER_RESOLVED STREQUAL "NONE") + target_link_libraries(UnitTests PRIVATE SQLite::SQLite3) +endif() +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..50a82a874 100644 --- a/tests/unittests/HttpClientCurlTests.cpp +++ b/tests/unittests/HttpClientCurlTests.cpp @@ -57,6 +57,63 @@ 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); +} + +class HttpClientCurlHeaderTests : public ::testing::Test, + public HttpServer::Callback +{ +protected: + HttpServer m_server; + std::string m_url; + + void SetUp() override + { + const int port = m_server.addListeningPort(0); + std::ostringstream address; + address << "127.0.0.1:" << port; + m_url = "http://" + address.str() + "/headers/"; + m_server.setServerName(address.str()); + m_server.addHandler("/headers/", *this); + m_server.start(); + } + + void TearDown() override + { + m_server.stop(); + } + + int onHttpRequest(HttpServer::Request const&, HttpServer::Response& response) override + { + response.headers["X-MAT-Test"] = "header-value"; + response.content = "body-value"; + return 200; + } +}; + +TEST_F(HttpClientCurlHeaderTests, CapturesResponseHeadersAndBody) +{ + const std::map requestHeaders; + const std::vector requestBody; + const HttpClient_Curl client; + (void)client; // Initialize curl globally before constructing the operation. + CurlHttpOperation operation("GET", m_url, nullptr, requestHeaders, requestBody); + + ASSERT_EQ(operation.Send(), 200L); + const auto responseHeaders = operation.GetResponseHeaders(); + const auto responseBody = operation.GetResponseBody(); + + ASSERT_EQ(responseHeaders.count("X-MAT-Test"), 1u); + EXPECT_EQ(responseHeaders.at("X-MAT-Test"), "header-value"); + EXPECT_EQ(std::string(responseBody.begin(), responseBody.end()), "body-value"); +} + // --- ILogConfiguration integration --- TEST(HttpClientCurlConfigTests, LogConfiguration_SslVerify_DefaultIsTrue) diff --git a/tests/vcpkg/test-vcpkg-ios.sh b/tests/vcpkg/test-vcpkg-ios.sh index c1097c3bd..df78234ea 100755 --- a/tests/vcpkg/test-vcpkg-ios.sh +++ b/tests/vcpkg/test-vcpkg-ios.sh @@ -96,7 +96,7 @@ cmake -S "${SCRIPT_DIR}" -B "${BUILD_DIR}/consumer" \ -DCMAKE_SYSTEM_NAME=iOS \ -DCMAKE_OSX_SYSROOT="${APPLE_SDK}" \ -DCMAKE_OSX_ARCHITECTURES=arm64 \ - -DCMAKE_OSX_DEPLOYMENT_TARGET=12.0 + -DCMAKE_OSX_DEPLOYMENT_TARGET=13.0 echo "" echo "--- Step 2: Build test consumer for iOS ---" 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/build-common.sh b/tools/build-common.sh new file mode 100644 index 000000000..1ba0ecb56 --- /dev/null +++ b/tools/build-common.sh @@ -0,0 +1,127 @@ +#!/bin/bash + +matsdk_clean_build_outputs() { + local script_name="$1" + + echo "$script_name: cleaning previous build artifacts" + rm -f CMakeCache.txt *.cmake + rm -rf out + rm -rf .buildtools +} + +matsdk_mark_buildtools_checked() { + local marker_file="$1" + + echo > "$marker_file" +} + +matsdk_install_buildtools_once() { + local marker_file="$1" + shift + + if [ ! -f "$marker_file" ]; then + if [ $# -gt 0 ]; then + "$@" + fi + matsdk_mark_buildtools_checked "$marker_file" + fi +} + +matsdk_try_buildtools_once() { + local marker_file="$1" + local failure_message="$2" + shift 2 + + if [ ! -f "$marker_file" ]; then + if [ $# -gt 0 ]; then + "$@" || echo "$failure_message" + fi + matsdk_mark_buildtools_checked "$marker_file" + fi +} + +matsdk_print_compiler_versions() { + if [ -f /usr/bin/gcc ]; then + echo "gcc version: `gcc --version`" + fi + + if [ -f /usr/bin/clang ]; then + echo "clang version: `clang --version`" + fi +} + +matsdk_require_cmake_preset_support() { + cmake -P "$DIR/cmake/MatsdkRequirePresetSupport.cmake" +} + +matsdk_append_cmake_opts_to_cmake_args() { + local input="${CMAKE_OPTS:-}" + local token="" + local char="" + local escaped=false + local in_single_quote=false + local in_double_quote=false + local token_started=false + local index + local length=${#input} + local -a parsed_args=() + + # Parse the existing shell-like CMAKE_OPTS format without evaluating it. + for ((index = 0; index < length; index++)); do + char="${input:index:1}" + if [[ "$escaped" == true ]]; then + token+="$char" + escaped=false + token_started=true + elif [[ "$char" == "\\" && "$in_single_quote" == false ]]; then + escaped=true + token_started=true + elif [[ "$char" == "'" && "$in_double_quote" == false ]]; then + if [[ "$in_single_quote" == true ]]; then + in_single_quote=false + else + in_single_quote=true + fi + token_started=true + elif [[ "$char" == '"' && "$in_single_quote" == false ]]; then + if [[ "$in_double_quote" == true ]]; then + in_double_quote=false + else + in_double_quote=true + fi + token_started=true + elif [[ "$char" =~ [[:space:]] && "$in_single_quote" == false && "$in_double_quote" == false ]]; then + if [[ "$token_started" == true ]]; then + parsed_args+=("$token") + token="" + token_started=false + fi + else + token+="$char" + token_started=true + fi + done + + if [[ "$escaped" == true || "$in_single_quote" == true || "$in_double_quote" == true ]]; then + echo "Error: CMAKE_OPTS contains an unterminated escape or quote." >&2 + return 1 + fi + if [[ "$token_started" == true ]]; then + parsed_args+=("$token") + fi + + cmake_args+=("${parsed_args[@]}") +} + +matsdk_run_logged_command() { + printf ' %q' "$@" + printf '\n' + "$@" +} + +matsdk_build_and_package_preset() { + local preset="$1" + + cmake --build --preset "$preset" + cmake --build --preset "$preset" --target package +} diff --git a/tools/ports/cpp-client-telemetry/portfile.cmake b/tools/ports/cpp-client-telemetry/portfile.cmake index b2fdab830..5bc5fddf4 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,28 @@ 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_APPLE_DEPLOYMENT_OPTIONS) +if(VCPKG_TARGET_IS_IOS) + list(APPEND MATSDK_APPLE_DEPLOYMENT_OPTIONS + -DCMAKE_OSX_DEPLOYMENT_TARGET=13.0) 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 +119,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 +169,9 @@ 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} + ${MATSDK_APPLE_DEPLOYMENT_OPTIONS} ) 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` *