Continuous Integration (CI) and Continuous Deployment (CD) are essential practices in modern software development, ensuring that code is consistently tested, built, and deployed. In this post, we'll explore how to build a project, a solution or a directory containing Windows driver projects using CI and CD, with a focus on utilizing Windows Driver Kit (WDK) NuGet packages.
Prerequisites
Before diving into the process, ensure you have the following prerequisites:
For local devbox scenarios
- Windows 11 system
- Visual Studio 2022 with C++ workload installed and other components, see https://learn.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk
For github
- A repository with windows driver projects
Using WDK NuGet Packages
WDK NuGet packages are latest edition to the packaging technology provided by Microsoft. Read more about that in this blog Here's a quick summary on how to get started with them:
Finding the Latest WDK NuGet Packages
To find the latest version of WDK NuGet packages, visit nuget.org and search for "Microsoft.Windows.WDK". Note the latest version number for use in your projects.
Challenges with Native C++ Projects
NuGet packages were primarily designed for .NET projects, and the PackageReference feature is not supported with native C++ projects. This can lead to issues when maintaining multiple projects in a source repository like GitHub, as updating NuGet versions would require editing every project file that references the NuGet package.
Solving the Problem with Directory.Build.props
The GitHub repository https://github.com/microsoft/Windows-driver-samples presents a solution to this problem. By using a Directory.Build.props file at the root directory level, which MSBuild imports by default, you can centralize the NuGet package references.
Sample `Directory.Build.props`:
<Project> <Import Project="packages\Microsoft.Windows.WDK.x64.10.0.26100.2454\build\native\Microsoft.Windows.WDK.x64.props" Condition="Exists('packages\Microsoft.Windows.WDK.x64.10.0.26100.2454\build\native\Microsoft.Windows.WDK.x64.props') and '$(Platform)' == 'x64'"/> <Import Project="packages\Microsoft.Windows.WDK.arm64.10.0.26100.2454\build\native\Microsoft.Windows.WDK.arm64.props" Condition="Exists('packages\Microsoft.Windows.WDK.arm64.10.0.26100.2454\build\native\Microsoft.Windows.WDK.arm64.props') and '$(Platform)' == 'ARM64'"/> <Import Project="packages\Microsoft.Windows.SDK.CPP.x64.10.0.26100.2454\build\native\Microsoft.Windows.SDK.cpp.x64.props" Condition="Exists('packages\Microsoft.Windows.SDK.CPP.x64.10.0.26100.2454\build\native\Microsoft.Windows.SDK.cpp.x64.props') and '$(Platform)' == 'x64'"/> <Import Project="packages\Microsoft.Windows.SDK.CPP.arm64.10.0.26100.2454\build\native\Microsoft.Windows.SDK.cpp.arm64.props" Condition="Exists('packages\Microsoft.Windows.SDK.CPP.arm64.10.0.26100.2454\build\native\Microsoft.Windows.SDK.cpp.arm64.props') and '$(Platform)' == 'ARM64'"/> <Import Project="packages\Microsoft.Windows.SDK.CPP.10.0.26100.2454\build\native\Microsoft.Windows.SDK.cpp.props" Condition="Exists('packages\Microsoft.Windows.SDK.CPP.10.0.26100.2454\build\native\Microsoft.Windows.SDK.cpp.props')"/> </Project> |
This file points to the location of the NuGet packages inside the packages folder at the root.
We still need to use the packages.config file, which will contain the NuGet packages' IDs and versions e.g.
<?xml version="1.0" encoding="utf-8"?> <packages> <package id="Microsoft.Windows.SDK.CPP" version="10.0.26100.2454" targetFramework="native" /> <package id="Microsoft.Windows.SDK.CPP.x64" version="10.0.26100.2454" targetFramework="native" /> <package id="Microsoft.Windows.WDK.x64" version="10.0.26100.2454" targetFramework="native" /> </packages> |
This file will help restore the packages on disk using the command:
nuget restore .\packages.config -PackagesDirectory .\packages\
Building the Projects Locally
Add a packages.config file to the root directory and provide the list of NuGets required for building the projects. For example to build x64 driver you will need x64 version of SDK and WDK NuGets, take a hint from the example above.
Add a Directory.Build.props file to the root directory and the content similar to the sample provided above.
To build the driver project you need to do the following later which we will convert to a github action
- Using the Visual Studio Developer Command Prompt, restore the packages using: nuget restore .\packages.config -PackagesDirectory .\packages\
- msbuild /t:build path\to\your\project.vcxproj This command will build the project with the restored NuGets.
Setting Up Continuous Integration with GitHub Actions
To automate the build process with every pull request, we can create a GitHub Action in our repository. Here’s a step-by-step guide:
Creating a GitHub Action for CI
- In your GitHub repository, navigate to the `.github/workflows` directory. If it doesn’t exist, create it.
- Create a new file, e.g., `ci.yml`.
Example content of `ci.yml`:
yaml
name: CI Build
on:
pull_request:
branches:
- main
jobs:
build:
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup NuGet
uses: NuGet/setup-nuget@v1
- name: Restore NuGet packages
run: nuget restore .\packages.config -PackagesDirectory .\packages\
- name: Build solution
run: msbuild /t:build path\to\your\solution.sln
This GitHub Action will:
- Trigger on every pull request to the main branch
- Checkout the code
- Setup NuGet
- Restore NuGet packages
- Build the solution
Conclusion
By following this guide, you can efficiently manage and build your Windows driver projects using WDK NuGet packages and automate the process with GitHub Actions for CI. This setup not only simplifies dependency management but also ensures a consistent build process across different environments and development stages.
Updated Feb 15, 2025
Version 1.0prashantchahar
Microsoft
Joined October 16, 2024
Windows Driver Developer Blog
Follow this blog board to get notified when there's new activity