diff --git a/.github/workflows/test-embedding.yml b/.github/workflows/test-embedding.yml new file mode 100644 index 000000000..bc0199b5c --- /dev/null +++ b/.github/workflows/test-embedding.yml @@ -0,0 +1,154 @@ +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 + fetchcontent: OFF + preload-curl: ON + - dependencies: system + library-type: SHARED + fetchcontent: ON + preload-curl: OFF + - dependencies: self-contained + library-type: STATIC + fetchcontent: ON + preload-curl: 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_LIBRARY_TYPE=${{ matrix.library-type }} + ) + 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 + + 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_BUILD_IOS=ON + -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 8b2321e3c..4108ae131 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,45 @@ cmake_minimum_required(VERSION 3.15...3.31) + +# Backward-compatible translation for legacy Apple build scripts. Standard +# CMAKE_OSX_* variables are the canonical interface and must be initialized +# before project() so CMake's compiler/platform detection sees them. +if(NOT DEFINED CMAKE_OSX_ARCHITECTURES) + if(DEFINED IOS_ARCH AND NOT IOS_ARCH STREQUAL "") + set(CMAKE_OSX_ARCHITECTURES "${IOS_ARCH}" CACHE STRING + "Apple target architectures" FORCE) + elseif(DEFINED MAC_ARCH AND NOT MAC_ARCH STREQUAL "") + if(MAC_ARCH STREQUAL "universal") + set(_matsdk_legacy_apple_architectures "arm64;x86_64") + else() + set(_matsdk_legacy_apple_architectures "${MAC_ARCH}") + endif() + set(CMAKE_OSX_ARCHITECTURES "${_matsdk_legacy_apple_architectures}" CACHE STRING + "Apple target architectures" FORCE) + endif() +endif() +if(NOT DEFINED CMAKE_OSX_SYSROOT AND DEFINED IOS_PLAT AND NOT IOS_PLAT STREQUAL "") + set(CMAKE_OSX_SYSROOT "${IOS_PLAT}" CACHE STRING "Apple SDK sysroot" FORCE) +endif() +if(NOT DEFINED CMAKE_OSX_DEPLOYMENT_TARGET + AND DEFINED IOS_DEPLOYMENT_TARGET + AND NOT IOS_DEPLOYMENT_TARGET STREQUAL "") + set(CMAKE_OSX_DEPLOYMENT_TARGET "${IOS_DEPLOYMENT_TARGET}" CACHE STRING + "Apple deployment target" FORCE) +endif() +if((DEFINED FORCE_RESET_OSX_DEPLOYMENT_TARGET AND FORCE_RESET_OSX_DEPLOYMENT_TARGET) + OR (DEFINED FORCE_RESET_DEPLOYMENT_TARGET AND FORCE_RESET_DEPLOYMENT_TARGET)) + message(DEPRECATION + "FORCE_RESET_OSX_DEPLOYMENT_TARGET/FORCE_RESET_DEPLOYMENT_TARGET are no " + "longer needed. CMAKE_OSX_DEPLOYMENT_TARGET (or legacy " + "IOS_DEPLOYMENT_TARGET) is honored directly without mutating global flags.") +endif() + project(MSTelemetry LANGUAGES C CXX) +if(APPLE) + set(MATSDK_BUILD_PLATFORM_APPLE TRUE) +else() + set(MATSDK_BUILD_PLATFORM_APPLE FALSE) +endif() ################################################################################################ # Vcpkg dependency mode: detect early so it can guard platform-specific flag logic @@ -11,15 +51,12 @@ else() 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}") +set(MATSDK_SQLITE_TARGET "" CACHE STRING + "Optional existing CMake target to use for SQLite in non-vcpkg builds, instead of find_package(SQLite3)") +set(MATSDK_ZLIB_TARGET "" CACHE STRING + "Optional existing CMake target to use for zlib in non-vcpkg builds, instead of find_package(ZLIB)") + +include(cmake/MatsdkOptions.cmake) # Begin Uncomment for i386 build #set(CMAKE_SYSTEM_PROCESSOR i386) @@ -34,104 +71,20 @@ 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_BUILD_IOS + OR CMAKE_SYSTEM_NAME STREQUAL "iOS" + OR CMAKE_SYSTEM_NAME STREQUAL "visionOS") + set(MATSDK_BUILD_IOS ON) + set(TARGET_ARCH "APPLE") + set(IOS TRUE) + elseif(CMAKE_OSX_ARCHITECTURES) + set(TARGET_ARCH "${CMAKE_OSX_ARCHITECTURES}") endif() + message(STATUS "MATSDK_BUILD_IOS: ${MATSDK_BUILD_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 +97,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 +# 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) - 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. -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) @@ -300,10 +168,6 @@ 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) ################################################################################################ @@ -332,44 +196,51 @@ endif() message(STATUS "SDK version: ${SDK_VERSION_PREFIX}-${MATSDK_BUILD_VERSION}") ################################################################################################ -# User options (must be before HTTP stack section for BUILD_APPLE_HTTP) +# Embedding/dependency options ################################################################################################ -option(BUILD_HEADERS "Build API headers" YES) -option(BUILD_LIBRARY "Build library" YES) -option(BUILD_TEST_TOOL "Build console test tool" YES) -# Default the test suites ON only when this repository is the top-level project -# (developer/CI build), and OFF when it is consumed via add_subdirectory()/ -# FetchContent, so downstream projects don't build the tests or require the -# third_party/googletest submodule. PROJECT_IS_TOP_LEVEL exists on CMake >= 3.21; -# fall back to comparing the source dirs on older CMake (floor is 3.15). -if(DEFINED PROJECT_IS_TOP_LEVEL) - set(MATSDK_TESTS_DEFAULT ${PROJECT_IS_TOP_LEVEL}) -elseif(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - set(MATSDK_TESTS_DEFAULT ON) -else() - set(MATSDK_TESTS_DEFAULT OFF) +set(MATSDK_CURL_TARGET "" CACHE STRING + "Optional existing CMake target to use for libcurl in non-vcpkg builds, instead of find_package(CURL)") +set(MATSDK_CURL_PROVIDER "PACKAGE" CACHE STRING + "How non-vcpkg builds resolve libcurl: PACKAGE (find_package) or FETCH (FetchContent static curl)") +set_property(CACHE MATSDK_CURL_PROVIDER PROPERTY STRINGS PACKAGE 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 "PACKAGE" AND NOT MATSDK_CURL_PROVIDER_UPPER STREQUAL "FETCH") + message(FATAL_ERROR "MATSDK_CURL_PROVIDER must be PACKAGE or FETCH; got '${MATSDK_CURL_PROVIDER}'.") endif() -option(BUILD_UNIT_TESTS "Build unit tests" ${MATSDK_TESTS_DEFAULT}) -option(BUILD_FUNC_TESTS "Build functional tests" ${MATSDK_TESTS_DEFAULT}) -option(BUILD_JNI_WRAPPER "Build JNI wrapper" NO) -option(BUILD_OBJC_WRAPPER "Build Obj-C wrapper" YES) -option(BUILD_SWIFT_WRAPPER "Build Swift Wrappers" YES) -option(BUILD_PACKAGE "Build package" YES) -option(BUILD_PRIVACYGUARD "Build Privacy Guard" YES) -option(BUILD_CDS "Build CDS - Common Diagnostic Stack" YES) -option(BUILD_LIVEEVENTINSPECTOR "Build Live Event Inspector" YES) -option(BUILD_SIGNALS "Build Signals" YES) -option(BUILD_SANITIZER "Build Sanitizer" YES) -option(LINK_STATIC_DEPENDS "Link dependencies for static build" YES) - -# 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) +string(TOUPPER "${MATSDK_CURL_TLS_BACKEND}" MATSDK_CURL_TLS_BACKEND_UPPER) +if(NOT MATSDK_CURL_TLS_BACKEND_UPPER STREQUAL "MBEDTLS" AND NOT MATSDK_CURL_TLS_BACKEND_UPPER STREQUAL "OPENSSL") + message(FATAL_ERROR "MATSDK_CURL_TLS_BACKEND must be MBEDTLS or OPENSSL; got '${MATSDK_CURL_TLS_BACKEND}'.") endif() - -if(BUILD_APPLE_HTTP) +if(MATSDK_USE_VCPKG_DEPS 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(MATSDK_CURL_TARGET AND MATSDK_CURL_PROVIDER_UPPER STREQUAL "FETCH") + message(FATAL_ERROR + "MATSDK_CURL_TARGET and MATSDK_CURL_PROVIDER=FETCH are mutually exclusive.") +endif() +foreach(_matsdk_dependency_target_var MATSDK_CURL_TARGET MATSDK_SQLITE_TARGET MATSDK_ZLIB_TARGET) + if(${_matsdk_dependency_target_var} AND NOT TARGET "${${_matsdk_dependency_target_var}}") + message(FATAL_ERROR + "${_matsdk_dependency_target_var} was set to '${${_matsdk_dependency_target_var}}', " + "but no such CMake target exists. Define the target before adding " + "cpp_client_telemetry, or leave ${_matsdk_dependency_target_var} empty to " + "use the SDK's default dependency discovery.") + endif() +endforeach() +if(MATSDK_BUILD_APPLE_HTTP) add_definitions(-DAPPLE_HTTP=1) endif() @@ -380,9 +251,9 @@ endif() # Only use custom curl if compiling with CPP11 PAL set(MATSDK_NEEDS_CURL OFF) if(PAL_IMPLEMENTATION STREQUAL "CPP11" - AND NOT BUILD_IOS + AND NOT MATSDK_BUILD_IOS AND (NOT CMAKE_SYSTEM_NAME STREQUAL "Android" OR MATSDK_USE_VCPKG_DEPS) - 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) @@ -403,15 +274,26 @@ if(PAL_IMPLEMENTATION STREQUAL "CPP11" endif() list(APPEND LIBS CURL::libcurl) 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) + if(MATSDK_CURL_TARGET) + list(APPEND LIBS "${MATSDK_CURL_TARGET}") + elseif(MATSDK_CURL_PROVIDER_UPPER STREQUAL "FETCH") + include(cmake/MatsdkFetchCurl.cmake) + matsdk_fetch_curl(_matsdk_curl_target) + list(APPEND LIBS "${_matsdk_curl_target}") + elseif(TARGET CURL::libcurl) + # Parent superbuilds may create the canonical target before adding 1DS. list(APPEND LIBS CURL::libcurl) else() - include_directories(${CURL_INCLUDE_DIRS}) - list(APPEND LIBS "${CURL_LIBRARIES}") + 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}") + endif() endif() endif() endif() @@ -420,50 +302,35 @@ endif() # Dependency resolution (vcpkg mode vs vendored) ################################################################################################ if(MATSDK_USE_VCPKG_DEPS) - if(APPLE) - # macOS/iOS ship libsqlite3 and libz as system libraries (the SDK's SPM - # distribution links them the same way), so the vcpkg sqlite3/zlib packages are - # not pulled there -- find the system ones via CMake's standard find modules. - find_package(SQLite3 REQUIRED) - find_package(ZLIB REQUIRED) - find_package(nlohmann_json CONFIG REQUIRED) - set(MATSDK_APPLE_SYSTEM_DEPS ON) - message(STATUS "Apple: using system SQLite3 + zlib; vcpkg-provided nlohmann-json") - 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) + if(MATSDK_SQLITE_PROVIDER_RESOLVED STREQUAL "SYSTEM" AND NOT MATSDK_SQLITE_TARGET) + if(APPLE) + find_package(SQLite3 REQUIRED) + else() 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.") + "MATSDK_SQLITE_PROVIDER=SYSTEM requires the vcpkg sqlite3 package. " + "Install the system-sqlite feature, choose " + "MATSDK_SQLITE_PROVIDER=MINIMAL/VENDORED, or provide MATSDK_SQLITE_TARGET.") endif() endif() + endif() + if(MATSDK_ZLIB_PROVIDER_RESOLVED STREQUAL "SYSTEM" AND NOT MATSDK_ZLIB_TARGET) 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") - endif() endif() + find_package(nlohmann_json CONFIG REQUIRED) + message(STATUS + "Using vcpkg dependency mode with SQLite=${MATSDK_SQLITE_PROVIDER_RESOLVED}, " + "zlib=${MATSDK_ZLIB_PROVIDER_RESOLVED}") 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. + # nlohmann JSON remains header-only and vendored for source embedding. include_directories(${CMAKE_CURRENT_SOURCE_DIR}) - message(STATUS "Using vendored sqlite3, zlib, nlohmann-json") + message(STATUS + "Using source dependency mode with SQLite=${MATSDK_SQLITE_PROVIDER_RESOLVED}, " + "zlib=${MATSDK_ZLIB_PROVIDER_RESOLVED}, vendored nlohmann-json") endif() -if(BUILD_UNIT_TESTS OR BUILD_FUNC_TESTS) +if(MATSDK_BUILD_UNIT_TESTS OR MATSDK_BUILD_FUNC_TESTS) message(STATUS "Adding gtest") add_library(gtest STATIC IMPORTED GLOBAL) message(STATUS "Adding gmock") @@ -480,16 +347,16 @@ include_directories(lib/pal) # 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) @@ -499,7 +366,7 @@ endif() # Packaging ################################################################################################ -if (BUILD_PACKAGE) +if(MATSDK_BUILD_PACKAGE) if ("${CMAKE_PACKAGE_TYPE}" STREQUAL "deb") include(tools/MakeDeb.cmake) endif() diff --git a/README.md b/README.md index 3ddcbb580..a5deb9557 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ 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) Other resources to learn how to setup the build system: diff --git a/build-ios.sh b/build-ios.sh index d316fe2fa..9eb362af3 100755 --- a/build-ios.sh +++ b/build-ios.sh @@ -49,7 +49,6 @@ fi echo "IOS_ARCH = $IOS_ARCH, IOS_PLAT = $IOS_PLAT, BUILD_TYPE = $BUILD_TYPE" -FORCE_RESET_DEPLOYMENT_TARGET=NO DEPLOYMENT_TARGET="" if [ "$IOS_PLAT" == "iphoneos" ] || [ "$IOS_PLAT" == "iphonesimulator" ]; then @@ -57,19 +56,16 @@ if [ "$IOS_PLAT" == "iphoneos" ] || [ "$IOS_PLAT" == "iphonesimulator" ]; then DEPLOYMENT_TARGET="$IOS_DEPLOYMENT_TARGET" if [ -z "$DEPLOYMENT_TARGET" ]; then DEPLOYMENT_TARGET="12.0" - FORCE_RESET_DEPLOYMENT_TARGET=YES fi elif [ "$IOS_PLAT" == "xros" ] || [ "$IOS_PLAT" == "xrsimulator" ]; then SYS_NAME="visionOS" DEPLOYMENT_TARGET="$XROS_DEPLOYMENT_TARGET" if [ -z "$DEPLOYMENT_TARGET" ]; then DEPLOYMENT_TARGET="1.0" - FORCE_RESET_DEPLOYMENT_TARGET=YES fi fi echo "deployment target = $DEPLOYMENT_TARGET" -echo "force reset deployment target = $FORCE_RESET_DEPLOYMENT_TARGET" # Install build tools and recent sqlite3 FILE=".buildtools" @@ -92,7 +88,7 @@ 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 .." +cmake_cmd="cmake -DCMAKE_OSX_SYSROOT=$IOS_PLAT -DCMAKE_SYSTEM_NAME=$SYS_NAME -DCMAKE_OSX_ARCHITECTURES=$IOS_ARCH -DCMAKE_OSX_DEPLOYMENT_TARGET=$DEPLOYMENT_TARGET -DMATSDK_BUILD_IOS=ON -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PACKAGE_TYPE=$CMAKE_PACKAGE_TYPE $CMAKE_OPTS .." echo "${cmake_cmd}" eval $cmake_cmd diff --git a/build.sh b/build.sh index 52a5081b2..e2f8bf121 100755 --- a/build.sh +++ b/build.sh @@ -70,7 +70,7 @@ while [[ $# -gt 0 ]]; do echo "MAC_ARCH = $MAC_ARCH" ;; CUSTOM_BUILD_FLAGS*) - CUSTOM_CMAKE_CXX_FLAG="\"${ARG:19:999}\"" + CUSTOM_CMAKE_CXX_FLAG="${ARG:19:999}" echo "custom compiler flags = $CUSTOM_CMAKE_CXX_FLAG" ;; *) @@ -98,7 +98,7 @@ fi # Evaluate switches LINK_TYPE= -CMAKE_OPTS="${CMAKE_OPTS:--DBUILD_SHARED_LIBS=OFF}" +CMAKE_OPTS="${CMAKE_OPTS:--DMATSDK_LIBRARY_TYPE=STATIC}" while getopts "h?vl:D:" opt; do case "$opt" in h|\?) usage @@ -133,7 +133,7 @@ fi echo "CMAKE_OPTS from caller: $CMAKE_OPTS" if [ "$LINK_TYPE" == "shared" ]; then - CMAKE_OPTS="${CMAKE_OPTS} -DBUILD_SHARED_LIBS=ON" + CMAKE_OPTS="${CMAKE_OPTS} -DMATSDK_LIBRARY_TYPE=SHARED" fi # Set target MacOS minver @@ -185,10 +185,30 @@ 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 +cmake_args=(cmake) +if [[ "$OS_NAME" == *Darwin* ]]; then + if [[ "$MAC_ARCH" == "universal" ]]; then + cmake_args+=("-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64") + else + cmake_args+=("-DCMAKE_OSX_ARCHITECTURES=$MAC_ARCH") + fi +fi +cmake_args+=( + "-DCMAKE_BUILD_TYPE=$BUILD_TYPE" + "-DCMAKE_PACKAGE_TYPE=$CMAKE_PACKAGE_TYPE" +) +if [[ -n "$CUSTOM_CMAKE_CXX_FLAG" ]]; then + cmake_args+=("-DCMAKE_CXX_FLAGS=$CUSTOM_CMAKE_CXX_FLAG") +fi +if [[ -n "$CMAKE_OPTS" ]]; then + # Preserve existing support for callers passing multiple quoted -D arguments. + eval "extra_cmake_args=($CMAKE_OPTS)" + cmake_args+=("${extra_cmake_args[@]}") +fi +cmake_args+=(..) +printf ' %q' "${cmake_args[@]}" +printf '\n' +"${cmake_args[@]}" # TODO: strip symbols to minimize (release-only) diff --git a/cmake/MSTelemetryConfig.cmake.in b/cmake/MSTelemetryConfig.cmake.in index af3838d65..1f467cf23 100644 --- a/cmake/MSTelemetryConfig.cmake.in +++ b/cmake/MSTelemetryConfig.cmake.in @@ -2,15 +2,17 @@ include(CMakeFindDependencyMacro) -# Re-find dependencies that consumers need. -# On Apple the SDK links the system libsqlite3 (SQLite::SQLite3); elsewhere it uses -# the vcpkg sqlite3 package unless a private minimal SQLite is bundled. -if(@MATSDK_APPLE_SYSTEM_DEPS@) - find_dependency(SQLite3) -elseif(NOT @MATSDK_BUNDLE_SQLITE@) - find_dependency(unofficial-sqlite3 CONFIG) +# Re-find only dependencies that were external to the SDK package. +if(NOT @MATSDK_BUNDLE_SQLITE@) + if(@MATSDK_BUILD_PLATFORM_APPLE@) + find_dependency(SQLite3) + else() + find_dependency(unofficial-sqlite3 CONFIG) + endif() +endif() +if(NOT @MATSDK_BUNDLE_ZLIB@) + find_dependency(ZLIB) endif() -find_dependency(ZLIB) find_dependency(nlohmann_json CONFIG) # Curl is re-found only when the SDK was built with the curl HTTP client diff --git a/cmake/MatsdkFetchCurl.cmake b/cmake/MatsdkFetchCurl.cmake new file mode 100644 index 000000000..baa5ceb76 --- /dev/null +++ b/cmake/MatsdkFetchCurl.cmake @@ -0,0 +1,132 @@ +include(FetchContent) + +function(matsdk_fetch_curl out_target) + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux") + message(FATAL_ERROR + "MATSDK_CURL_PROVIDER=FETCH is currently supported only on Linux. " + "Use MATSDK_CURL_PROVIDER=PACKAGE or provide MATSDK_CURL_TARGET 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=PACKAGE " + "or provide MATSDK_CURL_TARGET instead.") + endif() + + set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0126 NEW) + + foreach(option IN ITEMS + BUILD_SHARED_LIBS + BUILD_TESTING + ENABLE_PROGRAMS + ENABLE_TESTING + GEN_FILES + UNSAFE_BUILD + INSTALL_MBEDTLS_HEADERS + MBEDTLS_FATAL_WARNINGS + USE_SHARED_MBEDTLS_LIBRARY + LINK_WITH_PTHREAD + BUILD_CURL_EXE + BUILD_EXAMPLES + BUILD_LIBCURL_DOCS + BUILD_MISC_DOCS + ENABLE_CURL_MANUAL + CURL_ENABLE_EXPORT_TARGET + CURL_USE_OPENSSL + CURL_USE_PKGCONFIG + CURL_USE_CMAKECONFIG + CURL_ZLIB + CURL_BROTLI + CURL_ZSTD + USE_LIBIDN2 + CURL_USE_LIBPSL + CURL_USE_LIBSSH2 + CURL_USE_LIBSSH + CURL_USE_GSSAPI + CURL_USE_GSASL + USE_NGHTTP2 + USE_NGTCP2 + USE_QUICHE + ENABLE_ARES + ENABLE_UNIX_SOCKETS) + set(${option} OFF) + endforeach() + + foreach(option IN ITEMS + BUILD_STATIC_LIBS + DISABLE_PACKAGE_CONFIG_AND_INSTALL + CURL_DISABLE_INSTALL + HTTP_ONLY + CURL_DISABLE_ALTSVC + CURL_DISABLE_HSTS + CURL_DISABLE_COOKIES + CURL_DISABLE_NETRC + CURL_DISABLE_MIME + CURL_DISABLE_DOH + CURL_DISABLE_AWS + CURL_DISABLE_BEARER_AUTH + CURL_DISABLE_DIGEST_AUTH + CURL_DISABLE_KERBEROS_AUTH + CURL_DISABLE_NEGOTIATE_AUTH) + set(${option} ON) + endforeach() + + if(MATSDK_CURL_TLS_BACKEND_UPPER STREQUAL "MBEDTLS") + set(USE_STATIC_MBEDTLS_LIBRARY ON) + set(CURL_USE_MBEDTLS ON) + set(HAVE_MBEDTLS_DES_CRYPT_ECB ON) + set(MBEDTLS_CONFIG_FILE "") + set(MBEDTLS_USER_CONFIG_FILE "") + + FetchContent_Declare( + matsdk_mbedtls + URL ${MATSDK_MBEDTLS_URL} + URL_HASH SHA256=${MATSDK_MBEDTLS_SHA256}) + FetchContent_MakeAvailable(matsdk_mbedtls) + + foreach(target mbedtls mbedx509 mbedcrypto) + if(NOT TARGET ${target}) + message(FATAL_ERROR "Embedded mbedTLS dependency target not found: ${target}") + endif() + set_target_properties(${target} PROPERTIES + POSITION_INDEPENDENT_CODE ON + C_VISIBILITY_PRESET hidden) + target_compile_options(${target} PRIVATE + $<$:-ffunction-sections;-fdata-sections>) + endforeach() + + set(MBEDTLS_INCLUDE_DIR "${matsdk_mbedtls_SOURCE_DIR}/include") + set(MBEDTLS_LIBRARY MbedTLS::mbedtls) + set(MBEDX509_LIBRARY MbedTLS::mbedx509) + set(MBEDCRYPTO_LIBRARY MbedTLS::mbedcrypto) + set(MBEDTLS_USE_STATIC_LIBS ON) + elseif(MATSDK_CURL_TLS_BACKEND_UPPER STREQUAL "OPENSSL") + set(CURL_USE_OPENSSL ON) + find_package(OpenSSL REQUIRED) + endif() + + FetchContent_Declare( + matsdk_curl + URL ${MATSDK_CURL_URL} + URL_HASH SHA256=${MATSDK_CURL_SHA256}) + FetchContent_MakeAvailable(matsdk_curl) + + if(NOT TARGET CURL::libcurl OR NOT TARGET libcurl_static) + message(FATAL_ERROR "The embedded static CURL::libcurl target was not created.") + endif() + + set_target_properties(libcurl_static PROPERTIES + POSITION_INDEPENDENT_CODE ON + C_VISIBILITY_PRESET hidden) + target_compile_options(libcurl_static PRIVATE + $<$:-ffunction-sections;-fdata-sections>) + + set(_matsdk_fetched_curl_targets libcurl_static) + if(MATSDK_CURL_TLS_BACKEND_UPPER STREQUAL "MBEDTLS") + list(APPEND _matsdk_fetched_curl_targets mbedtls mbedx509 mbedcrypto) + 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..0adeec662 --- /dev/null +++ b/cmake/MatsdkOptions.cmake @@ -0,0 +1,154 @@ +function(matsdk_bool_option canonical legacy description default_value) + set(initial_value "${default_value}") + set(canonical_predefined OFF) + if(DEFINED ${canonical}) + set(canonical_predefined ON) + endif() + set(legacy_defined OFF) + if(NOT "${legacy}" STREQUAL "") + if(DEFINED ${legacy}) + set(legacy_defined ON) + if(NOT canonical_predefined) + set(initial_value "${${legacy}}") + endif() + endif() + endif() + option(${canonical} "${description}" "${initial_value}") + if(canonical_predefined AND legacy_defined + AND NOT "${${legacy}}" STREQUAL "${${canonical}}") + message(DEPRECATION + "${legacy} is deprecated and conflicts with ${canonical}; " + "${canonical}=${${canonical}} takes precedence.") + endif() +endfunction() + +if(DEFINED PROJECT_IS_TOP_LEVEL) + set(MATSDK_PROJECT_IS_TOP_LEVEL "${PROJECT_IS_TOP_LEVEL}") +elseif(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + set(MATSDK_PROJECT_IS_TOP_LEVEL ON) +else() + set(MATSDK_PROJECT_IS_TOP_LEVEL OFF) +endif() + +matsdk_bool_option(MATSDK_BUILD_HEADERS BUILD_HEADERS + "Build API headers" ON) +matsdk_bool_option(MATSDK_BUILD_LIBRARY BUILD_LIBRARY + "Build the SDK library" ON) +matsdk_bool_option(MATSDK_BUILD_TEST_TOOL BUILD_TEST_TOOL + "Build the console test tool" "${MATSDK_PROJECT_IS_TOP_LEVEL}") +matsdk_bool_option(MATSDK_BUILD_UNIT_TESTS BUILD_UNIT_TESTS + "Build unit tests" "${MATSDK_PROJECT_IS_TOP_LEVEL}") +matsdk_bool_option(MATSDK_BUILD_FUNC_TESTS BUILD_FUNC_TESTS + "Build functional tests" "${MATSDK_PROJECT_IS_TOP_LEVEL}") +matsdk_bool_option(MATSDK_BUILD_JNI_WRAPPER BUILD_JNI_WRAPPER + "Build the JNI wrapper" OFF) +matsdk_bool_option(MATSDK_BUILD_OBJC_WRAPPER BUILD_OBJC_WRAPPER + "Build the Objective-C wrapper" ON) +matsdk_bool_option(MATSDK_BUILD_SWIFT_WRAPPER BUILD_SWIFT_WRAPPER + "Build Swift wrappers" ON) +matsdk_bool_option(MATSDK_BUILD_PACKAGE BUILD_PACKAGE + "Build an SDK package" "${MATSDK_PROJECT_IS_TOP_LEVEL}") +matsdk_bool_option(MATSDK_BUILD_PRIVACYGUARD BUILD_PRIVACYGUARD + "Build Privacy Guard" ON) +matsdk_bool_option(MATSDK_BUILD_CDS BUILD_CDS + "Build Common Diagnostic Stack" ON) +matsdk_bool_option(MATSDK_BUILD_LIVEEVENTINSPECTOR BUILD_LIVEEVENTINSPECTOR + "Build Live Event Inspector" ON) +matsdk_bool_option(MATSDK_BUILD_SIGNALS BUILD_SIGNALS + "Build Signals" ON) +matsdk_bool_option(MATSDK_BUILD_SANITIZER BUILD_SANITIZER + "Build Sanitizer" ON) +matsdk_bool_option(MATSDK_BUILD_AZMON BUILD_AZMON + "Build Azure Monitor / Application Insights support" ON) +matsdk_bool_option(MATSDK_BUILD_APPLE_HTTP BUILD_APPLE_HTTP + "Build the Apple-native HTTP client" "${APPLE}") + +set(_matsdk_ios_default OFF) +if(CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "visionOS") + set(_matsdk_ios_default ON) +endif() +matsdk_bool_option(MATSDK_BUILD_IOS BUILD_IOS + "Build for iOS or visionOS" "${_matsdk_ios_default}") + +matsdk_bool_option(MATSDK_WARNINGS_AS_ERRORS "" + "Treat warnings in SDK-owned targets as errors" "${MATSDK_PROJECT_IS_TOP_LEVEL}") +option(LINK_STATIC_DEPENDS + "Deprecated no-op retained for compatibility with legacy build scripts" ON) + +set(_matsdk_library_type_default STATIC) +if(NOT DEFINED MATSDK_LIBRARY_TYPE AND DEFINED BUILD_SHARED_LIBS AND BUILD_SHARED_LIBS) + set(_matsdk_library_type_default SHARED) +endif() +set(MATSDK_LIBRARY_TYPE "${_matsdk_library_type_default}" CACHE STRING + "SDK library type: STATIC or SHARED") +set_property(CACHE MATSDK_LIBRARY_TYPE PROPERTY STRINGS STATIC SHARED) +string(TOUPPER "${MATSDK_LIBRARY_TYPE}" MATSDK_LIBRARY_TYPE) +if(NOT MATSDK_LIBRARY_TYPE STREQUAL "STATIC" AND NOT MATSDK_LIBRARY_TYPE STREQUAL "SHARED") + message(FATAL_ERROR + "MATSDK_LIBRARY_TYPE must be STATIC or SHARED; got '${MATSDK_LIBRARY_TYPE}'.") +endif() + +set(MATSDK_SQLITE_PROVIDER "AUTO" CACHE STRING + "SQLite dependency provider: AUTO, SYSTEM, MINIMAL, or VENDORED") +set_property(CACHE MATSDK_SQLITE_PROVIDER PROPERTY STRINGS AUTO SYSTEM MINIMAL VENDORED) +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_SQLITE_TARGET) + set(MATSDK_SQLITE_PROVIDER_RESOLVED SYSTEM) + elseif(NOT MATSDK_USE_VCPKG_DEPS + 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(MATSDK_ZLIB_TARGET) + set(MATSDK_ZLIB_PROVIDER_RESOLVED SYSTEM) + elseif(NOT MATSDK_USE_VCPKG_DEPS + AND (WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Android")) + set(MATSDK_ZLIB_PROVIDER_RESOLVED VENDORED) + else() + set(MATSDK_ZLIB_PROVIDER_RESOLVED SYSTEM) + endif() +endif() + +if(NOT MATSDK_SQLITE_PROVIDER_RESOLVED MATCHES "^(SYSTEM|MINIMAL|VENDORED)$") + message(FATAL_ERROR + "MATSDK_SQLITE_PROVIDER must be AUTO, SYSTEM, MINIMAL, or VENDORED; " + "got '${MATSDK_SQLITE_PROVIDER}'.") +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() +if(MATSDK_SQLITE_TARGET AND NOT MATSDK_SQLITE_PROVIDER_RESOLVED STREQUAL "SYSTEM") + message(FATAL_ERROR + "MATSDK_SQLITE_TARGET requires MATSDK_SQLITE_PROVIDER=AUTO or SYSTEM.") +endif() +if(MATSDK_ZLIB_TARGET AND NOT MATSDK_ZLIB_PROVIDER_RESOLVED STREQUAL "SYSTEM") + message(FATAL_ERROR + "MATSDK_ZLIB_TARGET requires MATSDK_ZLIB_PROVIDER=AUTO or SYSTEM.") +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 "MATSDK_LIBRARY_TYPE: ${MATSDK_LIBRARY_TYPE}") +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/docs/building-with-vcpkg.md b/docs/building-with-vcpkg.md index 315fa8662..b40ebb144 100644 --- a/docs/building-with-vcpkg.md +++ b/docs/building-with-vcpkg.md @@ -211,7 +211,7 @@ will automatically use the optimized zlib-ng build. This section applies when the SDK is linked **statically** into your binary (the default for the `*-static` vcpkg triplets) — most footprint control then lives on *your* side of the link. If you instead consume a **dynamic** `mat` -(e.g. the default `x64-windows` triplet, or `BUILD_SHARED_LIBS=ON`), the runtime +(e.g. the default `x64-windows` triplet, or `MATSDK_LIBRARY_TYPE=SHARED`), the runtime ships as its own `mat.dll` / `libmat.so` / `libmat.dylib`; the SDK's own `-fvisibility=hidden` and `/Gy /Gw` already trim its exported symbol table, and the consumer-side linker options below are specific to the static-link case. @@ -357,7 +357,7 @@ requires a TLS backend, so omitting it would fail to configure (swap in 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 diff --git a/docs/cpp-start-ios.md b/docs/cpp-start-ios.md index ad80866e0..d00f2aa2a 100644 --- a/docs/cpp-start-ios.md +++ b/docs/cpp-start-ios.md @@ -37,6 +37,26 @@ 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_IOS=ON \ + -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..ca524f8fb --- /dev/null +++ b/docs/embedding-with-cmake.md @@ -0,0 +1,92 @@ +# 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(MATSDK_LIBRARY_TYPE STATIC CACHE STRING "" 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. + +`MATSDK_LIBRARY_TYPE` explicitly selects `STATIC` or `SHARED` without changing +the parent project's global `BUILD_SHARED_LIBS` value. Legacy `BUILD_*` inputs +remain accepted for compatibility, but new integrations should use the +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` uses `find_package()` unless a matching +`MATSDK_SQLITE_TARGET` or `MATSDK_ZLIB_TARGET` is supplied. `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 the dependency implementation (for example, libcurl +built with OpenSSL vs. mbedTLS) without changing the leaf consumer target, define +the desired dependency targets before adding the SDK and point the matching +`MATSDK_*_TARGET` cache variables at them: + +```cmake +# Created by your superbuild, package manager, or imported-target wrappers. +add_library(my_curl_target STATIC IMPORTED GLOBAL) # OpenSSL or mbedTLS curl +add_library(my_zlib_target STATIC IMPORTED GLOBAL) +add_library(my_sqlite_target STATIC IMPORTED GLOBAL) + +set(MATSDK_CURL_TARGET my_curl_target CACHE STRING "" FORCE) +set(MATSDK_ZLIB_TARGET my_zlib_target CACHE STRING "" FORCE) +set(MATSDK_SQLITE_TARGET my_sqlite_target CACHE STRING "" FORCE) +add_subdirectory(cpp_client_telemetry) + +target_link_libraries(your_target PRIVATE MSTelemetry::mat) +``` + +If a `MATSDK_*_TARGET` value is empty, the SDK falls back to its existing +dependency discovery for that library. + +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/docs/sharing-a-single-sdk-runtime.md b/docs/sharing-a-single-sdk-runtime.md index 10e69746d..b3515c220 100644 --- a/docs/sharing-a-single-sdk-runtime.md +++ b/docs/sharing-a-single-sdk-runtime.md @@ -86,7 +86,7 @@ else() endif() ``` -The port honors `VCPKG_LIBRARY_LINKAGE` / `BUILD_SHARED_LIBS` and emits the +The port honors `VCPKG_LIBRARY_LINKAGE` / `MATSDK_LIBRARY_TYPE` and emits the shared `mat` plus its import lib and the `MSTelemetry` CMake config package. ### Pin one version across all modules 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 97428a101..0c46a861d 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -6,10 +6,9 @@ cmake_policy(SET CMP0063 NEW) # 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") +# Legacy native builds may need system-installed deps from /usr/local/include. +# Never inject this host path into iOS, Android, or other cross-compiles. +if(NOT MATSDK_USE_VCPKG_DEPS AND NOT CMAKE_CROSSCOMPILING) include_directories(/usr/local/include) endif() @@ -66,7 +65,7 @@ set(SRCS decorators/BaseDecorator.cpp ) # Support for Azure Monitor / Application Insights -if(BUILD_AZMON) +if(MATSDK_BUILD_AZMON) include(modules/azmon/CMakeLists.txt OPTIONAL) endif() @@ -91,7 +90,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,14 +98,14 @@ 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) +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/cds/" AND MATSDK_BUILD_CDS) add_definitions(-DHAVE_MAT_CDS) list(APPEND SRCS modules/cds/CdsFactory.hpp @@ -114,14 +113,14 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/cds/" AND BUILD_CDS) ) 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 +152,7 @@ if(PAL_IMPLEMENTATION STREQUAL "CPP11") list(APPEND SRCS pal/posix/sysinfo_utils_apple.cpp ) - if(BUILD_IOS) + if(MATSDK_BUILD_IOS) list(APPEND SRCS pal/posix/sysinfo_utils_ios.mm ) @@ -178,7 +177,7 @@ if(PAL_IMPLEMENTATION STREQUAL "CPP11") endif() if(APPLE) - if(BUILD_APPLE_HTTP OR BUILD_IOS) + if(MATSDK_BUILD_APPLE_HTTP OR MATSDK_BUILD_IOS) list(APPEND SRCS http/HttpClient_Apple.mm ) @@ -216,7 +215,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 +232,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 +247,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,9 +270,6 @@ 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) list(APPEND SRCS @@ -310,6 +306,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) @@ -318,13 +323,32 @@ endif() ################################################################################################ # Build the library ################################################################################################ -if(BUILD_SHARED_LIBS) +if(MATSDK_LIBRARY_TYPE STREQUAL "SHARED") message(STATUS "Building shared SDK library") add_library(mat SHARED ${SRCS}) 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(MATSDK_LIBRARY_TYPE STREQUAL "SHARED") + 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 @@ -340,7 +364,7 @@ endif() # a consumer DLL/.so that statically absorbs this library. Windows needs an # explicit (empty) MATSDK_STATIC_LIB; elsewhere the empty MATSDK_LIBABI default # plus -fvisibility=hidden (root CMakeLists.txt) already hides them. -if(BUILD_SHARED_LIBS) +if(MATSDK_LIBRARY_TYPE STREQUAL "SHARED") target_compile_definitions(mat PRIVATE MATSDK_SHARED_LIB=1) if(WIN32) target_compile_definitions(mat INTERFACE MATSDK_IMPORT_LIB=1) @@ -375,8 +399,8 @@ target_include_directories(mat ${CMAKE_CURRENT_SOURCE_DIR}/utils ) -if(APPLE AND BUILD_OBJC_WRAPPER) - if(BUILD_SHARED_LIBS AND OBJC_WRAPPER_SRCS) +if(APPLE AND MATSDK_BUILD_OBJC_WRAPPER) + if(MATSDK_LIBRARY_TYPE STREQUAL "SHARED" 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 # the wrapper class symbols (_OBJC_CLASS_$_ODW*), which are public API on @@ -407,7 +431,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 +471,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,138 +478,132 @@ 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(APPLE AND (MATSDK_BUILD_IOS + OR CMAKE_SYSTEM_NAME STREQUAL "iOS" + OR CMAKE_SYSTEM_NAME STREQUAL "visionOS")) + # 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() -# TODO: allow adding "${Tcmalloc_LIBRARIES}" to target_link_libraries for memory leak debugging -# (USE_TCMALLOC / FindTcmalloc.cmake are configured for Debug builds in the root CMakeLists.txt, -# but the library is not yet linked here). -if(MATSDK_USE_VCPKG_DEPS) - # vcpkg mode: all deps resolved via find_package() in root CMakeLists.txt - # These are PUBLIC so static-library consumers get the transitive link set - # through the exported MSTelemetry::mat target. - if(APPLE) - # macOS/iOS link the system libsqlite3 + libz (SQLite::SQLite3 / ZLIB::ZLIB - # resolve to the OS libraries via CMake's find modules), so the vcpkg - # sqlite3/zlib packages are neither pulled nor linked here. - target_link_libraries(mat - PUBLIC - SQLite::SQLite3 - ZLIB::ZLIB - nlohmann_json::nlohmann_json - ${LIBS} - ) +if(MATSDK_BUNDLE_ZLIB AND NOT TARGET zlib_bundled) + add_library(zlib_bundled STATIC + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/adler32.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/compress.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/crc32.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/deflate.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/gzclose.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/gzlib.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/gzread.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/gzwrite.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/infback.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/inffast.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/inflate.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/inftrees.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/trees.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/uncompr.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../zlib/zutil.c" + ) + target_include_directories(zlib_bundled PUBLIC + "$") + set_target_properties(zlib_bundled PROPERTIES + POSITION_INDEPENDENT_CODE ON + C_VISIBILITY_PRESET hidden) + if(NOT WIN32) + target_compile_definitions(zlib_bundled PRIVATE Z_HAVE_UNISTD_H) else() - if(MATSDK_BUNDLE_SQLITE) - # Private minimal SQLite instead of the vcpkg sqlite3 package. PRIVATE so its - # include dirs / compile definitions are not propagated as a public usage - # requirement. A static mat still propagates the archive itself for linking - # (via $), so it is added to the export set for static builds - # below; a shared mat absorbs it and propagates nothing. - target_link_libraries(mat PRIVATE sqlite3_bundled) - else() - target_link_libraries(mat PUBLIC unofficial::sqlite3::sqlite3) - endif() - target_link_libraries(mat - PUBLIC - ZLIB::ZLIB - nlohmann_json::nlohmann_json - ${LIBS} - ) + target_compile_definitions(zlib_bundled PRIVATE ZLIB_WINAPI) + target_compile_definitions(zlib_bundled INTERFACE + $) + endif() + if(MSVC) + target_compile_options(zlib_bundled PRIVATE + /w /WX- /Gy + $<$:/Gw>) + else() + target_compile_options(zlib_bundled PRIVATE + -w -ffunction-sections + $<$>:-fdata-sections>) endif() +endif() + +if(MATSDK_BUNDLE_SQLITE) + set(_matsdk_sqlite_target sqlite3_bundled) +elseif(MATSDK_SQLITE_TARGET) + set(_matsdk_sqlite_target "${MATSDK_SQLITE_TARGET}") +elseif(MATSDK_USE_VCPKG_DEPS AND NOT APPLE) + set(_matsdk_sqlite_target unofficial::sqlite3::sqlite3) +elseif(APPLE AND NOT MATSDK_USE_VCPKG_DEPS) + # Resolve from the selected Apple SDK, not host Homebrew/pkg-config paths. + set(_matsdk_sqlite_target sqlite3) 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) + if(NOT TARGET SQLite::SQLite3) + find_package(SQLite3 REQUIRED) + endif() + set(_matsdk_sqlite_target SQLite::SQLite3) +endif() - 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}) - else() - # Linux legacy: system zlib + system (or private minimal) sqlite3. ZLIB::ZLIB - # and SQLite::SQLite3 are imported targets that carry their own include dirs. +if(MATSDK_BUNDLE_ZLIB) + set(_matsdk_zlib_target zlib_bundled) +elseif(MATSDK_ZLIB_TARGET) + set(_matsdk_zlib_target "${MATSDK_ZLIB_TARGET}") +elseif(APPLE AND NOT MATSDK_USE_VCPKG_DEPS) + # Resolve from the selected Apple SDK, not host Homebrew/pkg-config paths. + set(_matsdk_zlib_target z) +else() + if(NOT TARGET ZLIB::ZLIB) find_package(ZLIB REQUIRED) - if(MATSDK_BUNDLE_SQLITE) - target_link_libraries(mat PRIVATE sqlite3_bundled ZLIB::ZLIB ${LIBS}) - else() - # find_package(SQLite3) needs CMake >= 3.14, guaranteed by the project floor; - # SQLite::SQLite3 is an imported target carrying its own include dirs. - find_package(SQLite3 REQUIRED) - target_link_libraries(mat PRIVATE SQLite::SQLite3 ZLIB::ZLIB ${LIBS}) - endif() endif() + set(_matsdk_zlib_target ZLIB::ZLIB) +endif() + +target_link_libraries(mat PRIVATE + ${_matsdk_sqlite_target} + ${_matsdk_zlib_target} + ${LIBS}) +if(MATSDK_USE_VCPKG_DEPS) + target_link_libraries(mat PRIVATE nlohmann_json::nlohmann_json) 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") - endif() + target_link_libraries(mat PUBLIC Threads::Threads "${CMAKE_DL_LIBS}") if(CMAKE_SYSTEM_NAME STREQUAL "Android") target_link_libraries(mat PUBLIC log) endif() @@ -615,7 +617,7 @@ elseif(APPLE) "-framework Network" "-framework SystemConfiguration" ) - if(BUILD_IOS OR CMAKE_SYSTEM_NAME STREQUAL "iOS") + if(MATSDK_BUILD_IOS OR CMAKE_SYSTEM_NAME STREQUAL "iOS") target_link_libraries(mat PUBLIC "-framework UIKit") else() target_link_libraries(mat PUBLIC "-framework IOKit") @@ -625,31 +627,40 @@ 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_INSTALL_TARGETS mat) +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_INSTALL_TARGETS sqlite3_bundled) + endif() + if(MATSDK_BUNDLE_ZLIB AND TARGET zlib_bundled) + list(APPEND MATSDK_INSTALL_TARGETS zlib_bundled) endif() + foreach(_matsdk_fetched_target IN LISTS MATSDK_FETCHED_CURL_TARGETS) + if(TARGET ${_matsdk_fetched_target}) + list(APPEND MATSDK_INSTALL_TARGETS ${_matsdk_fetched_target}) + endif() + endforeach() +endif() + +if(MATSDK_USE_VCPKG_DEPS) install(TARGETS ${MATSDK_INSTALL_TARGETS} EXPORT MSTelemetryTargets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) +else() + install(TARGETS ${MATSDK_INSTALL_TARGETS} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) +endif() +if(MATSDK_USE_VCPKG_DEPS) message(STATUS "Library will be installed to ${CMAKE_INSTALL_LIBDIR}") # Generate and install CMake package config files @@ -681,11 +692,5 @@ if(MATSDK_USE_VCPKG_DEPS) DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MSTelemetry ) 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} - ) message(STATUS "Library will be installed to ${CMAKE_INSTALL_LIBDIR}") endif() diff --git a/lib/http/HttpClient_Curl.hpp b/lib/http/HttpClient_Curl.hpp index b1bb5344c..391f5db55 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; + } - 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 (!m_sslCaInfo.empty() && !SetOption(CURLOPT_CAINFO, m_sslCaInfo.c_str())) + { + DispatchEvent(OnCreateFailed); + return; + } + + 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 * @@ -499,7 +599,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) { size_t realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *)userp; @@ -531,10 +631,11 @@ 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) { + auto* data = static_cast*>(userp); if (data != nullptr) { - const auto* begin = static_cast(ptr); + const auto* begin = reinterpret_cast(ptr); const auto* end = begin + size * nmemb; data->insert( data->end(), begin, end); } diff --git a/lib/pal/posix/DeviceInformationImpl_Android.cpp b/lib/pal/posix/DeviceInformationImpl_Android.cpp index 61746d664..fc132629d 100644 --- a/lib/pal/posix/DeviceInformationImpl_Android.cpp +++ b/lib/pal/posix/DeviceInformationImpl_Android.cpp @@ -52,8 +52,10 @@ namespace PAL_NS_BEGIN { ///// IDeviceInformation API DeviceInformationImpl::DeviceInformationImpl(IRuntimeConfig& configuration) : + m_os_architecture(OsArchitectureType_Unknown), + m_powerSource(PowerSource_Battery), m_info_helper(), - m_powerSource(PowerSource_Battery) + m_registeredCount(0) {} std::string DeviceInformationImpl::GetDeviceTicket() const @@ -260,4 +262,3 @@ Java_com_microsoft_applications_events_HttpClient_onPowerChange(JNIEnv* env, PAL::AndroidDeviceInformationConnector::setModel(std::string(start, end)); env->ReleaseStringUTFChars(model, start); } - diff --git a/lib/pal/posix/NetworkInformationImpl_Android.cpp b/lib/pal/posix/NetworkInformationImpl_Android.cpp index 0c12464b4..15e2d646d 100644 --- a/lib/pal/posix/NetworkInformationImpl_Android.cpp +++ b/lib/pal/posix/NetworkInformationImpl_Android.cpp @@ -42,9 +42,11 @@ namespace PAL_NS_BEGIN { NetworkCost AndroidNetcostConnector::s_cost = NetworkCost_Unknown; NetworkInformationImpl::NetworkInformationImpl(IRuntimeConfig& configuration) : - m_info_helper(), + m_type(NetworkType_Unknown), m_cost(NetworkCost_Unknown), - m_isNetDetectEnabled(configuration[CFG_BOOL_ENABLE_NET_DETECT]){}; + m_info_helper(), + m_registeredCount(0), + m_isNetDetectEnabled(configuration[CFG_BOOL_ENABLE_NET_DETECT]){} NetworkInformationImpl::~NetworkInformationImpl() {}; @@ -156,4 +158,3 @@ Java_com_microsoft_applications_events_HttpClient_onCostChange(JNIEnv* env, { PAL::AndroidNetcostConnector::UpdateCost(isMetered ? NetworkCost_Metered : NetworkCost_Unmetered); } - diff --git a/lib/pal/posix/SystemInformationImpl_Android.cpp b/lib/pal/posix/SystemInformationImpl_Android.cpp index 15e0bb9b1..b1911f8ae 100644 --- a/lib/pal/posix/SystemInformationImpl_Android.cpp +++ b/lib/pal/posix/SystemInformationImpl_Android.cpp @@ -163,8 +163,8 @@ namespace PAL_NS_BEGIN { std::string AndroidSystemInformationConnector::s_device_class; SystemInformationImpl::SystemInformationImpl(IRuntimeConfig& configuration) : - m_info_helper(), - m_os_name("Android") + m_os_name("Android"), + m_info_helper() { if (configuration.HasConfig(CFG_PTR_ANDROID_JVM) && configuration.HasConfig(CFG_JOBJECT_ANDROID_ACTIVITY)) { @@ -245,4 +245,3 @@ extern "C" JNIEXPORT void JNICALL Java_com_microsoft_applications_events_HttpCli PAL::AndroidSystemInformationConnector::s_device_class, deviceClass); } - diff --git a/lib/system/EventProperties.cpp b/lib/system/EventProperties.cpp index 2ade77741..71d5f4c5b 100644 --- a/lib/system/EventProperties.cpp +++ b/lib/system/EventProperties.cpp @@ -474,7 +474,7 @@ namespace MAT_NS_BEGIN { evt_prop* EventProperties::pack() { size_t size = m_storage->properties.size() + m_storage->propertiesPartB.size() + 1; - evt_prop * result = static_cast(calloc(sizeof(evt_prop), size)); + evt_prop * result = static_cast(calloc(size, sizeof(evt_prop))); if (result==nullptr) { LOG_ERROR("Unable to allocate memory to pack EventProperties"); @@ -620,4 +620,3 @@ namespace MAT_NS_BEGIN { } MAT_NS_END - diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a1d0a1351..e73c0d27b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -14,11 +14,11 @@ 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) +if(MATSDK_BUILD_UNIT_TESTS) include_directories(${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..7c51fedf1 --- /dev/null +++ b/tests/embedding/CMakeLists.txt @@ -0,0 +1,45 @@ +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(MATSDK_LIBRARY_TYPE STATIC CACHE STRING "") +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_package(CURL REQUIRED) + # A later find_package(CURL REQUIRED) fails when this switch is enabled, so + # this configuration proves the SDK consumes the pre-created target directly. + set(CMAKE_DISABLE_FIND_PACKAGE_CURL ON CACHE BOOL "" FORCE) +endif() + +option(MATSDK_EMBEDDING_USE_FETCHCONTENT + "Exercise local-source FetchContent instead of add_subdirectory" OFF) +if(MATSDK_EMBEDDING_USE_FETCHCONTENT) + include(FetchContent) + FetchContent_Declare(cpp_client_telemetry + SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../..") + FetchContent_MakeAvailable(cpp_client_telemetry) +else() + add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../.." cpp_client_telemetry) +endif() + +add_executable(embedding_test "${CMAKE_CURRENT_LIST_DIR}/../vcpkg/main.cpp") +target_link_libraries(embedding_test PRIVATE MSTelemetry::mat) +if(MSVC) + target_compile_options(embedding_test PRIVATE /W4 /WX) +else() + target_compile_options(embedding_test PRIVATE -Wall -Wextra -Werror) +endif() diff --git a/tests/functests/CMakeLists.txt b/tests/functests/CMakeLists.txt index d09e31f62..785926139 100644 --- a/tests/functests/CMakeLists.txt +++ b/tests/functests/CMakeLists.txt @@ -8,14 +8,14 @@ set(SRCS MultipleLogManagersTests.cpp ) -if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/privacyguard/" AND BUILD_PRIVACYGUARD) +if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/privacyguard/" AND MATSDK_BUILD_PRIVACYGUARD) add_definitions(-DHAVE_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,7 +27,7 @@ if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/dataviewer/") ) endif() -if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/liveeventinspector/" AND BUILD_LIVEEVENTINSPECTOR) +if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/liveeventinspector/" AND MATSDK_BUILD_LIVEEVENTINSPECTOR) add_definitions(-DHAVE_MAT_LIVEEVENTINSPECTOR) list(APPEND SRCS "${PROJECT_SOURCE_DIR}/lib/modules/liveeventinspector/tests/functests/LiveEventInspectorFuncTests.cpp" @@ -48,7 +48,7 @@ endif() source_group(" " REGULAR_EXPRESSION "") source_group("common" REGULAR_EXPRESSION "/tests/common/") -if(BUILD_IOS) +if(MATSDK_BUILD_IOS) add_library(FuncTests ${SRCS} ${TESTS_COMMON_SRCS}) else() add_executable(FuncTests ${SRCS} ${TESTS_COMMON_SRCS}) @@ -61,15 +61,25 @@ if(PAL_IMPLEMENTATION STREQUAL "WIN32") 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 ) + if(TARGET zlib_bundled) + set(MATSDK_TEST_ZLIB zlib_bundled) + else() + set(MATSDK_TEST_ZLIB ${PROJECT_BINARY_DIR}/zlib/zlib.lib) + target_compile_definitions(FuncTests PRIVATE ZLIB_WINAPI) + endif() + if(TARGET sqlite3_bundled) + set(SQLITE3_LIB sqlite3_bundled) + else() + set(SQLITE3_LIB ${PROJECT_BINARY_DIR}/sqlite/sqlite.lib) + endif() 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 + mat + wininet.lib + ${PROJECT_BINARY_DIR}/gtest/gtest.lib + ${PROJECT_BINARY_DIR}/gmock/gmock.lib + ${MATSDK_TEST_ZLIB} + ${SQLITE3_LIB} ) else() @@ -99,7 +109,7 @@ else() # Add flags for obtaining system UUID via IOKit if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") set (PLATFORM_LIBS "-framework CoreFoundation -framework Foundation") - if(BUILD_IOS) + if(MATSDK_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") @@ -154,4 +164,8 @@ else() 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 7233d2920..db93ab514 100644 --- a/tests/unittests/CMakeLists.txt +++ b/tests/unittests/CMakeLists.txt @@ -61,7 +61,7 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/azmon/AIJsonSerializer.hpp") endif() if (APPLE) - if (BUILD_IOS) + if (MATSDK_BUILD_IOS) list(APPEND SRCS SysInfoUtilsTests_iOS.cpp) else() list(APPEND SRCS SysInfoUtilsTests_Mac.cpp) @@ -76,7 +76,7 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/exp/tests") ) endif() -if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/privacyguard/" AND BUILD_PRIVACYGUARD) +if(EXISTS "${PROJECT_SOURCE_DIR}/lib/modules/privacyguard/" AND MATSDK_BUILD_PRIVACYGUARD) add_definitions(-DHAVE_MAT_PRIVACYGUARD) list(APPEND SRCS "${PROJECT_SOURCE_DIR}/lib/modules/privacyguard/tests/unittests/InitializationConfigurationTests.cpp" @@ -87,7 +87,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,7 +109,7 @@ endif() source_group(" " REGULAR_EXPRESSION "") source_group("common" REGULAR_EXPRESSION "/tests/common/") -if(BUILD_IOS) +if(MATSDK_BUILD_IOS) add_library(UnitTests STATIC ${SRCS} ${TESTS_COMMON_SRCS}) else() add_executable(UnitTests ${SRCS} ${TESTS_COMMON_SRCS}) @@ -122,15 +122,25 @@ if(PAL_IMPLEMENTATION STREQUAL "WIN32") 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 ) + if(TARGET zlib_bundled) + set(MATSDK_TEST_ZLIB zlib_bundled) + else() + set(MATSDK_TEST_ZLIB ${PROJECT_BINARY_DIR}/zlib/zlib.lib) + target_compile_definitions(UnitTests PRIVATE ZLIB_WINAPI) + endif() + if(TARGET sqlite3_bundled) + set(SQLITE3_LIB sqlite3_bundled) + else() + set(SQLITE3_LIB ${PROJECT_BINARY_DIR}/sqlite/sqlite.lib) + endif() 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 + mat + wininet.lib + ${PROJECT_BINARY_DIR}/gtest/gtest.lib + ${PROJECT_BINARY_DIR}/gmock/gmock.lib + ${MATSDK_TEST_ZLIB} + ${SQLITE3_LIB} ) else() @@ -163,7 +173,7 @@ else() # 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) + if(MATSDK_BUILD_IOS) set (PLATFORM_LIBS "${PLATFORM_LIBS} -framework UIKit") endif() endif() @@ -221,4 +231,8 @@ else() 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 c9894b90d..f57788670 100644 --- a/tests/unittests/HttpClientCurlTests.cpp +++ b/tests/unittests/HttpClientCurlTests.cpp @@ -56,6 +56,15 @@ TEST_F(HttpClientCurlTests, CurlHttpOperation_ConstructsWithCaInfo) ASSERT_NE(op.GetHandle(), nullptr); } +TEST(HttpClientCurlOperationTests, SelectsHttp2OnlyWhenRuntimeSupportsIt) +{ + const curl_version_info_data* versionInfo = curl_version_info(CURLVERSION_NOW); + const long expected = (versionInfo != nullptr && (versionInfo->features & CURL_VERSION_HTTP2) != 0) + ? CURL_HTTP_VERSION_2_0 + : CURL_HTTP_VERSION_1_1; + EXPECT_EQ(CurlHttpOperation::GetPreferredHttpVersion(), expected); +} + // --- ILogConfiguration integration --- TEST(HttpClientCurlConfigTests, LogConfiguration_SslVerify_DefaultIsTrue) diff --git a/tools/ports/cpp-client-telemetry/portfile.cmake b/tools/ports/cpp-client-telemetry/portfile.cmake index c9ce3168c..db547ae53 100644 --- a/tools/ports/cpp-client-telemetry/portfile.cmake +++ b/tools/ports/cpp-client-telemetry/portfile.cmake @@ -22,7 +22,7 @@ else() 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) @@ -71,18 +71,40 @@ if(VCPKG_TARGET_IS_LINUX OR VCPKG_TARGET_IS_ANDROID) 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_LIBRARY_TYPE SHARED) + set(MATSDK_VCPKG_BUILD_SHARED_LIBS ON) +else() + set(MATSDK_VCPKG_LIBRARY_TYPE STATIC) + set(MATSDK_VCPKG_BUILD_SHARED_LIBS OFF) +endif() vcpkg_cmake_configure( SOURCE_PATH "${SOURCE_PATH}" OPTIONS - ${FEATURE_OPTIONS} -DMATSDK_USE_VCPKG_DEPS=ON + -DMATSDK_SQLITE_PROVIDER=${MATSDK_VCPKG_SQLITE_PROVIDER} + -DMATSDK_LIBRARY_TYPE=${MATSDK_VCPKG_LIBRARY_TYPE} + -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} + -DMATSDK_BUILD_IOS=${MATSDK_BUILD_IOS} + # Legacy aliases keep the pinned release fallback buildable until the + # next release contains the canonical MATSDK_* options. + -DBUILD_SHARED_LIBS=${MATSDK_VCPKG_BUILD_SHARED_LIBS} -DBUILD_HEADERS=ON -DBUILD_LIBRARY=ON -DBUILD_TEST_TOOL=OFF @@ -92,7 +114,6 @@ 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} )