C++ Packages in 2024

Philips
Philips Technology Blog
10 min readOct 18, 2024

Insights from Philips Radiology Informatics

Author: Nadav Sinai, Radiology Informatics R&D Technical Leader

When creating products and solutions for healthcare, customers expect you to be able to respond quickly to bugs, security flaws, and requests for new features. Quick response is needed in any domain, to react to the market or to stay ahead of the competition, but In healthcare, a swift response is even more essential, for what’s at stake is the ability to keep hospitals running productively and maintain the safety of patients’ personal and health data.

Healthcare software developers need a solid, manageable, and secure codebase to meet these goals. At Philips, we take these requirements seriously, as our products serve hundreds of millions of people across the globe.

Many of our products are built with C++, which remains one of the top choices of programming languages for embedded systems and software that interface with hardware. In recent years, the

consumption and packaging of C++ libraries has been changing. However, as with many things in the world of C++, such changes occur slowly. This is in conflict with our goal of serving our customers as quickly and efficiently as possible, so we decided to address it and created a reliable software package management pipeline for our C++ systems.

In this blog post, I will describe the landscape I encountered while trying to move third-party code into packages within the Philips Vue PACS system, which has been developed in C++ for over 30 years.

Background to C++ Packaging

Unlike many modern languages such as Go and Rust, where packaging standards are built into the language or natural toolset, as of 2024, there still isn’t a standard tool or central package repository for C++. Furthermore, unlike non-native languages that compile to a known runtime platform, sharing source code in C++ is not trivial. C++ projects are closely tied to the compilation toolchains used to develop them. Library authors often cannot offer pre-compiled binaries for all platforms due to the intricate compilation process, including CPU-specific optimizations, static/dynamic linking, and changes for library-specific features.

Compatibility with the application binary interface (ABI) compatibility is essential when linking a library to a project’s binary. The ABI is primarily based on the OS/platform, which sets standards such as calling conventions and exception handling. But in practice, compilation with a different compiler or even just an upgrade to the compiler version can cause linking errors or runtime bugs. Therefore, for the best compatibility, the library code should be compiled on the same platform and preferably using the same build chain as the application.

My background is in web development with Typescript and C#, where the packaging story is clear. To understand how developers manage their third-party dependencies, I referred to two surveys: the ISO C++ survey of 2023 and the JetBrains C++ ecosystem survey.

Below is the data on how developers manage third-party libraries:

Source: ISO C++ survey
Source: ISO C++ survey

In both surveys, developers indicated that the most frustrating aspect of C++ development is managing third-party code. As I have already pointed out, C++ was not created with source-code portability in mind. The code reuse and OSS mentality that is so common today was not the norm in the 70s and 80s.

In my view, some of the answers in the surveys are practically the same — for if you’re taking in library source files into your project or prebuild the binaries per the library’s instructions, the manual work involved differs for each library, and much of that effort would probably have to be re-invested if one would need to upgrade the library version, as those instructions may change.

Also, having integrated library source code brings in the danger of it being changed (intentionally or accidentally) inside the consuming project and thus making upgrades harder.

Downloading prebuilt binaries from library repositories and sites is not much different either. It’s manual work, and the available builds may not always meet specific requirements, especially when there are transitive dependencies — e.g., ACE prebuilt with a different SSL version to the one you’re using, etc.

In any of these setups, it can be difficult to control which version of a dependency lib the prebuilt lib was compiled with. For example, say that you sourced ACE from apt, and ACE uses OpenSSL — but which version was it referring to during compile time? And if I need to upgrade to OpenSSL -will ACE link (and work) with the updated version?

A major challenge in packaging systems is known as “The Diamond Problem”: if lib A uses lib C 1.x, and lib B uses Lib C 2.x, which version of lib C should be used?

In my experience, the only valid option for addressing third-party packages in a project of any meaningful size is to use package managers, which can be system-level or project-level.

If you need more than one version of a lib or declarative restoration of the dependencies, you will require a project-level package manager.

Some projects will use system-level package managers since their distribution platform is in a sandboxed container, where a Dockerfile becomes the declarative source of truth of the project

dependencies. Note that this “declarative-ness” is not so useful for automations such as Dependabot compared to declarative manifests that project-based package managers use.

In our case, we use Windows-based distribution, without containers. And since we have many supported versions — each with its own set of lib versions — we needed a declarative project-level package manager that does not “pollute” the environment.

C++ in Philips Vue PACS

Source : Philips Radiology Informatics

Radiology informatics PACS RCD has many products, most of which are composed of a single monorepo with 12M lines of code, 2.6M of which are in C/C++. We rely on numerous third-party libraries, ranging from common low-level abstractions such as Boost and ACE to specifics of Philips proprietary DICOM fields.

Our third-party folder contains over 100 libraries, each with its own compilation story. Dealing with the variance in our third-party dependencies was challenging, especially when addressing CVE security issues and performing upgrades. Furthermore, keeping large binaries in Git caused performance issues, which we attempted to mitigate using Git LFS and submodules. However, this caused other complications, particularly when libraries used other open-source libraries.

Considering C++ Package Managers

As I began evaluating package managers, I sought the following features:

- Declarative configuration of dependencies

- Seamless integration with Visual Studio

- Full control over the sourcing, compiling, and post-processing of packages.

- Reliable performance — once lib compilation is done for a set ABI — it will not happen again — binary caching will allow the reuse of jobs already done.

Based on the surveys — I explored two project-level package managers -VCPKG and Conan. CONAN

Conan is an open-source project with active community support. It is rooted in the Python ecosystem and is installed using pip. The Conanfile, the “recipe” for building a package, is to be written in Python, although it also has first-class support for integrating with existing CMake-based builds.

Conan.io serves as a public central registry for packages, but users can also set up their own registry via Artifactory.

You can easily consume packages from Conan. You only need a conanfile.txt to specify your requirements without any Python code. But you’ll soon find that you need more control and will end up with a more intricate conanfile.py to control the static/dynamic or lib features you need.

In Feb 2023, the Conan team released a new and rearchitected v2.0 of the package manager. So, I must say I may have looked at it differently if I did this today, but back then, I encountered a few problems with Conan on Windows C MSBuild when trying to consume ACE C SSL, which did not work well with each other. It may have been problems specific to those libraries we set for our POC.

VCPKG

VCPKG is a C++ cross-platform package manager from Microsoft, and its roots are as a system- level package manager. However, it has added support for project-level (manifest mode) package management since 2021.

VCPKG builds on CMake. You describe packages compilation steps as you do in CMake but also have access to VCPKG-supplied helper functions to download, build, and process files.

As this is a Microsoft product, its integration with Visual Studio is exceptional.

VCPKG uses CI automation to ensure that each pull request to update a library portfile (the recipe to build a package) not only passes its own build, but also verifies that all library dependents still work with the updated library. This validation ensures that all the libs declared in a vcpkg.json configuration file have been verified to work with each other as the file also includes the registry “baseline” (git SHA) from which all dependencies portfiles are sourced.

This effectively resolves the “Diamond problem” nicely, yet VCPKG does allow for version override control.

Additionally, VCPKG features advanced binary caching capabilities, which allow you to control and debug the elements (compiler versions, environment variables, etc.) which go into making the package checksum for ABI to make sure that once we built for a certain ABI, we don’t need to build again.

There are many options for backend storage and recipes for CI integration, such as Github Actions with the use of its Action Cache for binary storage or Azure Repos pipelines and other backing stores such as Artifactory, AWS S3, etc.

Implementation of our vcpkg integration

Philips Vue (Picture Archiving and Communication System) PACS is an image-management platform that provides scalable local and wide-area PACS solutions for hospitals and related institutions. PACS is used primarily in healthcare organizations to securely store and digitally transmit electronic images and clinically-relevant reports. Detecting and fixing security flaws is very important to ensure the integrity of PACS systems.

In our efforts to manage third-party dependencies more effectively within the Philips Vue PACS system, we adopted VCPKG because of its strong integration with Visual Studio, ability to handle complex dependencies, and advanced binary caching capabilities.

To implement VCPKG, we created two repositories:

ri-vcpkg-fork: A fork of the main VCPKG registry repository.

ri-vcpkg-registry: A repository where we develop and maintain our own packages that are not available in the primary VCPKG repository.

We integrated VCPKG into our Visual Studio toolchain by configuring it to automatically include the necessary dependencies for all projects. This setup ensures that the correct versions of libraries are used consistently across different projects, reducing the risk of compatibility issues.

One of the key features we leveraged is VCPKG’s “binary caching.” This feature allows us to reuse precompiled binaries, which significantly speeds up the build process and ensures that once a library is built for a specific configuration, it doesn’t need to be rebuilt unless there are changes. This approach also helps maintain a clean and efficient development environment.

Publishing your own packages

To publish our own packages using VCPKG, we follow a structured process that involves creating specific configuration files. These files define how to obtain the source code, compile it, and where to place the resulting binaries and headers.

The process involves:

Defining the Source: Specifying where the source code for the package can be found, typically from a version control system like Git.

Compilation Instructions: Providing instructions on how to compile the source code, including any configurations for different build environments (e.g., debug or release modes).

Post-Processing: Indicating additional steps needed after compilation, such as copying files to specific directories.

Once these steps are completed, the package will be ready for use on our projects. However, manually managing these configurations can be cumbersome, so we plan to automate this process to ensure consistency and reduce potential errors.

Conclusion

Using a package manager for C++ offers numerous advantages, such as simplifying the management of third-party code, streamlining the updating of libraries and introducing new ones. Additionally, it allows for the use of tooling for security auditing and software bill of materials (sBOM) generation. VCPKG is an excellent choice for such tasks, as it provides a comprehensive public registry that ensures the compatibility of packages. Its declarative manifest simplifies tooling integration and offers efficient and reproducible builds through its binary caching feature.

The adoption of VCPKG at Philips Radiology Informatics RCD has enabled us to tackle the challenges of managing third-party dependencies, improve our development workflow, and streamline the packaging process within the Philips Vue PACS system. By leveraging VCPKG’s advanced features and seamless integration with Visual Studio, we have simplified the management of third-party libraries and ensured efficient and reliable builds while enhancing the security and maintainability of our software.

As we prepare to deploy the new version of Vue PACS in production, we are better prepared to iterate quickly and make sure we can respond to the feedback we receive from our customers and the wider health-tech community.

Curious about working in tech at Philips? Find out more here

References:

JetBrains Survey 2023

ISO C++ Survey 2023

https://learn.microsoft.com/en-us/vcpkg/

https://conan.io/ Recommended reads:

https://decovar.dev/blog/2022/10/30/cpp-dependencies-with-vcpkg

https://moderncppdevops.com/pkg-mngr-roundup/

https://cloudsmith.com/blog/why-programmers-need-a-c-package-manager

--

--

Philips Technology Blog
Philips Technology Blog

Published in Philips Technology Blog

Learn more about how Philips designs, builds, and operates our systems and engineering organizations

Philips
Philips

Written by Philips

All about Philips’ innovation, health technology and our people. Learn more about our tech and engineering teams.

Responses (2)