This repository contains deeply nested file paths that exceed Windows' default 260-character path limit. Before cloning or building on Windows, you must enable long path support.
-
Enable long paths in Windows (requires administrator privileges):
# Run as Administrator Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1
Alternatively, enable it via Group Policy: Computer Configuration → Administrative Templates → System → Filesystem → Enable Win32 long paths.
-
Enable long paths in Git:
git config --system core.longpaths true
Note: A system restart may be required after changing the Windows registry setting.
firely-cql-sdk/
├── Cql/ # Core SDK source — all Hl7.Cql.* packages and PackagerCLI
├── Demo/ # Demonstrates the full CQL-to-measure pipeline with real HEDIS/CMS measures
├── Examples/ # Runnable C# examples for common SDK scenarios
│ └── CqlSdkExamples/ # Packaging (200s), Invocation (300s–400s), Extensions (500s)
├── docs/ # This documentation
└── spec/ # CQL specification reference and conformance reports
External submodule repositories:
submodules/Firely.Cql.Sdk.Integration.Runner/— integration test runner for CMS measures
Build the core SDK using the Cql-Sdk.slnf solution filter (recommended):
dotnet build Cql-Sdk.slnfTo also build demos and examples, use Cql-Sdk-Demos-Examples.slnf. The Cql-Sdk-All.sln solution includes submodule projects and requires them to be initialized first (git submodule update).
The primary way to execute CQL from .NET is via the Invocation Toolkit (Hl7.Cql.Invocation). It:
- Compiles CQL through ELM to a .NET assembly in a single pipeline
- Manages assembly loading in an isolated
AssemblyLoadContext - Handles version checking of generated code
- Provides a clean API for invoking definitions, functions, and bulk expression enumeration
Always use the invocation toolkit instead of calling generated library classes directly. Direct calls to generated classes bypass context management, caching, and version safety.
using Hl7.Cql.CqlToElm.Toolkit;
using Hl7.Cql.CqlToElm.Toolkit.Extensions;
using Hl7.Cql.Fhir;
using Hl7.Cql.Invocation.Toolkit.Extensions;
using Microsoft.Extensions.Logging;
var loggerFactory = LoggerFactory.Create(b => b.AddConsole());
var cql = (CqlLibraryString)"""
library HelloWorldLib version '1.0.0'
define "HelloWorld" : 'Hello from CQL!'
""";
using var invoker = new CqlToolkit(loggerFactory)
.AddCqlLibraries(cql)
.CreateLibrarySetInvoker();
var result = invoker.InvokeLibraryDefinition(
FhirCqlContext.WithDataSource(),
cql.LibraryIdentifier,
"HelloWorld");
Console.WriteLine(result); // Hello from CQL!using Hl7.Cql.Invocation.Toolkit;
using Hl7.Cql.Invocation.Toolkit.Extensions;
using Hl7.Cql.Fhir;
// Load pre-packaged FHIR Library resources (containing embedded assembly binaries)
var invocationToolkit = new InvocationToolkit()
.AddAssemblyBinariesInFhirLibrariesFromDirectory(new DirectoryInfo("output/fhir"));
using var invoker = invocationToolkit.CreateLibrarySetInvoker();
var context = FhirCqlContext.WithDataSource();
var results = invoker
.SelectExpressions()
.ToList()
.SelectResults(context)
.ToList();See the Examples project for complete, runnable samples:
- 210–251: Packaging CQL/ELM into FHIR Library resources
- 310–340: Invoking CQL definitions, parameters, functions, and caching
- 400–410: Loading and invoking from FHIR resource directories
- 500: Extending SDK functionality
The SDK follows a pipeline from CQL source to .NET execution results:
-
CQL → ELM: CQL text is parsed and compiled to ELM (a structured representation). The .NET
Hl7.Cql.CqlToElmpackage handles this. For production use with complex measures, the Java-based CQL-to-ELM tool may also be used. -
ELM → LINQ Expressions: The
Hl7.Cql.Compilerpackage interprets the ELM tree and producesSystem.Linq.Expressionslambdas for each CQL definition. -
LINQ Expressions → .NET Assembly: The
Hl7.Cql.CodeGeneration.NETpackage converts the expressions to C# source code, which is then compiled to a .NET assembly by Roslyn. -
Assembly → CQL Results: The
Hl7.Cql.Invocationtoolkit loads the assembly, binds aCqlContext(containing patient data, parameters, value sets, and the reference date), and invokes individual definitions.
Steps 1–3 are handled automatically by the toolkits when you call CreateLibrarySetInvoker(). See the CQL Engine Architecture document for deeper background.
The Demo/ folder demonstrates the complete packaging pipeline for real HEDIS and CMS measures. It uses the Java-based CQL-to-ELM tooling and MSBuild targets to go from CQL source files all the way to packaged FHIR Library resources and .NET assemblies.
To build the Demo projects you need:
- JDK (21+)
- Maven (3.9+)
- PowerShell Core 7+ (
pwsh)
Once prerequisites are installed, open Cql-Sdk-Demos-Examples.slnf in Visual Studio or run dotnet build to build the demo measures.
See the Demo Projects guide for the project structure, pipeline stages, and how to configure your own measure project. The CQL Build Pipeline document covers the build.ps1/build.sh scripts, all MSBuild props/targets files, and the Java dependency management in detail. To learn about the individual PackagerCLI commands and options, see the CQL Packager Reference.
- CQL Engine Architecture — internal design and key classes
- Toolkit Services Dependency Diagrams — service dependency graphs
- Demo Projects — project structure and how to configure a measure project
- CQL Build Pipeline — build scripts, Java CQL-to-ELM tooling, PackagerCLI, and MSBuild targets
- CQL Packager Reference — all
cql-packagecommands, options, and examples - Technical README — multi-targeting, code generation versioning, and CI/CD details (maintainers)
- DevDays 2023 presentation — introductory walkthrough