<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://moderncppdevops.com/</id>
    <title>Modern C++ DevOps Blog</title>
    <updated>2024-09-09T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://moderncppdevops.com/"/>
    <subtitle>Modern C++ DevOps Blog</subtitle>
    <icon>https://moderncppdevops.com/img/logo.png</icon>
    <entry>
        <title type="html"><![CDATA[Toolchain Evolution: Designing and Operating a Native Build System Over Many Years]]></title>
        <id>https://moderncppdevops.com/2024/09/09/planning-toolchain-evolution</id>
        <link href="https://moderncppdevops.com/2024/09/09/planning-toolchain-evolution"/>
        <updated>2024-09-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Managing a native build system for complex products over extended periods requires a strategic approach to toolchain evolution. This blog post explores the key considerations and challenges faced by product planning and development teams. Discover the pros and cons of various strategies like owning hardware design, controlling the toolchain, or staying on the bleeding edge. Learn how to navigate security updates, technical debt, and knowledge transfer while ensuring long-term product success. Optimize your CI/CD pipeline and build a robust build process that embraces innovation and future-proofing.]]></summary>
        <content type="html"><![CDATA[<p>In the DevOps playground of software development, designing and maintaining a <a href="https://en.wikipedia.org/wiki/Native_(computing)" target="_blank" rel="noopener noreferrer">native</a> <a href="https://en.wikipedia.org/wiki/Build_automation" target="_blank" rel="noopener noreferrer">build automation</a> process for a complex product <a href="https://www.toptal.com/c/after-all-these-years-the-world-is-still-powered-by-c-programming" target="_blank" rel="noopener noreferrer">over many years</a> presents unique challenges. One topic which often gets over looked by <a href="https://www.atlassian.com/agile/product-management/product-roadmaps" target="_blank" rel="noopener noreferrer">product planning</a> is upgrading compilers. The gritty work for ensuring the product maintains supported for existing platforms while offering access to new tools to developers to be innovative for a competitive edge.</p>
<p>Planning for this change is <a href="https://moderncppdevops.com/2024/08/26/designing-a-build-process"><strong>Toolchain Evolution</strong></a>.</p>
<blockquote>
<p>Either maintaining old toolchains as new platforms arrive or a backport of toolchain on to an older platforms or any combination would satisfy the definitions.</p>
</blockquote>
<p>There are two main forces driving teams to upgrade their toolchains, the first being security and the second also being security. The first is product security or "code safety", every year compilers and sanitizers are improving and offer new features that when utilized can detect <a href="https://owasp.org/www-community/vulnerabilities/Buffer_Overflow" target="_blank" rel="noopener noreferrer">buffer-overflow</a> or <a href="https://cwe.mitre.org/data/definitions/416.html?" target="_blank" rel="noopener noreferrer">free-after-use</a> and prevent many vulnerabilities which are discovered. The second, less talked about, is corporate IT Security or "software supply chain security" where with native toolchains might be obsolete and pose a greater burden to maintain development.</p>
<p>Regardless which of these factors is motivating you, this post will explore the strategic considerations and operational challenges of managing a native build system for long-term success leveraging the concept of Toolchain Evolution during a product's lifecycle to help address both security needs.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-strategic-business-planing-is-key">Why Strategic Business Planing is Key<a href="https://moderncppdevops.com/2024/09/09/planning-toolchain-evolution#why-strategic-business-planing-is-key" class="hash-link" aria-label="Direct link to Why Strategic Business Planing is Key" title="Direct link to Why Strategic Business Planing is Key">​</a></h2>
<p>Slow builds slow down the business, not just engineering. Ensuring <a href="https://www.redhat.com/en/services/training/tl500-devops-culture-and-practice-enablement" target="_blank" rel="noopener noreferrer">enough priority</a> is balanced with improving and evolving builds is critical to keeping up with changing requirements. Given the complexity and scale a one-size-fits-all build process is unlikely to succeed. Instead, a strategic approach that divides the work and optimizes for different types of builds is essential. These complicated distributed systems will be prime targets for threat actors - <a href="https://www.microsoft.com/insidetrack/blog/improving-security-by-protecting-elevated-privilege-accounts-at-microsoft/" target="_blank" rel="noopener noreferrer">requiring IT security baseline</a> to be up held to prevent being the weak line in a <a href="https://www.zscaler.com/resources/security-terms-glossary/what-is-a-supply-chain-attack" target="_blank" rel="noopener noreferrer">supply chain attack</a>. This connection is directly pulled from the <a href="https://moderncppdevops.com/why-devops-in-cpp">philosophy of DevOps</a>.</p>
<p>Far to often this topic is over shadowed with making the <em>code</em> safe. <a href="https://herbsutter.com/2024/03/11/safety-in-context/" target="_blank" rel="noopener noreferrer">"C++ Safety"</a> and <a href="https://www.youtube.com/watch?v=I8UvQKvOSSw" target="_blank" rel="noopener noreferrer">"Delivering Safe C++"</a> have gotten a lot of attention, but both piece suggest, that is only part of a good <a href="https://csrc.nist.gov/glossary/term/defense_in_depth" target="_blank" rel="noopener noreferrer">Defense in Depth</a> strategy. Back in 2023, an excellent report about <a href="https://www.infoworld.com/article/2335793/the-state-of-the-c-plus-plus-developer-ecosystem.html" target="_blank" rel="noopener noreferrer">C++ Standards Usage</a> which highlighted the lack luster adoption of C++23... The <a href="https://isocpp.org/files/papers/CppDevSurvey-2024-summary.pdf" target="_blank" rel="noopener noreferrer">2024 C++ ISO Survey</a> once again has 61% are "not allowed" to use C++23 along with 36% "not allowed" to use C++20. This sluggishness is not new, even if we invent a better more safe version of C++ it very well could take 10 years for it to be adopted by the industry.</p>
<p>This is why it's imperative to incorporate toolchain evolution into the product development roadmap.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="assumptions-and-context">Assumptions and Context<a href="https://moderncppdevops.com/2024/09/09/planning-toolchain-evolution#assumptions-and-context" class="hash-link" aria-label="Direct link to Assumptions and Context" title="Direct link to Assumptions and Context">​</a></h2>
<p>Before diving into the details, let's establish some baseline assumptions:</p>
<ol>
<li><strong>Complex Product</strong>: The product in question is complex enough that any build will require significant effort (i.e time on a CPU). This isn't a simple application but a multifaceted system with numerous <a href="https://www.lawinsider.com/dictionary/interdependent-components" target="_blank" rel="noopener noreferrer">interdependent components</a>.</li>
<li><a href="https://link.springer.com/book/10.1007/11783565" target="_blank" rel="noopener noreferrer"><strong>Component-Based Architecture</strong></a>: The software is divided into several components, each of which contributes to the overall functionality. These components may be developed by different teams or even across different geographies.</li>
<li><a href="https://enterprisecraftsmanship.com/posts/short-term-vs-long-term-perspective/" target="_blank" rel="noopener noreferrer"><strong>Long-Term Perspective</strong></a>: The build system needs to be designed not just for today but with an eye toward <a href="https://patrickkarsh.medium.com/designing-for-long-term-vs-complexity-in-software-architecture-mastering-system-design-0c30e7e0f576" target="_blank" rel="noopener noreferrer">future-proofing</a>, scalability, and adaptability.</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-a-native-build-system">What is a Native build system?<a href="https://moderncppdevops.com/2024/09/09/planning-toolchain-evolution#what-is-a-native-build-system" class="hash-link" aria-label="Direct link to What is a Native build system?" title="Direct link to What is a Native build system?">​</a></h3>
<p>A <a href="https://docs.gradle.org/current/userguide/native_software.html" target="_blank" rel="noopener noreferrer"><strong>native build system</strong></a> is a software infrastructure designed to compile, link, and package code into executable programs or libraries specifically for a particular operating system and/or hardware platform. It operates directly within a target environment, utilizing the system's native tools, compilers, and dependencies to produce optimized, platform-specific binaries which may run on the same or different target platform.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="various-strategic-approaches">Various Strategic Approaches<a href="https://moderncppdevops.com/2024/09/09/planning-toolchain-evolution#various-strategic-approaches" class="hash-link" aria-label="Direct link to Various Strategic Approaches" title="Direct link to Various Strategic Approaches">​</a></h2>
<p>With unlimited money and large workforces it's easier to practice a large philosophical design concepts for how products and developed can be released to costumers. Large tech companies are often easy examples to see what different variations exist.</p>
<p>Planning to innovate and adopt technologies is always a balancing act which comes at odds with supporting existing hardware. The combinatorics of platform support means inevitably old platforms will no longer be supported. There's will always be <a href="https://en.wikipedia.org/wiki/Technology_adoption_life_cycle" target="_blank" rel="noopener noreferrer">laggards</a> and those systems will need to be moved on to newer platforms which might no be compatible.</p>
<p>Building into the build automation process to support both can be a huge advantage.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="owning-the-hardware-design">Owning the Hardware Design<a href="https://moderncppdevops.com/2024/09/09/planning-toolchain-evolution#owning-the-hardware-design" class="hash-link" aria-label="Direct link to Owning the Hardware Design" title="Direct link to Owning the Hardware Design">​</a></h3>
<p>One strategy, that has been increasing in the spotlight thanks to large tech companies, for controlling toolchain evolution is to own the hardware design. By designing their own chips, companies can tailor the underlying architecture to their specific needs and ensure that the existing toolchain remains tightly integrated and provides greater control. Ensuring hardware support over the generations of the product allows for more predictable updates and support.</p>
<p>A notable example of this strategy is Google's decision to develop its own <a href="https://blog.google/products/pixel/introducing-google-tensor/" target="_blank" rel="noopener noreferrer">mobile processors for its Pixel smartphones</a>. By designing these processors in-house, Google can ensure that they are optimized for its specific software requirements and that the toolchain remains tightly integrated. Furthermore, Google's commitment to <a href="https://support.google.com/pixelphone/answer/4457705?hl=en#zippy=%2Cpixel-pixel-pro-pixel-pro-xl-pixel-pro-fold" target="_blank" rel="noopener noreferrer">providing seven years of security updates</a> for its Pixel devices demonstrates its long-term focus on toolchain evolution and product support.</p>
<p>While owning the hardware design offers significant advantages for controlling toolchain evolution, it's not without drawbacks. The high upfront investment, increased complexity, and potential for delays can be significant hurdles for smaller companies. Additionally, custom hardware may not be suitable for all markets, and companies may face <a href="https://support.apple.com/en-us/102772" target="_blank" rel="noopener noreferrer">obsolescence down the line</a> when committing to older technologies.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="controlling-the-toolchain">Controlling the Toolchain<a href="https://moderncppdevops.com/2024/09/09/planning-toolchain-evolution#controlling-the-toolchain" class="hash-link" aria-label="Direct link to Controlling the Toolchain" title="Direct link to Controlling the Toolchain">​</a></h3>
<p>Another effective strategy for managing toolchain evolution is to maintain control over the toolchain itself. This involves developing or customizing the tools that allow access or control of the product and ensuring that the toolchain remains compatible. By controlling the toolchain, organizations can maintain greater flexibility in their product development process.</p>
<p>Apple's SDKs are an excellent example of this. By releasing it's own toolchain, Apple has gained greater control over what hardware configurations are supported, and by tying this into the <a href="https://developer.apple.com/support/xcode/" target="_blank" rel="noopener noreferrer">operating systems release cycle</a>. The Apple-clang compiler, which is specifically designed for Apple's tightly controlled architecture, provides a powerful and optimized tool for developing software for these platforms. This allows them to dictate what <a href="https://developer.apple.com/news/upcoming-requirements/?id=04292024a" target="_blank" rel="noopener noreferrer">version of the toolchains</a> are used and can plan to phase out older toolchains.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Stay Tuned</div><div class="admonitionContent_BuS1"><p>This strategy can be scaled up or down in some unique and useful ways. This will be the third post focusing on bringing older compilers to newer platforms with the aim of maintaining legacy code bases.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="inventing-the-build-systems">Inventing the Build Systems<a href="https://moderncppdevops.com/2024/09/09/planning-toolchain-evolution#inventing-the-build-systems" class="hash-link" aria-label="Direct link to Inventing the Build Systems" title="Direct link to Inventing the Build Systems">​</a></h3>
<p>While maintaining control over the toolchain is important, it is also essential to stay on the cutting edge of technology. By adopting new tools and techniques as they emerge, organizations can improve product quality, reduce development time, and stay ahead of the competition. However, it is crucial to balance the benefits of adopting new technology with the risks associated with early adoption.</p>
<p>Facebook's approach to software development, which involves <a href="https://engineering.fb.com/2014/01/07/core-infra/scaling-mercurial-at-facebook/" target="_blank" rel="noopener noreferrer">rebuilding its entire codebase (a monorepo)</a> together, demonstrates a commitment to living on the bleeding edge. By continually modernizing its <a href="https://engineering.fb.com/2023/06/27/developer-tools/meta-developer-tools-open-source/" target="_blank" rel="noopener noreferrer">infrastructure and toolchain</a> along with the <a href="https://engineering.fb.com/2023/10/24/data-infrastructure/automating-dead-code-cleanup/" target="_blank" rel="noopener noreferrer">code base</a>, Facebook can take advantage of the <a href="https://ndmitchell.com/#build_01_jan_2022" target="_blank" rel="noopener noreferrer">latest advancements in technology</a> and ensure that its products remain competitive. However, this approach also requires significant investment in infrastructure, testing, and risk management.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="a-combined-approach">A Combined Approach<a href="https://moderncppdevops.com/2024/09/09/planning-toolchain-evolution#a-combined-approach" class="hash-link" aria-label="Direct link to A Combined Approach" title="Direct link to A Combined Approach">​</a></h3>
<p>To achieve the best results,  most organizations should consider a combined approach that incorporates all three strategies and variations of these ideas tweaked to meet their unique needs. Planning to maintain hardware compatibility, building your own toolchains and designing a solid build process, companies can create a robust and flexible product development ecosystem that supports long-term innovation and success. That is easier said then done. There are trade-offs at every corners and picking the write ones for your business are imperative.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="operational-challenges-and-long-term-considerations">Operational Challenges and Long-Term Considerations<a href="https://moderncppdevops.com/2024/09/09/planning-toolchain-evolution#operational-challenges-and-long-term-considerations" class="hash-link" aria-label="Direct link to Operational Challenges and Long-Term Considerations" title="Direct link to Operational Challenges and Long-Term Considerations">​</a></h2>
<p>Maintaining support for older hardware generations is offers a lot of incentive to customer, however eventually will not be feasible. Tesla is a fun example where they still offer updates for a 2012 Model S with <a href="https://www.tesla.com/support/infotainment#:~:text=Owners%20of%20Model%20S%20and,installation%2C%20for%20all%20other%20vehicles." target="_blank" rel="noopener noreferrer">upgrade infotainment systems</a> but the 2023 Model 3 and Model Y may <a href="https://www.notateslaapp.com/news/2149/tesla-fsd-v125-now-supports-additional-models-hardware-3-vehicles-still-waiting" target="_blank" rel="noopener noreferrer">no longer receive updates</a> for the long await <a href="https://www.autoevolution.com/news/elon-musk-suggests-it-s-the-end-of-the-road-for-the-hardware-3-autopilot-computer-236318.html" target="_blank" rel="noopener noreferrer">"FSD" beta-program</a>. Building the same code across many generations of hardware changes is no small feet.</p>
<p>Over time, several challenges will inevitably arise when managing a build system:</p>
<ul>
<li><strong>Scalability</strong>: As your product grows, so too will the complexity of your code and the build system. Regularly review and optimize your build processes to handle increased demands with an iterative approach.</li>
<li><strong>Toolchain Evolution</strong>: The tools and technologies used in your build system will evolve. Ensure that your system is adaptable and that you have a plan for updating and integrating new tools as they become available.</li>
<li><strong>Technical Debt</strong>: Build systems, like any other part of the software, can accrue technical debt. Regular refactoring and cleanup of build scripts, configurations, and dependencies are necessary to prevent build times from ballooning and reliability from degrading.</li>
<li><strong>Documentation and Knowledge Sharing</strong>: Maintain thorough documentation of the build system and processes. As team members come and go, this documentation will be invaluable in preserving institutional knowledge and ensuring continuity.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="long-term-support-for-specific-hardware-platforms">Long-Term Support for Specific Hardware Platforms<a href="https://moderncppdevops.com/2024/09/09/planning-toolchain-evolution#long-term-support-for-specific-hardware-platforms" class="hash-link" aria-label="Direct link to Long-Term Support for Specific Hardware Platforms" title="Direct link to Long-Term Support for Specific Hardware Platforms">​</a></h3>
<p>Supporting software on specific hardware platforms for five or more years presents a unique set of challenges. The tools you choose at the start of a project may not be supported on future versions of the operating system or may lack the necessary updates to remain viable as the security landscape evolves. The other side is also true, newer version of tools many stop support or become incompatible with older platforms preventing their adoptions. Aim to have support your own toolchains or work with vendors to ensure their support cycle is correctly aligned.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="strategies-for-managing-toolchain-evolution">Strategies for Managing Toolchain Evolution<a href="https://moderncppdevops.com/2024/09/09/planning-toolchain-evolution#strategies-for-managing-toolchain-evolution" class="hash-link" aria-label="Direct link to Strategies for Managing Toolchain Evolution" title="Direct link to Strategies for Managing Toolchain Evolution">​</a></h3>
<p>Successfully managing toolchain evolution requires a proactive and strategic approach. <a href="https://moderncppdevops.com/build-more-configurations" target="_blank" rel="noopener noreferrer">Build more configurations</a> is the best default advice.</p>
<ol>
<li><strong>Regular Audits and Updates</strong>: Conduct regular audits of your platform (hardware or operating systems) to identify any components that may be nearing the end of their support life or that have known vulnerabilities. Schedule updates and migrations well before they become critical, ensuring that your build system remains secure and functional.</li>
<li><strong>Automated Testing and Validation</strong>: Implement automated testing frameworks that can validate the output of your build system across different versions of your toolchain. This helps ensure that updates or changes do not introduce regressions or new issues.</li>
<li><strong>Early Adopter Releases</strong>: Provide a copy of each release with a development copy to customer to beta test and provide early feedback. Having an exact copy with a newer toolchain can help smooth the transition when migrating with newer generations.</li>
<li><strong>Vendor Collaboration</strong>: Maintain strong relationships with tool and platform vendors. Early access to new versions, patches, and support can be crucial in ensuring a smooth transition when updating your toolchain. Vendors can also provide insights into future changes that might affect your build system.</li>
<li><strong>Documentation and Knowledge Transfer</strong>: As your team evolves, it's essential to maintain thorough documentation of your toolchain choices, configurations, and the rationale behind them. This documentation should include detailed procedures for updating tools, managing compatibility issues, and handling security patches. This ensures that future team members can continue to manage the build system effectively, even if they weren't involved in its original design.</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://moderncppdevops.com/2024/09/09/planning-toolchain-evolution#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>Toolchain evolution is not a one-size-fits-all solution, but rather a strategic dance between security, innovation, and practicality. By considering the various approaches – owning the hardware design, controlling the toolchain, or staying on the bleeding edge – organizations can craft a plan that best suits their needs.  Understanding the long-term implications of hardware compatibility, technical debt, and knowledge transfer are all crucial components for building a robust build process.</p>
<p>Ultimately, a well-designed and well-maintained build system that embraces toolchain evolution is the cornerstone of long-term product success.  It allows developers to innovate with the latest tools and technologies, while ensuring that the product remains secure and functional for existing hardware platforms. This delicate balance between legacy support and future-proofing is the key to building software that endures.</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="toolchain evolution" term="toolchain evolution"/>
        <category label="build system" term="build system"/>
        <category label="security updates" term="security updates"/>
        <category label="native software" term="native software"/>
        <category label="product planning" term="product planning"/>
        <category label="scalability" term="scalability"/>
        <category label="continuous integration" term="continuous integration"/>
        <category label="continuous deployment" term="continuous deployment"/>
        <category label="security" term="security"/>
        <category label="toolchain management" term="toolchain management"/>
        <category label="operating systems" term="operating systems"/>
        <category label="hardware platforms" term="hardware platforms"/>
        <category label="security compliance" term="security compliance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Building Securely and Efficiently: A Modern Approach to Native Build Processes]]></title>
        <id>https://moderncppdevops.com/2024/08/26/designing-a-build-process</id>
        <link href="https://moderncppdevops.com/2024/08/26/designing-a-build-process"/>
        <updated>2024-08-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[This comprehensive guide reveals the secrets to building secure and efficient native software. Discover the latest strategies for optimizing your build process, including modular builds, parallel execution, and cloud-based solutions. Learn how to balance cold, warm, and incremental builds for maximum efficiency. Master the art of build caching to dramatically accelerate your development cycle. Implement robust CI/CD pipelines to ensure code quality and rapid delivery. And most importantly, stay ahead of evolving security threats by regularly updating your toolchain and adopting best practices for secure development. With this expert guidance, you'll unlock the full potential of your native build process and deliver innovative software faster than ever before.]]></summary>
        <content type="html"><![CDATA[<p>The software development landscape is a nebulous. On one front, developers strive to craft innovative features at <a href="https://youtu.be/8mUosAh3gLc?t=758" target="_blank" rel="noopener noreferrer">breakneck speed</a> before requirements change. On another, <a href="https://csrc.nist.gov/Projects/cyber-supply-chain-risk-management/ssca" target="_blank" rel="noopener noreferrer">security threats loom</a>, constantly evolving to exploit vulnerabilities. In this environment, a robust and secure build process is no longer a luxury, it's a necessity as <a href="https://www.securitysystemsnews.com/article/synopsys-report-finds-over-half-of-surveyed-orgs-suffered-supply-chain-attack-in-2023" target="_blank" rel="noopener noreferrer">software supply chain attacks become more sophisticated</a>.</p>
<p>This guide introduces the high-level designing a native C or C++ build process that prioritizes both speed and security.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="distributing-the-build-work">Distributing the Build Work<a href="https://moderncppdevops.com/2024/08/26/designing-a-build-process#distributing-the-build-work" class="hash-link" aria-label="Direct link to Distributing the Build Work" title="Direct link to Distributing the Build Work">​</a></h2>
<p>Imagine a factory with multiple assembly lines, each focused on a specific part of the product. This parallel approach increases efficiency and speeds up production. Similarly, in a build process, distributing work of various modules across multiple machines creates <a href="https://bitrise.io/blog/post/build-pipelines-efficient-ci-cd-workflows-with-parallelization" target="_blank" rel="noopener noreferrer">parallel build pipelines</a>, leading to faster builds and improved scalability. This can be achieved through various means:</p>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Component-based_software_engineering" target="_blank" rel="noopener noreferrer"><strong>Modular Builds</strong></a>: Break down the build process by <a href="https://moderncppdevops.com/2024/06/24/distributing-builds">design components or compilation units</a>. Each module is built independently, allowing teams to work concurrently without waiting for a monolithic build to complete. This modular approach can significantly reduce build times and improve efficiency.</li>
<li><a href="https://www.incredibuild.com/blog/speed-up-your-builds-by-parallelizing" target="_blank" rel="noopener noreferrer"><strong>Parallel Builds</strong></a>: Utilize parallelism by distributing the build across multiple machines or cores. Modern build systems can automatically detect dependencies and run independent tasks concurrently, further speeding up the process.</li>
<li><a href="https://www.linkedin.com/advice/0/what-key-features-benefits-using-cloud-based-cicd-tools" target="_blank" rel="noopener noreferrer"><strong>Cloud-Based Builds</strong></a>: Leverage cloud infrastructure to dynamically scale build resources based on demand. This is particularly useful for large-scale builds that would otherwise require significant on-premises hardware investment.</li>
</ul>
<p>Services that provide this functionality are a dime as dozen, <a href="https://docs.github.com/en/get-started/learning-about-github/githubs-plans#github-enterprise" target="_blank" rel="noopener noreferrer">GitHub Enterprise</a>, <a href="https://docs.gitlab.com/" target="_blank" rel="noopener noreferrer">GitLab</a>, or <a href="https://www.atlassian.com/software/bitbucket/features/pipelines" target="_blank" rel="noopener noreferrer">BitBucket Pipelines</a> all lend themselves very well to this.</p>
<p>The biggest limiting factor will actually be your product software design. The order of which C or C++ code can be compiled, linked, or archived is a direct consequence of the design. Favoring <a href="https://www.capitalone.com/tech/software-engineering/microservices-design-patterns/" target="_blank" rel="noopener noreferrer">microservices design patterns</a> along with re-usable components are likely to lead to better build times.</p>
<p>Not all builds are equal, you'll want to consider different strategies for developer versus automation.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="cold-vs-warm-vs-incremental-builds">Cold vs Warm vs. Incremental Builds<a href="https://moderncppdevops.com/2024/08/26/designing-a-build-process#cold-vs-warm-vs-incremental-builds" class="hash-link" aria-label="Direct link to Cold vs Warm vs. Incremental Builds" title="Direct link to Cold vs Warm vs. Incremental Builds">​</a></h3>
<p>Not all <a href="https://en.wikipedia.org/wiki/Software_build" target="_blank" rel="noopener noreferrer">software builds</a> are equal. Understanding the difference between cold builds and incremental builds is key to optimizing your build strategy. Many of these ideas carry over from other aspect such as <a href="https://www.geeksforgeeks.org/hot-and-cold-deployment-in-tomcat/" target="_blank" rel="noopener noreferrer">deployment</a> or <a href="https://www.instabug.com/blog/understanding-cold-hot-and-warm-app-launch-time" target="_blank" rel="noopener noreferrer">application start</a>.</p>
<ul>
<li><strong>Cold Builds</strong>: A cold build is a complete build of the software from scratch. This is typically required when a new copy of the codebase is checked out on a clean system, such as during CI/CD when integrating all of the software. Cold builds are time-consuming but necessary to ensure that all components are correctly integrated.</li>
<li><strong>Warm Builds</strong>: A warm build refers to a complete rebuild of the software from an existing working copy. This is typically required when there are significant changes across the codebase, such as after a major refactor or when integrating a large number of changes. Warm builds are extremely time-consuming and in general require interrupt any work on that system.</li>
<li><a href="https://learn.microsoft.com/en-us/visualstudio/msbuild/incremental-builds?view=vs-2022" target="_blank" rel="noopener noreferrer"><strong>Incremental Builds</strong></a>: Incremental builds only compile and link the parts of the software that have changed since the last build. This approach is much faster and is suitable for day-to-day development activities where only a few files have been modified.</li>
</ul>
<p>Balancing the frequency of cold and incremental builds is crucial. While incremental builds save time during development, regular cold builds should be scheduled to ensure that the build system remains reliable and that no hidden dependencies are introduced.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="build-caching-speeding-up-software-compilation">Build Caching: Speeding Up Software Compilation<a href="https://moderncppdevops.com/2024/08/26/designing-a-build-process#build-caching-speeding-up-software-compilation" class="hash-link" aria-label="Direct link to Build Caching: Speeding Up Software Compilation" title="Direct link to Build Caching: Speeding Up Software Compilation">​</a></h2>
<p>Build caching is a technique used to <a href="https://gradle.com/gradle-enterprise-solutions/build-cache" target="_blank" rel="noopener noreferrer">accelerate the software build process</a> by storing and <a href="https://docs.incredibuild.com/lin/latest/linux/build_avoidance.htm" target="_blank" rel="noopener noreferrer">reusing previously generated build outputs</a>. Instead of recompiling the entire codebase from scratch, a build cache stores intermediate compiler outputs—such as object files, libraries, or executables—so that only the changed components need to be rebuilt.</p>
<p>There are two key types of build caching:</p>
<ol>
<li><strong>Intermediate Compiler Output Caching</strong>: This involves caching the results of individual compilation steps, such as object files. If the source code hasn't changed, the cached outputs can be reused, reducing build times.</li>
<li><strong>Component Caching</strong>: This caches entire components or modules, particularly useful in complex projects with many interdependent parts.</li>
</ol>
<p>Both types of caching are closely <a href="https://community.atlassian.com/t5/Bitbucket-questions/Re-caches-vs-artifacts/qaq-p/865764/comment-id/31225#M31225" target="_blank" rel="noopener noreferrer">related to artifact management</a>, where these <a href="https://docs.docker.com/build/cache/#order-your-layers" target="_blank" rel="noopener noreferrer">cached outputs</a> (artifacts) are stored, versioned, and retrieved efficiently. Proper build caching can dramatically speed up incremental builds and ensure consistency across different development environments.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="ensuring-quality-and-efficiency-with-cicd-pipelines">Ensuring Quality and Efficiency with CI/CD Pipelines<a href="https://moderncppdevops.com/2024/08/26/designing-a-build-process#ensuring-quality-and-efficiency-with-cicd-pipelines" class="hash-link" aria-label="Direct link to Ensuring Quality and Efficiency with CI/CD Pipelines" title="Direct link to Ensuring Quality and Efficiency with CI/CD Pipelines">​</a></h2>
<p>To ensure that all individual contributions from your teams are cohesive, and that the final software package is <a href="https://www.embedded.com/how-to-define-your-ideal-embedded-ci-cd-pipeline/" target="_blank" rel="noopener noreferrer">ready for the release process</a>, a robust <a href="https://www.redhat.com/en/topics/devops/what-is-ci-cd" target="_blank" rel="noopener noreferrer">CI/CD pipeline</a> is essential.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="continuous-integration-ci">Continuous Integration (CI)<a href="https://moderncppdevops.com/2024/08/26/designing-a-build-process#continuous-integration-ci" class="hash-link" aria-label="Direct link to Continuous Integration (CI)" title="Direct link to Continuous Integration (CI)">​</a></h3>
<p>CI is the practice of <a href="https://www.mullineaux.com.au/infrastructure-as-code-with-azure-devops/part-3/" target="_blank" rel="noopener noreferrer">automatically integrating code changes</a> from multiple contributors into the main branch frequently. Each integration is verified by an automated build and automated tests, which helps detect errors early.</p>
<ul>
<li><strong>Integration Builds</strong>: Set up integration builds that <a href="https://aws.amazon.com/devops/continuous-integration/#:~:text=Continuous%20integration%20refers%20to%20the,for%20a%20release%20to%20production." target="_blank" rel="noopener noreferrer">compile and link the entire product</a>, even if individual components are developed and tested independently. This ensures that the final product will function as expected when all components are combined.</li>
<li><a href="https://medium.com/@HirenDhaduk1/how-automation-testing-is-used-in-ci-cd-pipeline-f297d4a1bc65#a68c" target="_blank" rel="noopener noreferrer"><strong>Automated Testing</strong></a>: Incorporate a comprehensive suite of automated tests that run with each build. This ensures that new changes do not introduce regressions or break existing functionality.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="continuous-deployment-cd">Continuous Deployment (CD)<a href="https://moderncppdevops.com/2024/08/26/designing-a-build-process#continuous-deployment-cd" class="hash-link" aria-label="Direct link to Continuous Deployment (CD)" title="Direct link to Continuous Deployment (CD)">​</a></h3>
<p>CD is the practice of automatically deploying software that has passed the CI pipeline into production or a production-like environment. This ensures that the software is always in a deployable state.</p>
<ul>
<li><a href="https://moderncppdevops.com/2024/05/20/what-is-a-package"><strong>Artifact Management</strong></a>: Implement an artifact repository to manage the outputs of your build process. This includes binaries, libraries, and other build artifacts that are versioned and stored for later use.</li>
<li><strong>Deployment Pipelines</strong>: This is not limited to <a href="https://www.beningo.com/streamline-your-development-embedded-ci-cd-its-value-and-essential-tools/#" target="_blank" rel="noopener noreferrer">deploying to a fleet of devices</a>. Internal deployment pipelines that automatically deploy builds to staging environments for further testing. Having a single unified way for Quality Assurance or System Test teams to have the latest copy of the software reduces bottlenecks and <a href="https://allspice.io/post/ci-cds-impact-on-hardware-development-life-cycles" target="_blank" rel="noopener noreferrer">communication errors across teams</a>. This allows for thorough validation before a release candidate is considered ready for production.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-security-driven-imperative-for-toolchain-evolution">The Security-Driven Imperative for Toolchain Evolution<a href="https://moderncppdevops.com/2024/08/26/designing-a-build-process#the-security-driven-imperative-for-toolchain-evolution" class="hash-link" aria-label="Direct link to The Security-Driven Imperative for Toolchain Evolution" title="Direct link to The Security-Driven Imperative for Toolchain Evolution">​</a></h2>
<p>In today's software landscape, security threats are <a href="https://thecyberexpress.com/supply-chain-attacks-now-common-cyble-research/" target="_blank" rel="noopener noreferrer">constantly evolving</a> not just for the product but also the critical IT infrastructure internally to the business - this <a href="https://www.techtarget.com/whatis/feature/SolarWinds-hack-explained-Everything-you-need-to-know" target="_blank" rel="noopener noreferrer">includes the build process</a> as Solarwinds proved, and this has a direct impact on the toolchain used to build and maintain your software. Security vulnerabilities in tool dependencies such as compilers, linkers, libraries, and even build scripts can become points of exploitation. System dependencies such as <a href="https://docs.gitlab.com/ee/user/clusters/agent/" target="_blank" rel="noopener noreferrer">CI/CD Agents</a>, Operating Systems and <a href="https://www.crowdstrike.com/platform/endpoint-security/" target="_blank" rel="noopener noreferrer">Security Agents</a> themselves evolve to mitigate these threats, they often introduce changes that can render older tools obsolete or incompatible. This forces you to continuously <a href="https://moderncppdevops.com/tool-dep-strategies" target="_blank" rel="noopener noreferrer">update your dependencies</a>, ensuring that everything remains secure and capable of producing reliable software.</p>
<ul>
<li><strong>Operating System Upgrades</strong>: Operating systems frequently undergo major upgrades to address security vulnerabilities, improve performance, and introduce new features. These upgrades can introduce changes in system libraries, APIs, or even file system structures that may not be compatible with older versions of your toolchain.<!-- -->
<ul>
<li>Investing in <a href="https://moderncppdevops.com/windows-iac-for-cpp" target="_blank" rel="noopener noreferrer">Infrastructure as Code</a> to develop and test new build agents is a foundation strategy.</li>
</ul>
</li>
<li><strong>Hardware Platform Changes</strong>: As hardware platforms evolve, especially in the context of new processor architectures or enhanced security features like secure boot and trusted execution environments, your existing toolchain may not be able to generate binaries that fully leverage these advancements, or worse, might fail to work altogether.<!-- -->
<ul>
<li>Support using <a href="https://developers.redhat.com/blog/2021/05/07/use-multiple-compilers-to-build-better-projects#" target="_blank" rel="noopener noreferrer">multiple compilers</a> and <a href="https://moderncppdevops.com/build-more-configurations" target="_blank" rel="noopener noreferrer">build several configurations</a> of your software.</li>
<li>Build the toolchain for your supported platforms or work with vendors to ensure platform compatibility.</li>
</ul>
</li>
<li><strong>Security Compliance</strong>: Over time, <a href="https://www.nhtsa.gov/research/vehicle-cybersecurity" target="_blank" rel="noopener noreferrer">industry standards and compliance requirements evolve</a>. New security protocols, encryption standards, and coding practices may require updates to your compilers, debuggers, and other tools to remain compliant.<!-- -->
<ul>
<li>Providing a <a href="https://www.cisa.gov/sbom" target="_blank" rel="noopener noreferrer">Software Bill of Materials (SBOM)</a> is becoming a <a href="https://www.synopsys.com/company/legal/info-security.html" target="_blank" rel="noopener noreferrer">legal requirement</a> and by necessity managing dependencies.</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://moderncppdevops.com/2024/08/26/designing-a-build-process#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>By understanding the techniques outlined in this guide, you can elevate your native build process to new heights. This empowers you to achieve both speed and security, the cornerstones of a modern development environment. Understanding the nuances of cold, warm, and incremental builds equips you to choose the right approach for each situation. We've also unveiled the power of build caching, a technique that dramatically accelerates builds by reusing previously generated outputs. Mot importantly, <strong>implement security best practices.</strong>  Regularly update your toolchain and enforce secure coding practices.</p>
<p>But remember, the journey doesn't stop there. In today's threat landscape, security is paramount.  We've explored the ever-evolving security challenges that necessitate the continuous evolution of your build toolchain. Factors like operating system upgrades, hardware platform changes, and evolving security compliance requirements all demand a proactive approach to toolchain management.</p>
<p>By embracing the strategies outlined in this guide, you can establish a secure and efficient native build process for your C and C++ code. This empowers your team to deliver innovative software with confidence, knowing that your build process is both robust and resilient.</p>
<p>By following these steps and leveraging the knowledge from this guide, you can build a secure and efficient native build process that propels your software development efforts forward.</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="software development" term="software development"/>
        <category label="build process" term="build process"/>
        <category label="native development" term="native development"/>
        <category label="c++" term="c++"/>
        <category label="c" term="c"/>
        <category label="ci/cd" term="ci/cd"/>
        <category label="devops" term="devops"/>
        <category label="automation" term="automation"/>
        <category label="modular builds" term="modular builds"/>
        <category label="parallel builds" term="parallel builds"/>
        <category label="cloud-based builds" term="cloud-based builds"/>
        <category label="incremental builds" term="incremental builds"/>
        <category label="cold builds" term="cold builds"/>
        <category label="warm builds" term="warm builds"/>
        <category label="build caching" term="build caching"/>
        <category label="artifact management" term="artifact management"/>
        <category label="continuous integration" term="continuous integration"/>
        <category label="continuous deployment" term="continuous deployment"/>
        <category label="security" term="security"/>
        <category label="toolchain management" term="toolchain management"/>
        <category label="operating systems" term="operating systems"/>
        <category label="hardware platforms" term="hardware platforms"/>
        <category label="security compliance" term="security compliance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[C++ Distributed Builds: Strategies to Reduce Build Times]]></title>
        <id>https://moderncppdevops.com/2024/06/24/distributing-builds</id>
        <link href="https://moderncppdevops.com/2024/06/24/distributing-builds"/>
        <updated>2024-06-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[C++ developers struggling with slow build times can leverage distributed builds to harness the power of multiple machines and significantly reduce wait times. This guide explores two distribution strategies: distributing compilation units for smaller projects and distributing targets for larger ones with complex configurations. Both approaches benefit from caching mechanisms to further optimize builds. By understanding these strategies and choosing the right fit for your project, you can streamline your development workflow, improve scalability, and conquer C++ build times once and for all.]]></summary>
        <content type="html"><![CDATA[<p>Have you ever stared longingly at that <em>time-consuming</em> progress bar, willing your C++ project to compile faster? If you're nodding along, you're not alone. The <a href="https://moderncppdevops.com/2024-survey-results">ISO's annual "lite" developer survey</a> consistently reveals that over 60% of respondents consider long build times a major pain point, with little improvement year over year.</p>
<p>Thankfully, there's an old solution: <a href="https://cppdepend.com/blog/importance-of-cpp-distributed-build-systems/" target="_blank" rel="noopener noreferrer">distributing the build</a> burden across multiple machines. This approach can <a href="https://devblogs.microsoft.com/engineering-at-microsoft/large-scale-distributed-builds-with-microsoft-build-accelerator/" target="_blank" rel="noopener noreferrer">dramatically slash those wait times</a> (<a href="https://www.distcc.org/" target="_blank" rel="noopener noreferrer">either way you go</a>) and free you to focus on what matters - writing great code. This blog post will explore two prominent distribution techniques and how they've evolved: distributing compilation units and distributing targets. But here's the secret sauce: a <a href="https://enccs.github.io/cmake-workshop/targets/" target="_blank" rel="noopener noreferrer">target-based approach</a>, the current best practice, can not only accelerate builds but also lead you to design cleaner and more maintainable build pipelines. Let's dive in!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="distributing-makefile-builds-the-predecessor">Distributing Makefile Builds: The Predecessor<a href="https://moderncppdevops.com/2024/06/24/distributing-builds#distributing-makefile-builds-the-predecessor" class="hash-link" aria-label="Direct link to Distributing Makefile Builds: The Predecessor" title="Direct link to Distributing Makefile Builds: The Predecessor">​</a></h2>
<p>This strategy leverages <a href="https://stackoverflow.com/questions/6264249/how-does-the-compilation-linking-process-work" target="_blank" rel="noopener noreferrer">C++'s compilation process</a>, this strategy focuses on splitting the build into individual source files (compilation units) and compiling them into object files in parallel. Each machine receives a unit, compiles it independently, and returns the object file. This method is sometimes refered to as a task-based, where the order of the tasks needs to be preserved.</p>
<p>This approach has roots in the historical use of <strong>Makefiles</strong> for parallelizing builds. Makefiles, with their <a href="https://www.gnu.org/software/make/" target="_blank" rel="noopener noreferrer">file-based structure</a>, allowed developers to define separate targets for object, assembled, archived, linked and other build artifact files. By leveraging the <code>make -j</code> flag, builds could be spread across multiple cores or machines.</p>
<p>However, Makefiles faced limitations:</p>
<ul>
<li><strong>Limited Dependency Management:</strong> Makefile's rely on explicit dependencies between intermediate compilation artifacts. This becomes cumbersome for complex projects with intricate relationships between <a href="https://firefox-source-docs.mozilla.org/contributing/build/artifact_builds.html" target="_blank" rel="noopener noreferrer">build artifacts</a> or when implementing extra processing like <a href="https://moderncppdevops.com/2024/06/03/sast-without-slow">sanitizers</a>.</li>
<li><strong>Scalability Challenges:</strong> Managing distributed builds across multiple machines with Makefiles can be complex, demanding careful coordination of build order, resource allocation, and error handling as the build environment grows. There's a few commercial products, like <a href="https://docs.oracle.com/cd/E19422-01/819-3697/dmake.html" target="_blank" rel="noopener noreferrer">dmake</a> or <a href="https://docs.cloudbees.com/docs/cloudbees-build-acceleration/latest/emake-user-guide/" target="_blank" rel="noopener noreferrer">emake</a> that implemented this strategy - none of them are really used anymore.</li>
</ul>
<p>Both of these combine to limit the ability to perform incremental builds. This will cost all the developers to rebuild or "cold build" more often. As all the task need to be re-ran in the same order dividing the a sub graph pulls is more difficult.</p>
<p>Makefile's language of "targets" referred to <a href="https://makefiletutorial.com/#makefile-syntax" target="_blank" rel="noopener noreferrer">compilation targets</a> for instance going from a <code>.c</code> to a <code>.o</code> creating a dependency that could be tracked for a single linked target. These compilation unit themselves could be distributed with other strategies.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="distributing-compilation-units-still-relevant">Distributing Compilation Units: Still Relevant?<a href="https://moderncppdevops.com/2024/06/24/distributing-builds#distributing-compilation-units-still-relevant" class="hash-link" aria-label="Direct link to Distributing Compilation Units: Still Relevant?" title="Direct link to Distributing Compilation Units: Still Relevant?">​</a></h2>
<p>Despite the challenges with distributing tasks within Makefile, distributing compilation units can still be relevant for a variety of projects with few targets but could still benefit from <a href="https://en.wikipedia.org/wiki/Incremental_build_model" target="_blank" rel="noopener noreferrer">incremental builds</a>. Here are some tools that implement this strategy:</p>
<ul>
<li><strong>Distcc (Distributed C/C++ Compiler):</strong> A free, open-source tool that replaces the system compiler and distributes compilation tasks across a network. You can <a href="https://developers.redhat.com/blog/2019/05/15/2-tips-to-make-your-c-projects-compile-3-times-faster#tip__2__using_a_distcc_server_container" target="_blank" rel="noopener noreferrer">manage this with IaC</a>. There are <a href="https://engineering.celonis.com/blog/homcc-a-traffic-efficient-distributed-compiler/" target="_blank" rel="noopener noreferrer">other similar implementations</a> though less mature or actively developed.</li>
<li><strong>IncrediBuild:</strong> A commercial solution offering advanced features like dependency management and caching. Easy out of the box support for cross-platform development.</li>
</ul>
<p>A crucial element for reducing redundant compilations is caching previously compiled object files based on the source code, compiler flags, and header versions. If a unit hasn't changed, the cached object file can be reused, significantly accelerating the build process. A very popular approach is <a href="https://blog.zaleos.net/giving-ccache-distcc-a-spin/" target="_blank" rel="noopener noreferrer">combining it with ccache</a> which has been <a href="https://www.jamessjackson.com/gcc/ccache/distcc/compiling/c++/2017/07/25/ccache-and-distcc/" target="_blank" rel="noopener noreferrer">deployed for a long while</a>. these two tools are intended to be used at the compiler level, they can be drop in replacements that wrap the compiler. This ability can be very useful to combine with other other distribution models.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="modern-tools-and-target-distribution-a-powerful-partnership">Modern Tools and Target Distribution: A Powerful Partnership<a href="https://moderncppdevops.com/2024/06/24/distributing-builds#modern-tools-and-target-distribution-a-powerful-partnership" class="hash-link" aria-label="Direct link to Modern Tools and Target Distribution: A Powerful Partnership" title="Direct link to Modern Tools and Target Distribution: A Powerful Partnership">​</a></h2>
<p>Modern build tools like <a href="https://bazel.build/basics/artifact-based-builds" target="_blank" rel="noopener noreferrer">Bazel</a> address the challenges seen with distributing Makefile builds by emphasizing the <strong>target-level dependencies</strong>. This is the current best practice, this <a href="https://schedule.cppnow.org/session/2024/the-importance-of-the-build-system-target-model/" target="_blank" rel="noopener noreferrer">recent talk by CMake</a> does a great job presenting this. Each target (library, executable, etc.) explicitly declares its dependencies on other targets. This allows the build system to intelligently determine the optimal build order and efficiently distribute tasks across machines. It's worth noting Bazel language for target's is artifacts, which  much more closely aligns with DevOps' principal for <a href="https://instatus.com/blog/devops-artifacts" target="_blank" rel="noopener noreferrer">artifact management</a>.</p>
<p>Here's how Bazel, handles target-level dependencies:</p>
<ol>
<li><strong>Target Definition:</strong> Each target is defined as a build artifact within a <code>.bzl</code> file (Bazel's build language).</li>
<li><strong>Dependency Declaration:</strong> Targets explicitly declare their dependencies on other targets using functions like <code>cc_library.deps</code> and <code>cc_binary.deps</code>.</li>
<li><strong>Dependency Resolution:</strong> Bazel analyzes the dependency graph formed by all targets and their dependencies.</li>
<li><strong>Parallel Execution:</strong> Based on the dependency graph, Bazel identifies independent tasks that can be executed in parallel across available machines.</li>
</ol>
<p>With a sample project, simply running <code>bazel build json_formatter</code> which correct order the targets and leverage all the resources in the local system.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token comment" style="color:rgb(106, 153, 85)"># Define the application binary</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">cc_binary</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  name </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"json_formatter"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  srcs </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token string" style="color:rgb(206, 145, 120)">"json_formatter.cpp"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  deps </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token comment" style="color:rgb(106, 153, 85)"># Dependencies for JSON parsing and formatting</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token string" style="color:rgb(206, 145, 120)">"@com_github_nlohmann_json//:json"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># nlohmann_json library</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># Download nlohmann_json as an external repository</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">http_archive</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  name </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"com_github_nlohmann_json"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  urls </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token string" style="color:rgb(206, 145, 120)">"https://github.com/nlohmann/json/archive/v3.11.2.tar.gz"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  sha256 </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0e498fea8a781f7eafc11b9a8efa9b7e28d8fb7e774c0c5a5e30fc4eda309a9e4"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  strip_prefix </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"json-3.11.2"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  build_file </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"@com_github_nlohmann_json//:BUILD"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Bazel, like other popular C++ build systems, do not include <a href="https://bazel.build/remote/rules#toolchain-rules" target="_blank" rel="noopener noreferrer">remote build execution</a> (at least for C++). Remote Build Execution (RBE) Is popular option from Google's <a href="https://www.buildbuddy.io/docs/rbe-setup/" target="_blank" rel="noopener noreferrer">BuildBuddy RBE</a>. RBE requires a separate server setup and worker machines. An open-source alternative is <a href="https://gitlab.com/BuildGrid/buildbox/buildbox" target="_blank" rel="noopener noreferrer">BuildGrid's buildbox</a>, though it's far more difficult to find information.</p>
<p><strong>Benefits of Target-Level Dependencies:</strong></p>
<ul>
<li><strong>Improved Maintainability:</strong> Explicit dependency declarations make build logic easier to understand and maintain.</li>
<li><strong>Scalability:</strong> Bazel manages the complexity of distributed builds, allowing for efficient scaling to large build environments. Just remark is does not handle the infrastructure to run the builds on, you'll need to bring your own.</li>
<li><strong>Reduced Build Times:</strong> Parallel execution significantly reduces overall build times, especially for large projects where incremental and partial builds represent smaller sections.</li>
</ul>
<p>Bazel and similar tools can cache not only object files but also entire build outputs for specific targets. If a target's dependencies haven't changed, the <a href="https://bazel.build/basics/distributed-builds#remote_caching" target="_blank" rel="noopener noreferrer">cached output can be reused</a>, eliminating the need to rebuild the entire target from scratch.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="cruciality-of-caching-in-both-strategies">Cruciality of Caching in Both Strategies<a href="https://moderncppdevops.com/2024/06/24/distributing-builds#cruciality-of-caching-in-both-strategies" class="hash-link" aria-label="Direct link to Cruciality of Caching in Both Strategies" title="Direct link to Cruciality of Caching in Both Strategies">​</a></h2>
<p>Both distributing compilation units and distributing targets benefit significantly from effective caching mechanisms.</p>
<ul>
<li><strong>Compilation Unit Distribution:</strong> Caching eliminates redundant compilations.  If a unit hasn't changed since the last build, the cached object file can be reused, regardless of which machine it was built on previously. This significantly speeds up subsequent builds, especially for large projects with many shared units.</li>
<li><strong>Target Distribution:</strong> Caching can <a href="https://scons.org/doc/production/HTML/scons-user/ch22.html" target="_blank" rel="noopener noreferrer">store entire target outputs</a>, not just object files. This is particularly valuable for distributing targets because:<!-- -->
<ul>
<li><strong>Incremental Builds:</strong> When a target's dependencies haven't changed, the cached output can be used directly, avoiding the need to rebuild the entire target from scratch. This is especially beneficial for large or complex targets with many dependencies.</li>
<li><strong>Remote Builds:</strong> When downloading pre-built cached artifacts from a remote server, build times are significantly <a href="https://forum.gitlab.com/t/making-long-build-times-short-by-using-cache/12540/2" target="_blank" rel="noopener noreferrer">reduced compared to transferring and rebuilding</a> everything from scratch. This is crucial for scaling builds across geographically distributed environments.</li>
</ul>
</li>
</ul>
<p>Both distribution strategies benefit from caching by reducing redundant work. This frees up machines to focus on building new or changed parts of the project, leading to more efficient resource utilization. These concept extend to local builds, where you can leverage <a href="https://bazel.build/remote/caching" target="_blank" rel="noopener noreferrer">Bazel's remote caching</a> capabilities. Configure a local cache using <code>--remote_cache</code> to store build artifacts and potentially avoid redundant compilations. Package managers are another <a href="https://learn.microsoft.com/en-us/vcpkg/users/binarycaching" target="_blank" rel="noopener noreferrer">implementation of a caching</a> strategy. Stay tunned for more topic.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="choosing-the-right-strategy">Choosing the Right Strategy<a href="https://moderncppdevops.com/2024/06/24/distributing-builds#choosing-the-right-strategy" class="hash-link" aria-label="Direct link to Choosing the Right Strategy" title="Direct link to Choosing the Right Strategy">​</a></h2>
<p>The best approach is using <strong>both strategies</strong>. If you need to pick one distributing compilation units can be simpler for smaller projects with well-defined dependencies and few target platforms. Distributing targets tend be more efficient for larger projects with complex build configurations when incremental builds have the most potential.</p>
<p>Here's a decision-making framework to help you choose the right strategy.</p>
<ul>
<li>Start with distributing targets<!-- -->
<ul>
<li>This will encourage you to <a href="https://softwareengineering.stackexchange.com/a/405228" target="_blank" rel="noopener noreferrer">write smaller more reusable components</a>. Caching a library is less complex then compilation object files.</li>
<li>It's easier to leverage package managers to handle the encapsulation and dependents management. This often have built-in tools to determine what needs to be rebuilt.</li>
<li>This is have the most immediate impact on overall build times. Downloading prebuilt cached artifacts and only performing incremental builds for local development.</li>
</ul>
</li>
</ul>
<p>This might not translate to all projects types. So for the other side of the spectrum, if you have a monorepo where source files are shared across multiple projects, then distributing the compilation would most likely have the larger impact upfront.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://moderncppdevops.com/2024/06/24/distributing-builds#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>Distributing C++ builds offers a powerful tool to improve development efficiency. By leveraging these strategies and available tools, you can significantly reduce build times and streamline your C++ development workflow. Remember to consider your project's specific needs when choosing the best approach for your build distribution.</p>
<p>You'll know you've done it right when <a href="https://blog.gradle.org/general-build-distribution" target="_blank" rel="noopener noreferrer">testing is the longest</a> portion of you pipeline.</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="c++" term="c++"/>
        <category label="build times" term="build times"/>
        <category label="distributed builds" term="distributed builds"/>
        <category label="compilation units" term="compilation units"/>
        <category label="targets" term="targets"/>
        <category label="caching" term="caching"/>
        <category label="performance" term="performance"/>
        <category label="development efficiency" term="development efficiency"/>
        <category label="scalability" term="scalability"/>
        <category label="ci/cd" term="ci/cd"/>
        <category label="pipelines" term="pipelines"/>
        <category label="local builds" term="local builds"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Boosting C++ Memory Safety with Parallel Builds and Shared Configurations]]></title>
        <id>https://moderncppdevops.com/2024/06/03/sast-without-slow</id>
        <link href="https://moderncppdevops.com/2024/06/03/sast-without-slow"/>
        <updated>2024-06-03T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Struggling with memory leaks and crashes in your C++ projects? This guide unveils a powerful approach to significantly improve memory safety using sanitizers like AddressSanitizer (ASan) and LeakSanitizer (LSan). Learn how to build multiple configurations for production and memory checks, harness parallel builds to optimize your CI/CD pipelines, and implement caching strategies for efficient third-party dependency management. Gain practical steps for integrating sanitizers into your build process, real-world examples using CMake and GitHub Actions, and valuable insights on boosting overall memory safety practices. Take control of your C++ development and build robust, reliable applications with exceptional memory safety.]]></summary>
        <content type="html"><![CDATA[<p>C++ grants developers immense power, but with it comes the <a href="https://thenewstack.io/out-with-c-and-c-in-with-memory-safety/" target="_blank" rel="noopener noreferrer">greater responsibility of managing memory</a>. Memory leaks and access violations can bring down even the most robust applications. To combat these issues, <a href="https://en.wikipedia.org/wiki/Code_sanitizer" target="_blank" rel="noopener noreferrer">sanitizers</a> like AddressSanitizer (ASan) and LeakSanitizer (LSan) are <a href="https://blog.trailofbits.com/2024/05/16/understanding-addresssanitizer-better-memory-safety-for-your-code/#:~:text=ASan%20inserts%20checks%20around%20memory,compared%20to%20other%20similar%20tools." target="_blank" rel="noopener noreferrer">invaluable tools</a>. When it comes to addressing security, this is <a href="https://herbsutter.com/2024/03/11/safety-in-context/" target="_blank" rel="noopener noreferrer">only the tip of the iceberg</a>; you are expected to do more but sanitizers are an approachable starting pointing.</p>
<p>Despite these obvious upsides <a href="https://moderncppdevops.com/2024-survey-results">50% of developers don't leverage these tools</a>, integrating them into the build process often raises concerns about increased build times. This blog post explores a strategy to leverage modern build tools and parallelization to achieve exceptional memory safety without sacrificing CI speed.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-power-of-many-building-more-configurations">The Power of Many: Building More Configurations<a href="https://moderncppdevops.com/2024/06/03/sast-without-slow#the-power-of-many-building-more-configurations" class="hash-link" aria-label="Direct link to The Power of Many: Building More Configurations" title="Direct link to The Power of Many: Building More Configurations">​</a></h2>
<p>Traditionally, projects might ship with a single build configuration optimized for production - they are built exclusive for the platforms they support. But what if we <a href="https://moderncppdevops.com/build-more-configurations">built more configurations</a> specifically designed for memory safety checks? We can introduce configurations that enable sanitizers like ASan and LSan during the build process. These configurations would catch memory issues early on, preventing them from reaching production.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Tip</div><div class="admonitionContent_BuS1"><p>This also possible <a href="https://learn.microsoft.com/en-us/cpp/sanitizers/asan-continue-on-error?view=msvc-170" target="_blank" rel="noopener noreferrer">cross-platform</a>, thought it might be more effective to target just one depending on your infrastructure.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="foundation-simple-ci-pipeline">Foundation: Simple CI Pipeline<a href="https://moderncppdevops.com/2024/06/03/sast-without-slow#foundation-simple-ci-pipeline" class="hash-link" aria-label="Direct link to Foundation: Simple CI Pipeline" title="Direct link to Foundation: Simple CI Pipeline">​</a></h2>
<p>As previously covered, CMake Preset are an excellent way to <a href="https://moderncppdevops.com/simple-ci-with-presets">organize build configurations</a>. If you are unsure about them, checkout <a href="https://www.reddit.com/r/cpp/comments/lmj32h/integrating_sanitizers_into_your_ci_workflow/" target="_blank" rel="noopener noreferrer">the old school way</a> or this <a href="https://ngathanasiou.wordpress.com/2022/07/04/sanitizers-in-continuous-integration/" target="_blank" rel="noopener noreferrer">far more restrictive implementation</a>, there's an elegance to the simplicity presets can bring. Let's take the release preset and wrap that in a pipeline to get started.</p>
<p><strong>Pre-conditions:</strong></p>
<ul>
<li><strong>Compiler Toolchain:</strong> The CI environment should have the necessary compiler toolchain (e.g., GCC, Clang) pre-installed.</li>
<li><strong>Dependencies:</strong> Any project dependencies should be readily available through package managers or pre-downloaded artifacts.</li>
<li><strong>Test Coverage:</strong> Good test coverage either through unit or integration tests where the code can be exercised; working examples are a good substitute.</li>
</ul>
<p><strong>Pipeline Stages:</strong></p>
<!-- -->
<ol>
<li><strong>Checkout:</strong> Fetch the latest code from the version control system (e.g., Git).</li>
<li><strong>Install Dependencies:</strong> If dependencies aren't pre-installed, use package managers to install them during this stage.</li>
<li><strong>Configure:</strong>
<ul>
<li>Select the desired build configurations using CMake. For example one for production and one for each sanitizer (ASan, LSan, etc.).</li>
</ul>
</li>
<li><strong>Build:</strong>
<ul>
<li>Execute the build commands defined in the CMake configurations from stage 3.</li>
</ul>
</li>
<li><strong>Test:</strong>
<ul>
<li>Run unit tests and other automated tests for each successfully built configuration.</li>
</ul>
</li>
<li><strong>Artifacts:</strong>
<ul>
<li>Archive and store build artifacts like executables and test reports for further analysis or future reference.</li>
</ul>
</li>
</ol>
<p>Check the <a href="https://moderncppdevops.com/simple-ci-with-presets#refactoring-ci-pipelines">examples for GitHub Actions</a> from the presets post putting these principals practice.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-key-parallel-builds-for-speed">The Key: Parallel Builds for Speed<a href="https://moderncppdevops.com/2024/06/03/sast-without-slow#the-key-parallel-builds-for-speed" class="hash-link" aria-label="Direct link to The Key: Parallel Builds for Speed" title="Direct link to The Key: Parallel Builds for Speed">​</a></h2>
<p>The challenge? Building with multiple sanitizers can significantly <a href="https://github.com/google/sanitizers/wiki/AddressSanitizerPerformanceNumbers" target="_blank" rel="noopener noreferrer">impact build times</a> especially if they are already problematic. Here's where the magic of <strong>parallel builds</strong> comes in. By leveraging tools like CMake, we can define separate build configurations for each sanitizer. More importantly, we can configure these builds to run <a href="https://about.gitlab.com/blog/2021/01/20/using-run-parallel-jobs/" target="_blank" rel="noopener noreferrer">in parallel</a>, a well established technique to reduce build times.</p>
<!-- -->
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="implementing-this-on-github-actions">Implementing this on GitHub Actions<a href="https://moderncppdevops.com/2024/06/03/sast-without-slow#implementing-this-on-github-actions" class="hash-link" aria-label="Direct link to Implementing this on GitHub Actions" title="Direct link to Implementing this on GitHub Actions">​</a></h2>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> CI with Parallel Sanitizer Builds</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">on</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">push</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">branches</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"> main </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">jobs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">build</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">runs-on</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> ubuntu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">latest </span><span class="token comment" style="color:rgb(106, 153, 85)"># Make sure to have a proper version-controlled build image</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">strategy</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">matrix</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">preset</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">release</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> asan</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> lsan</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">steps</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> actions/checkout@v4</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> Install dependencies</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> ./.github/actions/install_deps </span><span class="token comment" style="color:rgb(106, 153, 85)"># Setup caching and call favorite package manager</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> Configure with preset</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> cmake </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">preset $</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> matrix.preset </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> Build</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> cmake </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">build </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">preset $</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> matrix.preset </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> Run tests</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> cmake </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">build </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">target unit_tests_run </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">preset $</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> matrix.preset </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">if</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> matrix.preset == 'release'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> Upload artifacts</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> actions/upload</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">artifacts@v4</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">with</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">          </span><span class="token key atrule">paths</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> build/release</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="caching-third-party-dependencies-for-effective-sanitizer-builds">Caching Third-Party Dependencies for Effective Sanitizer Builds<a href="https://moderncppdevops.com/2024/06/03/sast-without-slow#caching-third-party-dependencies-for-effective-sanitizer-builds" class="hash-link" aria-label="Direct link to Caching Third-Party Dependencies for Effective Sanitizer Builds" title="Direct link to Caching Third-Party Dependencies for Effective Sanitizer Builds">​</a></h2>
<p>When using sanitizers, it's crucial to ensure that the entire build graph, <a href="https://gaultier.github.io/blog/you_inherited_a_legacy_cpp_codebase_now_what.html#sanitizers" target="_blank" rel="noopener noreferrer">including third-party dependencies</a>, is built with sanitizers enabled. This guarantees that memory issues are detected across the entire codebase, not just within your own code, as the boundaries are were mistakes are most likely.</p>
<p>As we've established, building with sanitizers can significantly impact build times; to address this challenge, caching mechanisms play a vital role in optimizing the CI workflow. Third-party dependencies are less likely to change, but need to be <a href="https://softwareengineering.stackexchange.com/a/348772" target="_blank" rel="noopener noreferrer">treated with the same care</a>, between build are offer an effective return on investment for the effort to implement more complex workflows.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="why-caching-matters">Why Caching Matters<a href="https://moderncppdevops.com/2024/06/03/sast-without-slow#why-caching-matters" class="hash-link" aria-label="Direct link to Why Caching Matters" title="Direct link to Why Caching Matters">​</a></h3>
<p>Caching third-party dependencies can <a href="https://blog.gradle.org/introducing-gradle-build-cache#does-it-help" target="_blank" rel="noopener noreferrer">significantly improve build times</a> by avoiding redundant downloads and builds. This is particularly beneficial when using sanitizers, as the entire build graph needs to be re-evaluated with sanitizers enabled for each configuration.</p>
<p>Here's why caching is crucial:</p>
<ul>
<li><strong>Reduced Build Times:</strong> Caching eliminates the need to repeatedly download and build dependencies, especially for frequently used libraries. This can drastically reduce build times, especially on CI pipelines.</li>
<li><strong>Consistent Results:</strong> Caching ensures that the same dependencies are used across different builds, leading to more consistent and reliable results.</li>
<li><strong>Improved Developer Experience:</strong> Faster builds translate to a smoother development experience for the team, allowing them to iterate and test code changes more efficiently.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="strategies-for-caching-third-party-dependencies">Strategies for Caching Third-Party Dependencies<a href="https://moderncppdevops.com/2024/06/03/sast-without-slow#strategies-for-caching-third-party-dependencies" class="hash-link" aria-label="Direct link to Strategies for Caching Third-Party Dependencies" title="Direct link to Strategies for Caching Third-Party Dependencies">​</a></h3>
<p>Several strategies can be employed to effectively cache third-party dependencies when using sanitizers in C++ projects:</p>
<ul>
<li><strong>Per-Preset Caches:</strong> Create separate caches for each build configuration (e.g., release, asan, lsan). This ensures that dependencies are only downloaded and built once for each configuration, reducing redundancy.</li>
<li><strong>Conan Packages:</strong> Utilize package managers like Conan to manage third-party dependencies. Conan allows for caching packages remote (and <a href="https://blog.conan.io/2023/11/28/Conan-new-features-2-0-14.html" target="_blank" rel="noopener noreferrer">locally</a>) and reusing them across different builds.</li>
</ul>
<p>Adding onto the pipeline example, this looks like the following:</p>
<!-- -->
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="putting-it-all-together">Putting it All Together<a href="https://moderncppdevops.com/2024/06/03/sast-without-slow#putting-it-all-together" class="hash-link" aria-label="Direct link to Putting it All Together" title="Direct link to Putting it All Together">​</a></h2>
<ol>
<li><strong>Define Build Configurations:</strong> Use CMake to create individual build configurations for each sanitizer and a standard production configuration.</li>
<li><strong>Enable Parallel Builds:</strong> Leverage multiple cores or machines for parallel execution of these configurations.</li>
<li><strong>Implement Caching:</strong>
<ul>
<li>Utilize per-preset caches and/or Conan packages to efficiently manage third-party dependencies, ensuring consistent results and faster builds.</li>
</ul>
</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="benefits">Benefits<a href="https://moderncppdevops.com/2024/06/03/sast-without-slow#benefits" class="hash-link" aria-label="Direct link to Benefits" title="Direct link to Benefits">​</a></h2>
<ul>
<li><strong>Improved Memory Safety:</strong> Sanitizers catch memory issues early on, preventing them from reaching production.</li>
<li><strong>Fast CI Builds:</strong> Parallel builds mitigate the impact of additional configurations on CI pipelines.</li>
<li><strong>Consistent Development Workflow:</strong> Shared CMake presets streamline the development process by providing a familiar environment with memory safety checks readily available.</li>
</ul>
<p>By adopting this strategy, you can elevate your C++ project's memory safety without sacrificing development speed or introducing workflow friction. Remember, memory safety is not just a CI concern; it's an essential part of the entire development lifecycle. So, build more configurations, leverage parallelization, and empower your developers to write robust, memory-safe code!</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="c++" term="c++"/>
        <category label="memory safety" term="memory safety"/>
        <category label="sanitizers" term="sanitizers"/>
        <category label="address sanitizer" term="address sanitizer"/>
        <category label="leak sanitizer" term="leak sanitizer"/>
        <category label="parallel builds" term="parallel builds"/>
        <category label="ci" term="ci"/>
        <category label="cmake" term="cmake"/>
        <category label="github actions" term="github actions"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Packages: The Building Blocks of C++ Development]]></title>
        <id>https://moderncppdevops.com/2024/05/20/what-is-a-package</id>
        <link href="https://moderncppdevops.com/2024/05/20/what-is-a-package"/>
        <updated>2024-05-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[C++ packages are the foundation for efficient and maintainable C++ development. This blog post explores how C++ packages organize code with core artifacts like headers and libraries, guiding you on crafting valid packages for seamless compilation. Leverage build systems and package managers to optimize C++ builds and avoid binary compatibility issues, streamlining your development workflow. Whether you're a seasoned C++ developer or new to the language, this comprehensive guide equips you to improve code organization, reusability, and build times in your C++ projects. Dive deeper into popular build systems and package managers to unlock the full potential of C++ packages!]]></summary>
        <content type="html"><![CDATA[<p>In the ever-evolving world of C++, managing code effectively is paramount. Packages, a fundamental concept in <a href="https://en.wikipedia.org/wiki/Category:Software_distribution_platforms" target="_blank" rel="noopener noreferrer">software distribution</a>, provide a structured approach to organizing and distributing reusable components. This blog post delves into the core elements of C++ packages, their essential properties, and how they streamline the development process and proposes a set of core concepts that should be captured by any specification.</p>
<p>The reason this is so important from a CI design point of view is creating an <a href="https://www.incredibuild.com/blog/build-cache-today-and-tomorrow" target="_blank" rel="noopener noreferrer">effective caching solution</a> to help <a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/release/caching?view=azure-devops" target="_blank" rel="noopener noreferrer">improve build times</a>. Avoid uploading unnecessary files is an <a href="https://cloud.google.com/build/docs/optimize-builds/speeding-up-builds#gcloudignore" target="_blank" rel="noopener noreferrer">imperative requirement</a> for this strategy.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="unpacking-the-essentials-what-makes-a-c-package">Unpacking the Essentials: What Makes a C++ Package<a href="https://moderncppdevops.com/2024/05/20/what-is-a-package#unpacking-the-essentials-what-makes-a-c-package" class="hash-link" aria-label="Direct link to Unpacking the Essentials: What Makes a C++ Package" title="Direct link to Unpacking the Essentials: What Makes a C++ Package">​</a></h2>
<p>A C++ package encapsulates a collection of core <a href="https://devops.stackexchange.com/a/470" target="_blank" rel="noopener noreferrer">artifacts</a>, the lifeblood of your codebase. This does not extend to delivering the product for example as <a href="https://en.wikipedia.org/wiki/On-premises_software" target="_blank" rel="noopener noreferrer">on-premise software</a> but might be bundled for a <a href="https://en.wikipedia.org/wiki/Software_development_kit" target="_blank" rel="noopener noreferrer">software development kit</a>. These artifacts serve as building blocks that are ingested by build systems to execute the compilation, archiving, and linking processes. Here's a breakdown of the key components:</p>
<ul>
<li><strong>Core Artifacts:</strong>
<ul>
<li><strong><a href="https://www.learncpp.com/cpp-tutorial/header-files/" target="_blank" rel="noopener noreferrer">Headers</a> (.hpp files):</strong> These files contain declarations (functions, classes, variables, etc.) that serve as blueprints for your code. Other source files can <code>#include</code> headers to access the declared entities.</li>
<li><strong><a href="https://domiyanyue.medium.com/c-development-tutorial-4-static-and-dynamic-libraries-7b537656163e" target="_blank" rel="noopener noreferrer">Libraries</a> (Static and Shared):</strong> These are compiled archives (.a or .lib for static, .so or .dll for shared) that bundle object code representing compiled functions and variables. Libraries provide reusable functionality that can be integrated into your programs.</li>
<li><strong><a href="https://www.modernescpp.com/index.php/c-20-module-interface-unit-and-module-implementation-unit/" target="_blank" rel="noopener noreferrer">Binary Modules</a> (C++20 Modules):</strong> C++20 introduces modules (.ixx files) as a more granular unit of code organization and compilation compared to traditional headers. They enable stricter dependency management and improve build times.</li>
</ul>
</li>
<li><strong>Supporting Artifacts:</strong>
<ul>
<li><strong>License Information (.txt or .md files):</strong> It's crucial to include licensing details to comply with copyright and distribution requirements.</li>
</ul>
</li>
</ul>
<p>There's often a temptation to include <strong>Executables</strong> (.exe or .out); these can be utilities used during the build process, such as code generators or testing frameworks. However I'd argue there's likely an extension to the idea of a "package" called "tool" which could be specialized and more adapt at covering this use case.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-package-imperative-what-makes-a-valid-package">The Package Imperative: What Makes a Valid Package?<a href="https://moderncppdevops.com/2024/05/20/what-is-a-package#the-package-imperative-what-makes-a-valid-package" class="hash-link" aria-label="Direct link to The Package Imperative: What Makes a Valid Package?" title="Direct link to The Package Imperative: What Makes a Valid Package?">​</a></h2>
<p>To guarantee robust development, C++ packages must adhere to specific criteria:</p>
<ul>
<li><strong><a href="https://en.cppreference.com/w/cpp/language/definition" target="_blank" rel="noopener noreferrer">One Definition Rule</a> (ODR) Compliance:</strong> Package contents must strictly follow the ODR, ensuring there's only one definition for a given entity across all included files. This prevents ambiguities and potential compilation errors.</li>
<li><strong><a href="https://www.ece.uvic.ca/~frodo/cppbook/cppdraft/n4861/defns.well.formed" target="_blank" rel="noopener noreferrer">Well-Formed</a> Programs:</strong> A valid package must yield functional, well-formed programs when all its core artifacts are consumed. Errors arising from improper interaction between different components disqualify a package.</li>
</ul>
<p>The primary goal is to enable downstream consumption; capturing the <a href="https://stackoverflow.com/questions/6264249/how-does-the-compilation-linking-process-work" target="_blank" rel="noopener noreferrer">inputs for the compiler</a> is the practical application of this concept. Packages should be readily consumable by other build systems for downstream projects. A clear and well-defined interface is essential for smooth integration.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="beyond-the-bare-essentials-configuration-considerations">Beyond the Bare Essentials: Configuration Considerations<a href="https://moderncppdevops.com/2024/05/20/what-is-a-package#beyond-the-bare-essentials-configuration-considerations" class="hash-link" aria-label="Direct link to Beyond the Bare Essentials: Configuration Considerations" title="Direct link to Beyond the Bare Essentials: Configuration Considerations">​</a></h2>
<p>While core artifacts form the foundation of a package, however there is more information necessary for <a href="https://www.youtube.com/watch?v=cpkDQaYttR4" target="_blank" rel="noopener noreferrer">compiling and linking</a> which plays a vital role in specifying details like:</p>
<ul>
<li><strong>Compiler Flags:</strong> These flags control the behavior of the compiler, influencing optimization levels, warning modes, and other compilation settings.</li>
<li><strong>Include Paths:</strong> Build systems need to know where to locate headers during the compilation process. Package specifications should explicitly define include paths to avoid errors.</li>
<li><strong>Linker Flags:</strong> Linker flags instruct the linker on how to combine object files (libraries) into executable programs. These can be specified within package configurations.</li>
<li><strong>Library and Library Path:</strong> Packages may depend on external libraries. Explicitly declaring required libraries and their paths facilitates linking during the build.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="avoid-binary-compatibility">Avoid Binary Compatibility<a href="https://moderncppdevops.com/2024/05/20/what-is-a-package#avoid-binary-compatibility" class="hash-link" aria-label="Direct link to Avoid Binary Compatibility" title="Direct link to Avoid Binary Compatibility">​</a></h2>
<p>C++ packages benefit from avoiding <a href="https://stackoverflow.com/questions/2171177/what-is-an-application-binary-interface-abi" target="_blank" rel="noopener noreferrer">binary compatibility</a> information within the package itself. This simplifies package and leaves the that be tooling specific; often teams have <a href="https://www.codalogic.com/blog/2021/05/09/Understanding-the-C%2B%2B-ABI-Breakage-debate" target="_blank" rel="noopener noreferrer">contradictory requirements</a> (<a href="https://thephd.dev/to-save-c-we-must-save-abi-fixing-c-function-abi" target="_blank" rel="noopener noreferrer">save it</a> or <a href="https://www.reddit.com/r/cpp/comments/dbcm11/20_abi_application_binary_interface_breaking/" target="_blank" rel="noopener noreferrer">break it</a>) and the tooling or <a href="https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html" target="_blank" rel="noopener noreferrer">vendor specific</a> implementation should not be decided here.</p>
<p><strong>The Build System Should not Care:</strong></p>
<ul>
<li>Build systems like CMake or Make are adept at handling <a href="https://learn.microsoft.com/en-us/cpp/build/cmakesettings-reference?view=msvc-170" target="_blank" rel="noopener noreferrer">platform-specific configurations</a>. They take compiler flags, target architectures, and other factors into account to ensure correct compilation and linking.</li>
</ul>
<p><strong>Package Managers, Right Tool for the Job:</strong></p>
<ul>
<li><a href="https://moderncppdevops.com/pkg-mngr-roundup">Package managers</a> like Conan or vcpkg offer a powerful solution for dependency management.</li>
<li>They maintain a database of packages with specific versions and configurations (triplets) catering to different environments.</li>
<li>When a new project depends on a package, the package manager can:<!-- -->
<ol>
<li><strong>Rebuild from source</strong> if the package has no compatibility information, ensuring the build process leverages the specific project's configuration.</li>
<li><strong>Strict Compatibility Checks</strong> (for packages with well-defined compatibility):<!-- -->
<ul>
<li>The package manager verifies if the existing package version aligns with the project's requirements.</li>
<li>If so, the package can be reused, saving build time.</li>
<li>If not, the manager triggers a rebuild from source.</li>
</ul>
</li>
</ol>
</li>
</ul>
<p><strong>The Case for "No Compatibility" Definition:</strong></p>
<ul>
<li>By leaving binary compatibility out of the package metadata, the package becomes more adaptable.</li>
<li>Build systems and package managers can then apply their knowledge and strategies for optimal builds.</li>
<li>This reduces duplication of effort and streamlines the development process.</li>
</ul>
<p><strong>Trade-offs and Best Practices:</strong></p>
<ul>
<li>While avoiding binary compatibility information generally simplifies package management, there are situations where pre-built binaries might be beneficial (e.g., for performance optimization on a specific system).</li>
<li>In such cases, <a href="https://learn.microsoft.com/en-us/vcpkg/users/triplets" target="_blank" rel="noopener noreferrer">package managers often offer mechanisms</a> for providing pre-built binaries with clear <a href="https://docs.conan.io/2/reference/conanfile/methods/package_id.html" target="_blank" rel="noopener noreferrer">versioning and compatibility</a> guidelines.</li>
</ul>
<p>However, as a general rule, keeping packages free of binary compatibility information promotes flexibility and maintainability for C++ projects in diverse environments. This approach fosters collaboration between packages, builds systems, and package managers, resulting in more robust and adaptable C++ development ecosystems.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion-packages---the-powerhouse-of-c-development">Conclusion: Packages - The Powerhouse of C++ Development<a href="https://moderncppdevops.com/2024/05/20/what-is-a-package#conclusion-packages---the-powerhouse-of-c-development" class="hash-link" aria-label="Direct link to Conclusion: Packages - The Powerhouse of C++ Development" title="Direct link to Conclusion: Packages - The Powerhouse of C++ Development">​</a></h2>
<p>Packages empower C++ developers with a structured and efficient way to organize code, promote reusability, and ensure project maintainability. By adhering to the essential properties outlined in this guide, you can craft robust and portable packages that act as the cornerstones of successful C++ development endeavors.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="ready-to-dive-deeper">Ready to Dive Deeper?<a href="https://moderncppdevops.com/2024/05/20/what-is-a-package#ready-to-dive-deeper" class="hash-link" aria-label="Direct link to Ready to Dive Deeper?" title="Direct link to Ready to Dive Deeper?">​</a></h2>
<p>For further exploration, consider delving into specific build systems like CMake or Make to understand how they handle package creation and configuration. Explore popular package managers like Conan or vcpkg that simplify dependency management and facilitate the sharing of C++ packages across diverse projects.</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="c++" term="c++"/>
        <category label="devops" term="devops"/>
        <category label="packages" term="packages"/>
        <category label="build systems" term="build systems"/>
        <category label="package managers" term="package managers"/>
        <category label="development" term="development"/>
        <category label="reusability" term="reusability"/>
        <category label="build times" term="build times"/>
        <category label="binary compatibility" term="binary compatibility"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Automated Testing for Seamless CMake Config File Integration]]></title>
        <id>https://moderncppdevops.com/testing-cmake-install</id>
        <link href="https://moderncppdevops.com/testing-cmake-install"/>
        <updated>2024-05-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Struggling with user frustration caused by missing headers or library path woes during C++ library integration?  This comprehensive guide offers a powerful solution: automated testing of your CMake config files using a Behavior-Driven Development (BDD) approach on GitHub Actions.  Imagine a world where users seamlessly integrate your library without any roadblocks – that's the power of this testing strategy.
Not only does automated testing ensure smoother integration, it also eliminates the need for slower, header-only libraries that can lead to ballooned build times due to a bottlenecked pre-processing stage.  By implementing these tests, you'll not only be creating a more user-friendly library, but you'll also be contributing valuable testing expertise to the open-source community.  This guide dives deep, equipping you with the knowledge to tackle both core testing essentials and explore advanced techniques for a truly robust testing suite.  The path to a well-received, high-quality C++ library starts with mastering the art of CMake config file testing – and this guide is your roadmap to success]]></summary>
        <content type="html"><![CDATA[<p>As a C++ developer, ensuring your library integrates flawlessly with other projects is crucial for driving adoption. <a href="https://moderncppdevops.com/2024-survey-results">CMake being the defacto standard</a> plays a vital role in this process by providing installed configuration files; guiding consumers on how to find and utilize your library using <a href="https://cmake.org/cmake/help/latest/command/find_package.html" target="_blank" rel="noopener noreferrer"><code>find_package</code></a>. But how do you guarantee these config files are installed correctly and provide all the necessary information? Enter automated testing!</p>
<p>This blog post explores an approach for testing CMake config files inspired by <a href="https://en.wikipedia.org/wiki/Behavior-driven_development" target="_blank" rel="noopener noreferrer">Behavioral Driven Development</a> practices and showcases a powerful implementation on <a href="https://github.com/features/actions" target="_blank" rel="noopener noreferrer">GitHub Actions</a> featuring 14+ test cases.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-test-cmake-config-files">Why Test CMake Config Files?<a href="https://moderncppdevops.com/testing-cmake-install#why-test-cmake-config-files" class="hash-link" aria-label="Direct link to Why Test CMake Config Files?" title="Direct link to Why Test CMake Config Files?">​</a></h2>
<p>Imagine creating a fantastic C++ library, only to have users encounter missing headers or library paths when they attempt to integrate it within their builds. This very real headache is why many open-source developers have <a href="https://github.com/search?q=repo%3Aconan-io%2Fconan-center-index+package_type+%22header-library%22&amp;type=code" target="_blank" rel="noopener noreferrer">opted for header-only libraries</a>.  "Just copying the headers" eventually became the norm. However, this trend has culminated in ballooned build times, as the <a href="https://devtalk.blender.org/t/speed-up-c-compilation/30508" target="_blank" rel="noopener noreferrer">preprocessing stage can become a bottleneck</a>.</p>
<p>The code required to activate this CMake feature is verbose and complex. A prime example is the well-known <a href="https://github.com/friendlyanon/cmake-init" target="_blank" rel="noopener noreferrer">cmake-init</a> project, which includes the <a href="https://github.com/friendlyanon/cmake-init/blob/40c63e4/cmake-init/templates/common/cmake/install-rules.cmake" target="_blank" rel="noopener noreferrer"><code>install-rules.cmake</code></a> file. This file clearly demonstrates the significant amount of <a href="https://en.wikipedia.org/wiki/Boilerplate_code" target="_blank" rel="noopener noreferrer">boilerplate code</a> present.</p>
<p>This complexity arises from the need to cover many use cases. Ideally, most users expect a seamless experience "out of the box" without needing to provide any input. However, a global system install isn't a viable long-term strategy, and advanced users will expect custom installation locations to function correctly. Additionally, package managers like <a href="https://docs.conan.io/2.0/reference/tools/cmake/cmake.html#conan.tools.cmake.cmake.CMake.install" target="_blank" rel="noopener noreferrer">Conan</a> and <a href="https://learn.microsoft.com/en-us/vcpkg/maintainers/functions/vcpkg_cmake_install" target="_blank" rel="noopener noreferrer">Vcpkg</a> rely on this same mechanism to capture the output. All these scenarios become even more intricate due to CMake's <a href="https://cmake.org/cmake/help/latest/command/find_package.html#config-mode-search-procedure" target="_blank" rel="noopener noreferrer">lengthy list of default search path</a> that can be further extended by providing hints, both at the command line and from the consumer's build scripts.</p>
<p>Testing the installed CMake config files helps prevent such headaches by guaranteeing:</p>
<ul>
<li><strong>Correct Installation:</strong> Verifies the config files are placed in the expected locations based on the chosen installation prefix.</li>
<li><strong>Complete Configuration:</strong> Ensures the config files provide all essential information for users, including header locations, libraries, defines, and dependencies.</li>
<li><strong>Broad Compatibility:</strong> Confirms the library is correctly detected and loaded across different operating systems and architectures.</li>
</ul>
<p>Before we can automate the testing, we need to setup the installation scripts first.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="installing-cmake-targets">Installing CMake Targets<a href="https://moderncppdevops.com/testing-cmake-install#installing-cmake-targets" class="hash-link" aria-label="Direct link to Installing CMake Targets" title="Direct link to Installing CMake Targets">​</a></h3>
<p>The foremost expert on this subject is likely Craig Scott, author of <a href="https://crascit.com/professional-cmake/" target="_blank" rel="noopener noreferrer"><em>Professional CMake: A Practical Guide</em></a>. His book includes two very relevant sections: <strong>Chapter 33: Finding Things</strong>, which covers using <code>find_package</code>, and <strong>Chapter 34: Installing</strong>. This refers to the <a href="https://crascit.com/professional-cmake/release-notes/16th-edition/" target="_blank" rel="noopener noreferrer">sixteenth edition</a> of the book; later editions include improvements with topics like C++20 Modules.</p>
<p>The minimal example presented, is very similar to this:</p>
<div class="language-cmake codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">/CMakeLists.txt</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cmake codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">include</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">GNUInstallDirs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">include</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">CMakePackageConfigHelpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">configure_package_config_file</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">   MyProjConfig.cmake.in MyProjConfig.cmake</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">   INSTALL_DESTINATION </span><span class="token punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token variable" style="color:rgb(156, 220, 254)">CMAKE_INSTALL_LIBDIR</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain">/cmake/MyProj</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">   NO_SET_AND_CHECK_MACRO</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">   NO_CHECK_REQUIRED_COMPONENTS_MACRO</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">install</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">FILES </span><span class="token punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token variable" style="color:rgb(156, 220, 254)">CMAKE_CURRENT_BINARY_DIR</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain">/MyProjConfig.cmake</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">   DESTINATION </span><span class="token punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token variable" style="color:rgb(156, 220, 254)">CMAKE_INSTALL_LIBDIR</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain">/cmake/MyProj</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">   COMPONENT ...</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Alternatively, check the <a href="https://cmake.org/cmake/help/latest/module/CMakePackageConfigHelpers.html#example-generating-package-files" target="_blank" rel="noopener noreferrer">CMake documentation's example</a> for the same segment of code.</p>
<p>However, this approach does not include exporting namespaced targets or ensuring version compatibility, both of which are highly recommended practices. For a more comprehensive example, we can revisit the cmake-init project. It offers an <a href="https://github.com/friendlyanon/cmake-init-shared-static" target="_blank" rel="noopener noreferrer">example repository</a> for a shared library. This sample project provides a more complete view of the generated <a href="https://github.com/friendlyanon/cmake-init-shared-static/blob/d0f853f/cmake/install-rules.cmake" target="_blank" rel="noopener noreferrer">install rules</a> (which required some <em>trimming</em> for this article).</p>
<p>The installation process typically involves two key files:</p>
<ul>
<li>The <code>install-config.cmake</code> file typically includes another file, <code>${project}Targets.cmake</code>, which contains the details about the library's <a href="https://discourse.cmake.org/t/clarification-on-public-private-with-target-source-group/7845/2" target="_blank" rel="noopener noreferrer">public and interface properties</a>. Public properties define aspects of the library visible to users, while interface properties facilitate internal communication between targets within the library.</li>
</ul>
<div class="language-cmake codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">/cmake/install-config.cmake</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cmake codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">include</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token string interpolation variable" style="color:rgb(156, 220, 254)">CMAKE_CURRENT_LIST_DIR</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">/sharedTargets.cmake"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ul>
<li>The <code>install-config.cmake</code> file dictates how the configuration files are generated and installed. It specifies the destination for the generated files and which library targets should be included in the installation process. While we won't delve into the specifics of this file here, skimming its contents can give you a general understanding of the configuration involved.</li>
</ul>
<div class="language-cmake codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">/cmake/install-rules.cmake</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cmake codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">include</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">CMakePackageConfigHelpers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">include</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">GNUInstallDirs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># find_package(&lt;package&gt;) call for consumers to find this project</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">set</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">package shared</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">install</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    DIRECTORY</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    include/</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token string interpolation variable" style="color:rgb(156, 220, 254)">PROJECT_BINARY_DIR</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">/export/"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    DESTINATION </span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token string interpolation variable" style="color:rgb(156, 220, 254)">CMAKE_INSTALL_INCLUDEDIR</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    COMPONENT shared</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">install</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    TARGETS shared_shared</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    EXPORT sharedTargets</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    INCLUDES DESTINATION </span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token string interpolation variable" style="color:rgb(156, 220, 254)">CMAKE_INSTALL_INCLUDEDIR</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">write_basic_package_version_file</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token string interpolation variable" style="color:rgb(156, 220, 254)">package</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">ConfigVersion.cmake"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    COMPATIBILITY SameMajorVersion</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># Allow package maintainers to freely override the path for the configs</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">set</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    shared_INSTALL_CMAKEDIR </span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token string interpolation variable" style="color:rgb(156, 220, 254)">CMAKE_INSTALL_LIBDIR</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">/cmake/</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token string interpolation variable" style="color:rgb(156, 220, 254)">package</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token variable" style="color:rgb(156, 220, 254)">CACHE</span><span class="token plain"> STRING </span><span class="token string" style="color:rgb(206, 145, 120)">"CMake package config location relative to the install prefix"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">set_property</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token variable" style="color:rgb(156, 220, 254)">CACHE</span><span class="token plain"> shared_INSTALL_CMAKEDIR PROPERTY </span><span class="token property">TYPE</span><span class="token plain"> PATH</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">mark_as_advanced</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">shared_INSTALL_CMAKEDIR</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">install</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    FILES cmake/install-config.cmake</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    DESTINATION </span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token string interpolation variable" style="color:rgb(156, 220, 254)">shared_INSTALL_CMAKEDIR</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    RENAME </span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token string interpolation variable" style="color:rgb(156, 220, 254)">package</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">Config.cmake"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    COMPONENT shared</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">install</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    FILES </span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token string interpolation variable" style="color:rgb(156, 220, 254)">PROJECT_BINARY_DIR</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">/</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token string interpolation variable" style="color:rgb(156, 220, 254)">package</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">ConfigVersion.cmake"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    DESTINATION </span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token string interpolation variable" style="color:rgb(156, 220, 254)">shared_INSTALL_CMAKEDIR</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    COMPONENT shared</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">install</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    EXPORT sharedTargets</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    NAMESPACE shared::</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    DESTINATION </span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token string interpolation variable" style="color:rgb(156, 220, 254)">shared_INSTALL_CMAKEDIR</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    COMPONENT shared</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Again this example does not have optional features or dependencies that are required or optionally supported. We'll take a look at a more complex <code>install-config.cmake</code> equivalent.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="demystifying-the-configcmakein-file">Demystifying the <code>config.cmake.in</code> File<a href="https://moderncppdevops.com/testing-cmake-install#demystifying-the-configcmakein-file" class="hash-link" aria-label="Direct link to demystifying-the-configcmakein-file" title="Direct link to demystifying-the-configcmakein-file">​</a></h2>
<p>Let's delve into a real <code>.cmake.in</code> (or <code>install-config.cmake</code> to reference the <code>cmake-init</code> terminology), this comes from <a href="https://github.com/Thalhammer/jwt-cpp" target="_blank" rel="noopener noreferrer">Thalhammer/jwt-cpp</a> which will serves as the more complicated example which has support for both optional and interchangeable dependencies.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Feel Free to Contribute</div><div class="admonitionContent_BuS1"><p>If you have ideas on how to improve on this formula, don't hesitate to contribute to the project.</p></div></div>
<p>It should be very easy to see the jump in complexity from <code>cmake-init</code>'s one liner configuration file.</p>
<div class="language-cmake codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">/cmake/jwt-cpp.cmake.in</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cmake codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">@PACKAGE_INIT@</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">set</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">JWT_EXTERNAL_PICOJSON @JWT_EXTERNAL_PICOJSON@</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">set</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">JWT_SSL_LIBRARY @JWT_SSL_LIBRARY@</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">include</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">CMakeFindDependencyMacro</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">if</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token plain">JWT_SSL_LIBRARY</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">MATCHES</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"wolfSSL"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token function" style="color:rgb(220, 220, 170)">find_dependency</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">PkgConfig REQUIRED</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token function" style="color:rgb(220, 220, 170)">pkg_check_modules</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">wolfssl REQUIRED IMPORTED_TARGET wolfssl</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">list</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">TRANSFORM wolfssl_INCLUDE_DIRS APPEND </span><span class="token string" style="color:rgb(206, 145, 120)">"/wolfssl"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)"># This is required for OpenSSL compatibility</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">else</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token function" style="color:rgb(220, 220, 170)">find_dependency</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token plain">JWT_SSL_LIBRARY</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"> REQUIRED</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">endif</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">if</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">JWT_EXTERNAL_PICOJSON</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token function" style="color:rgb(220, 220, 170)">find_dependency</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">picojson REQUIRED</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">endif</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">include</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token string interpolation variable" style="color:rgb(156, 220, 254)">CMAKE_CURRENT_LIST_DIR</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">/jwt-cpp-targets.cmake"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The behavioral requirement is to preserve the options specified when the consumer configured the project so they do not need to be repeated downstream.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="key-elements-which-need-to-be-tested">Key Elements Which Need to Be Tested<a href="https://moderncppdevops.com/testing-cmake-install#key-elements-which-need-to-be-tested" class="hash-link" aria-label="Direct link to Key Elements Which Need to Be Tested" title="Direct link to Key Elements Which Need to Be Tested">​</a></h3>
<ul>
<li><strong>@PACKAGE_INIT@ Replacement:</strong> When configure_package_config_file is used, it replaces <code>@PACKAGE_INIT@</code> with a block of code that sets up variables with a PACKAGE_ prefix based on values defined earlier in the script. This ensures relative paths within the installed config file are adjusted based on the installation location.</li>
<li><strong>Placeholders (<code>@JWT_EXTERNAL_PICOJSON@</code>, <code>@JWT_SSL_LIBRARY@</code>):</strong> These placeholders are replaced with actual values during the install process, allowing for customization based on user configuration. These value will be captured in the generate <code>config.cmake</code> files.</li>
<li><strong>Dependency Management:</strong> The script conditionally finds dependencies based on the library chosen for SSL (<code>JWT_SSL_LIBRARY</code>) and whether an external <code>picojson</code> library is used (<code>JWT_EXTERNAL_PICOJSON</code>).<!-- -->
<ul>
<li><strong>wolfSSL Handling:</strong> For wolfSSL, the script leverages <code>PkgConfig</code> and additionally modifies the include search path to access the OpenSSL compatibility API.</li>
</ul>
</li>
<li><strong>Target Inclusion:</strong> The final line includes another script (<code>jwt-cpp-targets.cmake</code>) that defines the actual library targets exposed to consumers through <code>find_package</code>. This targets file is generated by CMake on install and include the namespace, include directories, link libraries and other properties set to the install or public interface of the target.</li>
<li><strong>Optional Features:</strong> Handled else where, some of the features are tracked with the targets themselves changing which files are installed and what preprocessor set set on the public target.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="summary-of-use-cases">Summary of Use Cases<a href="https://moderncppdevops.com/testing-cmake-install#summary-of-use-cases" class="hash-link" aria-label="Direct link to Summary of Use Cases" title="Direct link to Summary of Use Cases">​</a></h2>
<p>There's a lot that might happen when <code>find_package(jwt-cpp CONFIG REQUIRED)</code> is called so let's unpack them:</p>
<ol>
<li><strong>Default Install</strong>: This is the basic <code>cmake --preset release &amp;&amp; cmake --install build/</code> where none of the options are modified.</li>
<li><strong>Custom Location</strong>: This builds on the previous example by changing the <a href="https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html" target="_blank" rel="noopener noreferrer"><code>CMAKE_INSTALL_PREFIX</code></a> to a path which is not on the CMake's default search list.</li>
<li><strong>Preserved Options</strong>: The principal of DRY code extends to managing external dependencies, <code>cmake . -DJWT_DISABLE_PICOJSON</code> should create an installation where this optional dependency is not included and is carried downstream provided the <code>#define</code> with the <code>jwt-cpp::jwt-cpp</code> target.</li>
<li><strong>Managed Dependencies</strong>: When the users selects the <code>JWT_SSL_LIBRARY</code> this should be captured in the installation and the correct <code>find_dependency</code> is called without adding extra unnecessary dependencies.</li>
</ol>
<p>With these outlined we'll be able to leverage some <a href="https://en.wikipedia.org/wiki/Behavior-driven_development" target="_blank" rel="noopener noreferrer">Behavioral Driven Development</a> practices and define test cases such as "Should find jwt-cpp with picoJSON" to ensure the functionality for consumers is correct.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="leveraging-github-actions-for-automated-testing">Leveraging GitHub Actions for Automated Testing<a href="https://moderncppdevops.com/testing-cmake-install#leveraging-github-actions-for-automated-testing" class="hash-link" aria-label="Direct link to Leveraging GitHub Actions for Automated Testing" title="Direct link to Leveraging GitHub Actions for Automated Testing">​</a></h2>
<p>Let's write some <a href="https://en.wikipedia.org/wiki/Acceptance_testing" target="_blank" rel="noopener noreferrer">acceptance tests</a> using GitHub Actions. Here's how it works:</p>
<ol>
<li><strong>Matrix Strategy:</strong> This allows testing across various platforms (e.g., Linux, macOS, Windows) and architectures (e.g., x86, x64) in parallel. The leans into CMake's strength for being cross-platform.</li>
<li><strong>CMake Configure:</strong> Sets up the setting and configuration with <code>cmake</code> that are desired.<!-- -->
<ul>
<li>This is where most of the variation between the tests will occur.</li>
</ul>
</li>
<li><strong>Installation:</strong> Executes <code>cmake --install</code> with different prefixes (<code>CMAKE_INSTALL_PREFIX</code>) to simulate various installation scenarios.</li>
<li><strong><code>find_package</code> Test:</strong> Within a separate build directory for each test, the workflow uses <code>find_package</code> to locate your library and verifies if all required information is found (e.g., target names, include directories).</li>
</ol>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">/.github/workflows/cmake.yml</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token key atrule">jobs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">default</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">runs-on</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> matrix.os </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">strategy</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">matrix</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">os</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">macos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">latest</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> windows</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">latest</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> ubuntu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">latest</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">steps</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> actions/checkout@v4</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> lukka/get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">cmake@latest</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> setup</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token scalar string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          cmake --preset release</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          sudo cmake --build --preset release --target install</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> test</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">working-directory</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> tests/cmake </span><span class="token comment" style="color:rgb(106, 153, 85)"># Example consumer project</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token scalar string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          cmake .</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          cmake --build .</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><strong>By adapting this workflow to use the various options or dependencies in isolation, you can achieve a reliable and future-proof testing strategy.</strong> This is extensible by expanding the matrix in a new job to include non-default installation paths or with different present names for pre-defined configurations that are supported.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="testing-cmake-config-file-installation-with-a-consumer-project">Testing CMake Config File Installation with a Consumer Project<a href="https://moderncppdevops.com/testing-cmake-install#testing-cmake-config-file-installation-with-a-consumer-project" class="hash-link" aria-label="Direct link to Testing CMake Config File Installation with a Consumer Project" title="Direct link to Testing CMake Config File Installation with a Consumer Project">​</a></h2>
<p>A robust approach to verify your CMake config file installation is by creating a basic consumer project. This technique has the added benefit of acting as <a href="https://cucumber.io/blog/podcast/living-documentation/" target="_blank" rel="noopener noreferrer">living documentation</a> for potential consumer to reference. This section explores this technique using a sample <code>CMakeLists.txt</code> file.</p>
<p><strong>Sample Consumer Project:</strong></p>
<div class="language-cmake codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">/tests/cmake/CMakeLists.txt</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cmake codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">cmake_minimum_required</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token property">VERSION</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">3.8</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">project</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">jwt-cpp-installation-tests</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># Setup your own source code here</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">set</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">TEST </span><span class="token variable" style="color:rgb(156, 220, 254)">CACHE</span><span class="token plain"> STRING </span><span class="token string" style="color:rgb(206, 145, 120)">"The test source file to be used"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">find_package</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">jwt-cpp </span><span class="token number" style="color:rgb(181, 206, 168)">0.7.0</span><span class="token plain"> EXACT REQUIRED CONFIG</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">add_executable</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">test-project </span><span class="token punctuation" style="color:rgb(212, 212, 212)">${</span><span class="token plain">TEST</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain">.cpp</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">target_link_libraries</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">test-project jwt-</span><span class="token inserted class-name" style="color:rgb(78, 201, 176)">cpp::jwt</span><span class="token plain">-cpp</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><strong>Explanation:</strong></p>
<ol>
<li>
<p><strong>Project Setup:</strong> Required field to have a standalone CMake project.</p>
<ul>
<li><code>cmake_minimum_required(VERSION 3.8)</code>: Specifies the minimum required CMake version.</li>
<li><code>project(jwt-cpp-installation-tests)</code>: Names the project for better organization.</li>
</ul>
</li>
<li>
<p><strong>Test File Selection:</strong></p>
<ul>
<li><code>set(TEST CACHE STRING)</code>: Defines a cache variable named <code>TEST</code> to store the path of the source file to compile. This allows you to easily switch between different test files which should all work with the same entry point. By leveraging compiler features we can test for the presence of preprocessor and header files to ensure the installation is complete.</li>
</ul>
</li>
<li>
<p><strong>Finding the <code>jwt-cpp</code> Library:</strong></p>
<ul>
<li><code>find_package(jwt-cpp 0.7.0 EXACT REQUIRED CONFIG)</code>: Attempts to locate the <code>jwt-cpp</code> library using <code>find_package</code>.<!-- -->
<ul>
<li><code>0.7.0 EXACT</code>: Specifies the exact version of <code>jwt-cpp</code> to search for. This will help ensure the value is correctly captured by the <code>write_version_file</code> CMake helper.</li>
<li><code>REQUIRED CONFIG</code>: Ensures the CMake will return a non-zero exit code if our library is not found.</li>
</ul>
</li>
</ul>
</li>
<li>
<p><strong>Building the Test Executable:</strong></p>
<ul>
<li><code>add_executable(test-project ${TEST}.cpp)</code>: Creates an executable named <code>test-project</code> that is built from the source file specified by the <code>TEST</code> variable.</li>
</ul>
</li>
<li>
<p><strong>Linking the Library:</strong></p>
<ul>
<li><code>target_link_libraries(test-project jwt-cpp::jwt-cpp)</code>: Instructs the linker to include the <code>jwt-cpp</code> library when building the <code>test-project</code> executable. This implies all the transitive dependencies will be included implicitly.</li>
</ul>
</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="success-or-failure">Success or Failure<a href="https://moderncppdevops.com/testing-cmake-install#success-or-failure" class="hash-link" aria-label="Direct link to Success or Failure" title="Direct link to Success or Failure">​</a></h3>
<ul>
<li><strong>Successful Build:</strong> If the build completes without errors, it indicates that your CMake config file was installed correctly and the consumer project was able to find and link against the <code>jwt-cpp</code> library as well as the dependencies and ny optional features.</li>
<li><strong>Build Failure:</strong> If the build fails with errors related to missing headers or libraries, it suggests an issue with the installation or the config file. Double-check your installation rules and ensure the config file accurately reflects the library's location and targets. <a href="https://cmake.org/cmake/help/latest/variable/CMAKE_FIND_DEBUG_MODE.html" target="_blank" rel="noopener noreferrer"><code>CMAKE_FIND_DEBUG_MODE</code></a>, introduced in version 3.17, is an excellent tool to check the search paths being used.</li>
</ul>
<p>This approach provides a quick and straightforward method to verify the functionality of your CMake config file installation.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="example-ci-jobs">Example CI Jobs<a href="https://moderncppdevops.com/testing-cmake-install#example-ci-jobs" class="hash-link" aria-label="Direct link to Example CI Jobs" title="Direct link to Example CI Jobs">​</a></h3>
<p>The use case  outline earlier have lot of variations, most of which include the users configure of a non-default configuration. Ensuring the generated and installed targets and <code>config.cmake</code> files correctly is also important.</p>
<p><strong>Testing Different Options:</strong></p>
<p>The "No Base64" option allows consumer to exclude the jwt-cpp built-in functions, these generalized implementation are not extensively optimized and many other libraries exist with this feature. This can be described as "Should find jwt-cpp without including base.h" as out BDD test case. This unique configuration will need it's own job. This will perform an out-os-source build and install with the option set to <code>ON</code> before an in-source consumer workflow to configure and build.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">no-base64</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">runs-on</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> ubuntu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">latest</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">steps</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> actions/checkout@v4</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> lukka/get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">cmake@latest</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> setup</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token scalar string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          mkdir build</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          cd build</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          cmake .. -DJWT_DISABLE_BASE64=ON -DJWT_BUILD_EXAMPLES=OFF</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          sudo make install</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> test</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token scalar string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          cd tests/cmake</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          cmake . -DCMAKE_PREFIX_PATH=/usr/local/cmake -DTEST:STRING="base64-is-disabled"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          cmake --build .</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>In order to test the library is installed and packaged correct, we can define our source test <code>.cpp</code> file instrumented with <a href="https://learn.microsoft.com/en-us/cpp/preprocessor/hash-error-directive-c-cpp" target="_blank" rel="noopener noreferrer"><code>#error</code> directives</a> and <a href="https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html" target="_blank" rel="noopener noreferrer"><code>_has_include</code> marco</a> to validate the contents.</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">tests/cmake/base64-is-disabled.cpp</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">ifndef</span><span class="token macro property"> </span><span class="token macro property expression">JWT_DISABLE_BASE64</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">error</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(206, 145, 120)">"This test expects 'JWT_DISABLE_BASE64' to be defined!"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">endif</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">if</span><span class="token macro property"> </span><span class="token macro property expression function" style="color:rgb(220, 220, 170)">__has_include</span><span class="token macro property expression punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token macro property string" style="color:rgb(206, 145, 120)">"jwt-cpp/base.h"</span><span class="token macro property expression punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">error</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(206, 145, 120)">"This test expects 'jwt-cpp/base.h' to be absent from the installation!"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">endif</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">include</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(206, 145, 120)">"jwt-cpp/jwt.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">int</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">main</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">   jwt</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">date date</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">   </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><strong>Testing Different Dependencies:</strong></p>
<p>By strictly controlling our build environment and pinning the dependency's version we'd like to test, we can ensure a robust test case for "Should find jwt-cpp and use wolfSSL" can be implemented.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">runs-on</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> ubuntu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">latest</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">steps</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> actions/checkout@v4</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> lukka/get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">cmake@latest</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> ./.github/actions/install/wolfssl</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">with</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">          </span><span class="token key atrule">version</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> ab3bbf11e9d39b52e24bf42bbc6babc16d4a669b</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> setup</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token scalar string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          mkdir build</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          cd build</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          cmake .. -DJWT_SSL_LIBRARY:STRING="wolfSSL" -DJWT_BUILD_EXAMPLES=OFF</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          sudo make install</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> test</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token scalar string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          cd tests/cmake</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          cmake . -DTEST:STRING="wolfssl-is-used"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          cmake --build .</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Once again, we can design a test source file to validate the include and marco from the dependency are provided. This also includes calling a core function from the library, <code>wolfSSL_library_init()</code> in this case, to ensure the library or runtime as well as link paths are correctly setup for consumers.</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">tests/cmake/wolfssl-is-used.cpp</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">if</span><span class="token macro property"> </span><span class="token macro property expression operator" style="color:rgb(212, 212, 212)">!</span><span class="token macro property expression function" style="color:rgb(220, 220, 170)">__has_include</span><span class="token macro property expression punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token macro property expression operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token macro property expression">wolfssl</span><span class="token macro property expression operator" style="color:rgb(212, 212, 212)">/</span><span class="token macro property expression">ssl</span><span class="token macro property expression punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token macro property expression">h</span><span class="token macro property expression operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token macro property expression punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">error</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(206, 145, 120)">"missing wolfSSL's SSL header!"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">endif</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">ifndef</span><span class="token macro property"> </span><span class="token macro property expression">OPENSSL_EXTRA</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">error</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(206, 145, 120)">"missing wolfSSL's OPENSSL_EXTRA macro!"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">endif</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">ifndef</span><span class="token macro property"> </span><span class="token macro property expression">OPENSSL_ALL</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">error</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(206, 145, 120)">"missing wolfSSL's OPENSSL_ALL macro!"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">endif</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">include</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(206, 145, 120)">"jwt-cpp/jwt.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">include</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(206, 145, 120)">&lt;wolfssl/ssl.h&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">int</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">main</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">   </span><span class="token function" style="color:rgb(220, 220, 170)">wolfSSL_library_init</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">   jwt</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">date date</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">   </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="supporting-various-c-package-managers">Supporting Various C++ Package Managers<a href="https://moderncppdevops.com/testing-cmake-install#supporting-various-c-package-managers" class="hash-link" aria-label="Direct link to Supporting Various C++ Package Managers" title="Direct link to Supporting Various C++ Package Managers">​</a></h2>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>Disclaimer</div><div class="admonitionContent_BuS1"><p>This currently does not exists! With the big package managers running curated central repositories, their repositories and internal CI systems need to be aware of your project. The burden rests on their respective communities integrated and contributing back.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="summary">Summary<a href="https://moderncppdevops.com/testing-cmake-install#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary">​</a></h2>
<p>This automated testing approach empowers you to deliver a robust and user-friendly library by ensuring your CMake config files function as intended across various environments. <strong>Test Essentials!</strong> Run standard install commands (<code>cmake --preset release &amp;&amp; cmake --install build/</code>) to verify config file placement. Building on this to handle more complex requirements like optional features or dependencies, remember the following approach:</p>
<ul>
<li><strong>Multi-Platform Power:</strong> Leverage CMake's strength to test across platforms (Linux, macOS, Windows) in parallel.</li>
<li><strong>Tailored Setups:</strong> Use <code>cmake --presets</code> to configure different supported settings and configurations.</li>
<li><strong>Simulated Installations:</strong> Run <code>cmake --install</code> with varying prefixes to mimic real-world user scenarios.</li>
<li><strong><code>find_package</code> Verification:</strong> Confirm your library and crucial information are found using <code>find_package</code> in separate detected sample consumer project and utilize a pass/fail test strategy.</li>
</ul>
<p>If you are looking to implement and practice these ideas, this is an excellent opportunity to get involved in open-source libraries you are using, may projects will appreciate a thorough test suite for these features.</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="c++" term="c++"/>
        <category label="cmake" term="cmake"/>
        <category label="configuration files" term="configuration files"/>
        <category label="bdd" term="bdd"/>
        <category label="testing" term="testing"/>
        <category label="github actions" term="github actions"/>
        <category label="open source" term="open source"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Breaking down the 2024 Survey Results]]></title>
        <id>https://moderncppdevops.com/2024-survey-results</id>
        <link href="https://moderncppdevops.com/2024-survey-results"/>
        <updated>2024-04-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The C++ ecosystem and developer landscape is a mix of progress and persistent challenges. While build scripts are becoming easier to manage, setting up complex development environments remains a hurdle. Python reigns supreme as the companion language for scripting and data tasks. Build times are showing signs of improvement, but setting up CI pipelines continues to be a pain point for many developers. Adoption of modern C++ features like Modules is slow, and nearly half of projects lack the memory safeguards provided by sanitizers and fuzzing. This blog goes through the result highlighting the key results and exploring the possible explanations for why these trend might be occurring.]]></summary>
        <content type="html"><![CDATA[<p>It's that time of year once again! The ISO Committee published the summary of the results for the <a href="https://isocpp.org/blog/2024/04/2024-annual-cpp-developer-survey-lite" target="_blank" rel="noopener noreferrer"><em>C++ Developer Survey "Lite"</em></a>. This has been <a href="https://isocpp.org/blog/2021/04/2021-annual-cpp-developer-survey-lite" target="_blank" rel="noopener noreferrer">running for several years</a> and it's probably the first time we can start to see some trends... hopefully!</p>
<p>The survey results, with less than 1300 developers compared to 1700 last year, is only partially explained by <a href="https://help.surveymonkey.com/en/surveymonkey/policy/export-control-policy/" target="_blank" rel="noopener noreferrer">third-party restrictions</a> as noted by the <a href="https://isocpp.org/blog/2024/04/results-summary-2024-annual-cpp-developer-survey-lite" target="_blank" rel="noopener noreferrer">blog post sharing the results</a>. Regardless a wider sample would be ideal. The dominance of CMake with an 83% market share is striking. Could this 4% growth be linked to the lower burden for managing build scripts? Despite these limitations, the survey offers valuable insights into C++ ecosystem trends.</p>
<p>Since this blog is all about building and shipping C++ software, I'll be focusing on the tooling and ecosystem questions and results.  There's a natural bias here, as I'm particularly interested in how these trends affect developers like us. But fear not, there's plenty for everyone!  In fact, I'm curious what aspects other bloggers will delve into.  Let's jump right in as there are some fascinating statistical correlations to explore!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="overall-impression">Overall Impression<a href="https://moderncppdevops.com/2024-survey-results#overall-impression" class="hash-link" aria-label="Direct link to Overall Impression" title="Direct link to Overall Impression">​</a></h2>
<p>There are positive signs! Build times, a crucial metric for build pipeline efficiency, are improving. The distribution of pain levels is also shifting downward. "Major Pain" responses have decreased to 43%, while "Minor Pain" holds steady at 37%.  "Not Significant" responses are on the rise, reaching nearly 20%.</p>
<!-- -->
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>For enhanced clarity, I've opted to present the rest of the data in a table format in addition to the graphs. While the official diagram plugin, Mermaid-JS, doesn't currently support legends for this specific chart type (see issue <a href="https://github.com/mermaid-js/mermaid/issues/5292" target="_blank" rel="noopener noreferrer">mermaid#5292</a>); the tables allow for a clear connection between the data points and their corresponding lines.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="key-highlights">Key Highlights<a href="https://moderncppdevops.com/2024-survey-results#key-highlights" class="hash-link" aria-label="Direct link to Key Highlights" title="Direct link to Key Highlights">​</a></h2>
<p>Here's a summary of the 2024 Annual C++ Developer Survey "Lite":</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="who-are-the-respondents">Who are the respondents?<a href="https://moderncppdevops.com/2024-survey-results#who-are-the-respondents" class="hash-link" aria-label="Direct link to Who are the respondents?" title="Direct link to Who are the respondents?">​</a></h3>
<ul>
<li>Almost all respondents (91%) use C++ at work.</li>
<li>Over two-thirds (67%) use C++ for personal projects or hobbies.</li>
<li>The majority of respondents (52%) have 6-20 years of experience in C++.</li>
<li>Even more (64%) have 6-20 years of total programming experience (including languages other than C++).</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="what-platforms-and-build-tools-do-c-developers-use">What platforms and build tools do C++ developers use?<a href="https://moderncppdevops.com/2024-survey-results#what-platforms-and-build-tools-do-c-developers-use" class="hash-link" aria-label="Direct link to What platforms and build tools do C++ developers use?" title="Direct link to What platforms and build tools do C++ developers use?">​</a></h3>
<ul>
<li>CMake is the dominant build tool, used by over 80% of respondents.</li>
<li>Ninja (45%) has a well establish place.</li>
<li>Windows (desktop and server) is the most popular target platform, with over 60% of respondents developing for it.<!-- -->
<ul>
<li>Make/nmake (36%) are also popular choices.</li>
<li>MSBuild is commonly used for Windows development (30%).</li>
</ul>
</li>
<li>Linux (desktop and server) is also very common (over 50%).</li>
<li>Nearly a third (32%) develop for embedded systems.<!-- -->
<ul>
<li>The most common project type was embedded systems (33%)</li>
</ul>
</li>
<li>Mobile development is less common (Android: 15%, iOS: 10%) but still used by a significant number of respondents.</li>
</ul>
<p>While the survey results provide valuable insights, access to the raw data would allow for a more granular analysis. This would enable us to answer intriguing questions like:</p>
<ul>
<li>What percentage of developers targeting Windows, Linux, and macOS?</li>
<li>Is there a significant overlap between developers building for Android and iOS?</li>
<li>How does Ninja usage vary across different operating systems and target platforms?</li>
</ul>
<p>With additional data, we could delve deeper into the trends and potentially uncover hidden correlations.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="how-is-the-cloud-used-in-c-development">How is the cloud used in C++ development?<a href="https://moderncppdevops.com/2024-survey-results#how-is-the-cloud-used-in-c-development" class="hash-link" aria-label="Direct link to How is the cloud used in C++ development?" title="Direct link to How is the cloud used in C++ development?">​</a></h3>
<ul>
<li>The most common cloud use cases are CI/CD (continuous integration and continuous delivery) and testing (around 53% and 29% respectively).</li>
<li>Cloud storage and deployment are also used by a significant portion of respondents (around 26% and 22% respectively).</li>
</ul>
<p>It appears there may be a discrepancy in the choices for this question. Since CI/CD encompasses building, testing, <em>and</em> deploying code, the combined total of these individual options should ideally exceed the percentage of respondents who use CI/CD. For future surveys, ensuring clear and comprehensive answer choices would improve the interpretability of the results.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="do-c-projects-use-sanitizers-and-fuzzing">Do C++ projects use sanitizers and fuzzing?<a href="https://moderncppdevops.com/2024-survey-results#do-c-projects-use-sanitizers-and-fuzzing" class="hash-link" aria-label="Direct link to Do C++ projects use sanitizers and fuzzing?" title="Direct link to Do C++ projects use sanitizers and fuzzing?">​</a></h3>
<ul>
<li>Nearly half (49%) of projects use sanitizers or fuzzing as part of their development process.</li>
<li>However, a significant portion (45%) do not use them.</li>
</ul>
<p>Given the amount of focus on memory safety, as the 5 dedicated "pain" questions to it would suggest, and how <a href="https://medium.com/mit-security-seminar/beyond-sanitizers-guided-fuzzing-and-security-hardening-9cc8155e19fb" target="_blank" rel="noopener noreferrer">these techniques improve security</a>. It  might be a surprise to learn these number have not see any significant movement. It seems to suggest the burden of upgrading CI/CD pipelines might be inhibiting the progress in adopting these tools.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="what-major-recent-features-do-you-planning-on-adoption-this-year">What major recent features do you planning on adoption this year?<a href="https://moderncppdevops.com/2024-survey-results#what-major-recent-features-do-you-planning-on-adoption-this-year" class="hash-link" aria-label="Direct link to What major recent features do you planning on adoption this year?" title="Direct link to What major recent features do you planning on adoption this year?">​</a></h3>
<ul>
<li>Among the three features surveyed (Concepts, Coroutines, and Modules), Modules have the lowest planned adoption rate, only 29.25% of respondents indicated their projects would allow module usage.</li>
</ul>
<p>As the article <a href="https://anarthal.github.io/cppblog/modules" target="_blank" rel="noopener noreferrer">C++20 modules and Boost: an analysis</a> highlights, concerns exist around managing the potential increase in complexity for build systems. This is likely in addition to modules introducing interoperability challenges between build systems and package managers - a concern that many of respondents are likely to have as usage of multiple build systems was very high - might delay the adoption process until broader tooling support matures.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="what-other-programming-languages-do-c-developers-use">What other programming languages do C++ developers use?<a href="https://moderncppdevops.com/2024-survey-results#what-other-programming-languages-do-c-developers-use" class="hash-link" aria-label="Direct link to What other programming languages do C++ developers use?" title="Direct link to What other programming languages do C++ developers use?">​</a></h3>
<ul>
<li>Python (73%) and C (53%) are the most popular companions to C++.</li>
<li>JavaScript (27%), C# (24%), and Rust (18%) are also commonly used.</li>
</ul>
<p>The survey results reveal a fascinating interplay between C++ and other programming languages. Python's dominance (73%) as a companion language likely stems from its versatility in scripting, data analysis, and build orchestration tasks, particularly for developers supporting multiple platforms (a common scenario based on the survey). Where JavaScript (27%) and C# (24%) likely play a significant role due to their <a href="https://learn.microsoft.com/en-us/archive/msdn-magazine/2012/november/javascript-building-and-using-controls-in-windows-store-apps-with-javascript" target="_blank" rel="noopener noreferrer">platform specific integrations</a> which resonates well with the high usage of Windows (over 60%). Meanwhile, the rise of Rust (18%) aligns with the growing emphasis on memory safety in C++ development.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="dependency-management">Dependency Management<a href="https://moderncppdevops.com/2024-survey-results#dependency-management" class="hash-link" aria-label="Direct link to Dependency Management" title="Direct link to Dependency Management">​</a></h2>
<blockquote>
<p>How do you manage your C++ 1st and 3rd party libraries?</p>
</blockquote>
<table><thead><tr><th>Year</th><th>1. Inlined</th><th>2. Dedicated</th><th>3. System Manager</th><th>4. Download</th><th>5. Conan</th><th>6. vcpkg</th><th>7. other</th><th>8. nuget</th><th>9. None</th></tr></thead><tbody><tr><td>2021</td><td>68.96% 1,284</td><td>55.75% 1,038</td><td>37.49% 698</td><td>32.28% 601</td><td>15.95% 297</td><td>14.82% 276</td><td>9.02% 168</td><td>7.84% 146</td><td>1.66% 31</td></tr><tr><td>2022</td><td>69.91% 827</td><td>50.89% 602</td><td>38.80% 459</td><td>27.56% 326</td><td>18.93% 224</td><td>18.34% 217</td><td>9.30% 110</td><td>8.37% 99</td><td>1.35% 16</td></tr><tr><td>2023</td><td>68.11% 1,162</td><td>48.30% 824</td><td>36.23% 618</td><td>27.43% 468</td><td>21.34% 364</td><td>18.93% 323</td><td>11.25% 192</td><td>7.50% 128</td><td>1.41% 24</td></tr><tr><td>2024</td><td>68.54% 854</td><td>48.48% 604</td><td>37.80% 471</td><td>25.60% 319</td><td>19.34% 241</td><td>19.10% 238</td><td>14.53% 181</td><td>5.30% 66</td><td>1.69% 21</td></tr></tbody></table>
<ol>
<li>The library source code is part of my build</li>
<li>I compile the libraries separately using their instructions</li>
<li>System package managers (e.g., apt, brew, …)</li>
<li>I download prebuilt libraries from the Internet</li>
<li>Conan</li>
<li>Vcpkg</li>
<li>Other (please specify)</li>
<li>Nuget</li>
<li>None of the above, I do not have any dependencies</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="dedicated-build-instructions-are-being-replaced-by-package-managers">Dedicated Build Instructions are being Replaced by Package managers<a href="https://moderncppdevops.com/2024-survey-results#dedicated-build-instructions-are-being-replaced-by-package-managers" class="hash-link" aria-label="Direct link to Dedicated Build Instructions are being Replaced by Package managers" title="Direct link to Dedicated Build Instructions are being Replaced by Package managers">​</a></h3>
<p>Taking the sum of usage of Conan, Vcpkg, Other, and Nugest (disclaimer: "other" is assumed to be another package manager but there's no data about what people wrote) and calculating the delta over the previous year.
Calculating the <a href="https://www.ncl.ac.uk/webtemplate/ask-assets/external/maths-resources/statistics/regression-and-correlation/strength-of-correlation.html" target="_blank" rel="noopener noreferrer">Pearson's Product Moment Correlation Coefficient</a>. Give <code>r = -0.9983817302</code> where "−0.8 &gt; r &gt; −1" is Strong negative linear correlation. Nearly perfect.</p>
<p>This is the best evidence for the entry point to using a package manager is handling dependencies with their own unique workflow and pipelines. Eliminating those extra processes can certainly reduce the pain of managing build system complexity.</p>
<table><thead><tr><th>Year</th><th>Dedicated</th><th>Package Managers</th></tr></thead><tbody><tr><td>2022</td><td>-4.86%</td><td>7.31%</td></tr><tr><td>2023</td><td>-2.59%</td><td>4.08%</td></tr><tr><td>2024</td><td>0.18%</td><td>-0.75%</td></tr></tbody></table>
<!-- -->
<p>Comparing other categories against Package Managers and System Package Managers did not result in any significant correlations which exception to slight connection with downloads getting replace by package managers.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="package-manager-preferences">Package Manager Preferences<a href="https://moderncppdevops.com/2024-survey-results#package-manager-preferences" class="hash-link" aria-label="Direct link to Package Manager Preferences" title="Direct link to Package Manager Preferences">​</a></h3>
<p>It is encouraging to see Nuget, which is for .NET and C# losing ground. The data for <em>"other"</em> will hopefully inspire a revised list of choices next year. This would make up and coming package managers more appealing by helping to promote and attract users. This would be an excellent driver for more innovation in this space.</p>
<!-- -->
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="pain-points">Pain Points<a href="https://moderncppdevops.com/2024-survey-results#pain-points" class="hash-link" aria-label="Direct link to Pain Points" title="Direct link to Pain Points">​</a></h2>
<p>There's is thankfully a large focus on improving the tooling and "evolving the ecosystem", to steal the lingo, so let's dive in.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>The colors are <span style="color:var(--color-secondary-500)">Major Pain</span>, <span style="color:var(--color-secondary-300)">Minor Pain</span>, <span style="color:var(--color-secondary-900)">Not Significant Pain</span> for the follow graphs.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="managing-libraries-my-application-depends-on">Managing libraries my application depends on<a href="https://moderncppdevops.com/2024-survey-results#managing-libraries-my-application-depends-on" class="hash-link" aria-label="Direct link to Managing libraries my application depends on" title="Direct link to Managing libraries my application depends on">​</a></h3>
<p>Positive signs for supporting external dependencies! The percentage of developers reporting this topic as a major pain point has steadily decreased, with a 3% decline from 2021 to 2024. This is accompanied by a corresponding increase in those reporting it as a minor pain or not significant at all.</p>
<!-- -->
<table><thead><tr><th>Year</th><th>Major Pain</th><th>Minor Pain</th><th>Not Significant</th></tr></thead><tbody><tr><td>2021</td><td>48.46% 899</td><td>35.47% 658</td><td>16.06% 298</td></tr><tr><td>2022</td><td>47.63% 563</td><td>34.77% 411</td><td>17.60% 208</td></tr><tr><td>2023</td><td>47.37% 810</td><td>35.09% 600</td><td>17.54% 300</td></tr><tr><td>2024</td><td>45.43% 571</td><td>36.44% 458</td><td>18.14% 228</td></tr></tbody></table>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="delta-change">Delta Change<a href="https://moderncppdevops.com/2024-survey-results#delta-change" class="hash-link" aria-label="Direct link to Delta Change" title="Direct link to Delta Change">​</a></h4>
<p>With the previous year</p>
<table><thead><tr><th>Year</th><th>Major Pain</th><th>Minor Pain</th><th>Not Significant</th></tr></thead><tbody><tr><td>2022</td><td>-0.83%</td><td>-0.70%</td><td>1.54%</td></tr><tr><td>2023</td><td>-0.26%</td><td>0.32%</td><td>-0.06%</td></tr><tr><td>2024</td><td>-1.94%</td><td>1.35%</td><td>0.60%</td></tr></tbody></table>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="build-times">Build times<a href="https://moderncppdevops.com/2024-survey-results#build-times" class="hash-link" aria-label="Direct link to Build times" title="Direct link to Build times">​</a></h3>
<p><strong>Encouraging signs for build times!</strong> So much so, it's included twice. Over the past four years, the survey data reveals a consistent downward trend in the percentage of developers reporting long build times as a major pain point. This decrease of 2.38% from 2021 to 2024 suggests that the C++ build ecosystem is becoming more efficient. There's a still a very slim number of developer who are not burdened by long times times.</p>
<p>Further exploration could investigate:</p>
<ul>
<li>Is there any correlation with the decrease in pain managing dependencies?</li>
<li>Are there correlations between specific build tools and perceived build times?</li>
<li>How do build times vary across different project types or target platforms?</li>
</ul>
<!-- -->
<table><thead><tr><th>Year</th><th>Major Pain</th><th>Minor Pain</th><th>Not Significant</th></tr></thead><tbody><tr><td>2021</td><td>45.24% 837</td><td>38.05% 704</td><td>16.70% 309</td></tr><tr><td>2022</td><td>43.94% 515</td><td>38.65% 453</td><td>17.41% 204</td></tr><tr><td>2023</td><td>43.34% 735</td><td>37.56% 637</td><td>19.10% 324</td></tr><tr><td>2024</td><td>42.86% 537</td><td>37.35% 468</td><td>19.79% 248</td></tr></tbody></table>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="setting-up-a-continuous-integration-pipeline-from-scratch">Setting up a continuous integration pipeline from scratch<a href="https://moderncppdevops.com/2024-survey-results#setting-up-a-continuous-integration-pipeline-from-scratch" class="hash-link" aria-label="Direct link to Setting up a continuous integration pipeline from scratch" title="Direct link to Setting up a continuous integration pipeline from scratch">​</a></h3>
<p>The survey results indicate a persistent challenge. While there's a slight decrease in the percentage of developers reporting it as a major pain point (down to 1% from 2023 to 2024), it remains a significant hurdle for many (nearly a third of respondents!). There's little to no improvement over the 2021 data.</p>
<p>Is there a light at the end of the tunnel?</p>
<p>Perhaps! The data does shows a downward trend in those reporting it as a minor pain, suggesting some improvement. Additionally, the "Not Significant" category remains relatively stable. This could indicate that for certain segment of the ecosystem, setting up CI pipelines is becoming a more manageable task.</p>
<!-- -->
<table><thead><tr><th>Year</th><th>Major Pain</th><th>Minor Pain</th><th>Not Significant</th></tr></thead><tbody><tr><td>2021</td><td>30.85% 568</td><td>42.15% 776</td><td>27.00% 497</td></tr><tr><td>2022</td><td>33.73% 394</td><td>40.75% 476</td><td>25.51% 298</td></tr><tr><td>2023</td><td>31.35% 531</td><td>40.85% 692</td><td>27.80% 471</td></tr><tr><td>2024</td><td>30.35% 376</td><td>42.53% 527</td><td>27.12% 336</td></tr></tbody></table>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="setting-up-a-development-environment-from-scratch">Setting up a development environment from scratch<a href="https://moderncppdevops.com/2024-survey-results#setting-up-a-development-environment-from-scratch" class="hash-link" aria-label="Direct link to Setting up a development environment from scratch" title="Direct link to Setting up a development environment from scratch">​</a></h3>
<p>The data on setting up development environments reveals a fascinating trend. While there's a positive shift with more respondents finding it a "not significant" pain point (up to 31.93% in 2024), there's also a concerning slight increase in those reporting it as a major pain (26.27% in 2024).</p>
<p>One explanation could be advancements in techniques for build script. There are some very high quality sources for CMake. That category saw a in the number of respondents experiencing pain that. However, the challenge of setting up the entire environment, especially for complex systems, seems to be persisting.</p>
<!-- -->
<table><thead><tr><th>Year</th><th>Major Pain</th><th>Minor Pain</th><th>Not Significant</th></tr></thead><tbody><tr><td>2021</td><td>25.82% 479</td><td>43.56% 808</td><td>30.62% 568</td></tr><tr><td>2022</td><td>27.83% 329</td><td>42.98% 508</td><td>29.19% 345</td></tr><tr><td>2023</td><td>26.83% 459</td><td>41.09% 703</td><td>32.09% 549</td></tr><tr><td>2024</td><td>26.27% 330</td><td>41.80% 525</td><td>31.93% 401</td></tr></tbody></table>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="closing-remarks">Closing Remarks<a href="https://moderncppdevops.com/2024-survey-results#closing-remarks" class="hash-link" aria-label="Direct link to Closing Remarks" title="Direct link to Closing Remarks">​</a></h2>
<p>Get subscribed or make sure to follow. I will absolutely be continuing to post about these topics. There is 15-25% range of developers that have figured out how to build, test and ship this code with a not significant amount fo pain, and the goal is to get you there as well.</p>
<p>There an interesting pessimism that was present in 2022, maybe a global health pandemic and financial uncertainty impacted how respondents felt? It does make the current data trend well.</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="c++" term="c++"/>
        <category label="c++ developer survey" term="c++ developer survey"/>
        <category label="build systems" term="build systems"/>
        <category label="development environment" term="development environment"/>
        <category label="package management" term="package management"/>
        <category label="ci/cd" term="ci/cd"/>
        <category label="modules" term="modules"/>
        <category label="memory safety" term="memory safety"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Package Management vs. Reproducible Builds... Or Complementary Approaches?]]></title>
        <id>https://moderncppdevops.com/pkg-mngr-vs-repro-builds</id>
        <link href="https://moderncppdevops.com/pkg-mngr-vs-repro-builds"/>
        <updated>2024-04-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Discover the synergy between package management and reproducible builds in C++ development. Learn how these seemingly opposing forces can actually complement each other, leading to a streamlined and efficient workflow. Explore the definitions, required traits, and exiting tool pairs, along with key takeaways for ensuring identical binaries from identical source code and environments. Find out how to leverage both approaches for enhanced control, compatibility, and productivity in your development projects.]]></summary>
        <content type="html"><![CDATA[<p>Let's face it, in the land of C++ development, package management and reproducible builds can feel like oil and water. Package managers promise lightning-fast builds with pre-built libraries, while reproducible builds preach control and consistency by rebuilding everything. But here's the thing: <strong>they're not sworn enemies.</strong></p>
<p>Think of it this way.</p>
<p>Let's start with the basic build system. Imagine you're spending hours compiling your code. You throw more cores at the problem, and the build time shrinks – but there's a limit. Eventually, adding more cores won't magically make it compile any faster. Now imagine you don't build at all. Poof! Your build time is divided by zero, because it's not happening at all, it's just not a factor anymore. <strong>The most reproducible builds are the ones you don't have to repeat endlessly.</strong>  That's where package management comes in, saving you from endless build marathons. Yet there's even more benefits for reproducibility as well.</p>
<p>This post will explore how these two seemingly opposing forces can actually work together to create a <strong>streamlined and efficient development workflow</strong>. Despite being a new idea, there is evidence of this already being used along with potential new opportunities for future development in this space.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="definitions">Definitions<a href="https://moderncppdevops.com/pkg-mngr-vs-repro-builds#definitions" class="hash-link" aria-label="Direct link to Definitions" title="Direct link to Definitions">​</a></h2>
<p>This is important because you probably have a different one. Most teams actually have a very weak or loose definition for both of these terms.</p>
<p><a href="https://reproducible-builds.org/docs/definition/" target="_blank" rel="noopener noreferrer">Reproducible builds</a>:</p>
<blockquote>
<p>A build is reproducible if given the same source code, build environment and build instructions, any party can recreate bit-by-bit identical copies of all specified artifacts.</p>
</blockquote>
<p>It's reproducible if anyone else can verify it. That's a pretty tall order, but seems like the <a href="https://reproducible-builds.org/docs/rebuilders/" target="_blank" rel="noopener noreferrer">rebuild it a few times</a> is the low hanging fruit. Most teams are not reaching this level of reproducibility, regardless it's the standard.</p>
<p><a href="https://en.wikipedia.org/wiki/Package_manager" target="_blank" rel="noopener noreferrer">Package Manager</a>:</p>
<blockquote>
<p>A package management system is a collection of software tools that automates the process of installing, upgrading, configuring, and removing [...] distributions of software and data in archive files. Designed to eliminate the need for manual installs and updates to ensure the authenticity and integrity of the package. Putting packages in the correct locations in your project and writing the code to include the package(s) in your project. <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Package_management#what_exactly_is_a_package_manager" target="_blank" rel="noopener noreferrer">[ref]</a></p>
</blockquote>
<p>The definition for a "package manager" has evolved, the expectation for what it should do and provide has grown as <a href="https://aws.amazon.com/what-is/sdlc/" target="_blank" rel="noopener noreferrer">SDLC</a> has matured as a topic. A package manager <em>must</em> provision a unique isolated environment (i.e. automatically pull in <em>only</em> necessary the dependencies). This is the best practice across ecosystems take <a href="https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/" target="_blank" rel="noopener noreferrer">Python and it's virtual environments</a> which are now the recommendation.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="leveraging-both-approaches">Leveraging Both Approaches<a href="https://moderncppdevops.com/pkg-mngr-vs-repro-builds#leveraging-both-approaches" class="hash-link" aria-label="Direct link to Leveraging Both Approaches" title="Direct link to Leveraging Both Approaches">​</a></h2>
<p>The key to a successful workflow lies in understanding the strengths of each approach and using them together. Here's how:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="package-management-the-power-of-pre-built-libraries">Package Management: The Power of Pre-built Libraries<a href="https://moderncppdevops.com/pkg-mngr-vs-repro-builds#package-management-the-power-of-pre-built-libraries" class="hash-link" aria-label="Direct link to Package Management: The Power of Pre-built Libraries" title="Direct link to Package Management: The Power of Pre-built Libraries">​</a></h3>
<p>Package managers like Nuget, Conan, and Conda offer a compelling advantage: pre-built libraries. These tools save developers countless hours by eliminating the need to local build dependencies from source. A notable way this is achieved is by large well tested repositories which often provide abstractions to the project specific inputs that often existing. This translates to faster development cycles and a more streamlined workflow. However, package management can introduce challenges.</p>
<p>The importance of these packages is they are re-usable, typically any <a href="https://conda.io/projects/conda/en/latest/user-guide/concepts/pkg-specs.html" target="_blank" rel="noopener noreferrer">changes to the output contents</a> will be labeled, this makes the need of tracking individual variations of source code take less precedency. The output or package of one project is often the input for another. This is a powerful abstraction when aiming for reproducible builds as it can simplify the integration of third-party dependencies which likely do not conform the <a href="https://reproducible-builds.org/docs/commandments/" target="_blank" rel="noopener noreferrer">commandments</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="reproducible-builds-determinism-and-control">Reproducible Builds: Determinism and Control<a href="https://moderncppdevops.com/pkg-mngr-vs-repro-builds#reproducible-builds-determinism-and-control" class="hash-link" aria-label="Direct link to Reproducible Builds: Determinism and Control" title="Direct link to Reproducible Builds: Determinism and Control">​</a></h3>
<p>Reproducible builds prioritize <a href="https://go.dev/blog/rebuild" target="_blank" rel="noopener noreferrer">control and consistency</a>. By building <em>everything</em> from source with a defined set of tools, developers ensure that the build process is deterministic. This means that the same source code will always produce the same binary, given the same environment. Faster more trust worthy builds and test results ensure developers are focused and <a href="https://www.atlassian.com/blog/productivity/context-switching" target="_blank" rel="noopener noreferrer">boost productivity</a> <a href="https://asana.com/resources/context-switching" target="_blank" rel="noopener noreferrer">[ref]</a>.</p>
<p>The downside of reproducible builds is the complexity they can introduce. Manually managing dependencies and build systems can be time-consuming and error-prone. Often teams can not rely on the standard build tools, for examples, Rust's compiler, <code>rustc</code>, has support for this but that has not been added to <code>Cargo</code> <a href="https://github.com/rust-secure-code/wg/issues/28" target="_blank" rel="noopener noreferrer">[ref]</a> the main build system for that ecosystem. This ends up becoming a burden with trying to make the build reproducible when incorporating third-party dependencies. If external build systems are not directly supported by the reproducible build system then you are likely to lose control of the inputs and settings. The lack of insight to the source build graph also reduce the effectiveness of the <a href="https://webpack.js.org/guides/tree-shaking/" target="_blank" rel="noopener noreferrer">build tree shaking</a> and <a href="https://sluongng.hashnode.dev/bazel-caching-explained-pt-1-how-bazel-works" target="_blank" rel="noopener noreferrer">caching strategies</a> less efficient. To close out the pain point the outputs of dependencies can be project specific and require extensive manual work to be integrated back into the reproducible system.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="required-traits">Required Traits<a href="https://moderncppdevops.com/pkg-mngr-vs-repro-builds#required-traits" class="hash-link" aria-label="Direct link to Required Traits" title="Direct link to Required Traits">​</a></h2>
<p>In order to ensure easy of use, build systems overwhelming will allow you to pull in system libraries. This loose rule makes it very easy to break the <a href="https://bazel.build/basics/hermeticity" target="_blank" rel="noopener noreferrer">hermetic</a> build ideal required to be reproducible; resulting with a non-reproducible environment. This problems are beautifully outlined in a talk by <a href="https://www.linkedin.com/in/andreas-herrmann-2081751ba" target="_blank" rel="noopener noreferrer">Andreas Herrmann</a> titled <a href="https://youtu.be/2wI5J8XYxM8?t=943" target="_blank" rel="noopener noreferrer">Fast, correct, reproducible builds with Nix + Bazel</a>. The challenge of doing this is also outline in <a href="https://buck2.build/docs/concepts/build_rule/#package-boundaries-and-access-to-source-files" target="_blank" rel="noopener noreferrer">Buck2</a> so it's quiet general.</p>
<p>Using a build system that offers distributions and correct <a href="https://bazel.build/reference/glossary#depset" target="_blank" rel="noopener noreferrer">dependency set</a> and <a href="https://bazel.build/reference/glossary#incremental-build" target="_blank" rel="noopener noreferrer">incremental builds</a> while a package managers strictness with toolchain management and control over third-party dependencies is the winning combination. Additionally package managers which offer distribution of compiled artifacts rather then local caching can <em>correctly</em> reduce the number for build branches. To round off the shopping list, not only should the package manager provide an isolated environment, the build system should also enforce this by isolating the build tree's filesystem (i.e not have default search paths).</p>
<ol>
<li>
<p><strong>Utilize Package Managers for Controlling Toolchains:</strong> The number one advantage of using a package manager is the large community driven repositories which have generally been tested against a large list of toolchains. The build instructions are typically well controlled already as these tool setup for handling the variations in the build scripts. They can handle all the complex mapping of different inputs to each individual flavor of build scripts. This generally makes the integration more streamlined.</p>
</li>
<li>
<p><strong>Build Critical Third-Party Dependencies:</strong> When dealing with critical project dependencies or those with specific version requirements, consider building them from source. This gives you greater control over the build process and ensures compatibility. Being able to resolve more complex graphs to get the best version when managing dependencies is critical. As they all support building from source you will be able to ensure all the impacted make targets are tracked.</p>
</li>
<li>
<p><strong>Handling Heterogenous Developer Environments:</strong> It's very likely on larger distributed teams, individual will have different variations are be slightly skewed in terms of the operating system they use and the supported environments. This requires a high-order tool that is able to understand the current system configuration and provide the correct binaries. Using a package manager to control and provision the exact build environment and dependencies will reduce this by creating the dedicated sandbox required.</p>
</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="existing-tool-pairs">Existing Tool Pairs<a href="https://moderncppdevops.com/pkg-mngr-vs-repro-builds#existing-tool-pairs" class="hash-link" aria-label="Direct link to Existing Tool Pairs" title="Direct link to Existing Tool Pairs">​</a></h2>
<p>When exploring integration possibilities between package managers and reproducibility focused build systems in the realm of C++ development, Conan stands out as a supportive tool. Conan not only <a href="https://docs.conan.io/2/examples/tools/google/bazeltoolchain/build_simple_bazel_project.html#examples-tools-bazel-toolchain-build-simple-bazel-project" target="_blank" rel="noopener noreferrer">supports Bazel</a>, but also offers advanced features such as build graphs and toolchain combinations, so you can very likely achieve this with other build systems as well. However, it's worth noting that Conan does support for <a href="https://docs.conan.io/2/reference/tools/google/bazeldeps.html#build-context-activated" target="_blank" rel="noopener noreferrer">build tools</a>, it <a href="https://github.com/conan-io/conan/blob/06297af6798f26b38717773aab5752a1158aa04c/conan/tools/google/toolchain.py#L7" target="_blank" rel="noopener noreferrer">lacks direct integration</a> with Bazel's <a href="https://bazel.build/tutorials/ccp-toolchain-config" target="_blank" rel="noopener noreferrer">user-defined toolchains</a> through it's <code>compiler_executables</code> configuration, a feature that is support with it's CMake Presets.</p>
<p>On the other hand, Vcpkg, another prominent package manager, is primarily tailored for CMake, limiting its compatibility with other build systems. This has led <a href="https://igormcoelho.medium.com/building-cross-platform-c-gmp-library-with-vcpkg-cmake-and-bazel-lessons-learned-ea2cba4b697d" target="_blank" rel="noopener noreferrer">some developers to resort to manual configurations</a>, effectively hardcoding dependencies into Bazel build files for each package. Despite efforts to bridge this gap, Bazel still <a href="https://blog.envoyproxy.io/external-c-dependency-management-in-bazel-dd37477422f5" target="_blank" rel="noopener noreferrer">faces challenges in accommodating</a> various C++ package managers, with Nix and Conan emerging as the preferred choices due to their <em>existing</em> support. The limited interoperability between <a href="https://bazelbuild.github.io/rules_foreign_cc/main/index.html" target="_blank" rel="noopener noreferrer">other build systems</a> exists if you are curious.</p>
<p>Switching gears, within the embedded space, Yocto presents a compelling case with its BitBake package manager. Yocto's support for <a href="https://docs.yoctoproject.org/test-manual/reproducible-builds.html" target="_blank" rel="noopener noreferrer">reproducible builds</a> has contributed to its success, offering a reliable solution for managing dependencies and ensuring consistent build outputs. Unfortunately this is not seen in other application specific segments of the ecosystem.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://moderncppdevops.com/pkg-mngr-vs-repro-builds#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>The integration of package management and reproducible builds in C++ development presents a nuanced landscape where both approaches, although initially seem contradictory, can harmonize to enhance development workflows. Package managers like Nix or Conan offer the advantage of tightly controlled libraries and environments, reducing development cycles needed to create robust hermetic build environments. Complementary to this, reproducible builds prioritize control and consistency by rebuilding everything, ensuring deterministic outputs and boosting productivity through more efficient optimization that can be made with these constraints.</p>
<p>Despite the challenges each approach presents, the key lies in understanding their respective strengths and leveraging them together effectively. Utilizing package managers for controlling toolchains and handling critical third-party dependencies can enhance build processes, while reproducible builds offer deeper control and insight into build outputs.</p>
<p><strong>Key Takeaways:</strong></p>
<ul>
<li><strong>Package managers</strong> streamline development with pre-built libraries and provide deterministic builds by leveraging pre-configured toolchains. Ensure control and compatibility with normalized build inputs/outputs for more efficient build graph shaking.</li>
<li><strong>Reproducible Build Systems</strong> offer deeper per project build tree shaking by caching intermediate build artifacts. Having better visibility on incremental changes between builds offers better build times and more insights to potential problems.</li>
</ul>
<p>Together they guarantee identical binaries from identical source code and environments, aiding ensure correct secure software.</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="package management" term="package management"/>
        <category label="reproducible builds" term="reproducible builds"/>
        <category label="development workflow" term="development workflow"/>
        <category label="conan" term="conan"/>
        <category label="bazel" term="bazel"/>
        <category label="nix" term="nix"/>
        <category label="vcpkg" term="vcpkg"/>
        <category label="nuget" term="nuget"/>
        <category label="conda" term="conda"/>
        <category label="nix" term="nix"/>
        <category label="nixpkgs" term="nixpkgs"/>
        <category label="buck2" term="buck2"/>
        <category label="toolchains" term="toolchains"/>
        <category label="build systems" term="build systems"/>
        <category label="dependency management" term="dependency management"/>
        <category label="deterministic builds" term="deterministic builds"/>
        <category label="pre-built libraries" term="pre-built libraries"/>
        <category label="build optimization" term="build optimization"/>
        <category label="hermetic builds" term="hermetic builds"/>
        <category label="embedded systems" term="embedded systems"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Const Correctness for C++ Builds]]></title>
        <id>https://moderncppdevops.com/const-correct-builds</id>
        <link href="https://moderncppdevops.com/const-correct-builds"/>
        <updated>2024-03-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[In the fast-paced world of software development, ensuring code quality and maintainability is crucial. This blog explores how seemingly unrelated concepts, const correctness in C++ and ephemeral builds from DevOps, come together to create a strong foundation for reliable software. We'll delve into const correctness and its benefits like preventing accidental modifications, improved code clarity, and compiler optimizations. We'll also explore ephemeral builds and their advantages such as reproducible builds, reduced complexity, and enhanced security. Additionally, we'll discuss popular tools for ephemeral builds and how Infrastructure as Code (IaC) complements this approach. Finally, we'll examine how version control ties const correctness and ephemeral builds together, establishing a unified Software Development Lifecycle (SDLC) and a single source of truth for your code and build environment. By combining these practices, you can ensure fewer bugs, easier maintenance, and ultimately, more dependable software.]]></summary>
        <content type="html"><![CDATA[<p>In the ever-evolving world of software development, ensuring code quality and maintainability is paramount. Two seemingly unrelated concepts, const correctness in C++ and ephemeral build environments from DevOps, share a surprising connection, both aiming to build a strong foundation for reliable software.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="const-correctness-enforcing-immutability-in-code">Const Correctness: Enforcing Immutability in Code<a href="https://moderncppdevops.com/const-correct-builds#const-correctness-enforcing-immutability-in-code" class="hash-link" aria-label="Direct link to Const Correctness: Enforcing Immutability in Code" title="Direct link to Const Correctness: Enforcing Immutability in Code">​</a></h2>
<p><a href="https://isocpp.org/wiki/faq/const-correctness" target="_blank" rel="noopener noreferrer">Const correctness</a> is a programming paradigm in C++ that emphasizes the use of the <code>const</code> keyword to explicitly declare variables and objects that shouldn't be modified. This enforces a form of immutability within your code. Just like an immutable object in other languages, a <code>const</code> variable cannot have its value changed after initialization.</p>
<p>Here's the magic:</p>
<ol>
<li><strong>Prevents Accidental Modifications:</strong>  <code>const</code> acts as a safeguard against accidental changes, preventing bugs caused by unintended assignments.</li>
<li><strong>Improved Code Clarity:</strong> It clearly communicates intent to both the compiler and future developers, making code easier to understand and maintain.</li>
<li><strong>Compiler Optimizations:</strong> The compiler can leverage <code>const</code> to improve performance by making assumptions about the data's immutability.</li>
</ol>
<p>Let's implement a hypothetical C++ CI service.</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(86, 156, 214)">include</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(206, 145, 120)">&lt;string_view&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">build_image</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">public</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token function" style="color:rgb(220, 220, 170)">build_image</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">string_view version</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">string_view name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">version_</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">version</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">name_</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token function" style="color:rgb(220, 220, 170)">download_build_image</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token keyword" style="color:rgb(86, 156, 214)">this</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">// Takes a non-const to populate in `this-&gt;id`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token function" style="color:rgb(220, 220, 170)">open_shell_handle</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token keyword" style="color:rgb(86, 156, 214)">this</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">string </span><span class="token function" style="color:rgb(220, 220, 170)">version</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token function" style="color:rgb(220, 220, 170)">string</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">version_</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">string </span><span class="token function" style="color:rgb(220, 220, 170)">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token function" style="color:rgb(220, 220, 170)">string</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">name_</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">string </span><span class="token function" style="color:rgb(220, 220, 170)">id</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> id_</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">void</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">id</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">string_view id</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> id_ </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token function" style="color:rgb(220, 220, 170)">string</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">id</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">private</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">const</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">string_view version_</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">const</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">string_view name_</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">string id_</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">void</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">download_build_image</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">build_image</span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token plain"> image</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">void</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">open_shell_handle</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">const</span><span class="token plain"> build_image</span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token plain"> image</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">// Contents of a build_image can not be modified while commands are executed</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">bool</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">run_command</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">const</span><span class="token plain"> build_image</span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token plain"> image</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">const</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">string</span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token plain"> cmd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token comment" style="color:rgb(106, 153, 85)">// Simulate opening a shell and executing commands</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">// Code never fails to compile</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">int</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">main</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">const</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">string_view version </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"24.04"</span><span class="token plain">sv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">const</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">string_view name </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"ubuntu"</span><span class="token plain">sv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">const</span><span class="token plain"> build_image </span><span class="token function" style="color:rgb(220, 220, 170)">ubuntu24</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">version</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">const</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">auto</span><span class="token plain"> build_result </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token function" style="color:rgb(220, 220, 170)">run_command</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">ubuntu24</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"./terrible-do-everything.sh debug all"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">cout </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;&lt;</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"Build complete! "</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;&lt;</span><span class="token plain"> build_result </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;&lt;</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:rgb(212, 212, 212)">::</span><span class="token plain">endl</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="ephemeral-build-images-fresh-starts-for-every-build">Ephemeral Build Images: Fresh Starts for Every Build<a href="https://moderncppdevops.com/const-correct-builds#ephemeral-build-images-fresh-starts-for-every-build" class="hash-link" aria-label="Direct link to Ephemeral Build Images: Fresh Starts for Every Build" title="Direct link to Ephemeral Build Images: Fresh Starts for Every Build">​</a></h2>
<p>Ephemeral, meaning "short-lived," refers to a build environment that is created, used for a specific task (like building software), and then discarded. This approach is gaining traction due to its numerous benefits:</p>
<ol>
<li><strong>Reproducible Builds:</strong> Every build starts with a clean slate, ensuring consistency regardless of the developer's environment or previous build artifacts. Version controlling these ephemeral build images guarantees reproducibility across builds.</li>
<li><strong>Reduced Complexity:</strong> Ephemeral builds eliminate the need to manage complex build environments on developer machines, simplifying the development process.</li>
<li><strong>Security Enhancements:</strong> Since the build environment is discarded after use, it minimizes the attack surface and potential vulnerabilities.</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="popular-tools-for-ephemeral-builds">Popular Tools for Ephemeral Builds<a href="https://moderncppdevops.com/const-correct-builds#popular-tools-for-ephemeral-builds" class="hash-link" aria-label="Direct link to Popular Tools for Ephemeral Builds" title="Direct link to Popular Tools for Ephemeral Builds">​</a></h3>
<ul>
<li><strong>Docker:</strong> A containerization platform that allows packaging applications and their dependencies into lightweight, portable units called containers. Docker excels at creating isolated and consistent build environments.</li>
<li><strong>Kubernetes:</strong> An open-source system for automating deployment, scaling, and management of containerized applications. Kubernetes can orchestrate the creation and management of multiple Docker containers that form a complex build environment.</li>
<li><strong>Azure Pipelines:</strong> A cloud-based CI/CD platform from Microsoft that provides pre-built agents for Windows environments. These agents offer isolated and pre-configured build environments for running build tasks.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="infrastructure-as-code-iac-and-ephemeral-builds">Infrastructure as Code (IaC) and Ephemeral Builds<a href="https://moderncppdevops.com/const-correct-builds#infrastructure-as-code-iac-and-ephemeral-builds" class="hash-link" aria-label="Direct link to Infrastructure as Code (IaC) and Ephemeral Builds" title="Direct link to Infrastructure as Code (IaC) and Ephemeral Builds">​</a></h3>
<p>Infrastructure as Code (IaC) refers to the practice of managing infrastructure (like servers, networks, and storage) in a programmatic way using code. Tools like Terraform allow developers to define the configuration of their build environment in code files. These code files can then be version controlled alongside the application code, ensuring consistency and reproducibility.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="version-control-tying-it-all-together">Version Control: Tying it All Together<a href="https://moderncppdevops.com/const-correct-builds#version-control-tying-it-all-together" class="hash-link" aria-label="Direct link to Version Control: Tying it All Together" title="Direct link to Version Control: Tying it All Together">​</a></h2>
<p>Version control systems (VCS) like Git play a crucial role in both const correctness and ephemeral builds. It allows you to manage changes to your codebase (enforcing <code>const</code> usage) and the definitions of your ephemeral build environments, fostering a unified Software Development Lifecycle (SDLC) for both.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="artifact-management-with-version-control">Artifact Management with Version Control<a href="https://moderncppdevops.com/const-correct-builds#artifact-management-with-version-control" class="hash-link" aria-label="Direct link to Artifact Management with Version Control" title="Direct link to Artifact Management with Version Control">​</a></h3>
<ul>
<li><strong>Codebase Versioning:</strong> Git tracks changes to your C++ source code. This enables reverting to previous versions if necessary and identifying who made specific changes that might have introduced issues. Enforcing <code>const</code> correctness through code reviews and linting tools further strengthens the codebase's integrity.</li>
<li><strong>Build Environment Definitions:</strong> You can store the configuration files or scripts that define your ephemeral build environments (e.g., Dockerfiles, Terraform configurations) alongside your code. Version controlling these definitions ensures everyone uses the same build environment and allows for rollbacks to previous configurations if needed.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="benefits-of-a-unified-sdlc">Benefits of a Unified SDLC<a href="https://moderncppdevops.com/const-correct-builds#benefits-of-a-unified-sdlc" class="hash-link" aria-label="Direct link to Benefits of a Unified SDLC" title="Direct link to Benefits of a Unified SDLC">​</a></h3>
<p><strong>A Single Source of Truth:</strong> By leveraging version control, you establish a single source of truth for both your code and build environment definitions. This streamlines your SDLC by ensuring everyone works with the latest and approved versions of both components.</p>
<p>Combining const correctness with ephemeral builds and managing them through version control creates a robust and cohesive foundation for reliable software development. You enforce code immutability, guarantee clean build environments for each build, and establish a clear audit trail for changes, leading to fewer bugs, easier maintenance, and ultimately, more dependable software.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-connection-immutable-code-fresh-builds">The Connection: Immutable Code, Fresh Builds<a href="https://moderncppdevops.com/const-correct-builds#the-connection-immutable-code-fresh-builds" class="hash-link" aria-label="Direct link to The Connection: Immutable Code, Fresh Builds" title="Direct link to The Connection: Immutable Code, Fresh Builds">​</a></h2>
<p>Const correctness and ephemeral builds, seemingly separate concepts, share a surprising connection: building a strong foundation for reliable software. Const correctness enforces immutability in your C++ code, while ephemeral builds provide a clean slate for each build. Together, they create a powerful synergy:</p>
<ul>
<li><strong>Immutable Code, Consistent Builds:</strong> Const correctness safeguards code, and ephemeral builds provide a fresh starting point.</li>
<li><strong>Simplified Maintenance:</strong> Version control streamlines development by managing both code and build environments.</li>
<li><strong>Ephemeral builds</strong> provide a clean, consistent starting point for every build, eliminating the risk of inconsistencies from previous builds.</li>
</ul>
<p>Imagine a scenario where a non-<code>const</code> variable in your C++ code accidentally gets modified during the build process. This could lead to unexpected behavior in the final product. Ephemeral builds mitigate this risk by ensuring a fresh, unmodified codebase for each build.</p>
<p>Similarly, consider an ephemeral build environment containing cached data or temporary files from previous builds. This can lead to inconsistencies if these remnants influence the build outcome. Const correctness in your code helps prevent such issues by ensuring the code itself remains immutable, regardless of the build environment.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://moderncppdevops.com/const-correct-builds#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>In conclusion, combining const correctness with ephemeral builds and managing them through version control creates a robust and cohesive foundation for reliable software development. You enforce code immutability, guarantee clean build environments for each build, and establish a clear audit trail for changes, leading to fewer bugs, easier maintenance, and ultimately, more dependable software.</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="const correctness" term="const correctness"/>
        <category label="c++" term="c++"/>
        <category label="ephemeral builds" term="ephemeral builds"/>
        <category label="devops" term="devops"/>
        <category label="software development" term="software development"/>
        <category label="build environments" term="build environments"/>
        <category label="version control" term="version control"/>
        <category label="git" term="git"/>
        <category label="docker" term="docker"/>
        <category label="kubernetes" term="kubernetes"/>
        <category label="iac" term="iac"/>
        <category label="terraform" term="terraform"/>
        <category label="reliable software" term="reliable software"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[CPS: A Streamlined Future for C++ or Overly Specific?]]></title>
        <id>https://moderncppdevops.com/cps-and-why</id>
        <link href="https://moderncppdevops.com/cps-and-why"/>
        <updated>2024-03-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[C++ developers have long struggled with package management and battling cryptic build systems. The Common Package Specification (CPS) aims to be a game-changer, offering a standardized way to describe dependencies. But is it a silver bullet or an overly ambitious proposal? This blog explores CPS, its potential benefits, and the questions it raises.]]></summary>
        <content type="html"><![CDATA[<p>The most relevant <a href="https://isocpp.org/files/papers/CppDevSurvey-2023-summary.pdf" target="_blank" rel="noopener noreferrer">problems for C++ developers</a> are package management, setting up CI/CD pipelines, and maintaining build scripts. Talking to developers and builds teams the cause of that frustration is the lack of interoperability between build systems.</p>
<p>The <a href="https://cps-org.github.io/cps/index.html" target="_blank" rel="noopener noreferrer">Common Package Specification</a> (CPS) aims to revolutionize C++ development by standardizing how dependencies are described. While the core concept holds promise, specific aspects raise questions about its practicality within the C++ ecosystem.</p>
<p>This leads to the <strong>Call to Actions</strong>. What do you think is a "package"? Headers, Libs, DLLs are pretty obvious. What about Compiler flags? What does Multi-Config mean to you? Is a package valid if it produces <a href="https://en.cppreference.com/w/cpp/language/definition" target="_blank" rel="noopener noreferrer">ODR</a> violations or does leads to <a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/AA.+Bibliography#AA.Bibliography-ISO/IEC14882-2014" target="_blank" rel="noopener noreferrer">ill-formed programs</a>? Share you ideas and thoughts.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-dependency-labyrinth">The Dependency Labyrinth<a href="https://moderncppdevops.com/cps-and-why#the-dependency-labyrinth" class="hash-link" aria-label="Direct link to The Dependency Labyrinth" title="Direct link to The Dependency Labyrinth">​</a></h2>
<p>C++ developers are no strangers to dependency woes. Different build systems have their own cryptic ways of handling external libraries, leading to compatibility nightmares and endless versioning headaches. These inconsistencies often culminate in cryptic build errors, leaving developers frustrated and wasting valuable time.</p>
<p>What ever we do it needs to be unanimous for all of us which is a tall order. The best approach is going to be an extensible format but we need to get the core right. So let's focus on those fields.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-universal-translator">The Universal Translator<a href="https://moderncppdevops.com/cps-and-why#the-universal-translator" class="hash-link" aria-label="Direct link to The Universal Translator" title="Direct link to The Universal Translator">​</a></h2>
<p>CPS proposes a standardized format for describing C++ libraries, including:</p>
<ul>
<li><strong>Package Name and Version:</strong> Clear identification of the library and version.</li>
<li><strong>Dependency Information:</strong> Explicit listing of all required dependencies.</li>
<li><strong>Compiler Flags and Features:</strong> Standardized instructions for integrating the library into a C++ project, regardless of the build system.</li>
</ul>
<p>A minimal CPS focused on core information:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">"Cps-Version"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0.9"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">"Name"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"sample"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">"Description"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"Sample CPS for a static library"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">"License"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"BSD"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">"Version"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"1.2.0"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">"Default-Components"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"sample"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">"Components"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"sample"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token property">"Type"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"archive"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token property">"Requires"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"libfoo:core"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token property">"Compile-Features"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"c++17"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token property">"Definitions"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"SAMPLE"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token property">"Includes"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"@prefix@/include"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token property">"Location"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"@prefix@/lib/libsample.a"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You can checkout the <a href="https://cps-org.github.io/cps/sample.html" target="_blank" rel="noopener noreferrer">CPS' example</a> for a more complete interpretation.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="benefits-for-c-developers">Benefits for C++ Developers<a href="https://moderncppdevops.com/cps-and-why#benefits-for-c-developers" class="hash-link" aria-label="Direct link to Benefits for C++ Developers" title="Direct link to Benefits for C++ Developers">​</a></h2>
<p>Widespread adoption by C++ build systems and package managers could offer advantages:</p>
<ul>
<li><strong>Simplified Package Management:</strong> A universal approach eliminates build system-specific  translation layers and duplicated effort by developers.</li>
<li><strong>Reduced Build Errors:</strong> Consistent dependency information across projects could minimizes errors caused by multiple installations with version conflicts, missing libraries, link order, or compiler flags.</li>
<li><strong>Farewell to the Dependency Hunt:</strong> Build systems could deterministically locate packages dependencies based on the CPS specification provided by other build systems or package managers.</li>
<li><strong>Simplified Project Evolution:</strong>  Easier switching between build systems and package managers as project needs evolve, fostering innovation within the C++ ecosystem.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="a-question-of-specificity-focusing-on-core-functionalities">A Question of Specificity: Focusing on Core Functionalities<a href="https://moderncppdevops.com/cps-and-why#a-question-of-specificity-focusing-on-core-functionalities" class="hash-link" aria-label="Direct link to A Question of Specificity: Focusing on Core Functionalities" title="Direct link to A Question of Specificity: Focusing on Core Functionalities">​</a></h2>
<p>The existence of many <a href="https://julienjorge.medium.com/an-overview-of-build-systems-mostly-for-c-projects-ac9931494444" target="_blank" rel="noopener noreferrer">build systems</a> (or <a href="https://hackingcpp.com/cpp/tools/build_systems.html" target="_blank" rel="noopener noreferrer">these</a>) and <a href="https://moderncppdevops.com/pkg-mngr-roundup">package managers</a> for C++ reflects the
diversity of project requirements. The challenge for CPS lies in defining a core set of functionalities that caters to the widest range of projects while remaining flexible enough to accommodate those with specific needs.</p>
<p>The inclusion of overly specific fields like JVM vendors and GLIBC runtime versions raises concerns:</p>
<ul>
<li><a href="https://cps-org.github.io/cps/schema.html#c-runtime-vendor" target="_blank" rel="noopener noreferrer">C Runtime Vendor</a> and <a href="https://cps-org.github.io/cps/schema.html#cpp-runtime-vendor" target="_blank" rel="noopener noreferrer">C++ Runtime Vendor</a>: Use case exists, but most developers don't target various flavors.</li>
<li><a href="https://cps-org.github.io/cps/schema.html#clr-vendor" target="_blank" rel="noopener noreferrer">.NET</a> and <a href="https://cps-org.github.io/cps/schema.html#jvm-vendor" target="_blank" rel="noopener noreferrer">JVM</a>: Only relevant to a subset of C++ developers.</li>
<li><a href="https://cps-org.github.io/cps/schema.html#compat-version" target="_blank" rel="noopener noreferrer">Compat-Version</a>: Little agreement on software versioning. Without a set format, this field will be tool-specific.</li>
<li><a href="https://cps-org.github.io/cps/features.html#nowarn" target="_blank" rel="noopener noreferrer">Warnings and Errors</a>: Consumer decisions, shouldn't be forced downstream. Has no impact on binaries packaged.</li>
</ul>
<p>The focus should be on fields all C++ developers use. These specific fields can be saved in a technical recommendation for future work. The specification should allow adding them later.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="reasonable-default-dependencies">Reasonable Default Dependencies<a href="https://moderncppdevops.com/cps-and-why#reasonable-default-dependencies" class="hash-link" aria-label="Direct link to Reasonable Default Dependencies" title="Direct link to Reasonable Default Dependencies">​</a></h3>
<p>A common issue with third-party dependencies is including more parts than necessary. A common example is providing a header-only variant and a compiled library in the same installation. This is the example for <a href="https://cps-org.github.io/cps/schema.html#default-components" target="_blank" rel="noopener noreferrer"><code>"Default-Components"</code></a> in the <a href="https://moderncppdevops.com/cps-and-why#additional-resources">CppCon 2023 talk</a>. Providing multiple copies of symbols such static and shared result in linker errors and will be error-prone.</p>
<p>Ideally, users shouldn't need to micromanage individual components within a dependency. Including all components by default ensures a well-formed and functional package must be provided by the project. This eliminates the need to specify every piece and reduces the chance of missing something crucial.</p>
<ul>
<li><strong>Proposed Solution: Granular Component Control</strong></li>
</ul>
<p>The specification does need to allow for granular control over components. An optional <code>"Excluded-Components"</code> field could be introduced, allowing authors to specify parts that are not need during the build process (e.g., executables or experimental additions). This approach balances providing all necessary components for most users while offering flexibility for advanced users to optimize dependency usage.</p>
<ul>
<li><strong>Challenge: Feature-Driven Dependencies</strong></li>
</ul>
<p>Current CPS doesn't handle feature-driven projects well. Build options can change a component's functionality and binary compatibility without altering its name, include directories or complier flags. This makes it difficult to specify exactly which features you need when using a dependency.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="configuration-dependent-inconsistency">Configuration Dependent Inconsistency<a href="https://moderncppdevops.com/cps-and-why#configuration-dependent-inconsistency" class="hash-link" aria-label="Direct link to Configuration Dependent Inconsistency" title="Direct link to Configuration Dependent Inconsistency">​</a></h3>
<p>There are some fields that require a bit more complexity, <a href="https://cps-org.github.io/cps/schema.html#compile-flags" target="_blank" rel="noopener noreferrer">compiler flags</a> and <a href="https://cps-org.github.io/cps/schema.html#link-flags" target="_blank" rel="noopener noreferrer">linker flags</a> are unfortunately platform specific. Currently there is no complete example for having different compiler flags for the the various implementation, however <a href="https://cps-org.github.io/cps/features.html#nowarn" target="_blank" rel="noopener noreferrer">nowarn</a> does give a hit to this problem.</p>
<ul>
<li><strong>Potential Solution: Define the Compiler and Flags under platform</strong></li>
</ul>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">"Platform"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"Kernel"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"linux"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"Compiler"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"gcc"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"Compiler-Flags"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token string" style="color:rgb(206, 145, 120)">"-finline-functions-called-once"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">// An unreasonable flag to force on downstream consumers?</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This is a very open topic, perhaps the CPS is only one configuration since the binary library would not be portable? However the current proposal's example is for an x86_64-Linux which could be used by either Clang or GCC and might (incorrectly) have incompatible flags. The header-only case, where the package and CPS should be re-usable cross operating-systems does not allow describing both MSVC <code>/bigobj</code> and GCC <code>-mbig-obj</code> might be cause to have different CPS with one package.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-road-ahead-a-balancing-act-for-success">The Road Ahead: A Balancing Act for Success<a href="https://moderncppdevops.com/cps-and-why#the-road-ahead-a-balancing-act-for-success" class="hash-link" aria-label="Direct link to The Road Ahead: A Balancing Act for Success" title="Direct link to The Road Ahead: A Balancing Act for Success">​</a></h2>
<p>For CPS to succeed within the C++ ecosystem, it needs to strike a delicate balance:</p>
<ul>
<li><strong>Standardization for Efficiency:</strong> A core set of standardized fields for essential dependency information.</li>
<li><strong>Flexibility for Innovation:</strong> Adaptable to accommodate diverse project needs and avoid hindering alternative solutions.</li>
<li><strong>Developer Adoption:</strong> Widespread adoption by C++ build systems like CMake and Meson in addition from package managers such as Conan and Vcpkg is essential for the impact of CPS to be realized.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion-a-promising-path-with-open-questions">Conclusion: A Promising Path with Open Questions<a href="https://moderncppdevops.com/cps-and-why#conclusion-a-promising-path-with-open-questions" class="hash-link" aria-label="Direct link to Conclusion: A Promising Path with Open Questions" title="Direct link to Conclusion: A Promising Path with Open Questions">​</a></h2>
<p>CPS holds immense potential to streamline C++ dependency management, but questions remain regarding its specific details.  If the community can ensure the right level of flexibility and focus on core functionalities, with enough feedback and input, CPS has the potential to be a valuable tool.  However, only time and developer adoption will tell if CPS becomes the universal language for C++ dependencies, or remains an ambitious proposal with unanswered questions.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="additional-resources">Additional Resources<a href="https://moderncppdevops.com/cps-and-why#additional-resources" class="hash-link" aria-label="Direct link to Additional Resources" title="Direct link to Additional Resources">​</a></h3>
<ul>
<li>
<p>CppCon 2023 Talks:</p>
<ul>
<li><a href="https://www.youtube.com/playlist?list=PLHTh1InhhwT6c2JNtUiJkaH8YRqzhU7Ag" target="_blank" rel="noopener noreferrer">Libraries: A First Step Toward Standard C++ Dependency Management</a>
<ul>
<li><a href="https://www.reddit.com/r/cpp/comments/171mtjk/libraries_a_first_step_toward_standard_c/" target="_blank" rel="noopener noreferrer">Brett Brown AMA</a></li>
</ul>
</li>
<li><a href="https://www.youtube.com/watch?v=ZTjG8fy6Bek" target="_blank" rel="noopener noreferrer">A Common Package Specification: Getting Build Tools to Talk to Each Other</a></li>
</ul>
</li>
<li>
<p><a href="https://doc.rust-lang.org/cargo/commands/cargo-metadata.html" target="_blank" rel="noopener noreferrer">Cargo's Package Metadata</a></p>
</li>
<li>
<p><a href="https://conda.io/projects/conda-build/en/latest/resources/package-spec.html#package-metadata" target="_blank" rel="noopener noreferrer">Conada Package Metadata format</a></p>
</li>
<li>
<p><a href="https://maven.apache.org/archetype/maven-archetype-plugin/specification/archetype-metadata.html" target="_blank" rel="noopener noreferrer">Similar functionality in Maven</a></p>
</li>
</ul>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="C++" term="C++"/>
        <category label="Common Package Specification" term="Common Package Specification"/>
        <category label="CPS" term="CPS"/>
        <category label="dependency management" term="dependency management"/>
        <category label="build systems" term="build systems"/>
        <category label="package managers" term="package managers"/>
        <category label="standardization" term="standardization"/>
        <category label="flexibility" term="flexibility"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Conquer C++ Dependency Challenges: A Comprehensive Guide]]></title>
        <id>https://moderncppdevops.com/2024/03/04/strats-for-deps</id>
        <link href="https://moderncppdevops.com/2024/03/04/strats-for-deps"/>
        <updated>2024-03-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Streamline your C++ development workflow and ensure long-term project sustainability with effective dependency management. This comprehensive guide delves deeper than just libraries, providing a holistic perspective on the entire toolchain ecosystem and equipping you with practical strategies for success.]]></summary>
        <content type="html"><![CDATA[<p>Streamline your C++ development workflow and ensure long-term project sustainability with effective dependency management. This comprehensive guide delves deeper than just libraries, providing a holistic perspective on the entire toolchain ecosystem and equipping you with practical strategies for success.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="mastering-the-art-of-dependency-management">Mastering the Art of Dependency Management<a href="https://moderncppdevops.com/2024/03/04/strats-for-deps#mastering-the-art-of-dependency-management" class="hash-link" aria-label="Direct link to Mastering the Art of Dependency Management" title="Direct link to Mastering the Art of Dependency Management">​</a></h2>
<p>By following these <strong>industry-proven best practices</strong>, you can establish a robust and sustainable approach to dependency management in your C++ projects:</p>
<ul>
<li><strong>Embrace Version Control and Lockfiles:</strong> Ensure reproducible builds and prevent unexpected behavior by explicitly specifying exact versions of dependencies in your project configuration files and utilizing tools that generate lockfiles to record downloaded versions.</li>
<li><strong>Minimize and Evaluate Dependencies:</strong> Carefully consider alternative approaches or existing libraries before introducing new dependencies to reduce complexity and potential issues. Regularly evaluate your existing dependencies and maintain an up-to-date list with documented justifications for each one.</li>
<li><strong>Strike a Balance with Updates:</strong> Stay informed about updates to your dependencies and address critical security vulnerabilities promptly. However, prioritize stability and avoid frequent updates unless strictly necessary. Focus on updating the fewest number of dependencies possible, prioritizing direct dependencies during development and limiting updates for transitive dependencies to patches addressing vulnerabilities.</li>
<li><strong>Implement Thorough Testing and Documentation:</strong>  Proactively identify and mitigate issues arising from dependency changes by incorporating comprehensive testing strategies that cover functionalities impacted by updates or conflicts. Maintain clear documentation listing all project dependencies and their purpose to aid understanding and future maintenance efforts.</li>
<li><strong>Leverage Artifact Management:</strong> Facilitate version control, sharing, and retrieval of build artifacts (compiled binaries, libraries, packages) across different environments and teams by utilizing a central artifact repository. Implement versioning and tagging schemes within your repository to track changes, identify specific builds, and ensure consistent deployments. Automate artifact publishing and promotion to streamline the workflow and reduce manual intervention.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://moderncppdevops.com/2024/03/04/strats-for-deps#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>Effective dependency management is an ongoing journey, but by embracing the insights and strategies outlined in this comprehensive guide, you can <strong>conquer the C++ dependency landscape</strong> with confidence. Build <strong>resilient and maintainable projects</strong>, <strong>streamline your development process</strong>, and <strong>empower yourself to deliver exceptional C++ applications.</strong></p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Layer by Layer: Navigating C++ Dependencies with Precision]]></title>
        <id>https://moderncppdevops.com/tool-dep-strategies</id>
        <link href="https://moderncppdevops.com/tool-dep-strategies"/>
        <updated>2024-02-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Unlock the secrets of effective C++ dependency management with our comprehensive guide! Delve into the intricate world of system tools, build toolchains, and libraries to optimize your project's functionality, stability, and maintainability. Learn best practices for version control, minimizing dependencies, regular updates, documentation, and testing. Explore real-world examples across different project types, from cross-platform native applications to containerized cloud services and embedded robotic devices. Equip yourself with the knowledge and tools to navigate the dependency landscape with confidence and efficiency.]]></summary>
        <content type="html"><![CDATA[<p>The ever-evolving world of C++ development unlocks incredible possibilities, but one persistent challenge haunts programmers: dependency management. While libraries often steal the spotlight, the true scope of dependencies extends far beyond. It encompasses the entire <strong>toolchain ecosystem</strong>, from the compilers and operating systems used to craft your code for the operating systems where it ultimately executes on.</p>
<p>Imagine building a spacecraft. While the engine is undeniably crucial, neglecting the guidance system, navigation tools, and communication equipment would be disastrous. Similarly, focusing solely on libraries paints an incomplete picture. <strong>Every software tool</strong> you utilize, from the ground up, contributes to the final product's functionality, stability, and maintainability.</p>
<p>This guide delves into the intricate tooling and dependencies, exploring the various categories, offering effective management strategies, and practical examples across diverse project types. By venturing beyond the surface level of libraries, we equip you with the knowledge and tools to navigate the dependency landscape with <strong>confidence and efficiency</strong>, ensuring your C++ projects reach their full potential.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="understanding-the-dependency-landscape">Understanding the Dependency Landscape<a href="https://moderncppdevops.com/tool-dep-strategies#understanding-the-dependency-landscape" class="hash-link" aria-label="Direct link to Understanding the Dependency Landscape" title="Direct link to Understanding the Dependency Landscape">​</a></h3>
<p>Dependencies fall into three broad categories:</p>
<ul>
<li><strong>System Tools:</strong> These are essential tools pre-installed on the development system, like IDEs, compilers, linkers, and debuggers. Operating systems typically manage them. These include tool to help manage the operating systems or integrate with continuous integration services. They are tightly coupled to the runtime environment of the specific platform.</li>
<li><strong>Build Tools:</strong> Build systems like CMake, Make, or Ninja orchestrate the compilation, linking, and packaging of your code. Toolchains like cross-building compilers and linkers, these are specific to the target platform. These tools often have their own dependency requirements, which need to be addressed.</li>
<li><strong>Libraries:</strong> These are pre-written code modules offering functionalities you can integrate into your project from external or internal repositories. Libraries introduce the most complex dependency management challenges, as they can have their own dependencies and versioning requirements.</li>
</ul>
<p>If you have a keen eye you'll notice, arguably the most important tool, compilers comes up twice. Differentiate between system tools and build tools by asking, <em>"Does this tool read the source code?"</em> If the answer is no, it's likely a system tool. Conversely, an affirmative response suggests a build tool.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="best-practices-for-effective-dependency-management">Best Practices for Effective Dependency Management<a href="https://moderncppdevops.com/tool-dep-strategies#best-practices-for-effective-dependency-management" class="hash-link" aria-label="Direct link to Best Practices for Effective Dependency Management" title="Direct link to Best Practices for Effective Dependency Management">​</a></h2>
<p>Regardless of the type of dependency (system tool, build tool, or library), adhering to these <a href="https://cloud.google.com/blog/topics/developers-practitioners/best-practices-dependency-management" target="_blank" rel="noopener noreferrer">best practices</a> can ensure a smooth and efficient development process:</p>
<p><strong>1. Version Control:</strong></p>
<ul>
<li><strong>Version pin your dependencies:</strong> Explicitly <a href="https://tss-yonder.com/insights/best-practices-for-dependency-management" target="_blank" rel="noopener noreferrer">specify the exact version</a> of each dependency in your project configuration files. This ensures reproducibility and prevents unexpected behavior due to dependency updates.</li>
<li><strong>Utilize lock files:</strong> Leverage tools that generate lock files to record downloaded dependency versions. Commit these files to version control, ensuring everyone uses the same versions. Use lockfile to identify reusable caches or using clean install.</li>
</ul>
<p><strong>2. Minimize Dependencies:</strong></p>
<ul>
<li><strong>Evaluate dependencies carefully:</strong> Before introducing a new dependency, consider alternative approaches or existing libraries that might fulfill your needs. <a href="https://hackernoon.com/selecting-the-right-dependencies-a-comprehensive-practical-guide" target="_blank" rel="noopener noreferrer">Guides are plentiful on this subject</a>.</li>
<li><strong>Remove outdated dependencies:</strong> Maintain an up-to-date list with documented justifications for each dependency to minimize potential issues and reduce overhead.</li>
</ul>
<p><strong>3. Regular Updates:</strong></p>
<ul>
<li><strong>Stay informed about updates:</strong> Automate checking for updates to your dependencies. Address critical security vulnerabilities promptly by upgrading to patched versions.</li>
<li><strong>Balance updates with stability:</strong> While staying <a href="https://stackoverflow.com/a/23922505" target="_blank" rel="noopener noreferrer">updated is essential</a>, avoid frequent updates unless strictly necessary. Evaluate the potential impact of updates on your project's stability and functionality before upgrading.</li>
<li><strong>Minimize the amount of changes you introduce:</strong> Updating the pinned version of one or the fewest number of dependencies. Focus on updating direct dependencies during development and only limit updates for transitives to patches when they address vulnerabilities.</li>
</ul>
<p><strong>4. Documentation and Testing:</strong></p>
<ul>
<li><strong>Document your dependencies:</strong> Maintain clear documentation listing all project direct dependencies and their purpose to aid understanding and future maintenance.</li>
<li><strong>Thorough testing:</strong> Implement comprehensive testing strategies that cover functionalities impacted by dependencies. This helps identify potential issues arising from dependency updates or conflicts.</li>
</ul>
<p><strong>5. Integrate Artifact Management:</strong></p>
<ul>
<li><strong>Utilize artifact repositories:</strong> <a href="https://codefresh.io/blog/enterprise-ci-cd-best-practices-part-1/" target="_blank" rel="noopener noreferrer">Store and manage build artifacts</a> (compiled binaries, libraries, packages) in a central repository. This facilitates version control, sharing, and retrieval of artifacts across different environments and teams.</li>
<li><strong>Implement versioning and tagging:</strong> Employ <a href="https://devops.stackexchange.com/a/4732" target="_blank" rel="noopener noreferrer">versioning and tagging</a> schemes within your artifact repository to track changes, identify specific builds, and ensure consistent deployments. Internal engineering versions do not need to be the marketing or product.</li>
<li><strong>Automate artifact publishing and promotion:</strong> Integrate your build process with the artifact repository to automatically <a href="https://stackoverflow.com/a/56670350" target="_blank" rel="noopener noreferrer">publish generated artifacts upon successful builds</a>. This streamlines the workflow and reduces manual intervention.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="examples-for-different-project-types">Examples for Different Project Types<a href="https://moderncppdevops.com/tool-dep-strategies#examples-for-different-project-types" class="hash-link" aria-label="Direct link to Examples for Different Project Types" title="Direct link to Examples for Different Project Types">​</a></h2>
<p>Going back to our minimizing dependencies, identifying which layers are more tightly coupled and can use the same tool and process is important. The goal should be enable agility, layers which are updated at drastically different frequents that are not cohesive should be separated.</p>
<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Industry Specific Vocabulary</div><div class="admonitionContent_BuS1"><p>Depending on the industry you've worked in or the your preferred tooling stack - you might have slightly different definitions. The best example of this is <a href="https://www.gnu.org/software/autoconf/manual/autoconf-2.68/html_node/Specifying-Target-Triplets.html" target="_blank" rel="noopener noreferrer">GNU</a> and <a href="https://bazel.build/extending/platforms" target="_blank" rel="noopener noreferrer">Bazel</a> have contradictory definitions for host, build/execute, and target. I picked language which would appeal to the largest audience.</p></div></div>
<p>To illustrate these concepts, let's explore how dependency management can be segmented across hypothetical projects:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="cross-platform-native-application">Cross-Platform Native Application<a href="https://moderncppdevops.com/tool-dep-strategies#cross-platform-native-application" class="hash-link" aria-label="Direct link to Cross-Platform Native Application" title="Direct link to Cross-Platform Native Application">​</a></h3>
<p>Think desktop applications or audio add-in card SDKs. These are often closely tied to the operating system, so compilers and toolchains are managed as system tools. Upgrading the compiler might require compiling it for older operating systems. Build environments are provisioned to reflect the product's lifecycle. Libraries, decoupled from this layer, are tied to the source code with exact versions for consistency. Strong caching solutions can effectively eliminate overhead from frequent library updates.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="containerized-cloud-service">Containerized Cloud Service<a href="https://moderncppdevops.com/tool-dep-strategies#containerized-cloud-service" class="hash-link" aria-label="Direct link to Containerized Cloud Service" title="Direct link to Containerized Cloud Service">​</a></h3>
<p>Consider microservices handling concurrent client connections with high read workloads. System tools depend on the developer's hardware, offering more flexibility for local development IDEs and compilers. These system tools might be managed ad hoc, with team specific instructions. However, container runtime versions have stricter requirements, often using exact runtime images to reproduce production environments. Toolchains can be managed as build tools for more flexibility. Providing build images that extend the runtime ones with the necessary build tools and libraries can serve as an effective caching strategy.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="embedded-robotic-device">Embedded Robotic Device<a href="https://moderncppdevops.com/tool-dep-strategies#embedded-robotic-device" class="hash-link" aria-label="Direct link to Embedded Robotic Device" title="Direct link to Embedded Robotic Device">​</a></h3>
<p>Imagine an extraterrestrial exploration unit comprising heterogeneous hardware architectures, from bare metal to micro-controllers and real-time operating systems, often sharing large communication dependencies. Dedicated cross-compilers and build toolchains are needed for various target platforms, and multiple binary library instances must be organized. These are often tightly coupled and managed together. This will manifest as dedicated build systems with coupled tooling and a separate platform agnostic library management.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://moderncppdevops.com/tool-dep-strategies#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>Effective dependency management is an ongoing practice, requiring constant evaluation and adaptation. By following these best practices, you can establish a robust and sustainable approach to dependency and artifact management, fostering a more streamlined development workflow, ensuring long-term reproducibility, and simplifying collaboration across teams. Remember, the key lies in striking a balance between leveraging existing functionalities and maintaining control over your project's footprint and complexity.</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="c++ development" term="c++ development"/>
        <category label="devops" term="devops"/>
        <category label="dependency management" term="dependency management"/>
        <category label="system tools" term="system tools"/>
        <category label="build toolchains" term="build toolchains"/>
        <category label="libraries" term="libraries"/>
        <category label="c++ projects" term="c++ projects"/>
        <category label="dependency strategies" term="dependency strategies"/>
        <category label="dependency best practices" term="dependency best practices"/>
        <category label="version control" term="version control"/>
        <category label="minimizing dependencies" term="minimizing dependencies"/>
        <category label="regular updates" term="regular updates"/>
        <category label="documentation" term="documentation"/>
        <category label="testing strategies" term="testing strategies"/>
        <category label="artifact management" term="artifact management"/>
        <category label="cross-platform development" term="cross-platform development"/>
        <category label="containerized cloud services" term="containerized cloud services"/>
        <category label="embedded systems" term="embedded systems"/>
        <category label="development workflow" term="development workflow"/>
        <category label="software engineering" term="software engineering"/>
        <category label="programming best practices" term="programming best practices"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[DevOps Is Software Engineering for Your Builds]]></title>
        <id>https://moderncppdevops.com/soeng-for-builds</id>
        <link href="https://moderncppdevops.com/soeng-for-builds"/>
        <updated>2024-02-19T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Battling manual builds and dependency nightmares in C++? Consider a dedicated DevOps role on your team! This post explores how a skilled DevOps engineer, often misunderstood in the C++ community, can revolutionize your workflow. Imagine your developers focused on crafting robust code while a dedicated pro automates builds, manages dependencies, and implements CI/CD for faster releases. But it's not just tools – a DevOps expert bridges the dev-ops gap, navigates the C++ ecosystem like a pro, and automates repetitive tasks with mastery. This translates to efficiency, reliability, and happier developers. Ready to unlock your C++ team's potential? Dive in, explore the possibilities, and join the discussion on shaping the future of C++ development together!]]></summary>
        <content type="html"><![CDATA[<p>C++ developers often approach DevOps with a reasonable degree of skepticism, and it's not without reason. Their top five challenges revolve around build scripts, dependency management, and setting up CI pipelines—areas traditionally associated with DevOps responsibilities. <a href="https://www.linkedin.com/in/mxymitoulias/" target="_blank" rel="noopener noreferrer">Michael Xymitoulias</a> articulated this sentiment well in a recent <a href="https://www.linkedin.com/posts/mxymitoulias_cpp-cppprogramming-devops-activity-7159324126099193856-oUP3" target="_blank" rel="noopener noreferrer">LinkedIn post</a> writing:</p>
<blockquote>
<p><em>Right now, it feels that C++ developers have to deal with way more than just writing business logic code. [...] Allowing devs to focus more on coding rather than trying to solve problems of the ecosystem would probably be liberating</em></p>
</blockquote>
<p>Xymitoulias suggestion that allowing developers to focus more on coding, rather than grappling with ecosystem problems, would be liberating. He's not alone, <a href="https://www.linkedin.com/feed/update/urn:li:activity:7159324126099193856?commentUrn=urn%3Ali%3Acomment%3A%28activity%3A7159324126099193856%2C7159438503947161600%29&amp;replyUrn=urn%3Ali%3Acomment%3A%28activity%3A7159324126099193856%2C7160306517584359426%29&amp;dashCommentUrn=urn%3Ali%3Afsd_comment%3A%287159438503947161600%2Curn%3Ali%3Aactivity%3A7159324126099193856%29&amp;dashReplyUrn=urn%3Ali%3Afsd_comment%3A%287160306517584359426%2Curn%3Ali%3Aactivity%3A7159324126099193856%29" target="_blank" rel="noopener noreferrer">Bill Hoffman, CTO behind CMake</a> supports this ideal of simplifying the developer workflows, something we've seen put in place with recent improvements to the popular build system.</p>
<p>While building in C++ certainly comes with its challenges, streamlining this process is our collective goal. So, let's delve into the core focus as it relates to C++ and dispel some common misconceptions.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="learning-from-the-past">Learning from the Past<a href="https://moderncppdevops.com/soeng-for-builds#learning-from-the-past" class="hash-link" aria-label="Direct link to Learning from the Past" title="Direct link to Learning from the Past">​</a></h2>
<p>These ideas have been circulating for quite some time.</p>
<blockquote>
<p><em>All aspects of software production Software engineering is not just concerned with the technical processes of software development but also with activities such as software project management and with the development of tools, methods and theories to support software production.</em>
"1.1.2 What is software engineering?" - Software Engineering (8th ed.) ISBN 978-0-321-31379-9</p>
</blockquote>
<p>This quote, from a book <a href="https://www.abebooks.com/9780201137958/Software-engineering-International-computer-science-020113795X/plp" target="_blank" rel="noopener noreferrer">originally published in 1982</a>, highlights the broader scope of software engineering, encompassing not only technical development but also project management and the development of tools and theories supporting software production.</p>
<p>Yet, expecting individuals to be experts in every tool, method, and theory is unrealistic. The diversity of modern software tooling and platforms necessitates specialized team members with technical skills and a passion for these tools. A Software Engineering team should consist of various roles catering to different aspects of the development process.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="applying-devops-in-c-development">Applying DevOps in C++ Development<a href="https://moderncppdevops.com/soeng-for-builds#applying-devops-in-c-development" class="hash-link" aria-label="Direct link to Applying DevOps in C++ Development" title="Direct link to Applying DevOps in C++ Development">​</a></h2>
<p>Diego Rodriguez-Losada, the lead architect and co-found of Conan, one of the leading C++ package managers, presented the idea <a href="https://youtu.be/NM-xp3tob2Q?t=2367" target="_blank" rel="noopener noreferrer">DevOps is dependency and package management over time</a> in his 2022 CppCon presentation. I would open that up to include not just the toolchains and libraries you use but the infrastructure which supports the builds. This quote, succinctly captures the question and motivation for doing this.</p>
<blockquote>
<p><em>We propose that "software engineering" encompasses not just the act of writing code, but all of the tools and processes an organization uses to build and maintain that code over time. What practices can a software organization introduce that will best keep its code valuable over the long term? How can engineers make a codebase more sustainable and the software engineering discipline itself more rigorous?</em>
"Programming Over Time." Software Engineering at Google (2020). ISBN 978-1-492-08279-8</p>
</blockquote>
<p>As a DevOps Engineer, the aim is to support Software Engineering activities past, present and future, which for C++ include:</p>
<ul>
<li><strong>Managing build environments</strong>: This involves detailing the contents, deployment methods, and update schedules of build environments. Infrastructure as code ensures repeatability and reliability, while versioning and storage solutions contribute to longevity. There are numerous tools for <a href="https://en.wikipedia.org/wiki/Deployment_environment" target="_blank" rel="noopener noreferrer">deployment environment</a> and this is just an extension of those best practices.</li>
<li><strong>Supporting building and testing</strong>: This entails encapsulating build scripts from the environment, enabling their reuse as environments evolve. Binary management ensures that assets generated by builds are captured and saved for reuse, ensuring consistency from development to production.</li>
<li><strong>Releasing and shipping to production</strong>: This outlines translating internal engineering versions into business-level products, ready for deployment in assembly lines or cloud environments. Each product will be unique just as the target architectures they are compiled for.</li>
</ul>
<p>This amalgamation constitutes the Software Development Lifecycle (SDLC), with <a href="https://slsa.dev/" target="_blank" rel="noopener noreferrer">security being a top priority</a> though out. Strong collaboration among team members with diverse skills ensures that developers can focus on implementing product features, while DevOps practices uphold the integrity and reliability of the software.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="demystifying-devops">Demystifying DevOps<a href="https://moderncppdevops.com/soeng-for-builds#demystifying-devops" class="hash-link" aria-label="Direct link to Demystifying DevOps" title="Direct link to Demystifying DevOps">​</a></h2>
<div class="theme-admonition theme-admonition-danger admonition_xJq3 alert alert--danger"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"></path></svg></span>Opinion</div><div class="admonitionContent_BuS1"><p>This section is a small rant. <a href="https://twitter.com/intent/tweet?text=%F0%9F%8C%B6%EF%B8%8F%20%40prince_chrismc%20here%20is%20my%20take" target="_blank" rel="noopener noreferrer">@me</a> on social media for discussion!</p></div></div>
<p>While <a href="https://www.linkedin.com/feed/update/urn:li:activity:7159324126099193856?commentUrn=urn%3Ali%3Acomment%3A%28activity%3A7159324126099193856%2C7159438503947161600%29&amp;dashCommentUrn=urn%3Ali%3Afsd_comment%3A%287159438503947161600%2Curn%3Ali%3Aactivity%3A7159324126099193856%29" target="_blank" rel="noopener noreferrer">criticism</a> of a <em>"fragile hodgepodge system of jerry-rigged things that were never intended to work together"</em> resonates with many in the C++ community, I'd argue that is a bias based on the fragmentation within the ecosystem. It's essential to broaden our perspectives before drawing conclusions.</p>
<p>In many ecosystems, building projects is trivial, with straightforward commands like <code>cargo build</code>, <code>npm build</code>, or <code>maven build</code>. This is why we only hear about CI/CD with no "continuous building" concept which is completely skipped over. Once the challenge of building applications at scale for numerous developers multiple times a day is overcome, it becomes less of a focal point at conferences. This is why <code>cmake --build --preset release</code> is a huge step in the <a href="https://moderncppdevops.com/simple-ci-with-presets">right direction</a>.</p>
<p>So maybe it is understandable to see the remark <em>"DevOps has such a full stack vibe about it"</em>? Not really, <a href="https://www.mongodb.com/languages/full-stack-development" target="_blank" rel="noopener noreferrer">fullstack means something completely different</a>. <strong>DevOps is a bridging the gap between IT Operations and Software Development</strong>. Contrary to beliefs that C++ is excluded from this paradigm, various tools and platforms support C++ development within the DevOps framework. GitHub Actions and Azure DevOps platoformns have support for less common toolchains like <a href="https://www.msys2.org/docs/ci/" target="_blank" rel="noopener noreferrer">MSYS2/Mingw-64</a>. <a href="https://about.gitlab.com/blog/2020/03/31/conan-c-cpp-package-management-integration/" target="_blank" rel="noopener noreferrer">GitLab</a> and <a href="https://docs.gitea.com/usage/packages/conan" target="_blank" rel="noopener noreferrer">Gitea</a> have <a href="https://about.gitlab.com/blog/2020/03/31/conan-c-cpp-package-management-integration/" target="_blank" rel="noopener noreferrer">integrations for Conan packages</a>. Jenkins has been used for <a href="https://www.jenkins.io/blog/2017/07/07/jenkins-conan/" target="_blank" rel="noopener noreferrer">C++ CI/CD for many years</a> and helped pioneer concepts like <a href="https://www.techtarget.com/searchsoftwarequality/definition/pipeline-as-code" target="_blank" rel="noopener noreferrer">Pipelines as Code</a>.</p>
<p>Comments like "neverending fighting non-coding related bugs is fun but only from devops perspectives" miss the mark. A strong DevOps Engineer possesses knowledge of <a href="https://www.redhat.com/en/topics/automation/what-is-infrastructure-as-code-iac" target="_blank" rel="noopener noreferrer">Infrastructure as Code</a>, enabling them to develop well-designed applications compatible with distributed systems and third-party services. Learning <a href="https://developer.hashicorp.com/terraform/language/syntax/configuration" target="_blank" rel="noopener noreferrer">HCL for Terraform</a>, <a href="https://www.hashicorp.com/blog/writing-custom-terraform-providers" target="_blank" rel="noopener noreferrer">extending it with Golang</a>, and <a href="https://developer.hashicorp.com/terraform/language/tests" target="_blank" rel="noopener noreferrer">developing test</a> are absolutely fundamental just like any robust software stack. It's no different then developing on top of <a href="https://stackoverflow.com/a/55652158" target="_blank" rel="noopener noreferrer">Boost.Asio</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="ecosystem-and-evolution">Ecosystem and Evolution<a href="https://moderncppdevops.com/soeng-for-builds#ecosystem-and-evolution" class="hash-link" aria-label="Direct link to Ecosystem and Evolution" title="Direct link to Ecosystem and Evolution">​</a></h2>
<p>To put it all into perspective, as a C++ developer, grappling with tedious build processes and platform-dependent multithreading complexities is a familiar struggle. However, embracing DevOps principles can alleviate these challenges, allowing developers to focus on crafting robust and efficient code.</p>
<p>In Xymitoulias post, Hoffman wrote:</p>
<blockquote>
<p><em>It is all about creating an environment where C++ developers can focus on code and have the DevOps happen for them.</em></p>
</blockquote>
<p>And I think that's the perfect place to aim for.</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="c++ development" term="c++ development"/>
        <category label="devops" term="devops"/>
        <category label="build automation" term="build automation"/>
        <category label="dependency management" term="dependency management"/>
        <category label="ci/cd" term="ci/cd"/>
        <category label="software engineering" term="software engineering"/>
        <category label="best practices" term="best practices"/>
        <category label="tools" term="tools"/>
        <category label="platforms" term="platforms"/>
        <category label="collaboration" term="collaboration"/>
        <category label="efficiency" term="efficiency"/>
        <category label="reliability" term="reliability"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[C++ Package Managers: The Ultimate Roundup]]></title>
        <id>https://moderncppdevops.com/pkg-mngr-roundup</id>
        <link href="https://moderncppdevops.com/pkg-mngr-roundup"/>
        <updated>2024-02-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Struggling with C++ dependencies and intricate build scripts? The landscape of C++ package managers has evolved significantly, offering powerful tools to streamline your workflow. Dive deeper in this comprehensive roundup! Explore popular options like vcpkg, Conan, Spack, and others, highlighting their strengths, weaknesses, and ideal use cases. Emerging contenders discover innovative tools like Xrepo and Tipi.Build. Learn how to select the best package manager for your specific project needs.]]></summary>
        <content type="html"><![CDATA[<p>C++'s journey with dependency management has seen numerous transformations. Early years were marked by manual library integration and complex build scripts, presenting significant challenges. However, the landscape has since evolved, offering an array of sophisticated package managers designed to streamline workflows but most of all reduce the burden on developers.</p>
<p>Join in and delve into the strengths and weaknesses of these diverse solutions, empowering you to make informed choices and conquer the challenge of dependency management in your C++ endeavors.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="comprehensive-list-of-c-package-managers-strengths-and-weaknesses">Comprehensive List of C++ Package Managers: Strengths and Weaknesses<a href="https://moderncppdevops.com/pkg-mngr-roundup#comprehensive-list-of-c-package-managers-strengths-and-weaknesses" class="hash-link" aria-label="Direct link to Comprehensive List of C++ Package Managers: Strengths and Weaknesses" title="Direct link to Comprehensive List of C++ Package Managers: Strengths and Weaknesses">​</a></h2>
<p>To help you navigate this diverse landscape, let's explore a <em>consolidated overview</em> of popular tools used as C++ package managers, highlighting their strengths and weaknesses along the way. This list is in <strong>relevance</strong> order, based on factors like how well it works as a package manager and how prominent is it in the ecosystem.</p>
<p>This list provides a snapshot of the evolving C++ package management landscape, but the journey doesn't end here! More feedback is needed. Have you tried any of these solutions? Are there hidden gems missing? Feel like the order is wrong? Share your experiences and recommendations in the comments on social media.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-vcpkg">1. vcpkg<a href="https://moderncppdevops.com/pkg-mngr-roundup#1-vcpkg" class="hash-link" aria-label="Direct link to 1. vcpkg" title="Direct link to 1. vcpkg">​</a></h3>
<p>Vcpkg is a cross-platform package manager for C and C++ libraries, simplifying dependency acquisition and management on Windows, Linux, and macOS. Developed by Microsoft, it offers a comprehensive catalog of libraries which can be built locally, seamless integration with popular development environments, and straightforward command-line usage.</p>
<p>Tutorial Video: <a href="https://youtu.be/Ae9EePOIouU?si=fbiY7aOiAag0MCRk" target="_blank" rel="noopener noreferrer">link</a></p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Large and growing repository of libraries</li>
<li>Easy to use</li>
<li>Integrates well with <a href="https://devblogs.microsoft.com/cppblog/vcpkg-is-now-included-with-visual-studio/" target="_blank" rel="noopener noreferrer">Visual Studio</a></li>
<li>Good support for Windows development</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Primarily focused on open-source libraries</li>
<li>Limited support for custom build configurations</li>
<li>Requires rebuild all dependencies are every machine</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-conan">2. Conan<a href="https://moderncppdevops.com/pkg-mngr-roundup#2-conan" class="hash-link" aria-label="Direct link to 2. Conan" title="Direct link to 2. Conan">​</a></h3>
<p>Conan is a powerful and flexible C and C++ package manager designed to simplify dependency management across different platforms and build systems. With Conan, developers can easily declare, install, and manage dependencies for their projects, ensuring seamless integration of third-party libraries without the hassle of manual configuration. Offering support for both public and private package repositories, Conan facilitates efficient dependency resolution, versioning, and package reuse, empowering developers to streamline their C and C++ development workflows with ease.</p>
<p>Tutorial Video: <a href="https://youtu.be/T-5t9de1XyI?si=mRsi_Y-tnuPIsLUM" target="_blank" rel="noopener noreferrer">link</a></p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Large and growing repository of libraries</li>
<li>Flexible and powerful <a href="https://blog.conan.io/2023/11/28/Conan-new-features-2-0-14.html" target="_blank" rel="noopener noreferrer">enterprise features</a></li>
<li>Supports both binary and source-based packages</li>
<li>Can manage custom build configurations</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Steeper learning curve than others for medium sized projects</li>
<li>Requires more explicit package information</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="3-xrepo">3. Xrepo<a href="https://moderncppdevops.com/pkg-mngr-roundup#3-xrepo" class="hash-link" aria-label="Direct link to 3. Xrepo" title="Direct link to 3. Xrepo">​</a></h3>
<p>Xmake/Xrepo, is a modern and cross-platform build system designed for efficiently compiling and managing C, C++, and other programming language projects. With a focus on simplicity, flexibility, and speed, xmake simplifies the build process by providing an intuitive Lua-based configuration file that allows developers to describe their project's build requirements and dependencies concisely.</p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Designed for cross-platform development</li>
<li>Supports add-ons for more build systems</li>
<li>Can manage <a href="https://xmake.io/#/manual/custom_toolchain" target="_blank" rel="noopener noreferrer">build configurations</a></li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Relatively new and less mature than some other options</li>
<li>Smaller community and ecosystem</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="4-spack">4. Spack<a href="https://moderncppdevops.com/pkg-mngr-roundup#4-spack" class="hash-link" aria-label="Direct link to 4. Spack" title="Direct link to 4. Spack">​</a></h3>
<p>Spack is a package manager for scientific computing and HPC environments, enabling software installation and management across various architectures and compilers, enabling reproducibility and efficient collaboration in research and computational workflows.</p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Excellent for scientific computing and high-performance computing (HPC)</li>
<li>Supports a wide range of compilers and <a href="https://spack.readthedocs.io/en/latest/build_systems.html" target="_blank" rel="noopener noreferrer">build systems</a></li>
<li>Can manage complex dependencies</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Can be challenging to set up and use</li>
<li>Not as well-suited for general-purpose development</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="5-hunter">5. Hunter<a href="https://moderncppdevops.com/pkg-mngr-roundup#5-hunter" class="hash-link" aria-label="Direct link to 5. Hunter" title="Direct link to 5. Hunter">​</a></h3>
<p>Hunter is a CMake-driven package manager for C and C++ projects, providing a simplified way to manage dependencies and integrate them into the build process, facilitating efficient development and collaboration in C++ projects.</p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Simple and easy to use</li>
<li>Good for finding and installing specific libraries</li>
<li>Integrates well with CMake</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Requires heavily <a href="https://hunter.readthedocs.io/en/latest/quick-start/simple.html" target="_blank" rel="noopener noreferrer">modifying build scripts</a> to add support</li>
<li>Smaller repository of libraries</li>
<li>Not as flexible for managing complex dependencies</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="6-cpm">6. CPM<a href="https://moderncppdevops.com/pkg-mngr-roundup#6-cpm" class="hash-link" aria-label="Direct link to 6. CPM" title="Direct link to 6. CPM">​</a></h3>
<p>CPM (CMake Package Manager) is a lightweight package manager integrated withing your project's <code>CMakeLists.txt</code>, enabling simplified dependency management and seamless integration of external libraries into C++ projects.</p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Designed for simplicity and ease of use</li>
<li>Good for managing dependencies in small to medium-sized projects</li>
<li>Integrates well with CMake</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Smaller repository of libraries</li>
<li>Requires <a href="https://github.com/cpm-cmake/CPM.cmake/wiki/More-Snippets#rang" target="_blank" rel="noopener noreferrer">heavily modifying build scripts</a></li>
<li>Not as flexible as Conan for managing complex dependencies</li>
<li>Very little active or development taking place</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="build-systems-and-environment-managers">Build Systems and Environment Managers<a href="https://moderncppdevops.com/pkg-mngr-roundup#build-systems-and-environment-managers" class="hash-link" aria-label="Direct link to Build Systems and Environment Managers" title="Direct link to Build Systems and Environment Managers">​</a></h2>
<p>These tools are doing double duty.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="7-meson">7. Meson<a href="https://moderncppdevops.com/pkg-mngr-roundup#7-meson" class="hash-link" aria-label="Direct link to 7. Meson" title="Direct link to 7. Meson">​</a></h3>
<p>Meson is a fast and user-friendly build system designed for efficiently compiling and managing C, C++, and other programming language projects, offering simplicity, speed, and cross-platform support for streamlined development workflows.</p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Fast and efficient</li>
<li>Good for managing build systems</li>
<li>Can be used with other <a href="https://mesonbuild.com/Dependencies.html#dependency-detection-method" target="_blank" rel="noopener noreferrer">package managers and build systems</a></li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Not primarily a package manager, but rather a build system</li>
<li>Requires more configuration than some other options</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="8-bazel">8. Bazel<a href="https://moderncppdevops.com/pkg-mngr-roundup#8-bazel" class="hash-link" aria-label="Direct link to 8. Bazel" title="Direct link to 8. Bazel">​</a></h3>
<p>Bazel can be a powerful and scalable build system developed by Google, supporting multiple programming languages including C++ and providing correctness, reproducibility, and speed for large-scale software projects.</p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Very powerful and flexible</li>
<li>Can manage large and complex projects</li>
<li>Good for distributed builds</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li><a href="https://bazel.build/tutorials/cpp-use-cases#run-c-tests" target="_blank" rel="noopener noreferrer">Steep learning curve</a></li>
<li>Can be overkill for small projects</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="9-nixos">9. NixOS<a href="https://moderncppdevops.com/pkg-mngr-roundup#9-nixos" class="hash-link" aria-label="Direct link to 9. NixOS" title="Direct link to 9. NixOS">​</a></h3>
<p>The Nix package manager is a powerful and purely functional package manager used in NixOS and other Linux distributions. It enables users to manage software packages and configurations in a reproducible and isolated manner, facilitating atomic upgrades and rollbacks.</p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Purely functional package management with atomic upgrades.</li>
<li>Reproducible builds across environments.</li>
<li>Declarative system configuration and package management.</li>
<li>Security focus with isolated package environments.</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Steep learning curve due to functional paradigm.</li>
<li>Less platform with smaller community.</li>
<li>Package selection might be less concentrated than dedicated managers.</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="10-build2">10. Build2<a href="https://moderncppdevops.com/pkg-mngr-roundup#10-build2" class="hash-link" aria-label="Direct link to 10. Build2" title="Direct link to 10. Build2">​</a></h3>
<p>Build2 is a modern and efficient build system designed for C and C++ projects, offering simplicity, scalability, and reliability for managing dependencies and building software.</p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Covers the entire project lifecycle: creation, development, testing, and delivery.</li>
<li>Aims to rebuild the C++ ecosystem with modern build principles.</li>
<li>Uniform and consistent interface across platforms and compilers.</li>
</ul>
</li>
<li><strong>weaknesses:</strong>
<ul>
<li>Relatively <a href="https://cppget.org/" target="_blank" rel="noopener noreferrer">new feature for dependency management</a></li>
<li>Smaller community and ecosystem compared to established tools.</li>
<li>Might require more configuration and scripting knowledge to fully utilize.</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="11-scons">11. SCons<a href="https://moderncppdevops.com/pkg-mngr-roundup#11-scons" class="hash-link" aria-label="Direct link to 11. SCons" title="Direct link to 11. SCons">​</a></h3>
<p>SCons is a software construction tool written in Python, providing a flexible and customizable build system for C and C++ projects, emphasizing simplicity and ease of use for managing project builds effectively.</p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Good for managing build systems</li>
<li>Can be used with other package managers like Conan</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Not primarily a package manager, but rather a build system</li>
<li>Requires more configuration than some other options</li>
<li>Dependency management is an add-on wrapper</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="12-tipibuild">12. Tipi.Build<a href="https://moderncppdevops.com/pkg-mngr-roundup#12-tipibuild" class="hash-link" aria-label="Direct link to 12. Tipi.Build" title="Direct link to 12. Tipi.Build">​</a></h3>
<p>Tipi.build is a versatile and customizable build system for C++ projects, designed with simplicity and flexibility in mind, offering efficient cloud based workflows.</p>
<p>Tutorial Video: <a href="https://youtu.be/cxNDmugjlFk?si=fUnr7I73CTHWVZeJ" target="_blank" rel="noopener noreferrer">link</a></p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Cloud based build distribution with caching</li>
<li>Aims to rebuild the C++ ecosystem with modern build principles.</li>
<li>Supports re-using pre compiled binaries</li>
</ul>
</li>
<li><strong>weaknesses:</strong>
<ul>
<li>Relatively new and less mature compared to some options.</li>
<li>Smaller community and ecosystem compared to established tools.</li>
<li>Might require more configuration and scripting knowledge to fully utilize.</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="13-soupbuild">13. SoupBuild<a href="https://moderncppdevops.com/pkg-mngr-roundup#13-soupbuild" class="hash-link" aria-label="Direct link to 13. SoupBuild" title="Direct link to 13. SoupBuild">​</a></h3>
<p>SoupBuild is a distributed build system with an almost no compatibility definition. This is similar to Bazel land Vcpkg respectively - both combined into a cargo inspired build tool chain.</p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Defines to ABI compatibility</li>
<li>Rebuilds from source and distributes builds</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Limit support for different toolchains</li>
<li>Very opinionated</li>
<li>Only in Alpha preview</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="14-pixi-prefix-dev">14. Pixi (prefix-dev)<a href="https://moderncppdevops.com/pkg-mngr-roundup#14-pixi-prefix-dev" class="hash-link" aria-label="Direct link to 14. Pixi (prefix-dev)" title="Direct link to 14. Pixi (prefix-dev)">​</a></h3>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Simplified experience with a Cargo-like CLI.</li>
<li>Multi-language support within projects.</li>
<li>Project-specific environments and automatic lockfiles.</li>
<li>Built on conda's package ecosystem.</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Newer and less mature with a smaller community and ecosystem.</li>
<li>Limited C++ package selection compared to dedicated managers.</li>
<li>Potential complexity due to multi-language management.</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="15-mamba">15. Mamba<a href="https://moderncppdevops.com/pkg-mngr-roundup#15-mamba" class="hash-link" aria-label="Direct link to 15. Mamba" title="Direct link to 15. Mamba">​</a></h3>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Reimplementation of conda optimized for speed</li>
<li>Built-on existing dependency resolver implementation</li>
<li>Lightweight client with a core subset of features for ease-of-use</li>
<li>Built on conda's package ecosystem</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Newer and less mature with a smaller community and ecosystem</li>
<li>Limited C++ package selection compared to dedicated managers</li>
<li>Might introduce challenges with standard C++ build systems and tools</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="16-gradle">16. Gradle<a href="https://moderncppdevops.com/pkg-mngr-roundup#16-gradle" class="hash-link" aria-label="Direct link to 16. Gradle" title="Direct link to 16. Gradle">​</a></h3>
<p><a href="https://gradle.org/" target="_blank" rel="noopener noreferrer">Gradle</a> is a build automation tool known for its flexibility and scalability, primarily used for Java projects but also supporting other languages like C++ through plugins. It handles dependency management, compilation, testing, and packaging of software.</p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Proven at managing complex build systems with a variety of dependencies, including C++.</li>
<li>Designed for cross-platform development</li>
<li>Integration with Java and other ecosystems</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Not primarily a C++ package manager</li>
<li>Limited package repository limited. While plugins like Gradle CppPlugin and CMakePlugin exist, the C++ package repository is not as extensive as dedicated managers.</li>
<li>Steeper learning curve compared to some C++-specific tools.</li>
<li>Performance overhead for simple C++ projects</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="17-conda">17. Conda<a href="https://moderncppdevops.com/pkg-mngr-roundup#17-conda" class="hash-link" aria-label="Direct link to 17. Conda" title="Direct link to 17. Conda">​</a></h3>
<p><a href="https://docs.conda.io/en/latest/" target="_blank" rel="noopener noreferrer">Conda</a> is a versatile package manager and environment management system primarily used for Python, but it also supports other languages like C++ and R. It simplifies dependency management and enables easy creation, sharing, and reproduction of software environments across different platforms.</p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Mature and established with a vast package ecosystem across various languages.</li>
<li>Cross-platform compatibility.</li>
<li>Flexible environment management for projects or systems.</li>
<li>Powerful dependency management for complex scenarios.</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Steeper learning curve compared to simpler tools like Hunter or CPM.</li>
<li>Not primarily designed for C++ development, requiring additional setup for C++ packages.</li>
<li>C++ package selection might be smaller than dedicated C++ package managers.</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="18-bitbake">18. BitBake<a href="https://moderncppdevops.com/pkg-mngr-roundup#18-bitbake" class="hash-link" aria-label="Direct link to 18. BitBake" title="Direct link to 18. BitBake">​</a></h3>
<p>The Yocto project's <a href="https://docs.yoctoproject.org/bitbake/dev/index.html" target="_blank" rel="noopener noreferrer">BitBake</a> is a complete embedded Linux system creation environment. BitBake is the build tool used within Yocto to manage the entire build process, including compiling source code, packaging software, and creating a final operating system image for your target device.</p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Streamlined workflow within Yocto Project, managing dependencies from source to final image.</li>
<li>Ensures consistent builds by meticulously controlling package versions within Yocto configuration.</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Primarily designed for Yocto Project and embedded development, less suitable for general C/C++ projects.</li>
<li>Relies heavily on building dependencies from source, potentially time-consuming.</li>
<li>Managing dependencies within Yocto recipes can be complex for beginners.</li>
<li>Version constraints compared to some package managers.</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="19-cmakes-fetchcontent">19. CMake's FetchContent<a href="https://moderncppdevops.com/pkg-mngr-roundup#19-cmakes-fetchcontent" class="hash-link" aria-label="Direct link to 19. CMake's FetchContent" title="Direct link to 19. CMake's FetchContent">​</a></h3>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Seamless integration avoids external tools and complexity.</li>
<li>Supports various download methods (git, archives, etc.) and allows customization.</li>
<li>Enables consuming content (like headers) during configuration step.</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Primarily for downloading, not advanced dependency management.</li>
<li>Scripting knowledge needed for complex setups.</li>
<li>Lacks features like a repository and versioning.</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="tools-that-laid-the-foundation">Tools that Laid the Foundation<a href="https://moderncppdevops.com/pkg-mngr-roundup#tools-that-laid-the-foundation" class="hash-link" aria-label="Direct link to Tools that Laid the Foundation" title="Direct link to Tools that Laid the Foundation">​</a></h2>
<p>This is a bonus shout out. You should not be considering these but they deserve credit.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="20-buckaroo">20. Buckaroo<a href="https://moderncppdevops.com/pkg-mngr-roundup#20-buckaroo" class="hash-link" aria-label="Direct link to 20. Buckaroo" title="Direct link to 20. Buckaroo">​</a></h3>
<p>Buckaroo is a package manager designed for C++ developers using the Buck build system, streamlining dependency management and integration into projects for efficient development workflows.</p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Designed for large-scale projects with many dependencies</li>
<li>Can manage complex build systems</li>
<li>Integrates well with other Buckaroo tools</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>No longer actively maintained</li>
<li>Can be challenging to <a href="https://github.com/LoopPerfect/buckaroo/wiki/Understanding-the-Resolver" target="_blank" rel="noopener noreferrer">pick the version</a></li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="21-biicode">21. Biicode<a href="https://moderncppdevops.com/pkg-mngr-roundup#21-biicode" class="hash-link" aria-label="Direct link to 21. Biicode" title="Direct link to 21. Biicode">​</a></h3>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Easy to use with a focus on dependency management</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>No longer Maintained</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="22-cget">22. CGet<a href="https://moderncppdevops.com/pkg-mngr-roundup#22-cget" class="hash-link" aria-label="Direct link to 22. CGet" title="Direct link to 22. CGet">​</a></h3>
<p><a href="https://cget.readthedocs.io/en/latest/" target="_blank" rel="noopener noreferrer">CGet</a> is a package manager designed to work with CMake and non-CMake packages. It provides a flexible way to install packages from a directory, file URL, or Github repository.</p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>CGet can manage both CMake and non-CMake packages, making it a versatile tool for various project needs.</li>
<li>It can install packages from various sources, including directories, file URLs, and Git repositories. Even has the concept of <a href="https://github.com/pfultz2/cget-recipes" target="_blank" rel="noopener noreferrer">recipes</a>. Supports using a <code>requirements.txt</code>.</li>
<li>integrates seamlessly with CMake, allowing for easy package management within your project's build system.</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>No longer Maintained.</li>
<li>While it can handle non-CMake packages, CGet's core functionality revolves around CMake, potentially making it less suitable for projects without a CMake dependency.</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="23-teaport">23. Teaport<a href="https://moderncppdevops.com/pkg-mngr-roundup#23-teaport" class="hash-link" aria-label="Direct link to 23. Teaport" title="Direct link to 23. Teaport">​</a></h3>
<p><a href="https://bitbucket.org/benman/teaport/src/master/" target="_blank" rel="noopener noreferrer">Teaport</a> is a dependency manager designed specifically for C++ projects, inspired by the simplicity and flexibility of CocoaPods. It prioritizes leveraging existing tools and focuses on providing a separation between dependency management and build systems.</p>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Flexibility in dependency sources, supporting Git repositories, directories, and ZIP archives. This caters to diverse project structures and simplifies dependency acquisition.</li>
<li>Utilizes a version lock file (<code>project.teaspec.lock</code>) to guarantee reproducible builds by locking down exact dependency versions.</li>
<li>Supports multiple dependency variants, enabling selection based on specific requirements (e.g., different architectures or library versions).</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>No longer Maintained.</li>
<li>Relies on basic file copy for distributing sources like <code>scp</code>, <code>ssh</code>, and <code>rsync</code> for downloading dependencies. Difficult to scale compared to HTTP with a load balancer or CDN.</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="24-c-archive-network">24. C++ Archive Network<a href="https://moderncppdevops.com/pkg-mngr-roundup#24-c-archive-network" class="hash-link" aria-label="Direct link to 24. C++ Archive Network" title="Direct link to 24. C++ Archive Network">​</a></h3>
<ul>
<li><strong>Strengths:</strong>
<ul>
<li>Supports the <a href="https://waf.io/" target="_blank" rel="noopener noreferrer">Waf</a> build system</li>
</ul>
</li>
<li><strong>Weaknesses:</strong>
<ul>
<li>Not primarily designed for C++ development anymore</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="choosing-the-right-package-manager">Choosing the Right Package Manager<a href="https://moderncppdevops.com/pkg-mngr-roundup#choosing-the-right-package-manager" class="hash-link" aria-label="Direct link to Choosing the Right Package Manager" title="Direct link to Choosing the Right Package Manager">​</a></h2>
<p>The best C++ package manager for you will depend on your specific needs and preferences. Consider factors such as:</p>
<ul>
<li><strong>The size and scope of your project:</strong> For small projects, a simple manager like CPM or Hunter may be sufficient. For larger projects, a more powerful manager like Conan may be necessary.</li>
<li><strong>The types of libraries you need:</strong> If you need mostly open-source libraries, vcpkg is a good option. If you need more specialized or industry specific, Spack may be a better choice.</li>
<li><strong>Your experience level:</strong> If you are new to C++ package managers, vcpkg or Conan are excellent choices which can very quickly get you up and running.</li>
</ul>
<p>Ultimately, the best way to choose a C++ package manager is to try out a few different options and see which one you like best.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>Changelog</div><div class="admonitionContent_BuS1"><ul>
<li>2024-02-13: Added Mamba suggested by u/mjklaim</li>
<li>2024-02-20: Added SoupBuild suggested by u/mwasplund</li>
<li>2024-04-07:<!-- -->
<ul>
<li>Moved NixOS up the list because package selection vs the platform limitations and it's ability to make dedicated environments.</li>
<li>Moved Buckaroo to honorable mentions because it's not been updated in three years.</li>
<li>Added BitBake</li>
</ul>
</li>
<li>2024-04-11: Added CGet and Teaport from <a href="https://en.cppreference.com/w/cpp/links/libs#Package_managers" target="_blank" rel="noopener noreferrer">cppreference</a></li>
</ul></div></div>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="c++" term="c++"/>
        <category label="dependency management" term="dependency management"/>
        <category label="build system" term="build system"/>
        <category label="library management" term="library management"/>
        <category label="c++ package manager comparison" term="c++ package manager comparison"/>
        <category label="vcpkg" term="vcpkg"/>
        <category label="conan" term="conan"/>
        <category label="spack" term="spack"/>
        <category label="xrepo" term="xrepo"/>
        <category label="tipi.build" term="tipi.build"/>
        <category label="meson" term="meson"/>
        <category label="bazel" term="bazel"/>
        <category label="best c++ package manager" term="best c++ package manager"/>
        <category label="c++ open source packages" term="c++ open source packages"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Comparing Linux System Package Managers with C++ Package Managers]]></title>
        <id>https://moderncppdevops.com/system-vs-cpp-pkg-mngr</id>
        <link href="https://moderncppdevops.com/system-vs-cpp-pkg-mngr"/>
        <updated>2024-02-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Discover the critical differences between Linux system package managers (rpm, dpkg, apt) and C++ package managers (vcpkg, Conan) in our in-depth comparison guide. Navigate the complexities of managing system-wide software versus C++ libraries for your projects, and learn which tool is best suited for your development needs. Streamline your package management strategy with expert insights and recommendations tailored to your workflow.]]></summary>
        <content type="html"><![CDATA[<p>Feeling lost in the jungle of C++ package managers? You're not alone. Wrangling dependencies in the C++ world can feel like navigating a tangled mess of vines, with cryptic tools and endless options leaving you frustrated. But fear not, intrepid C++ developer! This guide will cut through the undergrowth and help you get on the right path.</p>
<p><strong>First things first:</strong> Let's dispel a common misconception. System package managers like <code>rpm</code> and <code>apt</code> are great for keeping your operating system humming, but they're not designed for the unique challenges of C++ development. That's where C++ specific package managers like <code>vcpkg</code>, <code>Conan</code>, and <code>Xrepo</code> come in.</p>
<p>These specialized tools understand the pain points you face:</p>
<ul>
<li><strong>Dependency hell:</strong> Trying to manually juggle library versions and conflicts can drive you mad. Package managers automate this, ensuring your project has the right ingredients and plays nicely with others.</li>
<li><strong>Finding the right tools:</strong> With a vast ecosystem of libraries, discovering the best one for your needs can be overwhelming. Package managers offer curated repositories and search functionality to save you time and effort.</li>
<li><strong>Cross-platform headaches:</strong> Building code for different operating systems often means wrestling with compatibility issues. Package managers can streamline this process, providing pre-built binaries or simplifying the build process.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="linux-system-package-managers">Linux System Package Managers<a href="https://moderncppdevops.com/system-vs-cpp-pkg-mngr#linux-system-package-managers" class="hash-link" aria-label="Direct link to Linux System Package Managers" title="Direct link to Linux System Package Managers">​</a></h3>
<ul>
<li><strong>Purpose:</strong> Manage entire operating systems and their applications.</li>
<li><strong>Package Scope:</strong> Primarily distribute pre-built binaries of complete software packages, including libraries, applications, system tools, and utilities.</li>
<li><strong>Focus:</strong> Stability, security, and compatibility with the chosen Linux distribution.</li>
<li><strong>Examples:</strong>
<ul>
<li><strong>Debian/Ubuntu:</strong> dpkg, apt</li>
<li><strong>Red Hat/CentOS:</strong> rpm</li>
<li><strong>macOS:</strong> Homebrew (not technically a system package manager, but similar functionality)</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="c-package-managers">C++ Package Managers<a href="https://moderncppdevops.com/system-vs-cpp-pkg-mngr#c-package-managers" class="hash-link" aria-label="Direct link to C++ Package Managers" title="Direct link to C++ Package Managers">​</a></h3>
<ul>
<li><strong>Purpose:</strong> Manage C++ libraries and their dependencies specifically.</li>
<li><strong>Package Scope:</strong> Primarily focus on libraries used in C++ development, offering both pre-built binaries and source code options.</li>
<li><strong>Focus:</strong> Ease of use, flexibility, dependency management, and providing various versions and build configurations.</li>
<li><strong>Examples:</strong>
<ul>
<li><strong>vcpkg:</strong> Easy to use, large open-source library repository, good for Windows development.</li>
<li><strong>Conan:</strong> Powerful and flexible, supports binary and source-based packages, manages private libraries.</li>
<li><strong>Build2:</strong> Next-generation build toolchain, integrated ecosystem, modern build practices.</li>
<li><strong>Hunter:</strong> Simple and easy to use for finding specific libraries, integrates well with CMake.</li>
</ul>
</li>
</ul>
<p><strong>Comparison:</strong></p>
<table><thead><tr><th>Feature</th><th>Linux System Package Managers</th><th>C++ Package Managers</th></tr></thead><tbody><tr><td><strong>Main Purpose</strong></td><td>Manage operating system and applications</td><td>Manage C++ libraries and dependencies</td></tr><tr><td><strong>Package Scope</strong></td><td>Broader: system tools, apps, libraries</td><td>Narrower: C++ libraries</td></tr><tr><td><strong>Focus</strong></td><td>Stability, security, compatibility</td><td>Ease of use, flexibility, dependency management</td></tr><tr><td><strong>Pre-built Binaries</strong></td><td>Yes</td><td>Yes, but also often offer source code</td></tr><tr><td><strong>Dependency Management</strong></td><td>Limited</td><td>Advanced, can handle complex scenarios</td></tr><tr><td><strong>Multiple Versions</strong></td><td>Limited</td><td>Often offer multiple versions and configurations</td></tr><tr><td><strong>Community and Resources</strong></td><td>Large and established</td><td>Varied, some larger, some smaller communities</td></tr></tbody></table>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="choosing-the-right-tool">Choosing the Right Tool<a href="https://moderncppdevops.com/system-vs-cpp-pkg-mngr#choosing-the-right-tool" class="hash-link" aria-label="Direct link to Choosing the Right Tool" title="Direct link to Choosing the Right Tool">​</a></h2>
<p>The best choice depends on your specific needs:</p>
<ul>
<li><strong>Managing system-wide software:</strong> Use your distro's package manager (e.g., apt, rpm).</li>
<li><strong>Managing C++ libraries for your project:</strong> Use a dedicated C++ package manager like vcpkg, Conan, Build2, etc., considering factors like project size, library needs, and your experience level.</li>
</ul>
<p>Remember, these categories aren't mutually exclusive. You can use both types of package managers in your workflow depending on your needs.</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="c++" term="c++"/>
        <category label="package management" term="package management"/>
        <category label="package managers" term="package managers"/>
        <category label="rpm" term="rpm"/>
        <category label="dpkg" term="dpkg"/>
        <category label="apt" term="apt"/>
        <category label="brew" term="brew"/>
        <category label="vcpkg" term="vcpkg"/>
        <category label="conan" term="conan"/>
        <category label="xrepo" term="xrepo"/>
        <category label="build2" term="build2"/>
        <category label="package management comparison" term="package management comparison"/>
        <category label="system-wide software management" term="system-wide software management"/>
        <category label="c++ library management" term="c++ library management"/>
        <category label="dependency management tools" term="dependency management tools"/>
        <category label="linux package management" term="linux package management"/>
        <category label="c++ dependency resolution" term="c++ dependency resolution"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Unlock Efficiency & Innovation in C++ Development: Building More Configuration than You Ship]]></title>
        <id>https://moderncppdevops.com/build-more-configurations</id>
        <link href="https://moderncppdevops.com/build-more-configurations"/>
        <updated>2024-02-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Struggling to keep up with evolving C++ tools and features while maintaining existing code? Feeling stuck with limited access to new capabilities? You're not alone! This blog unveils a powerful solution: building more configurations in your CI pipelines.
Discover how this DevOps approach can: * Boost productivity: Unleash the potential of new features and tools. * Ensure project longevity: Guarantee compatibility across platforms and versions. * Improve code quality: Catch issues early through comprehensive testing. * Embrace innovation: Break down barriers to adopting new C++ advancements.
Learn by example: * We'll explore how Go's backward compatibility inspires similar practices in C++. * See practical techniques for testing with multiple compilers, standards, and platforms. * Get guided steps to implement this approach in your CI pipeline.
Don't miss out on: * Valuable tips to get started easily. * Real-world examples showcasing successful adoption. * Actionable steps to share your experiences and contribute to the C++ community!
Ready to revolutionize your C++ development workflow? Start now!
]]></summary>
        <content type="html"><![CDATA[<p>In the steadily evolving landscape of C++, where incremental improvements shape the tools we use, it can quickly become a challenge to stay up to date with the latest technologies while still supporting the code already in production. If you're apart of the <a href="https://www.jetbrains.com/lp/devecosystem-2023/cpp/" target="_blank" rel="noopener noreferrer">61% of C++ developers</a>, the concept of building more configurations might initially seem counterintuitive. However, it's precisely under such circumstances that this approach serves as a solution to the challenge of limited access to new features and tools within the C++ ecosystem.</p>
<p>By prioritizing testing a comprehensive list of configuration during CI, your team can unleash access to new features and tools, boosting productivity and ensuring project longevity and compatibility in a competitive landscape by <a href="https://www.techtarget.com/searchitoperations/tip/Putting-up-DevOps-guardrails-what-does-that-mean" target="_blank" rel="noopener noreferrer">establishing guardrails</a> for the project.</p>
<p>Let's delve deeper into the compelling reasons why this DevOps approach, centered around building more configurations, deserves widespread adoption in C++ environments.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-simplicity-of-building-more">The simplicity of building more<a href="https://moderncppdevops.com/build-more-configurations#the-simplicity-of-building-more" class="hash-link" aria-label="Direct link to The simplicity of building more" title="Direct link to The simplicity of building more">​</a></h2>
<p>As with C++, the Golang's runtime is backwards compatibility. Older binaries typically run seamlessly on newer Go versions without recompilation. This helped establish the best practice of thoroughly testing applications with multiple Go versions. In CI pipelines, running automated tests against <a href="https://github.com/actions/setup-go?tab=readme-ov-file#matrix-testing" target="_blank" rel="noopener noreferrer">multiple Go versions</a> looks something like this:</p>
<div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token key atrule">jobs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">build</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">runs-on</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> ubuntu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">latest</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">strategy</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">matrix</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">go</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'1.21'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'1.20'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'1.19'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> build (go</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">$</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> matrix.go </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain">)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">steps</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> actions/checkout@v4</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> actions/setup</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">go@v5</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">with</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">          </span><span class="token key atrule">go-version</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> matrix.go </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> go build app.go</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The key concept to note is the <code>strategy</code>, pun intended, which has the <code>matrix</code>, a declarative list, of Golang versions to test against. Go's approach can inspire similar practices in C++. All the popular CI services offer this feature (just with unique names).</p>
<p>At a high level, it's easy to think of this as a <code>template&lt;typename version&gt; class</code> where multiple instance of the job are instantiated each with a different version but perform the same algorithm and can be parallelized.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="tackling-c-configurations">Tackling C++ Configurations<a href="https://moderncppdevops.com/build-more-configurations#tackling-c-configurations" class="hash-link" aria-label="Direct link to Tackling C++ Configurations" title="Direct link to Tackling C++ Configurations">​</a></h2>
<p>The best strategy to identify the "version matrix" is looking at the platforms your project already supports. At a minimum that should be your LTS, production (latest release), and current build tools. This will help ensure any changes introduced will be compatible across the board. Building and testing the product with a newer toolchain will help build confidence with business stake holders as operation risk will be reduced.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="testing-with-more-compilers">Testing with more compilers<a href="https://moderncppdevops.com/build-more-configurations#testing-with-more-compilers" class="hash-link" aria-label="Direct link to Testing with more compilers" title="Direct link to Testing with more compilers">​</a></h3>
<p>The unified tool set behind Go is amazing, however competition is healthy and drives innovation for end-users. Let's do something similar to go version but try it with C++ compilers and language standards.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">strategy</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">matrix</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">compiler</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">g++</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token number" style="color:rgb(181, 206, 168)">12</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> clang</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token number" style="color:rgb(181, 206, 168)">15</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># Specify compiler versions to test</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">cxxstd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:rgb(181, 206, 168)">17</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">23</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># Specify the language standard to test</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You can the configure you build system normally.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">steps</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> cmake </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">preset release \</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">              </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">DCMAKE_CXX_COMPILER=$</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> matrix.compiler </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"> \</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">              </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">CMAKE_CXX_STANDARD=$</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> matrix.cxxstd </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The full workflow is over on <a href="https://gist.github.com/prince-chrismc/224bbc3ba583012fd3b6ffef8976ab10#file-compilers-yml" target="_blank" rel="noopener noreferrer">Gist</a>. It's a great idea to apply this idea to <a href="https://moderncppdevops.com/simple-ci-with-presets">sanitizer presets</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="ensuring-cross-platform-compatibility">Ensuring cross-platform compatibility<a href="https://moderncppdevops.com/build-more-configurations#ensuring-cross-platform-compatibility" class="hash-link" aria-label="Direct link to Ensuring cross-platform compatibility" title="Direct link to Ensuring cross-platform compatibility">​</a></h3>
<p>And there is no reason for this to not be cross-platform. Though for GitHub Actions, this is a little bit more involved since not all the C++ build environments are installed.</p>
<p>This should give you a good idea how you can tailor a <code>strategy.matrix</code> to your specific needs.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">test</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">runs-on</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> matrix.os </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># Use dynamic runner based on OS</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">strategy</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">matrix</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">os</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">windows</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">latest</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> ubuntu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">latest</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> macos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">latest</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">compiler</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">gcc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token number" style="color:rgb(181, 206, 168)">11</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> clang</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token number" style="color:rgb(181, 206, 168)">14</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">include</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">  </span><span class="token key atrule">os</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> windows</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">latest</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">             </span><span class="token key atrule">compiler</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> gcc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token number" style="color:rgb(181, 206, 168)">11</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">             </span><span class="token comment" style="color:rgb(106, 153, 85)"># Add extra fields to `choco install mingw-w64-x86_64-gcc-11``</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">             </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> mingw</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">w64</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">             </span><span class="token key atrule">version</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> 11.2.0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">os</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> windows</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">latest</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            </span><span class="token comment" style="color:rgb(106, 153, 85)"># Override `clang-14` to use the MSVC provided clang</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            </span><span class="token key atrule">compiler</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> cl</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">clang</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">os</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> macos</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">latest</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            </span><span class="token key atrule">compiler</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> gcc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token number" style="color:rgb(181, 206, 168)">11</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            </span><span class="token comment" style="color:rgb(106, 153, 85)"># Add extra fields to `brew install` the correct version</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            </span><span class="token key atrule">package</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> gcc@11</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The full workflow can be viewed as a <a href="https://gist.github.com/prince-chrismc/224bbc3ba583012fd3b6ffef8976ab10#file-cross-platform-yml" target="_blank" rel="noopener noreferrer">Gist</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://moderncppdevops.com/build-more-configurations#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>Incorporate these principles into your CI practices! Here's a few steps to get you started</p>
<ul>
<li>Identify the toolchains you are using to build you software.</li>
<li>Refactor you pipeline to isolate those changes and create a matrix with those preliminary configurations.</li>
<li>Once you've stabilized the builds, you are ready to introduce more configurations with updated toolchains to build.</li>
</ul>
<p>Designing a flexible CI pipeline with a variety of configurations breaks down barriers to adding new compilers. Staying up-to-date is essential for efficient software development, and comprehensive configuration testing ensures code quality, performance, and security from the outset.</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="c++" term="c++"/>
        <category label="ci" term="ci"/>
        <category label="continuous integration" term="continuous integration"/>
        <category label="build configurations" term="build configurations"/>
        <category label="devops" term="devops"/>
        <category label="efficiency" term="efficiency"/>
        <category label="innovation" term="innovation"/>
        <category label="code quality" term="code quality"/>
        <category label="compatibility" term="compatibility"/>
        <category label="golang" term="golang"/>
        <category label="compilers" term="compilers"/>
        <category label="cmake" term="cmake"/>
        <category label="github actions" term="github actions"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Optimizing CI Build Scripts and Enhancing Developer Experience with CMake Presets]]></title>
        <id>https://moderncppdevops.com/simple-ci-with-presets</id>
        <link href="https://moderncppdevops.com/simple-ci-with-presets"/>
        <updated>2024-01-29T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Explore the power of CMake presets in DevOps as we dive into optimizing CI pipelines and simplifying build scripts for efficient software development. Learn how SOLID design principles are applied to enhance developer experience and streamline workflows. Discover practical insights into CMake toolchains, presets, and build scripts, and gain valuable tips for cross-platform development. Elevate your software configuration with expert guidance on managing multiple build environments effortlessly. Join us on this journey of code optimization and discover how CMake presets can significantly improve your programming workflow. Stay ahead in the world of continuous integration and gain insights into IDE integrations, making your development process smoother. Uncover the secrets of C++ build systems and enhance your knowledge of best practices in software development. Ready to revolutionize your CI pipelines? Dive into this comprehensive guide and boost your skills in building robust and efficient software projects with CMake presets.]]></summary>
        <content type="html"><![CDATA[<p>Managing build scripts, especially in C++, can be a <a href="https://julienjorge.medium.com/an-overview-of-build-systems-mostly-for-c-projects-ac9931494444" target="_blank" rel="noopener noreferrer">daunting task</a> for development teams. CMake, with its powerful toolkit, offers a solution to this challenge. In this blog, we'll delve into the world of CMake presets and explore how they can significantly reduce CI build script complexity, leading to a more efficient and enjoyable development experience.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-challenge-of-build-scripts-in-c">The Challenge of Build Scripts in C++<a href="https://moderncppdevops.com/simple-ci-with-presets#the-challenge-of-build-scripts-in-c" class="hash-link" aria-label="Direct link to The Challenge of Build Scripts in C++" title="Direct link to The Challenge of Build Scripts in C++">​</a></h2>
<p>C++ teams often struggle with an extensive list of build systems, introducing layers of complexity. CMake, when mastered, becomes a game-changer. This blog focuses on CMake's key pillars: toolchains, presets, and build scripts. Understanding their roles and interactions is crucial for achieving a streamlined developer experience and unambiguous CI workflows.</p>
<p>Join us on a journey where we'll:</p>
<ul>
<li>Empower developers with effortless configuration and cross-platform builds.</li>
<li>Simplify CI pipelines for efficient testing.</li>
<li>Elevate project maintainability and collaboration across diverse environments.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="applying-solid-design-principles-to-build-scripts">Applying SOLID Design Principles to Build Scripts<a href="https://moderncppdevops.com/simple-ci-with-presets#applying-solid-design-principles-to-build-scripts" class="hash-link" aria-label="Direct link to Applying SOLID Design Principles to Build Scripts" title="Direct link to Applying SOLID Design Principles to Build Scripts">​</a></h2>
<p>In this blog, we'll apply <a href="https://en.wikipedia.org/wiki/SOLID" target="_blank" rel="noopener noreferrer">SOLID</a> design principles to our build scripts, focusing on the distinction between tool configurations, global project settings, and target-specific options. This effective design allows for supporting multiple build environments without the need to change <code>CMakeLists.txt</code> for each of them.</p>
<p>While new tools like XMake are promising, the blog predominantly focuses on CMake, given its prevalence in over 85% of development teams. For those starting new projects under research and development efforts, exploring alternative options like Meson is recommended.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="three-layers-of-cmake">Three Layers of CMake<a href="https://moderncppdevops.com/simple-ci-with-presets#three-layers-of-cmake" class="hash-link" aria-label="Direct link to Three Layers of CMake" title="Direct link to Three Layers of CMake">​</a></h2>
<p>Understanding the distinction between toolchains, presets, and build scripts is vital. Let's break down these three layers:</p>
<ol>
<li>
<p><strong><a href="https://cmake.org/cmake/help/book/mastering-cmake/chapter/Cross%20Compiling%20With%20CMake.html#toolchain-files" target="_blank" rel="noopener noreferrer">Toolchain</a>:</strong></p>
<ul>
<li>Purpose: Provide information about the build system, including compiler paths, library locations, and dependencies.</li>
<li>When to use: Cross-compiling, using a specific compiler or tool-set, employing custom build systems or dependency management tools.</li>
<li>How to use: Create a toolchain file (e.g., <code>my_toolchain.cmake</code>) and pass it to CMake using presets.</li>
</ul>
</li>
<li>
<p><strong><a href="https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html" target="_blank" rel="noopener noreferrer">Presets</a>:</strong></p>
<ul>
<li>Purpose: Encapsulate common configuration options, build flags, generator choices, and toolchain settings for easy reuse and sharing.</li>
<li>When to use: Managing multiple build configurations, streamlining workflows, integrating with IDEs and build systems.</li>
<li>How to use: Create a <code>CMakePresets.json</code> or <code>CMakeUserPresets.json</code> file, define presets, and use the <code>--preset</code> option with CMake commands.</li>
</ul>
</li>
<li>
<p><strong><a href="https://www.jetbrains.com/help/clion/cmakelists-txt-file.html" target="_blank" rel="noopener noreferrer">Build Scripts</a>:</strong></p>
<ul>
<li>Purpose: Define the project's structure, targets, dependencies, and build rules using CMake's language.</li>
<li>When to use: Creating a CMake project for multi-platform builds, organizing sources, setting compile flags, and defining custom build steps.</li>
<li>How to use: Write <code>CMakeLists.txt</code> files in your project's root and subdirectories.</li>
</ul>
</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="organizing-cmake-presets-for-effective-ci-pipelines">Organizing CMake Presets for Effective CI Pipelines<a href="https://moderncppdevops.com/simple-ci-with-presets#organizing-cmake-presets-for-effective-ci-pipelines" class="hash-link" aria-label="Direct link to Organizing CMake Presets for Effective CI Pipelines" title="Direct link to Organizing CMake Presets for Effective CI Pipelines">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="cmake-toolchains">CMake Toolchains<a href="https://moderncppdevops.com/simple-ci-with-presets#cmake-toolchains" class="hash-link" aria-label="Direct link to CMake Toolchains" title="Direct link to CMake Toolchains">​</a></h3>
<p>With a single responsibility, toolchains focus on compiler and tool setup for specific environments. They are essential for cross-compilation and non-standard tool setups.</p>
<p><strong>Example for Cross-Compiling:</strong></p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token key atrule">build</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">matrix</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">toolchains</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> my_toolchain_arm.cmake</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> my_toolchain_x86.cmake</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token scalar string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        cmake --preset release -DCMAKE_TOOLCHAIN_FILE="${{ matrix.toolchain }}"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        cmake --build --preset release</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> upload</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">artifacts@v4</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">with</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> matrix.toolchain </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">paths</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> build/release</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><strong>Example for Supporting Multiple Compilers:</strong></p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token key atrule">build</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">matrix</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">compiler</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token key atrule">"c"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"gcc-7"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token key atrule">"cxx"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"g++-7"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token key atrule">"c"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"gcc-11"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token key atrule">"cxx"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"g++-11"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token key atrule">"c"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"gcc-12"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token key atrule">"cxx"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"g++-12"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token scalar string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        cmake --preset test \</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">            -DCMAKE_C_COMPILER="${{ matrix.compiler.c }}"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">            -DCMAKE_CXX_COMPILER="${{ matrix.compiler.cxx }}"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        cmake --build --preset test</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        cmake --build --target unit_tests_run --preset test</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>It's entirely possible to define a preset for each configuration. This however posses significant challenges when configurations need to change over time or when downstream consumers desire different configurations. A reasonable compromise would be to make toolchain specific presets <code>hidden: true</code> to prevent their misuse.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="organizing-presets">Organizing Presets<a href="https://moderncppdevops.com/simple-ci-with-presets#organizing-presets" class="hash-link" aria-label="Direct link to Organizing Presets" title="Direct link to Organizing Presets">​</a></h3>
<p>Effective organization of presets enhances manageability and scalability. Follow a structured approach to organizing presets for different scenarios.</p>
<p><strong>Example Preset Organization:</strong></p>
<div class="language-txt codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-txt codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">├── cmake/</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   └── CMakePresets.json</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">├── include</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">├── src</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">├── examples/</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   └── CMakePresets.json</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">├── tests/</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   └── CMakePresets.json</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">├── CMakePresets.json</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">└── CMakeUserPresets.json</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>It's import to keep presets open for extension, but closed for modification. You should not be be redefine or overriding values.</p>
<ul>
<li><strong>Root <code>CMakePresets.json</code>:</strong> Define baseline configurations for consuming or developing the project.</li>
<li><strong><code>cmake/</code> Directory Presets:</strong> Include presets for the entire project.</li>
<li><strong><code>examples/</code> and <code>tests/</code> Directory Presets:</strong> Include presets specific to those targets.</li>
</ul>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>This concept also extends to monorepos, each sub component could define it's own set of presets that are aggregates but the root presets. Simply substitute in <code>core/</code> and <code>driver/</code> or <code>error/</code> and <code>math/</code> to match your use case.</p></div></div>
<p><strong>Including other <code>CMakePresets.json</code>:</strong></p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"version"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">6</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"cmakeMinimumRequired"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token property">"major"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">3</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token property">"minor"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">25</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token property">"patch"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"include"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token string" style="color:rgb(206, 145, 120)">"example/CMakePresets.json"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token string" style="color:rgb(206, 145, 120)">"tests/CMakePresets.json"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"configurePresets"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">/* ... */</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"buildPresets"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">/* ... */</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Presets should not be forced to depend upon configurations that they do not use.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="defining-presets">Defining Presets<a href="https://moderncppdevops.com/simple-ci-with-presets#defining-presets" class="hash-link" aria-label="Direct link to Defining Presets" title="Direct link to Defining Presets">​</a></h3>
<p>Most of the preparation needs to happen in configure presets. It's important to also create build preset with the same name.</p>
<p><strong><code>cmake/CMakePresets.json</code>:</strong></p>
<p>Define simple unobtrusive presets that can be inherited for more specialized. By setting a configuration preset to define the build folder, you will not need to call <code>mkdir</code> and you can reuse the preset name to access artifacts.</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"name"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"release"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"configuration"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"Release"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"binaryDir"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"${sourceDir}/build/${presetName}"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><strong><code>tests/CMakePresets.json</code>:</strong></p>
<p>Declare configurations that produce unique binaries with a narrow focus. Passing in all the global compiler flags and define the required environment variables for either configure or build.</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">"name"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"asan"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">"inherits"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"debug"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">"cacheVariables"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token property">"CMAKE_CXX_FLAGS"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"..."</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">// Global compiler files needed by all targets for complete results</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">"environment"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token property">"ASAN_OPTIONS"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"..."</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">// Configure EVN_VAR required to active more checks</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="refactoring-ci-pipelines">Refactoring CI Pipelines<a href="https://moderncppdevops.com/simple-ci-with-presets#refactoring-ci-pipelines" class="hash-link" aria-label="Direct link to Refactoring CI Pipelines" title="Direct link to Refactoring CI Pipelines">​</a></h3>
<p>Refactor CI pipelines to leverage the simplicity and power of CMake presets.</p>
<p><strong>Example CI Pipeline for Release:</strong></p>
<p>Remove the hassle of having the correct working directory.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token key atrule">build</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token scalar string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        cmake --preset release</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        cmake --build --preset release</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> upload</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">artifacts@v4</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">with</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">paths</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> build/release</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><strong>Example CI Pipeline for ASAN (AddressSanitizer):</strong></p>
<p>Setup custom "run" targets to launch tests with the correct environment variables to ensure consistency without polluting the workspace.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token key atrule">build</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token scalar string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        cmake --preset asan</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        cmake --build --preset asan</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        cmake --build --target unit_tests_run --preset test </span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="accommodating-all-developers">Accommodating All Developers<a href="https://moderncppdevops.com/simple-ci-with-presets#accommodating-all-developers" class="hash-link" aria-label="Direct link to Accommodating All Developers" title="Direct link to Accommodating All Developers">​</a></h3>
<p>Flexibility is crucial. Allow developers room to work efficiently while ensuring a green production environment. Use <code>CMakeUserPresets.json</code> for user-specific configurations.</p>
<p><strong>Example User-Specific Preset (<code>CMakeUserPresets.json</code>):</strong></p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">"name"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"clang"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">"inherits"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"debug"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">"generator"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"Ninja"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">"cacheVariables"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token property">"CMAKE_C_COMPILER"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"clang-16"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token property">"CMAKE_CXX_COMPILER"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"clang++-16"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token property">"CMAKE_CXX_STANDARD"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">23</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token property">"CMAKE_CXX_CLANG_TIDY"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"clang-tidy-16;fix"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><strong>Example Platform Specific Preset:</strong></p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"name"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"ccache-linux"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"hidden"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"cacheVariables"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token property">"CMAKE_C_COMPILER_LAUNCHER"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"/usr/bin/ccache"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token property">"CMAKE_CXX_COMPILER_LAUNCHER"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"/usr/bin/ccache"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"condition"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token property">"type"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"equals"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token property">"lhs"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"${hostSystemName}"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token property">"rhs"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"Linux"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"name"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"ccache-darwin"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"hidden"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"cacheVariables"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token property">"CMAKE_C_COMPILER_LAUNCHER"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"$env{HOMEBREW_PREFIX}/opt/ccache"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token property">"CMAKE_CXX_COMPILER_LAUNCHER"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"$env{HOMEBREW_PREFIX}/opt/ccache"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">"condition"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token property">"type"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"equals"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token property">"lhs"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"${hostSystemName}"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token property">"rhs"</span><span class="token operator" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"Darwin"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://moderncppdevops.com/simple-ci-with-presets#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<ul>
<li>Toolchains focus on compiler and tool setup for specific environments.</li>
<li>Presets provide reusable configuration sets for different build scenarios.</li>
<li>Build scripts define the project's structure and build rules using CMake commands.</li>
<li>Use toolchains for cross-compilation and non-standard tool setups.</li>
<li>Use presets for managing multiple build configurations and sharing settings.</li>
<li>Use build scripts to define the project's build structure and rules.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="further-reading">Further Reading<a href="https://moderncppdevops.com/simple-ci-with-presets#further-reading" class="hash-link" aria-label="Direct link to Further Reading" title="Direct link to Further Reading">​</a></h3>
<p>Explore other opinions and insights on CMake presets:</p>
<ul>
<li><a href="https://martin-fieber.de/blog/cmake-presets/" target="_blank" rel="noopener noreferrer">CMake Presets - A Fresh Start</a></li>
<li><a href="https://dominikberner.ch/cmake-presets-best-practices/" target="_blank" rel="noopener noreferrer">CMake Presets Best Practices</a></li>
<li><a href="https://mgibson.ca/posts/simplify-your-c-development-environment-using-cmakepresets-json/" target="_blank" rel="noopener noreferrer">Simplify Your C++ Development Environment using CMakePresets.json</a></li>
<li><a href="https://alexreinking.com/blog/how-to-use-cmake-without-the-agonizing-pain-part-2.html" target="_blank" rel="noopener noreferrer">How to Use CMake Without the Agonizing Pain (Part 2)</a></li>
<li><a href="https://crascit.com/professional-cmake/" target="_blank" rel="noopener noreferrer">Professional CMake, 16th Edition</a></li>
</ul>
<p>Explore IDE integrations and their support for CMake presets:</p>
<ul>
<li><a href="https://learn.microsoft.com/en-us/cpp/build/cmake-presets-vs?view=msvc-170" target="_blank" rel="noopener noreferrer">CMake Presets vs. CMakeSettings.json in Visual Studio</a></li>
<li><a href="https://www.jetbrains.com/help/clion/cmake-presets.html" target="_blank" rel="noopener noreferrer">CMake Presets in CLion</a></li>
<li><a href="https://www.qt.io/blog/qt-creator-9-cmakepresets" target="_blank" rel="noopener noreferrer">CMake Presets in Qt Creator</a></li>
<li><a href="https://github.com/microsoft/vscode-cmake-tools/blob/main/docs/cmake-presets.md" target="_blank" rel="noopener noreferrer">CMake Presets in Visual Studio Code</a></li>
</ul>
<p>Are you ready to optimize your CI pipelines and enhance your development workflow with CMake presets? Let the journey begin!</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="c++" term="c++"/>
        <category label="devops" term="devops"/>
        <category label="cmake" term="cmake"/>
        <category label="ci" term="ci"/>
        <category label="continuous integration" term="continuous integration"/>
        <category label="build scripts" term="build scripts"/>
        <category label="toolchains" term="toolchains"/>
        <category label="ci pipelines" term="ci pipelines"/>
        <category label="c++ build systems" term="c++ build systems"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[From Scratch to Scalable: Seamless CI for C++ Windows Build Infrastructure with Ansible and Terraform]]></title>
        <id>https://moderncppdevops.com/windows-iac-for-cpp</id>
        <link href="https://moderncppdevops.com/windows-iac-for-cpp"/>
        <updated>2024-01-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Tired of Windows CI nightmares? Struggling with inconsistent builds, manual configuration, and unreliable environments? Break free with this comprehensive guide to seamless C++ CI on Windows using Ansible and Terraform. Learn how to: Automate build configuration with Ansible playbooks for rock-solid reproducibility. Standardize toolchains for a consistent developer experience across machines.Scale effortlessly from local VMs to the Azure cloud for on-demand build capacity. Bridge the gap between developer needs and DevOps control with declarative infrastructure. Embrace robust builds and flexible CI with Ansible and Terraform. Start building better, faster, and smarter today! This epic guide unlocks the secrets of powerful CI automation for Windows machines with Ansible and Terraform. Forget manual setup, inconsistent environments, and build headaches. Dive into: Effortless configuration of C++ toolchains like Mingw-W64, CMake, and Ninja. Streamlined installation of Visual Studio Code and essential extensions. Pinning dependencies for predictable and reproducible builds. Effortless migration to the cloud with Azure VM provisioning and domain joining.]]></summary>
        <content type="html"><![CDATA[<p>One of the biggest challenges in C++ is setting up CI from scratch and of that, the biggest pain point is the system administration which can be very disconnected from the development tools. In order to bridge this gap we can leverage Infrastructure as Code (IaC) targeting existing machines, locally in our network or in the cloud, is an excellent enhancement to ensure consistent reproducible builds. Having version controlled configuration management tied to the codebase is key, this will allow us to deterministically install all the tools required with confidence even in the far far future.</p>
<p>Let's walk through adding Ansible to handle configuring a Windows virtual machine. These ideas apply to Unix environments as well but we can tackle those in a future post. Once we've gained control over our build environments, we can tackle availability and scalability by introducing Terraform to help provision and initialize new Windows instances in Azure. This two prong solution enables both a path for migrating to the cloud and establishing a hybrid setup.</p>
<p>Let's get setup! To set up, start with a freshly-provisioned, fully patched VM from IT. Enable <a href="https://learn.microsoft.com/en-us/windows/win32/winrm/portal" target="_blank" rel="noopener noreferrer">WinRM</a> using a <a href="https://learn.microsoft.com/en-us/windows/win32/winrm/installation-and-configuration-for-windows-remote-management#configuring-winrm-with-group-policy" target="_blank" rel="noopener noreferrer">Group Policy Object</a> for seamless remote management. If you are not connecting to a domain, follow the <a href="https://docs.ansible.com/ansible/latest/os_guide/windows_setup.html#winrm-setup" target="_blank" rel="noopener noreferrer">Ansible Setup Guide</a>. Ansible's Windows support, coupled with its extensive library of <a href="https://docs.ansible.com/ansible/2.9/modules/list_of_windows_modules.html#windows-modules" target="_blank" rel="noopener noreferrer">built-in modules</a>, streamlines configuration, often eliminating the need for manual PowerShell commands.</p>
<p>With that done, make sure to <a href="https://docs.ansible.com/ansible/latest/installation_guide/index.html" target="_blank" rel="noopener noreferrer">install Ansible</a> and prepare to use it's <a href="https://docs.ansible.com/ansible/latest/os_guide/windows_usage.html" target="_blank" rel="noopener noreferrer">Windows support</a>. You'll need to add Chocolatey to Ansible support since it's not included by default, simply running <code>ansible-galaxy collection install chocolatey.chocolatey</code> will do the trick.</p>
<p>With everything setup, you are ready for the exciting bits (or bytes).</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="configuring-an-existing-machine">Configuring an Existing Machine<a href="https://moderncppdevops.com/windows-iac-for-cpp#configuring-an-existing-machine" class="hash-link" aria-label="Direct link to Configuring an Existing Machine" title="Direct link to Configuring an Existing Machine">​</a></h2>
<p>The various operations that are required to configure the machines are organized into <a href="https://docs.ansible.com/ansible/latest/getting_started/basic_concepts.html#playbooks" target="_blank" rel="noopener noreferrer">Playbooks</a>. With these we can specify a host with a list of tasks we want to execute. This declarative approach allows you to easily specify the final state.</p>
<p>We are going to focus on a cross-compiled applications whose toolchain focuses on Mingw-64 environment where developers primarily work with CMake and Ninja.</p>
<p>Let's make a <code>playbook.yml</code>!</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> Install software on Windows machine</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">hosts</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> windows_vm</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">vars</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token comment" style="color:rgb(106, 153, 85)"># There's lots of authentication options to pick from</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token comment" style="color:rgb(106, 153, 85)"># https://docs.ansible.com/ansible/latest/os_guide/windows_winrm.html#winrm-authentication-options</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">ansible_user</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> username</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">ansible_password</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> password</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">tasks</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> Install C++ dev tools using Chocolatey</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">win_chocolatey</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"{{ item }}"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">state</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> present</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">loop</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> mingw</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> cmake</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> ninja</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This playbook will install <a href="https://chocolatey.org/" target="_blank" rel="noopener noreferrer">Chocolatey</a> if it's missing and then loop over the list of tools we provided. <a href="https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_intro.html#running-playbooks" target="_blank" rel="noopener noreferrer">Running a playbook</a> is simple, just run <code>ansible-playbook playbook.yml</code>.</p>
<p>Ansible has a "check mode" feature which is incredibly powerful to help prevent configuration drift.
This is incredibly important if the build nodes are persistent and re-used for different CI/CD jobs; as scripts ran during the build process can modify the environment and have unintended consequences.
This can be done with the same playbook by calling <code>ansible-playbook --check playbook.yml</code> which used to verify the integrity.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>This can be scaled very easily with an <a href="https://docs.ansible.com/ansible/latest/inventory_guide/intro_inventory.html" target="_blank" rel="noopener noreferrer">inventory</a> of hosts broken into groups which can be references as a whole.
Making workflows like applying security updates to all the nodes seamless.</p></div></div>
<p>Easy enough.</p>
<p>In order to streamline setting up developer systems we are also going to include Visual Studio Code with a few extra extensions installed. For this we can going to add <a href="https://learn.microsoft.com/en-us/windows/package-manager/winget/" target="_blank" rel="noopener noreferrer">WinGet</a> to the mix. This tool is the client to the Windows Package Manager service simplifies installing many Microsoft tools as well as popular software like <a href="https://winget.run/search?query=conferencing" target="_blank" rel="noopener noreferrer">video conferencing</a> applications. For extra points with the developers, we are going to include their favorite VSCode extensions.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">Adding developer tools to your playbook.yml</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> Install WinGet</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">win_chocolatey</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> winget</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">cli</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">state</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> present</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> Install C++ IDE using WinGet</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">win_shell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token scalar string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        winget install -e --id "{{ item }}"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">loop</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> Microsoft.VisualStudioCode</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> Microsoft.VisualStudio.2022.Enterprise.Preview</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> Run PowerShell script</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">win_shell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token scalar string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        $script = @"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        # PowerShell script to activate and install software</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        Write-Host "Activate MSVC Enterprise 2022..."</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\StorePID.exe" AAAAA-BBBBB-CCCCC-DDDDD-EEEEE 09660</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        Write</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">Host "Installing VSCode Extensions</span><span class="token punctuation" style="color:rgb(212, 212, 212)">...</span><span class="token plain">"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        code </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">install</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">extension ms</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">vscode.cpptools</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">extension</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">pack</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        code </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">install</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">extension ms</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">vscode.cmake</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">tools</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        Write</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">Host "Verifying Installed Extensions</span><span class="token punctuation" style="color:rgb(212, 212, 212)">...</span><span class="token plain">"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        code </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">list</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">extensions </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">show</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">versions</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        "@</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        Invoke</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">Expression </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">Command $script</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>One thing to take note is we can very easily run powershell scripts native on the machine. This gives use the flexibility to run extra commands like <a href="https://learn.microsoft.com/en-us/visualstudio/install/automatically-apply-product-keys-when-deploying-visual-studio?view=vs-2022" target="_blank" rel="noopener noreferrer">activating Visual Studio</a> with our product key. Extra care is be needed if you want to preserve <code>--check-mode</code> when directly running powershell cmdlets.</p>
<p>With that, we can setup (and update) developer environments with all the tools they require while allowing verification that the correct tools are installed to prevent drift.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="pin-down-required-packages">Pin Down Required Packages<a href="https://moderncppdevops.com/windows-iac-for-cpp#pin-down-required-packages" class="hash-link" aria-label="Direct link to Pin Down Required Packages" title="Direct link to Pin Down Required Packages">​</a></h3>
<p>For DevOps precision, meticulous version control of tools and dependencies is non-negotiable. It ensures a uniform environment across the development team, preventing compatibility issues and unpredictable behavior. The ability to pinpoint and manipulate specific versions empowers teams to troubleshoot and deliver software with a robust foundation.</p>
<p>Since we are using two different tools, we'll need to solve it for each of them respectively.</p>
<p>Going in order, we'll update Chocolatey to <a href="https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.html#iterating-over-a-list-of-hashes" target="_blank" rel="noopener noreferrer">loop over the name and version</a> we want to install and enable the <a href="https://docs.chocolatey.org/en-us/choco/commands/pin" target="_blank" rel="noopener noreferrer">pinned feature</a> to prevent upgrades. Playbooks support YAML syntax which allows use to have custom JSON objects with individualized properties for our use case.</p>
<div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">tasks</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> Install C++ dev tools using Chocolatey</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">win_chocolatey</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"{{ item.name }}"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">version</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"{{ item.version }}"</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)"># Exact version</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">pinned</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token boolean important">true</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)"># Only explicit upgrades</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">state</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> present</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">loop</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'mingw'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token key atrule">version</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'13.2.0'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'cmake'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token key atrule">version</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'3.27.9'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'ninja'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token key atrule">version</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'1.11.0'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'winget-cli'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token key atrule">version</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'1.6.3482'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>As these are the tools used to make the final produced shipping to customers that we are testing with we want to make sure these are exactly same every single time.</p>
<p>Tackling WinGet, we'll use the <a href="https://learn.microsoft.com/en-us/windows/package-manager/winget/pinning" target="_blank" rel="noopener noreferrer">pin command</a>. Though Chocolatey has some support for version ranges, WinGet's is more complete and since it's only used for the developer tools, we can install the latest patch version with confidence.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> Install C++ IDE using WinGet</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">win_shell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token scalar string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        winget pin add -e --id "{{ item.name }}" -v "{{ item.version_range }}"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">        winget install -e --id "{{ item.name }}"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">loop</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'Microsoft.VisualStudioCode'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token key atrule">version_range</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'1.76.*'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'Microsoft.VisualStudio.2022.Enterprise.Preview'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token key atrule">version_range</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'17.6.*'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="taking-a-declarative-approach">Taking a Declarative Approach<a href="https://moderncppdevops.com/windows-iac-for-cpp#taking-a-declarative-approach" class="hash-link" aria-label="Direct link to Taking a Declarative Approach" title="Direct link to Taking a Declarative Approach">​</a></h3>
<p>Declarative code is often more concise and easier to read. Developers can focus on the desired result rather than navigating through detailed step-by-step instructions. Changes can be made to the underlying system or logic without altering the overall structure of the code. With less emphasis on explicit instructions, there's a reduced chance of introducing errors due to misunderstandings or misinterpretations of imperative commands.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>For longevity, this separation between infrastructure and toolchain will help if you decided to transition to a <a href="https://thenewstack.io/platform-engineering/" target="_blank" rel="noopener noreferrer">Platform Engineering</a> approach with an IDP (<a href="https://thenewstack.io/internal-developer-portal-what-it-is-and-why-you-need-one/" target="_blank" rel="noopener noreferrer">internal developer portal</a>) for example.</p></div></div>
<p>Doing so is simple, we can run <code>choco export packages.config</code> to generate a list of dependencies.
This will give us a <a href="https://docs.chocolatey.org/en-us/guides/create/exporting-packages#installing-packages-from-a-manifest" target="_blank" rel="noopener noreferrer">manifest</a> of all the tools installed on the system.</p>
<div class="language-xml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-xml codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token prolog" style="color:rgb(0, 0, 128)">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:rgb(78, 201, 176)">packages</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:rgb(78, 201, 176)">package</span><span class="token tag" style="color:rgb(78, 201, 176)"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">id</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(212, 212, 212)">=</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">"</span><span class="token tag attr-value" style="color:rgb(206, 145, 120)">mingw</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">"</span><span class="token tag" style="color:rgb(78, 201, 176)"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">version</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(212, 212, 212)">=</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">"</span><span class="token tag attr-value" style="color:rgb(206, 145, 120)">13.2.0</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">"</span><span class="token tag" style="color:rgb(78, 201, 176)"> </span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:rgb(78, 201, 176)">package</span><span class="token tag" style="color:rgb(78, 201, 176)"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">id</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(212, 212, 212)">=</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">"</span><span class="token tag attr-value" style="color:rgb(206, 145, 120)">cmake</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">"</span><span class="token tag" style="color:rgb(78, 201, 176)"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">version</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(212, 212, 212)">=</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">"</span><span class="token tag attr-value" style="color:rgb(206, 145, 120)">3.27.9</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">"</span><span class="token tag" style="color:rgb(78, 201, 176)"> </span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:rgb(78, 201, 176)">package</span><span class="token tag" style="color:rgb(78, 201, 176)"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">id</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(212, 212, 212)">=</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">"</span><span class="token tag attr-value" style="color:rgb(206, 145, 120)">ninja</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">"</span><span class="token tag" style="color:rgb(78, 201, 176)"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">version</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(212, 212, 212)">=</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">"</span><span class="token tag attr-value" style="color:rgb(206, 145, 120)">1.11.0</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">"</span><span class="token tag" style="color:rgb(78, 201, 176)"> </span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;</span><span class="token tag" style="color:rgb(78, 201, 176)">package</span><span class="token tag" style="color:rgb(78, 201, 176)"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">id</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(212, 212, 212)">=</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">"</span><span class="token tag attr-value" style="color:rgb(206, 145, 120)">winget-cli</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">"</span><span class="token tag" style="color:rgb(78, 201, 176)"> </span><span class="token tag attr-name" style="color:rgb(156, 220, 254)">version</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(212, 212, 212)">=</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">"</span><span class="token tag attr-value" style="color:rgb(206, 145, 120)">1.6.3482</span><span class="token tag attr-value punctuation" style="color:rgb(212, 212, 212)">"</span><span class="token tag" style="color:rgb(78, 201, 176)"> </span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&lt;/</span><span class="token tag" style="color:rgb(78, 201, 176)">packages</span><span class="token tag punctuation" style="color:rgb(212, 212, 212)">&gt;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>For this example, the windows packages from WinGet are not critical for production builds, as such we'll skip those, but you are more then welcome to read their documentation for <a href="https://learn.microsoft.com/en-us/windows/package-manager/winget/install#local-install" target="_blank" rel="noopener noreferrer"><code>install --manifest</code></a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="migrating-to-the-cloud">Migrating to the Cloud<a href="https://moderncppdevops.com/windows-iac-for-cpp#migrating-to-the-cloud" class="hash-link" aria-label="Direct link to Migrating to the Cloud" title="Direct link to Migrating to the Cloud">​</a></h2>
<p>Here are the key advantages of incorporating cloud instances into a hybrid build infrastructure setup:</p>
<ol>
<li>Scalability and Elasticity:<!-- -->
<ul>
<li>Handle build spikes: Cloud instances can be provisioned quickly and on-demand, providing the flexibility to handle sudden surges in build requests or fluctuating workloads.</li>
<li>Reduce costs: Cloud resources can be scaled down during periods of low activity, optimizing resource usage and cost efficiency.</li>
</ul>
</li>
<li>Faster Build Times:<!-- -->
<ul>
<li>Access to powerful resources: Cloud instances often offer high-performance CPUs, GPUs, and large amounts of memory, accelerating build processes, especially for resource-intensive tasks.</li>
<li>Parallelization: Multiple cloud instances can be used in parallel to distribute builds across multiple machines, further reducing build times.</li>
</ul>
</li>
<li>Improved Developer Productivity:<!-- -->
<ul>
<li>Self-service provisioning: Developers can often provision cloud instances themselves, reducing reliance on IT teams and enabling faster access to build environments.</li>
<li>Experimentation and isolation: Cloud instances provide isolated environments for experimentation and testing, reducing the risk of affecting production systems.</li>
</ul>
</li>
</ol>
<p>It is possible to setup Windows VMs on Azure with both Terraform and Ansible, however this can be fairly involved. Here are some resources if you want to pursue that route.</p>
<!-- -->
<div class="tabs-container tabList__CuJ"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_LNqP tabs__item--active">Terraform</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_LNqP">Ansible</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_Ymn6"><p><a href="https://learn.microsoft.com/en-us/azure/virtual-machines/windows/quick-create-terraform" target="_blank" rel="noopener noreferrer">Writing your own a provider</a> to create a new Azure VM. Taking an extra step to <a href="https://pixelrobots.co.uk/2019/03/use-terraform-to-join-a-new-azure-virtual-machine-to-a-domain/" target="_blank" rel="noopener noreferrer">join a domain</a> or <a href="https://github.com/hashicorp/terraform/issues/14875#issuecomment-304828533" target="_blank" rel="noopener noreferrer">this alternative</a> method.</p></div><div role="tabpanel" class="tabItem_Ymn6" hidden=""><p>Using a <a href="https://github.com/Azure-Samples/ansible-playbooks/blob/76122f7/vm_create_windows.yml" target="_blank" rel="noopener noreferrer">playbook</a> to create an Azure Windows VM with <a href="https://dev.to/cloudskills/deploy-a-windows-vm-to-azure-with-ansible-2l9m" target="_blank" rel="noopener noreferrer">some extra options</a> in you need them as well as <a href="https://github.com/Azure/azure_preview_modules/issues/326" target="_blank" rel="noopener noreferrer">joining a domain</a>.</p></div></div></div>
<p>Thankfully, there's a flourishing community around Terraform Windows Azure support and there are providers that can help make this very easy.</p>
<div class="language-hcl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">main.tf</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-hcl codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">provider</span><span class="token keyword type variable" style="color:rgb(156, 220, 254)"> "azurerm" </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># Your Azure credentials</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">features</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">module</span><span class="token keyword type variable" style="color:rgb(156, 220, 254)"> "virtual-machine" </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">source</span><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"kumarvna/virtual-machine/azurerm"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">version</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"2.1.0"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># define resource group and subnet</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">virtual_machine_name</span><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"win-machine"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">os_flavor</span><span class="token plain">                 </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"windows"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">windows_distribution_name</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"windows2019dc"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">virtual_machine_size</span><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"Standard_A2_v2"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">admin_username</span><span class="token plain">            </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"azureadmin"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">admin_password</span><span class="token plain">            </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"P@$$w0rd1234!"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">instances_count</span><span class="token plain">           </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">nsg_inbound_rules</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token property">name</span><span class="token plain">                   </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"winrm"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token property">destination_port_range</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"5986"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token property">source_address_prefix</span><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"*"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain">,</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">module</span><span class="token keyword type variable" style="color:rgb(156, 220, 254)"> "domain-join" </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">source</span><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"kumarvna/domain-join/azurerm"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">version</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"1.1.0"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">virtual_machine_id</span><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> element(concat(module.virtual-machine.windows_virtual_machine_ids, </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token string" style="color:rgb(206, 145, 120)">""</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain">), </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain">)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">active_directory_domain</span><span class="token plain">   </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"myorg.com"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">active_directory_username</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"azureadmin"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token property">active_directory_password</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"P@$$w0rd1234!"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># Required TAGs for Azure resources</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now you can run Ansible normally with <code>ansible-playbook -i '${terraform.virtual-machine.windows_vm_private_ips},' playbook.yml</code> or you can add it as an extra step to the <code>main.tf</code> with:</p>
<div class="language-hcl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-hcl codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">provisioner</span><span class="token keyword type variable" style="color:rgb(156, 220, 254)"> "local-exec" </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">command</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"ansible-playbook -i '</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">$</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token string interpolation" style="color:rgb(206, 145, 120)">virtual-machine</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token string interpolation" style="color:rgb(206, 145, 120)">windows_vm_private_ips</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">,' playbook.yml"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="further-considerations">Further Considerations<a href="https://moderncppdevops.com/windows-iac-for-cpp#further-considerations" class="hash-link" aria-label="Direct link to Further Considerations" title="Direct link to Further Considerations">​</a></h2>
<p>For a comprehensive understanding, let's address some additional aspects.</p>
<ul>
<li>Testing. Testing. Testing. This would not be software engineering without a proper testing strategy.</li>
<li>Version scheme. Be able to track changes and re-deploy older environments when required.</li>
<li>Create costume base <a href="https://learn.microsoft.com/en-us/azure/virtual-machines/windows/image-builder-powershell" target="_blank" rel="noopener noreferrer">VM images on Azure</a></li>
<li>Handling Legacy systems, managing a Windows 7 machines for example, that do not support these tools.</li>
<li>Using KeyVault to a more secure automatic login <a href="https://1337.uk/articles/azure-devops-terraform-secure-vm-domain-join" target="_blank" rel="noopener noreferrer">reference</a></li>
<li>Using the <a href="https://medium.com/@fkeil/windows-ansible-chocolatey-a-beautifull-integration-acb08e9ca468" target="_blank" rel="noopener noreferrer">WSL2 shell</a></li>
<li>Supporting <a href="https://www.digitalocean.com/community/tutorials/how-to-use-ansible-with-terraform-for-configuration-management" target="_blank" rel="noopener noreferrer">Linux with Ansible</a></li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://moderncppdevops.com/windows-iac-for-cpp#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>By embracing Infrastructure as Code (IaC), like Ansible and Terraform show in the post, you can empower your C++ build infrastructure with:</p>
<ul>
<li>Streamlined Setup: Eliminate tedious manual configuration and ensure consistent, reproducible builds across build environments environments.</li>
<li>Scalability and Elasticity: Quickly adjust resources to handle sudden build spikes or fluctuating workloads, all while optimizing cost efficiency.</li>
<li>Improved Developer Productivity: Grant developers self-service provisioning and isolated, disposable environments for experimentation and testing.</li>
<li>Seamless Hybrid and Cloud Deployment: Bridge the gap between your local network and the cloud, enabling a flexible and future-proof approach to CI.</li>
</ul>
<p>Take control of your C++ build process today. Embrace IaC and unlock the agility, efficiency, and scalability you need to deliver software faster and with greater confidence.</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="c++" term="c++"/>
        <category label="devops" term="devops"/>
        <category label="windows" term="windows"/>
        <category label="ci" term="ci"/>
        <category label="continuous integration" term="continuous integration"/>
        <category label="ansible" term="ansible"/>
        <category label="terraform" term="terraform"/>
        <category label="azure cloud" term="azure cloud"/>
        <category label="infrastructure as code" term="infrastructure as code"/>
        <category label="mingw-w64" term="mingw-w64"/>
        <category label="cmake" term="cmake"/>
        <category label="ninja" term="ninja"/>
        <category label="visual studio enterprise" term="visual studio enterprise"/>
        <category label="visual studio code" term="visual studio code"/>
        <category label="reproducible builds" term="reproducible builds"/>
        <category label="cloud migration" term="cloud migration"/>
        <category label="azure vm" term="azure vm"/>
        <category label="vm domain join" term="vm domain join"/>
        <category label="devops automation" term="devops automation"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Revolutionizing C++ Development: A DevOps Odyssey]]></title>
        <id>https://moderncppdevops.com/devops-applied-to-cpp</id>
        <link href="https://moderncppdevops.com/devops-applied-to-cpp"/>
        <updated>2024-01-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Unlock the Future of C++ Development with DevOps: Explore how cutting-edge technologies like Artifact Management, Infrastructure as Code, and Platforms as a Service revolutionize the C++ ecosystem. Dive into solutions for managing dependencies, optimizing build times, and streamlining continuous integration pipelines. Join us on a DevOps odyssey where challenges transform into opportunities, propelling C++ developers towards efficiency, scalability, and resilience. Embrace the synergy of DevOps principles in our latest blog for a transformative journey in the world of C++ development.]]></summary>
        <content type="html"><![CDATA[<p>In the ever-evolving landscape of C++ development, challenges abound, but the journey to overcome them has a powerful ally: DevOps. The annual ISO committee's survey paints a vivid picture of the hurdles faced by C++ developers, but within these challenges lie opportunities for transformation through DevOps principles and cutting-edge technologies like Artifact Management, Infrastructure as Code (IaC), and Platforms as a Service (PaaS).</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="unveiling-the-challenges">Unveiling the Challenges<a href="https://moderncppdevops.com/devops-applied-to-cpp#unveiling-the-challenges" class="hash-link" aria-label="Direct link to Unveiling the Challenges" title="Direct link to Unveiling the Challenges">​</a></h3>
<p>The <a href="https://isocpp.org/files/papers/CppDevSurvey-2023-summary.pdf" target="_blank" rel="noopener noreferrer">2023 ISOCPP Survey</a> echoes the sentiments of C++ developers grappling with key issues:</p>
<ol>
<li><strong>Managing libraries my application depends on: 83%</strong></li>
<li><strong>Build times: 81%</strong></li>
<li><strong>Setting up a continuous integration pipeline from scratch: 72%</strong></li>
<li><strong>Managing CMake projects: 67% (MakeFiles MSBuild)</strong></li>
<li><strong>Setting up a development environment from scratch: 67%</strong></li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="devops-as-the-panacea">DevOps as the Panacea<a href="https://moderncppdevops.com/devops-applied-to-cpp#devops-as-the-panacea" class="hash-link" aria-label="Direct link to DevOps as the Panacea" title="Direct link to DevOps as the Panacea">​</a></h3>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="1-dependency-management-challenges">1. Dependency Management Challenges<a href="https://moderncppdevops.com/devops-applied-to-cpp#1-dependency-management-challenges" class="hash-link" aria-label="Direct link to 1. Dependency Management Challenges" title="Direct link to 1. Dependency Management Challenges">​</a></h4>
<p>DevOps, championing <a href="https://stackoverflow.com/questions/15086176/whats-the-purpose-of-an-artifact-repository" target="_blank" rel="noopener noreferrer">artifact management</a> through tools like <a href="https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html" target="_blank" rel="noopener noreferrer">Maven</a>, npm, and Cargo, unveils a canvas for addressing C++ dependency challenges. Specialized package managers such as Vcpkg and Conan offer a structured approach to managing libraries, automating retrieval and configuration. Ensuring the exact dependencies (both external open source or third-party and internal to a project) are consistently tracked and can be <a href="https://github.com/ossf/package-manager-best-practices/blob/main/published/npm.md#reproducible-installation" target="_blank" rel="noopener noreferrer">reproducibly installed</a> is a well established best practice. Through modular software design and "micro<del>services</del>libraries", C++ developers can distribute builds to enhance parallelization and fostering a streamlined development lifecycle.</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="2-monitoring-and-feedback-loop">2. Monitoring and Feedback Loop<a href="https://moderncppdevops.com/devops-applied-to-cpp#2-monitoring-and-feedback-loop" class="hash-link" aria-label="Direct link to 2. Monitoring and Feedback Loop" title="Direct link to 2. Monitoring and Feedback Loop">​</a></h4>
<p>The heartbeat of DevOps is a robust monitoring and feedback loop, powered by tools like <a href="https://www.metricfire.com/blog/monitoring-cicd-pipelines-metricfire/" target="_blank" rel="noopener noreferrer">Prometheus and Grafana</a>. For C++ developers, tracking performance metrics and build data is pivotal. Techniques such as analyzing data from <code>gcc -ftime-report</code> or <code>clang -ftime-trace</code> offer insights into the impact of changes, identifying trends enabling teams to proactively resolve issues. Increasing the granularity of the build graph and each step (configure, build, and test) can help isolate problems making the overall challenge less overwhelming. This continuous feedback loop ensures a seamless user experience and efficient CI operations.</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="3-build-script-complexity">3. Build Script Complexity<a href="https://moderncppdevops.com/devops-applied-to-cpp#3-build-script-complexity" class="hash-link" aria-label="Direct link to 3. Build Script Complexity" title="Direct link to 3. Build Script Complexity">​</a></h4>
<p>DevOps principles, particularly those of Continuous Integration/Continuous Delivery (CI/CD), are catalysts for streamlining build processes. CMake, a <a href="https://blog.jetbrains.com/clion/2023/01/cpp-ecosystem-in-2022/#what_s_up_with_cpp_tooling" target="_blank" rel="noopener noreferrer">cornerstone in the C++ ecosystem</a>, simplifies build script complexities with features like <a href="https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html" target="_blank" rel="noopener noreferrer">Presets and Workflows</a>. However, caution is advised against tightly coupling Build Scripts with Build Environments; Build scripts are software too and principals like <a href="https://stackoverflow.com/a/34634568" target="_blank" rel="noopener noreferrer">cohesion and coupling</a> still apply. Alternatively for a encompassing solution, innovative tools like <a href="https://xmake.io/#/" target="_blank" rel="noopener noreferrer">Xmake</a>, <a href="https://mesonbuild.com/" target="_blank" rel="noopener noreferrer">Meson</a> and <a href="https://bazel.build/" target="_blank" rel="noopener noreferrer">Bazel</a> are introducing features for dependency management, build orchestration, and scalability. Make sure to have a clear delineation between build environments and their toolchain, global configuration variant, and target specific compiler flags when refactoring your code.</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="4-deployable-build-environments">4. Deployable Build Environments<a href="https://moderncppdevops.com/devops-applied-to-cpp#4-deployable-build-environments" class="hash-link" aria-label="Direct link to 4. Deployable Build Environments" title="Direct link to 4. Deployable Build Environments">​</a></h4>
<p>DevOps extends its embrace to traditional IT operations, where technologies like Infrastructure as Code (IaC) take center stage. <a href="https://www.terraform.io/" target="_blank" rel="noopener noreferrer">Terraform</a> and <a href="https://www.ansible.com/" target="_blank" rel="noopener noreferrer">Ansible</a> automate infrastructure provisioning and configurations with routine checks to prevent <a href="https://www.opslevel.com/resources/understanding-and-managing-configuration-drift" target="_blank" rel="noopener noreferrer">configuration drift</a>, ensuring deployable build environments are robust and compliant. When reproducible builds are top of mind, having <a href="https://ephemeralenvironments.io/" target="_blank" rel="noopener noreferrer">ephemeral build environments</a> that can scale with elasticity is a key DevOps best practice to rely on. Leverage orchestration tools to ensure availability by provisioning the correct version controlled build environments. With the adoption of system package managers, a staple in the *Nix ecosystems with counter-parts like Chocolatey and WinGet on Windows, aligning with the ethos of reproducible builds. Ensure you treat your tools like dependencies with proper version control and <a href="https://www.unix-ag.uni-kl.de/~bloch/acng/" target="_blank" rel="noopener noreferrer">artifact management</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="embracing-the-future">Embracing the Future<a href="https://moderncppdevops.com/devops-applied-to-cpp#embracing-the-future" class="hash-link" aria-label="Direct link to Embracing the Future" title="Direct link to Embracing the Future">​</a></h3>
<p>As the C++ ecosystem navigates challenges, DevOps emerges as the guiding force, offering not just solutions but a cultural shift toward collaboration, automation, and continuous improvement. The synergy of Artifact Management, IaC, and PaaS technologies positions C++ developers on the cutting edge of a transformative journey. In this DevOps odyssey, the challenges of today become the stepping stones to a more efficient, scalable, and resilient tomorrow. Embrace the revolution, and let DevOps redefine your C++ development experience.</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="devops" term="devops"/>
        <category label="c++" term="c++"/>
        <category label="cpp" term="cpp"/>
        <category label="modern c++" term="modern c++"/>
        <category label="continuous integration" term="continuous integration"/>
        <category label="continuous delivery" term="continuous delivery"/>
        <category label="cmake projects" term="cmake projects"/>
        <category label="modular software architecture" term="modular software architecture"/>
        <category label="improving build times" term="improving build times"/>
        <category label="artifact management" term="artifact management"/>
        <category label="dependency management" term="dependency management"/>
        <category label="reproducible builds" term="reproducible builds"/>
        <category label="IaC" term="IaC"/>
        <category label="PaaS" term="PaaS"/>
        <category label="orchestration" term="orchestration"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Unveiling the Power of C++ DevOps: Bridging Disciplines for Seamless Development]]></title>
        <id>https://moderncppdevops.com/why-devops-in-cpp</id>
        <link href="https://moderncppdevops.com/why-devops-in-cpp"/>
        <updated>2024-01-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Explore the transformative synergy of C++ development and DevOps practices in our insightful blog. Uncover how the cultural shift advocated by DevOps aligns seamlessly with the historical and current roles within the C++ ecosystem, addressing prevalent challenges faced by developers. Dive deep into the philosophy, success stories, and specialized tools like CMake, Spack, and Xmake that redefine efficiency in C++ DevOps. From dependency management to build script complexities, discover how embracing the principles of DevOps not only streamlines processes but also fosters a collaborative and efficient development environment. Join us on this journey where software development meets cultural transformation, empowering teams to deliver high-quality code with speed, reliability, and precision.]]></summary>
        <content type="html"><![CDATA[<p>In the ever-evolving landscape of software development, the transformative influence of DevOps cannot be overstated. It has reshaped how teams collaborate, develop, build, test, and ultimately deliver applications. DevOps is more than a mere collection of practices or tools; it embodies a cultural shift, fostering collaboration and communication among software developers, QA professionals, and IT operations.</p>
<p>Today, we navigate the intricate landscape of C++, delving into how the DevOps approach aligns seamlessly with both historical and contemporary roles within the ecosystem. It becomes apparent that DevOps best practices hold the key to unlocking solutions for some of the most prevalent challenges faced by C++ developers.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="devops-philosophy-beyond-criticism">DevOps Philosophy: Beyond Criticism<a href="https://moderncppdevops.com/why-devops-in-cpp#devops-philosophy-beyond-criticism" class="hash-link" aria-label="Direct link to DevOps Philosophy: Beyond Criticism" title="Direct link to DevOps Philosophy: Beyond Criticism">​</a></h3>
<p>Critics, such as <a href="https://www.quora.com/What-should-a-DevOps-know-in-2015/answer/Scott-Willson-4" target="_blank" rel="noopener noreferrer">Scott Willson</a>, correctly predicted back in 2015 the far-reaching scope of DevOps, encompassing best practices, behaviors, and tools across various disciplines involved in the entire software development lifecycle. The essence is not about overburdening developers but applying good software practices universally, as exemplified in talks like <a href="https://legacy.devopsdays.org/events/2015-toronto/proposals/Chef,%20test-kitchen,%20Docker,%20CI,%20Oh%20My!" target="_blank" rel="noopener noreferrer">"Chef, test-kitchen, Docker, CI, Oh My!"</a> from <a href="https://legacy.devopsdays.org/events/2015-toronto/program/" target="_blank" rel="noopener noreferrer">DevOps Day Toronto back in 2015</a>. This philosophy transcends individual roles, emphasizing a comprehensive and collaborative approach. Software design principals likes Coupling and Cohesion should also apply to how we manage build environments.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="success-in-other-disciplines-a-call-to-action">Success in Other Disciplines: A Call to Action<a href="https://moderncppdevops.com/why-devops-in-cpp#success-in-other-disciplines-a-call-to-action" class="hash-link" aria-label="Direct link to Success in Other Disciplines: A Call to Action" title="Direct link to Success in Other Disciplines: A Call to Action">​</a></h3>
<p>DevOps emerged in 2010 as a <a href="https://www.atlassian.com/devops/what-is-devops/history-of-devops" target="_blank" rel="noopener noreferrer">response to the challenges posed by Agile methods</a>, eventually leading to the realization that faster software delivery could unlock competitive advantages. The <a href="https://www.prnewswire.com/news-releases/devops-research-and-assessment-dora-announces-the-2018-accelerate-state-of-devops-report-300703837.html" target="_blank" rel="noopener noreferrer">State of DevOps reports from 2018</a> underscored this, highlighting the strategic edge gained through accelerated software delivery. In 2023, the momentum has <a href="https://thenewstack.io/qa-patrick-debois-on-the-past-present-and-future-of-devops/" target="_blank" rel="noopener noreferrer">shifted towards Platform Engineering</a>, reflecting the evolving expectations for collaboration post-pandemic.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="understanding-c-devops-dispelling-misconceptions">Understanding C++ DevOps: Dispelling Misconceptions<a href="https://moderncppdevops.com/why-devops-in-cpp#understanding-c-devops-dispelling-misconceptions" class="hash-link" aria-label="Direct link to Understanding C++ DevOps: Dispelling Misconceptions" title="Direct link to Understanding C++ DevOps: Dispelling Misconceptions">​</a></h3>
<p>While skepticism exists about the necessity of DevOps for C++ development, some argue that it conflicts with the language's low-level programming focus and misconceptions that DevOps is exclusively for cloud deployment. This perspective views specialized DevOps roles as potentially distracting from the core development work.</p>
<p>However, despite reservations, there's a compelling acknowledgment that <a href="https://www.incredibuild.com/blog/top-8-c-developer-pain-points" target="_blank" rel="noopener noreferrer">certain challenges faced by C++ developers</a> undeniably fall within the DevOps domain. Managing dependencies, a persistent issue in C++ development, becomes increasingly complex as projects scale. Yet solutions to this problem can be <a href="https://devops.com/devops-challenges-c-c-projects/" target="_blank" rel="noopener noreferrer">traced back to 2017</a>. DevOps practices, particularly those executed by Build and Release Engineers, provide solutions for dependency management, version compatibility, and maintaining consistent build environments.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="demonstrating-devops-impact">Demonstrating DevOps Impact<a href="https://moderncppdevops.com/why-devops-in-cpp#demonstrating-devops-impact" class="hash-link" aria-label="Direct link to Demonstrating DevOps Impact" title="Direct link to Demonstrating DevOps Impact">​</a></h3>
<p>To illustrate the monumental potential for efficiency gains, consider the integration of DevOps principles like CI/CD with the addition of <a href="https://gitlab.kitware.com/cmake/cmake/-/issues/23118" target="_blank" rel="noopener noreferrer">Workflow Presets</a> in the ubiquitous build system tool CMake. This new feature can be a cornerstone in simplifying build script complexities. The recent introduction of innovative tools like <a href="https://spack.readthedocs.io/en/latest/" target="_blank" rel="noopener noreferrer">Spack</a>, <a href="https://xmake.io/#/" target="_blank" rel="noopener noreferrer">Xmake</a>, and <a href="https://tipi.build/" target="_blank" rel="noopener noreferrer">Tipi</a> building upon the success of Conan and Vcpkg further amplifies these gains, addressing challenges in dependency management. Build orchestration and scalability is another area where pioneering tools like <a href="https://bazel.build/basics/distributed-builds" target="_blank" rel="noopener noreferrer">Bazel</a> and <a href="https://www.incredibuild.com/" target="_blank" rel="noopener noreferrer">IncrediBuild</a> have seen huge success reducing build times across the ecosystem.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="specialized-roles-a-growing-necessity">Specialized Roles: A Growing Necessity<a href="https://moderncppdevops.com/why-devops-in-cpp#specialized-roles-a-growing-necessity" class="hash-link" aria-label="Direct link to Specialized Roles: A Growing Necessity" title="Direct link to Specialized Roles: A Growing Necessity">​</a></h3>
<p>The demand for highly specialized roles, such as Build and Release Engineer, C++ Build Tools Engineer, and Build Automation Engineer, remains high within the C++ ecosystem. <a href="https://isocpp.org/files/papers/CppDevSurvey-2023-summary.pdf" target="_blank" rel="noopener noreferrer">The 2023 ISOCPP Survey</a> reported 73% of developers struggle with setting up CI pipelines, with eight identified problems falling under the DevOps umbrella. Recognizing this, it becomes evident that the DevOps toolkit offers specialized tools and best practices aimed squarely at solving these pervasive problems.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion-a-cultural-transformation">Conclusion: A Cultural Transformation<a href="https://moderncppdevops.com/why-devops-in-cpp#conclusion-a-cultural-transformation" class="hash-link" aria-label="Direct link to Conclusion: A Cultural Transformation" title="Direct link to Conclusion: A Cultural Transformation">​</a></h3>
<p>In conclusion, while skepticism may linger, there's an increasing acknowledgment that integrating DevOps practices and technologies into the C++ development landscape is not just a choice; it's a strategic necessity. C++ DevOps is not solely a technical evolution; it's a cultural transformation that unites developers, QA professionals, and operations teams. Embracing C++ DevOps becomes indispensable for organizations aspiring to thrive in the ever-evolving and competitive software development landscape.</p>]]></content>
        <author>
            <name>Christopher McArthur</name>
            <uri>https://github.com/prince-chrismc</uri>
        </author>
        <category label="devops" term="devops"/>
        <category label="platform engineering" term="platform engineering"/>
        <category label="cpp" term="cpp"/>
        <category label="modern c++" term="modern c++"/>
        <category label="ci/cd" term="ci/cd"/>
        <category label="continuous integration" term="continuous integration"/>
        <category label="continuous delivery" term="continuous delivery"/>
        <category label="build automation" term="build automation"/>
        <category label="c++ build tools" term="c++ build tools"/>
        <category label="cmake" term="cmake"/>
        <category label="xmake" term="xmake"/>
        <category label="spack" term="spack"/>
        <category label="conan" term="conan"/>
        <category label="vcpkg" term="vcpkg"/>
        <category label="bazel" term="bazel"/>
    </entry>
</feed>