{"id":32767,"date":"2023-09-11T16:00:01","date_gmt":"2023-09-11T16:00:01","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/cppblog\/?p=32767"},"modified":"2023-09-08T20:32:30","modified_gmt":"2023-09-08T20:32:30","slug":"integrating-c-header-units-into-office-using-msvc-2-n","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/integrating-c-header-units-into-office-using-msvc-2-n\/","title":{"rendered":"Integrating C++ header units into Office using MSVC (2\/n)"},"content":{"rendered":"<p>In this follow-up blog, we will explore progress made towards getting header units working in the Office codebase.<\/p>\n<h2>Overview<\/h2>\n<ul>\n<li><a href=\"#overview\">Overview: Where we were, where we&#8217;re going.<\/a><\/li>\n<li><a href=\"#old-code\">Old Code, Old Problems: &#8216;fun&#8217; code issues found while scaling out.<\/a><\/li>\n<li><a href=\"#rethink\">Rethinking Compiler Tooling: How can the compiler rise to the scaling problems?<\/a><\/li>\n<li><a href=\"#ifc-ref\">A New Approach to Referencing an IFC.<\/a><\/li>\n<li><a href=\"#pch\">Playing Nice With Precompiled Headers (PCH).<\/a><\/li>\n<li><a href=\"#selection\">Selecting a Launch Project: REDACTED.<\/a><\/li>\n<li><a href=\"#looking-ahead\">Looking Ahead: Throughput.<\/a><\/li>\n<\/ul>\n<h2><span id=\"overview\">Overview<\/span><\/h2>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/integrating-c-header-units-into-office-using-msvc-1-n\/\">Last time<\/a> we talked about how and why header units can be integrated into a large cross-platform codebase like Office. We discussed\nhow header units helped surface conformance issues (good) and expose and fix compiler bugs (good-ish).<\/p>\n<p>We talked about how we went about taking &#8220;baby steps&#8221; to integrate header units into smaller liblets\u2014we&#8217;re talking\nsomething on the order of 100s of header units. This blog entry is all about scale and how we move from 100s of header\nunits to 1000s of header units, including playing nicely with precompiled headers!<\/p>\n<p>Office&#8217;s header unit experiments continued by following the charge that we left you with in the last blog post: &#8220;Header\nUnit All the Things!&#8221;. From that perspective we were wildly successful! By the last count we were able to successfully\ncreate over 5000 header units from liblet public headers. The road to reach that milestone wasn&#8217;t always smooth, and\nwe&#8217;ll cover some of the challenges.<\/p>\n<p>We&#8217;d like to highlight that the recent release of <a href=\"https:\/\/learn.microsoft.com\/en-us\/visualstudio\/releases\/2022\/release-notes-v17.6#17.6.6\">MSVC 17.6.6<\/a> makes\nthis one of the best times to get started with header units! The release contains the full set of fixes that were\ndiscovered in cooperation with Office. The full set of fixes will also be available in 17.7.5 and 17.8 preview 2.<\/p>\n<h2><span id=\"old-code\">Old Code, Old Problems<\/span><\/h2>\n<p>While scaling out we encountered quite a number of complications. Some fixes involved updating Office code, while\nothers needed to be solved on the compiler side. We&#8217;ll present just a few examples from each bucket.<\/p>\n<h3><span id=\"symlinks\">Symbolic Links<\/span><\/h3>\n<p>The way Office sources coalesce is a mix between sources populated by git and libraries populated by NuGet\npackages which are then linked into a build source tree via symbolic links. From a build perspective, this is extremely\nconvenient because you can decouple library updates from the sources and you can have one copy of library code shared\nacross multiple copies of the git sources.<\/p>\n<p>Symbolic links are interesting from a compiler perspective for two reasons: diagnostics and <a href=\"https:\/\/learn.microsoft.com\/en-us\/cpp\/preprocessor\/once?view=msvc-170\"><code>#pragma once<\/code><\/a>. For source\nlocations, there are two options: use the symbolic link as the file name or use the physical file the link resolves to.\nWhen issuing diagnostics, the compiler tries to use the symbolic link location because that is what was provided on the\n<a href=\"https:\/\/learn.microsoft.com\/en-us\/cpp\/build\/reference\/i-additional-include-directories?view=msvc-170\"><code>\/I<\/code><\/a>\nline, but there are cases where you might want the physical file location.<\/p>\n<p><code>#pragma once<\/code> is a whole other beast with respect to symbolic links. In the beginning, C-style include guards\nwere created as a method of preventing repeated file <em>content<\/em>. <code>#pragma once<\/code> came about as a method of\npreventing inclusion of the <em>same file<\/em>. The distinction between file and content is part of the reason why <code>#pragma\nonce<\/code> is difficult to standardize due to its reliance on filesystem vagaries to identify what it means to point to the\n&#8220;same file&#8221;.<\/p>\n<p>Consider a small example:<\/p>\n<ul>\n<li>Real file: <code>C:\\inc\\a.h<\/code> which contains a single <code>#pragma once<\/code><\/li>\n<li>Symlink 1: <code>C:\\syms\\inc\\lib1\\a.h -&gt; C:\\inc\\a.h<\/code><\/li>\n<li>Symlink 2: <code>C:\\syms\\inc\\lib2\\a.h -&gt; C:\\inc\\a.h<\/code><\/li>\n<\/ul>\n<p>Further consider a header in <code>C:\\syms\\inc\\lib2\\b.h<\/code>:<\/p>\n<pre>#pragma once\r\n#include \"a.h\"<\/pre>\n<p>Then in our sources we have:<\/p>\n<pre>#include \"lib1\/a.h\"\r\n#include \"lib2\/b.h\"<\/pre>\n<p>Let&#8217;s dive into what should happen here:<\/p>\n<ul>\n<li>The compiler sees symlink #1 through <code>\"lib1\/a.h\"<\/code>, sees <code>#pragma once<\/code> in the file content and records that file <code>C:\\syms\\inc\\lib1\\a.h<\/code> is associated with a pragma once.<\/li>\n<li>The compiler reads <code>\"lib2\/b.h\"<\/code> and sees an inclusion of <code>\"lib2\/a.h\"<\/code>.<\/li>\n<li>Symlink #2 is then read and the compiler observes that <code>#pragma once<\/code> is in the file content and records that file <code>C:\\syms\\inc\\lib2\\a.h<\/code> is associated with a pragma once.<\/li>\n<\/ul>\n<p>See a problem?<\/p>\n<p>The fact that the compiler read the file content from symlink #2 is where things start to go wrong. What should\nhave happened is that the compiler unwraps the symbolic link to discover what the underlying file is and records the\nreal file as the owner of the pragma once, which is exactly what we did to solve the problem in normal compilation\nscenarios.<\/p>\n<p>How does the situation above play into header units? Header units need to work like a PCH where they record\nmacros and pragma state, which includes <code>#pramga once<\/code>. This means that the IFC needs to record symbolic\nlinks and their &#8220;unwrapped&#8221; files so that the compiler can properly enforce <code>#pragma once<\/code>. After this work\nwas done, many more scenarios were unblocked in the Office build.<\/p>\n<p><em>As a side note: it is always better to rely on standard C++ features to prevent repeated file content\ninclusion and doing so side-steps the symbolic link problem entirely.<\/em><\/p>\n<h3><span id=\"conditional-compilation\">Inconsistent Conditional Compilation<\/span><\/h3>\n<p>We called out the most critical source of issues in the first blog post: inconsistent conditional compilation. As\nthe experiment added projects we ran into an increasing number of conflicts. Individual projects, or sometimes\nisolated build nodes, couldn&#8217;t agree if the <a href=\"https:\/\/learn.microsoft.com\/en-us\/cpp\/build\/reference\/j-default-char-type-is-unsigned?view=msvc-170\">default char\ntype is unsigned<\/a>, <a href=\"https:\/\/learn.microsoft.com\/en-us\/cpp\/build\/reference\/gr-enable-run-time-type-information?view=msvc-170\">if RTTI\nshould be enabled<\/a>, or if <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040212-00\/?p=40643\">UNICODE support\nshould be set<\/a>, and that&#8217;s only in command line options!<\/p>\n<p>Across liblet headers there were also code level macros to detangle: conditional selection of a memory allocator,\nmasks for disallowed Windows SDK functions, plus the <code>ASSUME<\/code> macro example still hadn&#8217;t been resolved! Solving such\nproblems could require touching nearly every project in Office.<\/p>\n<h3><span id=\"internal-linkage\">Internal Linkage<\/span><\/h3>\n<p>Declarations at namespace, including global, scope marked <code>static<\/code> have internal linkage. With textual includes\nthis isn&#8217;t an issue for declarations such as <code>static const float pi = 3.14<\/code> because the contents of the header file become\npart of the translation unit. The source used to compile a header unit is a translation unit unto itself and thus the\ndefinition of <code>pi<\/code> will not be visible when it is imported. Fortunately, the fix is simple. Such data declarations\nshould be marked as <code>inline constexpr<\/code>. However, after converting the constant declarations to be <code>inline constexpr<\/code> we\nwere still seeing many unresolved symbols during linking. These issues ultimately required a compiler change so that\nIFC could contain the full initialization information for the data.<\/p>\n<p>Naturally, the compiler had to account for the common case where global variables marked as <code>inline constexpr<\/code>\nshould have their values encoded into the actual IFC. In general, the compiler already does this for simpler values\nsuch as integral types, but more complex user-defined types or arrays of objects had to be accounted for. As a compiler optimization, the variable is only instantiated when it is referenced.\nMore specifically, the compiler will only materialize the initializer if the variable is odr-used.<\/p>\n<h3><span id=\"internal-linkage\">Mismatched Include Paths<\/span><\/h3>\n<p>Office has continued to utilize the <a href=\"https:\/\/learn.microsoft.com\/en-us\/cpp\/build\/reference\/translateinclude?view=msvc-170\"><code>\/translateInclude<\/code><\/a>\nflag to consume header units without rewriting source code. For this to operate as expected the <code>#include<\/code>\ndirectives in source must match what is specified by a <a href=\"https:\/\/learn.microsoft.com\/en-us\/cpp\/build\/reference\/headerunit?view=msvc-170\"><code>\/headerUnit<\/code><\/a>\nswitch. In Office the most common issue was a reference that used the internal path to a header instead of the external\none.<\/p>\n<table style=\"border-collapse: collapse; width: 100%; height: 84px;\">\n<tbody>\n<tr style=\"height: 28px;\">\n<td style=\"width: 7.59961%; height: 28px;\">Example switch:<\/td>\n<td style=\"width: 92.4004%; height: 28px;\"><code>\/headerUnit:quote componentA\/publicheader.h=ifcdir\/publicheader.h.ifc<\/code><\/td>\n<\/tr>\n<tr style=\"height: 28px;\">\n<td style=\"width: 7.59961%; height: 28px;\">Incorrect path:<\/td>\n<td style=\"width: 92.4004%; height: 28px;\"><code>#include &lt;src\/public\/publicheader.h&gt;<\/code><\/td>\n<\/tr>\n<tr style=\"height: 28px;\">\n<td style=\"width: 7.59961%; height: 28px;\">Correct path:<\/td>\n<td style=\"width: 92.4004%; height: 28px;\"><code>#include &lt;componentA\/publicheader.h&gt;<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>In the above example the incorrect path will not match the <em>header-filename<\/em> portion of the\n<code>\/headerUnit<\/code> switch and thus will be textually included. Finding incorrect include paths is tricky because\nthe code will compile correctly. The best way to discover any issues is to examine the output provided by <a href=\"https:\/\/learn.microsoft.com\/en-us\/cpp\/build\/reference\/sourcedependencies?view=msvc-170\"><code>\/sourceDependencies<\/code><\/a>\nfor unexpected textual includes.<\/p>\n<h3><span id=\"ifc-updates\">Updating the IFC Specification<\/span><\/h3>\n<p>There&#8217;s been a perennial feedback bug since the original modules implementation in the compiler: <a href=\"https:\/\/developercommunity.visualstudio.com\/t\/using-namespace-declaration-ignored-wh\/10211461\">`using namespace`\ndeclaration ignored when compiling as a header unit module<\/a>. The problem was that the IFC had no representation for\nusing-directives at namespace scope (e.g. <code>using namespace std;<\/code>). It turns out that Office also ran into this issue so to continue the experiment,\nwe had to fix it. After some thinking through the problem, we came up with <a href=\"https:\/\/github.com\/microsoft\/ifc-spec\/pull\/76\">IFC-76<\/a> which describes an encoding method\nfor persisting directives in a translation unit.<\/p>\n<h3><span id=\"assumptions\">Breaking Historical Assumptions<\/span><\/h3>\n<p>Before modules existed, the compiler had been around for nearly 25 years. This was enough time for the toolchain\nto develop several assumptions about how the front-end conveys data to the back-end. One such coupling was\nencoding type information directly into compiled functions. Handles to the compiler-generated type information are 0-index-based and the underlying data is generated along with each handle. There was one case where this type index was\nemitted directly into a tree for the purposes of annotating type information with <code>new<\/code> expressions for the\ndebugger:<\/p>\n<pre>int* make_int() {\r\n  return new int{}; \/\/ &lt;- generated a direct encoding of the type index for 'new'\r\n}<\/pre>\n<p>Why does this encoding cause a problem for modules? Since the compiler is now persisting compiled inline\nfunctions into the IFC the compiler also persists this type index from one compilation to the next and would, sometimes,\ncause a linker crash as it goes to lookup the type index from the PDB but crashes because the index for that particular\ntranslation unit is based on an array generated in a completely different translation unit. Office was able to reveal\nthis issue very quickly as many of the link steps involved lots of translation units from which this bug would\nsurface.<\/p>\n<h3><span id=\"windows-sdk\">Windows SDK Woes<\/span><\/h3>\n<p>There is a, quite an old now, bug out: <a href=\"https:\/\/developercommunity.visualstudio.com\/t\/Visual-Studio-cant-find-time-function\/1126857\">Visual Studio can&#8217;t find time() function using modules and std.core<\/a>. The\nroot cause here is that the UCRT contains a definition of the <code>time()<\/code> function from C where it is defined as a <code>static\ninline<\/code> function within the SDK header. These <code>static inline<\/code> functions stem from C not having the C++ meaning of\n<code>inline<\/code> but <code>static inline<\/code> on a function declaration allows the function to behave as if it had C++ <code>inline<\/code>-like\nsemantics. Note that defining the C standard function <code>time()<\/code> as <code>static inline<\/code> is in direct violation of the C\nstandard which explicitly says that C standard library functions have external linkage. The Windows SDK team is hard at\nwork fixing the issue above along with some other SDK issues that have plagued C++ modules interactions in the past, so\nstay tuned for fixes soon!<\/p>\n<h2><span id=\"rethink\">Rethinking Compiler Tooling<\/span><\/h2>\n<p>As we scaled the number of projects being built by the compiler using the header unit technology it became\nimmediately evident that we quickly needed to rethink how to debug compiler problems. The traditional loop involved\neither reducing the failure to a simple two or three file repro or attaching to a remote debugging instance where the\ncompiler was running on the build machine. It&#8217;s easy to see how and why these approaches do not scale. Here are the\nconcrete problems we needed to solve:<\/p>\n<ul>\n<li>Reproduction data collection should be asynchronous. We did not want the process of capturing a repro to be a blocking task.<\/li>\n<li>The data emitted by the compiler should be rich enough to reproduce the failure without debugging a remote compiler.<\/li>\n<li>The process of emitting data should be completely opt-in and not have a performance impact if you did not request it.<\/li>\n<li>The tool should offer a powerful visualization of the data such that we can easily navigate it and identify the underlying problem quickly.<\/li>\n<\/ul>\n<p>With the requirements outlined we designed a system inside the compiler which would act as a trace logging system\nfor any modules-related functionality. If you would find value in using these types of tools, please let us\nknow!<\/p>\n<h2><span id=\"ifc-ref\">A New Approach to Referencing an IFC<\/span><\/h2>\n<p>Before the Office header unit experiments, the compiler relied on a pair of command line switches to specify\nindividual IFC files: <a href=\"https:\/\/learn.microsoft.com\/en-us\/cpp\/build\/reference\/module-reference?view=msvc-170\"><code>\/reference<\/code><\/a>\nfor named modules, and <a href=\"https:\/\/learn.microsoft.com\/en-us\/cpp\/build\/reference\/headerunit?view=msvc-170\"><code>\/headerUnit<\/code><\/a> for\nheader units. It turns out that when thousands of header units or named modules are involved the command line grows\nquite long and unwieldy! An enormous list of flags is difficult to work with if there are compiler bugs to investigate,\nas you cannot &#8216;comment&#8217; out a header unit reference easily. We solved this problem by implementing a new\nway of conveying IFC dependencies to the compiler: <code>\/ifcMap<\/code>. The <code>\/ifcMap<\/code> allows the user to provide an IFC reference map\nfile, which is a subset of the <a href=\"https:\/\/toml.io\/en\/\">TOML<\/a> file format, to the compiler which details a mapping from named module name or\nheader-name to its respective IFC which should be loaded. Here&#8217;s a quick example of a valid .toml file for the switch:<\/p>\n<pre># Header Units\r\n[[header-unit]]\r\nname = ['quote', 'm1.h']\r\nifc = 'm1.h.ifc'\r\n\r\n[[header-unit]]\r\nname = ['quote', 'm2.h']\r\nifc = 'm2.h.ifc'\r\n\r\n# Modules\r\n[[module]]\r\nname = 'm1'\r\nifc = 'm1-renamed.ifc'\r\n\r\n[[module]]\r\nname = 'm2'\r\nifc = 'm2-renamed.ifc'<\/pre>\n<p><code>\/ifcMap<\/code> allowed office to scale the number of header units painlessly and offer a solution to easily manage lots\nof header unit references beyond having them splat on one giant command line. The IFC map also enables a tight\niterative approach when considering factors like debugging needs, both for the developer and the compiler team.<\/p>\n<h2><span id=\"pch\">Playing Nice with Precompiled Headers (PCH)<\/span><\/h2>\n<p>Part of scaling out for the compiler is that large projects often use <a href=\"https:\/\/learn.microsoft.com\/en-us\/cpp\/build\/creating-precompiled-header-files?view=msvc-170\">PCH<\/a> as a way of\nachieving build speed. PCH is a reliable technology and has had the benefit of over 30 years of hardening and\noptimization. Header units as the standardized replacement for PCH still need to integrate seamlessly into these older\nbuild environments still using tried and true PCH technology. Furthermore, Office needs to maintain compatibility with\nthe non-Windows platforms that aren&#8217;t ready to adopt header units yet.<\/p>\n<p>The approach mentioned last time to force include the Office shared precompiled header file into each header unit\nresulted in a lot of duplicated parsing in the compiler. To that end we added support to consume the binary PCH\ndirectly when creating a header unit. This resulted in a nice performance win when compiling header units!\nUnfortunately, this resulted in a large build throughput degradation when consuming header units. As much as possible\nwe would need to get precompiled headers out of the picture.<\/p>\n<p>The first, na\u00efve, tactic was to ensure that each public header was truly self-contained. Eliminating invisible\ndependencies felt like a virtuous task, even without considering the benefits to the header unit experiment! Thousands\nof <code>#include &lt;windows.h&gt;<\/code> and <code>#include &lt;stl.h&gt;<\/code> additions later, we were ready to\ntest performance again\u2026 and it was barely any better. The issue is that precompiled headers and IFC are fundamentally\ndifferent technologies. Requiring the compiler to reconcile data from both sources is incredibly wasteful. The headers\nbeing compiled into header units were free of binary PCH dependencies but a majority of cpp files were still using both\ntechnologies.<\/p>\n<p>At this point it&#8217;s worth noting that we measured a significant build throughput improvement in projects that\nconsumed header units but did not utilize a precompiled header. Individual compilands that switched from traditional\nPCH consumption to PCH-as-header unit import, saw build time improvements well above 50%. This is one of the key\nbenefits that modules promised!<\/p>\n<p>The idea to <em>create a header unit out of the existing PCH<\/em> was the flash of insight we needed to keep the experiment\nmoving forward! Although the compiler allows mixing PCH and header units it&#8217;s much more efficient to &#8220;pick a lane&#8221; in\nyour build system. By not presenting duplicate information to the compiler, it&#8217;s easier to create build throughput\nwins.<\/p>\n<h2><span id=\"selection\">Selecting a Launch Project: Microsoft Word<\/span><\/h2>\n<p>Although we were able to scale the experiment up and generate over 5000 header units from our liblet public\nheaders, some low-level blocks needed to be cleared before we could utilize header units in our production build\nenvironment. We looked for a sizable project that could avoid the inconsistent conditional compilation issues that\nneeded more time to clean up. Luckily, we found a great candidate in Microsoft Word.<\/p>\n<p>Word has utilized MSVC&#8217;s <a href=\"https:\/\/learn.microsoft.com\/en-us\/cpp\/build-insights\/get-started-with-cpp-build-insights?view=msvc-170\">C++ Build\nInsights<\/a> to craft optimal precompiled headers. Specifically, the techniques presented in <a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/faster-builds-with-pch-suggestions-from-c-build-insights\/\">Faster builds with PCH\nsuggestions from C++ Build Insights &#8211; C++ Team Blog<\/a> were used to measure the performance benefit for\neach individual file included in their main PCH. Word was to be our first test converting existing precompiled headers\ndirectly to header units. At a high level the steps required were:<\/p>\n<ol>\n<li>Create a header unit instead of a pch.\u00a0 Switch<code>\/Yc<\/code> to <code>\/exportHeader<\/code><\/li>\n<li>Replace the use PCH flag with a standard header unit reference: <code>\/Yu<\/code> to <code>\/headerUnit:quote word_shared.h=path\/to\/word_shared.ifc<\/code><\/li>\n<li>Profit?<\/li>\n<\/ol>\n<p>The code changes required in Word after adjusting the build flags were similar to what was described above. Constants needed to be made <code>inline\nconstexpr<\/code>, missing includes or forward declarations added, and a handful of function definitions moved out-of-line. In\ntotal only 2 dozen C++ files in Word required code changes to compile successfully after the switch! The most unexpected of\nthese changes were to standardize on quotes instead of angle brackets when writing the PCH&#8217;s <code>#include<\/code> for the sake of consistency with\nthe <code>\/headerUnit<\/code> switch.<\/p>\n<p>Along with the conversion from Word&#8217;s PCH to header units we created a header unit from the standard library.\nIn the C++23 world, C++ projects can utilize the standard library module that ships alongside the compiler via <code>import std;<\/code> or <code>import\nstd.compat;<\/code>. Unfortunately, Office makes edits to the standard library and thus must create its own header unit or\nnamed module.<\/p>\n<p>With this set of changes, we proved it possible to compile, link and launch Microsoft Word with header units!<\/p>\n<p><img decoding=\"async\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2023\/09\/word-with-header-units.png\" alt=\"Image of Microsoft Word running after being built using header units\" \/><\/p>\n<h2><span id=\"looking-ahead\">Looking Ahead: Throughput<\/span><\/h2>\n<p>The next step was to demonstrate the advantages that header units would bring to the Word engineering team.\nFortunately, we were able to show a build performance improvement great enough that the team agreed to adopt header\nunits into the Office production build system alongside msvc 17.6.6! In our next installment we&#8217;ll go over our performance findings in\ndepth.<\/p>\n<h4>Closing<\/h4>\n<p>As always, we welcome your feedback. Feel free to send any comments through e-mail at <a href=\"mailto:visualcpp@microsoft.com\">visualcpp@microsoft.com<\/a> or through <a href=\"https:\/\/twitter.com\/visualc\">Twitter @visualc<\/a>. Also, feel free to follow Cameron DaCamara on Twitter <a href=\"https:\/\/twitter.com\/starfreakclone\">@starfreakclone<\/a>.<\/p>\n<p>If you encounter other problems with MSVC in VS 2019\/2022 please let us know via the <a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/ide\/how-to-report-a-problem-with-visual-studio?view=vs-2019\">Report\na Problem<\/a> option, either from the installer or the Visual Studio IDE itself. For suggestions or bug reports, let us\nknow through <a href=\"https:\/\/developercommunity.visualstudio.com\/\">DevComm.<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this follow-up blog, we will explore progress made towards getting header units working in the Office codebase. Overview Overview: Where we were, where we&#8217;re going. Old Code, Old Problems: &#8216;fun&#8217; code issues found while scaling out. Rethinking Compiler Tooling: How can the compiler rise to the scaling problems? A New Approach to Referencing an [&hellip;]<\/p>\n","protected":false},"author":39620,"featured_media":32106,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1,512],"tags":[140,100,2064,3925,246,3924],"class_list":["post-32767","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cplusplus","category-general-cpp-series","tag-c","tag-c-language","tag-c20","tag-modernization","tag-modules","tag-office"],"acf":[],"blog_post_summary":"<p>In this follow-up blog, we will explore progress made towards getting header units working in the Office codebase. Overview Overview: Where we were, where we&#8217;re going. Old Code, Old Problems: &#8216;fun&#8217; code issues found while scaling out. Rethinking Compiler Tooling: How can the compiler rise to the scaling problems? A New Approach to Referencing an [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/32767","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/users\/39620"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=32767"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/32767\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/32106"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=32767"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=32767"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=32767"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}