This guide is for engineers who maintain or make substantial changes to the 1DS C/C++ SDK repository. It complements the platform-specific documentation; it does not replace those documents or the build definitions used by CI.
Before changing the SDK:
- Read the root README for supported platforms and the public support boundary.
- Read Coding style and the documentation for the area being changed.
- Read Versioning before making compatibility or release decisions.
- Read Embedding with CMake and Building with vcpkg when changing CMake targets, dependencies, exported packages, or feature selection.
- Read Sharing a single SDK runtime before changing binary boundaries, symbol visibility, CRT linkage, or the stable C API used by SDK-in-SDK consumers.
- Inspect the relevant workflows under
.github/workflows. They are executable documentation for supported build combinations.
Do not assume that a successful build of one configuration proves that another configuration works. Platform PALs, HTTP transports, storage implementations, static/shared linkage, optional modules, and generated configuration headers can select materially different code.
The public repository contains the core SDK. Some Microsoft-only modules are
maintained separately under lib/modules. Clone recursively only when work
requires those modules and your GitHub account has access:
git clone --recurse-submodules https://github.com/microsoft/cpp_client_telemetry.gitDo not make core behavior accidentally depend on a private module. Builds that
do not fetch lib/modules must continue to compile and link.
Important locations:
| Path | Purpose |
|---|---|
lib/include/public |
Supported public C and C++ headers |
lib/api, lib/system |
Public API implementation and telemetry pipeline |
lib/http |
Platform HTTP transports |
lib/offline |
Persistent and in-memory storage |
lib/pal |
Platform abstraction layers |
lib/modules |
Optional Microsoft-only modules |
tests/unittests |
Component-level tests |
tests/functests |
Public behavior and pipeline tests |
tests/vcpkg |
Installed-package consumer tests |
examples |
Sample integrations |
.github/workflows |
CI and release automation |
- Start from current
mainand create a focused topic branch. - Search for existing helpers and platform-specific implementations before adding new code.
- Preserve API and configuration compatibility unless the change explicitly requires a documented break.
- Update tests and directly related documentation with the implementation.
- Build and test the code paths selected by the change, not merely the easiest local configuration.
- Review the final diff for generated files, accidental dependency changes, warning suppressions, disabled tests, credentials, tenant tokens, and local paths.
- Open a PR with the behavior change, compatibility implications, and exact validation performed.
Treat a warning suppression, skipped test, conditional source exclusion, or
continue-on-error as an unverified safety claim. Check why it exists and
whether the changed code makes that claim invalid. Fix the underlying defect
instead of broadening a suppression.
List the maintained presets:
cmake --list-presetsThe compatibility wrappers use those presets:
# Windows; run from PowerShell with Visual Studio C++ tools installed
.\build-cmake.ps1 -Configuration Debug
.\build-cmake.ps1 -Configuration Release
# Build a shared SDK
.\build-cmake.ps1 -Configuration Release -SharedOn Linux, WSL, or macOS:
./build.sh debug
./build.sh releaseFor a clean source-package consumer check, use the installed-package and embedding guidance in Embedding with CMake. CMake and vcpkg builds exercise packaging behavior that an in-tree Visual Studio solution build does not.
The Windows CI path uses build-tests.cmd:
# Platform, configuration, optional .props/.targets file, transport
.\build-tests.cmd x64 Release "" WinHTTP
.\build-tests.cmd x64 Debug "" WinHTTP
# Exercise the opt-in legacy transport when transport code or selection changes
.\build-tests.cmd x64 Release "" WinInetThe default desktop transport is WinHTTP. It supports services and non-interactive processes; WinInet is retained for consumers that explicitly need its user-profile proxy or cookie behavior.
The supported Windows floor is Windows 10 and Windows Server 2016. Windows 7, Windows 8, and Windows 8.1 are not supported; do not add compatibility paths solely for those older systems. The Windows CI builds target the Windows 10 API floor.
From a WSL distribution with the compiler, CMake, and other documented prerequisites installed:
./build-tests.sh release
./tests/vcpkg/test-vcpkg-linux.shbuild-tests.sh currently excludes APITest.C_API_Test. Do not describe that
run as complete C API coverage, and re-evaluate the exclusion when changing the
C API or its implementation.
The scripts under tests/vcpkg configure, build, link, and run a separate
consumer against the package:
.\tests\vcpkg\test-vcpkg-windows.ps1 -VcpkgRoot C:\path\to\vcpkg
.\tests\vcpkg\test-vcpkg-windows.ps1 -VcpkgRoot C:\path\to\vcpkg -WinInet./tests/vcpkg/test-vcpkg-linux.sh
./tests/vcpkg/test-vcpkg-macos.sh
./tests/vcpkg/test-vcpkg-ios.sh --simulator
./tests/vcpkg/test-vcpkg-android.shSee the vcpkg test README for prerequisites, triplets, supported Android ABIs, and device deployment.
Android work requires Java 17+, the Android SDK, CMake, and a supported NDK. Set the SDK and NDK environment variables to the installed locations:
$env:ANDROID_SDK_ROOT = "C:\Android\android-sdk"
$env:ANDROID_HOME = $env:ANDROID_SDK_ROOT
$env:ANDROID_NDK_HOME = "$env:ANDROID_SDK_ROOT\ndk\27.0.12077973"
$env:ANDROID_NDK = $env:ANDROID_NDK_HOMEUse the Gradle project under lib/android_build for the AAR and Android test
application. Install an emulator image through Android Studio or the SDK manager
when no physical device is available. Run the test application on the emulator
or a connected device and inspect its logcat output. Changes to JNI, Room,
storage, networking, packaging, or ABI selection should not be validated only
with a host build.
Read Getting started with Android before changing the Android HTTP bridge or choosing between Room and native SQLite.
Use a macOS machine with Xcode for Apple-native code:
./tests/vcpkg/test-vcpkg-macos.sh
./tests/vcpkg/test-vcpkg-ios.sh --simulatorFor changes to Objective-C/Swift wrappers, Apple networking, packaging, or platform lifecycle behavior, also build the xcframework and run a representative sample in an iOS Simulator. Use a physical iOS device when the behavior depends on device identity, networking, background execution, or platform APIs that a simulator cannot represent.
See Getting started with iOS,
Getting started with macOS, and
tools/apple/README.md.
Scale validation to the affected behavior and the cost of a missed regression. The examples below are guidance, not permission to ignore a platform selected by the changed code.
| Change risk | Expected validation |
|---|---|
| Documentation or isolated, non-behavioral change | Manual diff review and any repository documentation checks; rely on CI for unaffected build matrices |
| Focused implementation change | Targeted unit/functional tests plus a Debug or Release build on the primary affected platform |
| Shared C++, CMake, dependency, storage, or transport change | Windows and WSL/Linux builds; relevant static/shared, package-consumer, and transport combinations |
| Android or Apple platform change | Host checks plus emulator/simulator execution; use a physical device when platform behavior warrants it |
| Cross-platform or release-critical change | Windows, WSL/Linux, Android, macOS, iOS Simulator, package-consumer tests, and representative physical-device checks where feasible |
| High-risk integration or ingestion change | Embed the local SDK in a real consuming application, exercise the changed scenario end to end, and verify expected events in the authorized telemetry destination |
Manual review and CI can be sufficient for a small, low-risk change. A larger change should use more independent environments. Record what was and was not tested in the PR so reviewers can assess residual risk.
The memory leak analysis workflow
runs Dr. Memory on Windows and Linux for unit tests, functional tests, and
SampleCppMini. It runs weekly, on relevant changes pushed to main, and by
manual dispatch. PRs trigger it only when the leak workflow, runner script, or
baseline changes; other PRs should not assume leak analysis ran before merge.
Review the job summaries and the Windows and Linux report artifacts (retained
for 90 days) against the leak baseline.
Leak-count increases produce warnings, not failures: a green job does not mean
the change introduced no leaks. Instrumentation or target failures fail the
job, and Windows also fails if netprofm.dll is loaded again.
Two tests remain in normal CI but are excluded under instrumentation:
BasicFuncTests.killSwitchWorks because Dr. Memory changes its asynchronous
drop count, and
OfflineStorageTests_SQLite.StoreThousandEventsTakesLessThanASecond on Windows
because instrumentation invalidates its one-second timing limit. Reassess
these exclusions when changing the affected code or test expectations.
When package-level tests are insufficient:
- Build the SDK locally in the same linkage and configuration used by a real consumer.
- Point the consumer at that local build without committing machine-specific paths.
- Exercise a scenario that emits an identifiable, privacy-safe event.
- Confirm the application remains stable through initialization, upload, flush, shutdown, and any background/service lifecycle involved.
- Use an approved, authenticated query path to verify that the event reached the intended database and table. Bound the query by test time and safe correlation fields.
- Record event time, ingestion time, SDK version, platform, and result. Do not commit access tokens, tenant tokens, customer data, raw device identifiers, or query exports.
- Remove temporary services, applications, local overrides, credentials, and test artifacts.
An empty offline queue alone does not prove ingestion: an event can be accepted, rejected, or removed before the downstream table is queried. Verify the destination when end-to-end delivery is the behavior under test.
- Public and private-module source configurations still compile as applicable.
- Changed public headers compile for consumers and preserve intended ABI/API behavior.
- Relevant unit, functional, package-consumer, and platform tests pass.
- No relevant tests are silently excluded.
- Static/shared and Debug/Release differences were considered.
- WinHTTP/WinInet, Room/SQLite, and platform PAL differences were considered where relevant.
- Documentation and examples match the implementation.
- The diff contains no credentials, tenant tokens, customer data, generated build trees, or machine-specific paths.
- CI failures and skipped jobs are understood before merge.
Releases use four components: X.Y.Z.W. The current generator policy is
documented in Solutions/version.txt; do not
hand-edit a version based on an outdated example.
-
Start from current
mainafter required changes have merged and required CI is green. -
Generate
lib/include/public/Version.hpp:.\tools\gen-version.cmd./tools/gen-version.sh
-
Verify the generated version, repository status, and diff. The release preparation PR should contain only intentional release changes.
-
Open and merge the release preparation PR through the normal review and approver process.
- Update local
mainto the merged release commit. - Create the four-component tag
vX.Y.Z.Won that commit and push it to the canonical repository. - Publish a non-draft, non-prerelease GitHub Release for the tag with release notes.
- Verify that the GitHub source archives resolve and contain the generated version.
Do not move or force-update a published release tag. Correct a bad release with
a new version and release notes describing the correction. If the correction
must reach SPM, choose a new X.Y.Z in Solutions/version.txt and regenerate
Version.hpp before tagging: changing only W produces the same SPM tag, so
the SPM workflow skips it and leaves consumers on the earlier package.
Publishing the GitHub Release triggers:
.github/workflows/spm-release.yml, which builds and validatesMATTelemetry.xcframework, uploads it to the release, and publishes the parallel three-component Swift Package Manager tag..github/workflows/vcpkg-release-bump.yml, which can prepare amicrosoft/vcpkgport update when its fork and credential settings are configured.
Check both workflows; do not assume that the release trigger completed all distribution work.
The vcpkg workflow requires repository configuration and a token capable of pushing to a fork and opening the upstream PR. If those credentials are intentionally unavailable, manually:
- Branch from current
microsoft/vcpkgmaster. - Update
ports/cpp-client-telemetry/portfile.cmaketo the new tag and source archive SHA512. - Update and format the port manifest.
- Run
vcpkg x-add-version cpp-client-telemetry --overwrite-version. - Build the production port from the published archive, not from a local SDK source override.
- Commit the port and version-database changes and open a
microsoft/vcpkgPR.
Coordinate updates to other maintained distribution channels, including CocoaPods, when the release is expected to be available there. Validate each package through a clean external consumer rather than only checking that an artifact exists.
- GitHub Release and four-component tag point to the intended commit.
Version.hppin the source archive reports the release version.- Release notes describe compatibility or migration requirements.
- SPM artifact, checksum, external consumer build, and three-component tag succeeded.
- The vcpkg port PR is open or the existing port already matches the release.
- Other maintained package feeds have been updated or explicitly tracked.
- A representative consumer can build against the released package.
- Release-critical telemetry changes have an authorized end-to-end ingestion result.
If a release workflow fails after publication, use its manual dispatch for the same tag when the workflow supports an idempotent rerun. Do not create duplicate tags or silently replace published artifacts without understanding the workflow's recovery behavior.