<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Low Level Bits]]></title><description><![CDATA[Talking to Machines]]></description><link>https://lowlevelbits.com</link><image><url>https://substackcdn.com/image/fetch/$s_!jflz!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134a5988-106b-4fdc-9802-a4b2921d5a98_491x491.png</url><title>Low Level Bits</title><link>https://lowlevelbits.com</link></image><generator>Substack</generator><lastBuildDate>Wed, 06 May 2026 11:05:32 GMT</lastBuildDate><atom:link href="https://lowlevelbits.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Alex Denisov]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[lowlevelbits@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[lowlevelbits@substack.com]]></itunes:email><itunes:name><![CDATA[AlexDenisov]]></itunes:name></itunes:owner><itunes:author><![CDATA[AlexDenisov]]></itunes:author><googleplay:owner><![CDATA[lowlevelbits@substack.com]]></googleplay:owner><googleplay:email><![CDATA[lowlevelbits@substack.com]]></googleplay:email><googleplay:author><![CDATA[AlexDenisov]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[The missing guide to Dataflow Analysis in MLIR]]></title><description><![CDATA[Things you need to know to work with MLIR's Dataflow Analysis Framework]]></description><link>https://lowlevelbits.com/p/the-missing-guide-to-dataflow-analysis</link><guid isPermaLink="false">https://lowlevelbits.com/p/the-missing-guide-to-dataflow-analysis</guid><dc:creator><![CDATA[AlexDenisov]]></dc:creator><pubDate>Thu, 29 May 2025 19:42:31 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!jsWz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F407524a8-6134-4a64-b230-424becf598a5_8592x3720.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>MLIR comes with the Dataflow Analysis Framework out of the box.<br>This article describes how it works, what&#8217;s the difference between Dense and Sparse analyses, and most importantly some pitfalls and gotchas you should be aware of before starting using it.</p><h3>Monotone Framework</h3><blockquote><p>This section is a very brief recap of the dataflow framework.<br>For more detailed and certainly more correct explanation consider watching <a href="https://www.cs.cornell.edu/courses/cs6120/2020fa/lesson/4/">these lectures</a> or diving even deeper with the <a href="https://cs.au.dk/~amoeller/spa/">SPA book</a> (chapters 4 and 5).</p></blockquote><p>The goal of a dataflow analysis is to collect some facts and information about the program, so that these facts can be used later for further analyses or transformations.</p><p>MLIR&#8217;s dataflow analysis is based on the classical <em><strong><a href="https://link.springer.com/article/10.1007/BF00290339">monotone framework</a></strong>.<br></em>Conceptually, it&#8217;s a very simple idea: run the analysis iteratively until no more new facts can be derived:</p><pre><code>let analysis = DataflowAnalysis();
let worklist = ParseProgram(sourceCode);
while (!worklist.empty()) {
  let node = worklist.pop();
  let knownFacts = analysis.getFacts(node.predecessors());
  if (analysis.canDeriveNewFacts(node, knownFacts)) {
     let newFacts = analysis.deriveNewFacts(node);
     analysis.mergeFacts(newFacts, knownFacts);
     worklist.add(node.successors());
  }
}</code></pre><p>The pseudocode above shows this idea in action: try deriving new facts for each node in the program, if new facts are indeed found, then update the existing information and add the successor nodes for further analysis.<br>The last step is crucial: the newly derived facts &#8220;invalidate&#8221; facts for the subsequent nodes, so some nodes might be analysed multiple times.</p><p>The invalidation part is important for at least two reasons:</p><ul><li><p>loops and cycles: if the program has loops in it (which most programs do), then we may need to re-analyze the loop body several times to accumulate all the facts</p></li><li><p>composability: it&#8217;s possible to run several analyses at the same time, in which case combined facts may yield more information. E.g., an analysis A didn&#8217;t find any facts for node X and completed, later an analysis B found some facts for node X, which triggers analysis A on the node X again, but now with the new facts.</p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://lowlevelbits.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://lowlevelbits.com/subscribe?"><span>Subscribe now</span></a></p><h3>Sparse vs Dense Analysis</h3><p>While MLIR has a generic implementation of the monotone framework, it also comes with several predefined implementations: DenseForward, DenseBackward, SparseForward, and SparseBackward analyses. Whenever you want to build your own analysis, these are perhaps the ones you should consider as a starting point.</p><p>While the difference between Forward vs Backward is clear, the Dense vs Sparse might be confusing at first.</p><p>The main difference between these two flavours is the way the information or facts are propagated.</p><p>MLIR&#8217;s dataflow framework attaches facts about a program to the abstract <code>LatticeAnchor</code>s. The abstract anchor can be either an <code>mlir::ProgramPoint</code>, an <code>mlir::Value</code>, or an <code>mlir::GenericLatticeAnchor.</code></p><p>The <code>ProgramPoint</code> represents the location of a fact within the program, e.g. &#8220;before an operation&#8220; or &#8220;after an operation.&#8221; Thus, the facts are propagated from one operation to another via (implicit) control-flow edges. This is the essence of the Dense Analysis.</p><p>The <code>Value</code> can be used to attach the facts to specific SSA-values. The facts are propagated from one value to another via data flow edges.</p><p>The generic anchor can be used to encode anything that doesn&#8217;t fit a <code>ProgramPoint</code> or a <code>Value</code>. For example, <code>DeadCodeAnalysis</code> uses it to represent a <code>CFGEdge.</code></p><p>Below is an illustration of the difference between Dense and Sparse analyses for the following program:</p><pre><code>func.func @do_stuff(%a: i32, %b: i32) -&gt; i32 {
  %two = arith.constant 2 : i32
  %three = arith.constant 3 : i32
  %t1 = arith.muli %a, %two : i32
  %t2 = arith.muli %b, %three : i32
  %res = arith.addi %t1, %t2 : i32
  return %res : i32
}</code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jsWz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F407524a8-6134-4a64-b230-424becf598a5_8592x3720.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jsWz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F407524a8-6134-4a64-b230-424becf598a5_8592x3720.png 424w, https://substackcdn.com/image/fetch/$s_!jsWz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F407524a8-6134-4a64-b230-424becf598a5_8592x3720.png 848w, https://substackcdn.com/image/fetch/$s_!jsWz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F407524a8-6134-4a64-b230-424becf598a5_8592x3720.png 1272w, https://substackcdn.com/image/fetch/$s_!jsWz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F407524a8-6134-4a64-b230-424becf598a5_8592x3720.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jsWz!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F407524a8-6134-4a64-b230-424becf598a5_8592x3720.png" width="1200" height="519.2307692307693" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/407524a8-6134-4a64-b230-424becf598a5_8592x3720.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:630,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:6318593,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://lowlevelbits.com/i/164708663?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F407524a8-6134-4a64-b230-424becf598a5_8592x3720.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jsWz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F407524a8-6134-4a64-b230-424becf598a5_8592x3720.png 424w, https://substackcdn.com/image/fetch/$s_!jsWz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F407524a8-6134-4a64-b230-424becf598a5_8592x3720.png 848w, https://substackcdn.com/image/fetch/$s_!jsWz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F407524a8-6134-4a64-b230-424becf598a5_8592x3720.png 1272w, https://substackcdn.com/image/fetch/$s_!jsWz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F407524a8-6134-4a64-b230-424becf598a5_8592x3720.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In the case of the Dense forward analysis, any change of facts of the op <strong>%three</strong> triggers new analysis for all the ops &#8220;below&#8221; it.<br>In the case of the Sparse forward analysis though, the same change would only affect &#8220;half&#8221; of the program.</p><p>The APIs of both analyses reflect the lattice anchors:</p><pre><code>// Dense Analysis
LogicalResult visitOperation(Operation *op,
                             const AnalysisState &amp;before,
                             AnalysisState *after);

// Sparse Analysis
LogicalResult visitOperation(Operation *op,
                             ArrayRef&lt;const AnalysisState*&gt; before,
                             ArrayRef&lt;AnalysisState *&gt; after);</code></pre><p>These are precisely the transfer/merge functions from the monotone framework, and it&#8217;s the analysis authors responsibility to implement them.</p><h3>Gotchas</h3><p>There is a very important detail one must keep in mind!</p><p>Looking at the documentation around the Dataflow Analysis Framework you can find the following lines at the top of both <strong>SparseAnalysis.h</strong> and <strong>DenseAnalysis.h </strong>(emphasis mine):</p><pre><code>This file implements sparse data-flow analysis using the data-flow analysis framework. The analysis is forward and conditional and <strong>uses the results of dead code analysis to prune dead code during the analysis</strong>.</code></pre><p>What the documentation doesn&#8217;t say however, is that by default everything is considered dead.<br>If you fail to include <strong>DeadCodeAnalysis</strong> in the solver, then all of the operations will be skipped as &#8220;dead&#8221;.<br>I observed similar behaviour due to the lack of <strong>SparseConstantPropagation</strong> as some of the nested regions (coming from <strong>scf</strong>) were ignored, even though they were in fact live and reachable.</p><p>At the time of writing (LLVM 20), this is the way to run your own analysis:</p><pre><code>mlir::DataFlowSolver solver;

// These two are strictly required for the complete analysis to work
solver.load&lt;mlir::dataflow::DeadCodeAnalysis&gt;();
solver.load&lt;mlir::dataflow::SparseConstantPropagation&gt;();

solver.load&lt;MyFancyAnalysis&gt;();
solver.initializeAndRun(op);</code></pre><p>This is the part you should be looking at very carefully, especially when upgrading to a newer version of LLVM/MLIR: at some point some new implicitly &#8220;required&#8221; analysis might be introduced, which may lead to an incomplete view of the program.</p><h3>More information</h3><blockquote><p>I&#8217;m still learning about the framework internals, so if you know of any examples of out-of-tree analyses - any pointers would be highly appreciated &#128588;</p></blockquote><p>I highly recommend watching these two talks to get a better idea of the motivation behind the current design and real-world use-cases.</p><ul><li><p><a href="https://www.youtube.com/watch?v=5BijBv2TDnU">2023 EuroLLVM - MLIR Dataflow Analysis</a></p></li><li><p><a href="https://www.youtube.com/watch?v=vvVR3FyU9TE">2024 EuroLLVM - Efficient Data-Flow Analysis on Region-Based Control Flow in MLIR</a></p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://lowlevelbits.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Low Level Bits! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Different ways to build LLVM/MLIR tools]]></title><description><![CDATA[Comparison of different LLVM/MLIR distributions]]></description><link>https://lowlevelbits.com/p/different-ways-to-build-llvmmlir</link><guid isPermaLink="false">https://lowlevelbits.com/p/different-ways-to-build-llvmmlir</guid><dc:creator><![CDATA[AlexDenisov]]></dc:creator><pubDate>Fri, 02 May 2025 22:03:40 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!iCwc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F670d014b-2b4f-4576-982b-a7066b2d4dcd_3268x1716.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>LLVM and MLIR frameworks are typically used to build compilers for various use cases, but I&#8217;m using word &#8220;tools&#8221; here to cover a broader set of possibilities (compilers, language plugins, analyzers, etc.).</p><p>If you want to build such a tool, then you obviously need to somehow &#8220;connect&#8221; your code to LLVM or MLIR libraries.</p><p>In this article I&#8217;m not going to cover how to do the build itself (I believe there are plenty of great resources out there already), but rather focus on various ways to actually obtain those LLVM libraries and what kinds of features those options bring with them.</p><p>I&#8217;m also considering the simplest integration: CMake and C++, no fancy build systems, no fancy languages. Different build systems and languages would require different considerations.</p><p>Effectively, this article is organized as a table with different ways to get LLVM/MLIR on one axis, and various available features on another.</p><p>The actual table is at the very end.</p><h2>Features</h2><p>Here is a non-exhaustive list of different features that I consider important.<br>If you believe something is missing, please leave a comment.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://lowlevelbits.com/p/different-ways-to-build-llvmmlir/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://lowlevelbits.com/p/different-ways-to-build-llvmmlir/comments"><span>Leave a comment</span></a></p><h3>(Fast) Build Times</h3><p>Obviously, everyone wants to have fast build times. There are two slightly different angles to this story: if you decide to build LLVM from scratch, it would obviously take long time. But even if you don&#8217;t build LLVM from scratch, you may still have to wait for way too long due to the static linking.</p><p>Also, building LLVM/MLIR from scratch without caching is going to be a huge bottleneck on the CI.</p><h3>Debugging Experience</h3><p>Once in a while things go south, so you need to debug not only your code, but also look into what&#8217;s &#8220;wrong&#8221; inside of LLVM.<br>What I mean here is not just having debug info and assertions enabled, but also facilities like <code>-debug-only=.</code><br>One example from MLIR is debugging long conversion pipelines/pattern matching, when things don&#8217;t quite work the way you&#8217;d expect.</p><h3>Testing Infrastructure</h3><p>Both LLVM and MLIR heavily rely on integration testing using <a href="https://llvm.org/docs/CommandGuide/lit.html">lit</a> and <a href="https://llvm.org/docs/CommandGuide/FileCheck.html">filecheck</a>.<br>None of these are part of the &#8220;official distribution&#8221; unfortunately<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. While the official lit can be installed as a separate python package, for filecheck your best bet is third-party solutions, which are actually pretty good starting points if you don&#8217;t need very advanced filecheck features (e.g. <a href="https://github.com/mull-project/filecheck.py">mull-project/filecheck.py</a> or <a href="https://github.com/AntonLydike/filecheck">AntonLydike/filecheck</a>).</p><h3>Bleeding Edge</h3><p>This is also an important factor. As a starting point, you can just use whatever is available from your default OS package manager (e.g. apt or homebrew), but at some point you may need to pick something much newer due to bugfixes or new features.</p><h3>Dynamic Linking</h3><p>This is more of a niche feature, but it is very important if you are working on any kind of plugins, or if you don&#8217;t want to deal with long static linking time during development.</p><h2>Different LLVM distributions</h2><p>Here I&#8217;m considering more or less cross-platform solutions, so I&#8217;m not covering Debian/Ubuntu specific <a href="https://apt.llvm.org">repo</a>. Which leaves us with three options: (semi-)official versions from an OS package manager, precompiled binaries (submitted by volunteers), and BYOB: &#8220;bring your own build&#8221; story.</p><h3>(Semi-)official OS packages</h3><p>These are the packages maintained by the OS maintainers and not necessarily by LLVM maintainers. These packages are the easiest way to start: just call <code>apt/brew install llvm</code> and you are done.</p><p>The packages come with dynamic libraries, which enables both fast build times and plugin support. The packages usually contain everything that is needed for testing, but they of course lack the debugging story.</p><p>The other inconvenience might be the age of the package: depending on the OS and its stability guarantees, the package might be way too old for your use case.<br>For LLVM it&#8217;s probably fine, but it gets trickier for MLIR as the APIs are less stable across the recent versions.</p><h3>Precompiled packages</h3><p>These packages are available as the release artifacts, for example <a href="https://github.com/llvm/llvm-project/releases/tag/llvmorg-20.1.4">20.1.4</a> or <a href="https://github.com/llvm/llvm-project/releases/tag/llvmorg-18.1.8">18.1.8</a>.</p><p>On one hand, this is the most convenient way to get those binaries: the most recent binaries appear there just a few days after the official release.<br>On the other hand, some packages are prepared by volunteers, so some releases might be missing the build for your specific OS/version, and the presence of e.g. <a href="https://github.com/llvm/llvm-project/releases/download/llvmorg-20.1.4/LLVM-20.1.4-Linux-X64.tar.xz">LLVM-20.1.4-Linux-X64.tar.xz</a> build doesn&#8217;t guarantee compatibility with e.g. Ubuntu 20.04 due to the the &#8220;old&#8221; glibc.</p><p>Just as with the official OS packages, the debugging story is not there: the packages are built in the release mode.</p><p>In general, these packages are kinda the &#8220;best effort&#8221;: if it works - great, if not - well, you are out of luck.</p><h3>Build your own LLVM</h3><p>This is obviously the most flexible approach: you can build any version/commit on any supported OS, you get the debugging facilities if you wish so, all the testing infrastructure is there, it&#8217;s your choice whether to use dynamic or static linking.</p><p>But of course the price is the long build times, especially if you want to get more than just LLVM (e.g, MLIR or clang libraries).</p><h2>Summary</h2><p>As a conclusion, the exact option depends on your use case.<br>Just to start with, you can pick the official package available on your OS and then decide whether you need more.</p><p>If you need the newest version, then the precompiled packages from LLVM releases page is your best bet, especially when it comes to CI integration.</p><p>However, at least at some point, you may consider building your own version of LLVM/MLIR libraries for local development, but still stick to the precompiled packages for CI checks.</p><p>To wrap it up, here is a table that sums it all up.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iCwc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F670d014b-2b4f-4576-982b-a7066b2d4dcd_3268x1716.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iCwc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F670d014b-2b4f-4576-982b-a7066b2d4dcd_3268x1716.png 424w, https://substackcdn.com/image/fetch/$s_!iCwc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F670d014b-2b4f-4576-982b-a7066b2d4dcd_3268x1716.png 848w, https://substackcdn.com/image/fetch/$s_!iCwc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F670d014b-2b4f-4576-982b-a7066b2d4dcd_3268x1716.png 1272w, https://substackcdn.com/image/fetch/$s_!iCwc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F670d014b-2b4f-4576-982b-a7066b2d4dcd_3268x1716.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iCwc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F670d014b-2b4f-4576-982b-a7066b2d4dcd_3268x1716.png" width="1456" height="765" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/670d014b-2b4f-4576-982b-a7066b2d4dcd_3268x1716.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:765,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2437212,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://lowlevelbits.com/i/162720123?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F670d014b-2b4f-4576-982b-a7066b2d4dcd_3268x1716.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!iCwc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F670d014b-2b4f-4576-982b-a7066b2d4dcd_3268x1716.png 424w, https://substackcdn.com/image/fetch/$s_!iCwc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F670d014b-2b4f-4576-982b-a7066b2d4dcd_3268x1716.png 848w, https://substackcdn.com/image/fetch/$s_!iCwc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F670d014b-2b4f-4576-982b-a7066b2d4dcd_3268x1716.png 1272w, https://substackcdn.com/image/fetch/$s_!iCwc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F670d014b-2b4f-4576-982b-a7066b2d4dcd_3268x1716.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://lowlevelbits.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://lowlevelbits.com/subscribe?"><span>Subscribe now</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Since some version of LLVM, both <code>apt</code> and <code>homebrew</code> actually do contain <code>FileCheck</code> binary, but it&#8217;s not exposed by default and I assume it&#8217;s not guaranteed to be present in the future versions.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Building LLVM plugins with Bazel]]></title><description><![CDATA[Technical note on how to build an LLVM plugin using Bazel]]></description><link>https://lowlevelbits.com/p/building-llvm-plugin-with-bazel</link><guid isPermaLink="false">https://lowlevelbits.com/p/building-llvm-plugin-with-bazel</guid><dc:creator><![CDATA[AlexDenisov]]></dc:creator><pubDate>Tue, 01 Apr 2025 09:18:04 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rO3B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43e06cce-72e0-4495-b822-be243aabd931_3756x4204.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One of the premises of <a href="https://bazel.build">Bazel</a> is to provide reproducible, hermetic builds, thus you shouldn&#8217;t depend on whatever is installed on the host OS and all the dependencies typically managed by Bazel directly.</p><p>However, if you want to build plugins for LLVM (or any other project really), then you should link against the specific versions installed on the user&#8217;s system.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://lowlevelbits.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Low Level Bits! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>As I&#8217;m working on <a href="https://github.com/mull-project/mull">such a plugin</a>, it&#8217;s been a long &#8220;dream&#8221; of mine to migrate to Bazel for the many benefits it provides. Over time, the existing build system (CMake) has grown its capabilities and I have certain requirements for how the builds should work.<br>Namely:</p><ul><li><p>the plugin must work on different versions of OS (Ubuntu 20.xx-24.xx, macOS)</p></li><li><p>the plugin must support different versions of LLVM, which are different on each OS (e.g., LLVM 12 on Ubuntu 20.04, LLVM 16, 17, 18 on Ubuntu 24.04 etc)</p></li><li><p>the plugin must be linking against the system libraries due to the ABI requirements</p></li><li><p>the build system should support multiple versions at the same time</p></li></ul><p>None of these are necessarily hard or impossible with Bazel, but the devil is always in the details.</p><p>What follows is my take on solving this problem.</p><p>Source code is available here <a href="https://github.com/AlexDenisov/bazel-llvm-plugin">https://github.com/AlexDenisov/bazel-llvm-plugin</a>.</p><blockquote><p><strong>Following the <a href="https://meta.wikimedia.org/wiki/Cunningham%27s_Law">Cunningham's Law</a> I claim that there is no better way to do it.</strong></p></blockquote><h3>Detecting available LLVM versions</h3><p>Third-party dependencies in Bazel are typically coming in a form of external repositories, thus all supported LLVM versions must be defined in <code>MODULE.bazel </code>upfront. However, what happens if the version is not supported or not installed on the host OS? In this case, these repositories must be defined dynamically.</p><p>To do so, first we need to define a custom dynamic repository which will check which versions are installed on the host OS and store this information in a global variable available for later use by different parts of the build system:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rO3B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43e06cce-72e0-4495-b822-be243aabd931_3756x4204.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rO3B!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43e06cce-72e0-4495-b822-be243aabd931_3756x4204.png 424w, https://substackcdn.com/image/fetch/$s_!rO3B!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43e06cce-72e0-4495-b822-be243aabd931_3756x4204.png 848w, https://substackcdn.com/image/fetch/$s_!rO3B!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43e06cce-72e0-4495-b822-be243aabd931_3756x4204.png 1272w, https://substackcdn.com/image/fetch/$s_!rO3B!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43e06cce-72e0-4495-b822-be243aabd931_3756x4204.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rO3B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43e06cce-72e0-4495-b822-be243aabd931_3756x4204.png" width="1456" height="1630" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/43e06cce-72e0-4495-b822-be243aabd931_3756x4204.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1630,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:913964,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://lowlevelbits.com/i/160324297?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43e06cce-72e0-4495-b822-be243aabd931_3756x4204.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rO3B!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43e06cce-72e0-4495-b822-be243aabd931_3756x4204.png 424w, https://substackcdn.com/image/fetch/$s_!rO3B!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43e06cce-72e0-4495-b822-be243aabd931_3756x4204.png 848w, https://substackcdn.com/image/fetch/$s_!rO3B!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43e06cce-72e0-4495-b822-be243aabd931_3756x4204.png 1272w, https://substackcdn.com/image/fetch/$s_!rO3B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43e06cce-72e0-4495-b822-be243aabd931_3756x4204.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Which must be defined in <code>MODULE.bazel:</code></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IMzC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45622ee7-ed74-444e-82a5-11238fb3627d_4004x724.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IMzC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45622ee7-ed74-444e-82a5-11238fb3627d_4004x724.png 424w, https://substackcdn.com/image/fetch/$s_!IMzC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45622ee7-ed74-444e-82a5-11238fb3627d_4004x724.png 848w, https://substackcdn.com/image/fetch/$s_!IMzC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45622ee7-ed74-444e-82a5-11238fb3627d_4004x724.png 1272w, https://substackcdn.com/image/fetch/$s_!IMzC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45622ee7-ed74-444e-82a5-11238fb3627d_4004x724.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IMzC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45622ee7-ed74-444e-82a5-11238fb3627d_4004x724.png" width="1456" height="263" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/45622ee7-ed74-444e-82a5-11238fb3627d_4004x724.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:263,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:193604,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://lowlevelbits.com/i/160324297?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45622ee7-ed74-444e-82a5-11238fb3627d_4004x724.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!IMzC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45622ee7-ed74-444e-82a5-11238fb3627d_4004x724.png 424w, https://substackcdn.com/image/fetch/$s_!IMzC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45622ee7-ed74-444e-82a5-11238fb3627d_4004x724.png 848w, https://substackcdn.com/image/fetch/$s_!IMzC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45622ee7-ed74-444e-82a5-11238fb3627d_4004x724.png 1272w, https://substackcdn.com/image/fetch/$s_!IMzC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45622ee7-ed74-444e-82a5-11238fb3627d_4004x724.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>Defining LLVM repositories</h3><p>Now, as we know which versions are available installed on the host system, we can define LLVM repositories which will expose <code>libLLVM.so</code> and all the needed headers.</p><p>This part requires a dynamic module extension which will either define a real repository, or will define a &#8220;fake&#8221; empty repo. This is needed so that all the repositories can be later defined in <code>MODULE.bazel </code>safely.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!M-jA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95873bd0-b515-4ba6-8f3e-17de5975c9d0_3204x3436.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!M-jA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95873bd0-b515-4ba6-8f3e-17de5975c9d0_3204x3436.png 424w, https://substackcdn.com/image/fetch/$s_!M-jA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95873bd0-b515-4ba6-8f3e-17de5975c9d0_3204x3436.png 848w, https://substackcdn.com/image/fetch/$s_!M-jA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95873bd0-b515-4ba6-8f3e-17de5975c9d0_3204x3436.png 1272w, https://substackcdn.com/image/fetch/$s_!M-jA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95873bd0-b515-4ba6-8f3e-17de5975c9d0_3204x3436.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!M-jA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95873bd0-b515-4ba6-8f3e-17de5975c9d0_3204x3436.png" width="1456" height="1561" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/95873bd0-b515-4ba6-8f3e-17de5975c9d0_3204x3436.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1561,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:671517,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://lowlevelbits.com/i/160324297?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95873bd0-b515-4ba6-8f3e-17de5975c9d0_3204x3436.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!M-jA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95873bd0-b515-4ba6-8f3e-17de5975c9d0_3204x3436.png 424w, https://substackcdn.com/image/fetch/$s_!M-jA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95873bd0-b515-4ba6-8f3e-17de5975c9d0_3204x3436.png 848w, https://substackcdn.com/image/fetch/$s_!M-jA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95873bd0-b515-4ba6-8f3e-17de5975c9d0_3204x3436.png 1272w, https://substackcdn.com/image/fetch/$s_!M-jA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95873bd0-b515-4ba6-8f3e-17de5975c9d0_3204x3436.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>How we can tell Bazel that these repos are available for consumption:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xr4f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf0d7cc-6f2e-4a0f-abb6-6b0e7efd1118_2836x820.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xr4f!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf0d7cc-6f2e-4a0f-abb6-6b0e7efd1118_2836x820.png 424w, https://substackcdn.com/image/fetch/$s_!xr4f!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf0d7cc-6f2e-4a0f-abb6-6b0e7efd1118_2836x820.png 848w, https://substackcdn.com/image/fetch/$s_!xr4f!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf0d7cc-6f2e-4a0f-abb6-6b0e7efd1118_2836x820.png 1272w, https://substackcdn.com/image/fetch/$s_!xr4f!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf0d7cc-6f2e-4a0f-abb6-6b0e7efd1118_2836x820.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xr4f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf0d7cc-6f2e-4a0f-abb6-6b0e7efd1118_2836x820.png" width="1456" height="421" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/baf0d7cc-6f2e-4a0f-abb6-6b0e7efd1118_2836x820.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:421,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:172080,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://lowlevelbits.com/i/160324297?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf0d7cc-6f2e-4a0f-abb6-6b0e7efd1118_2836x820.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xr4f!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf0d7cc-6f2e-4a0f-abb6-6b0e7efd1118_2836x820.png 424w, https://substackcdn.com/image/fetch/$s_!xr4f!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf0d7cc-6f2e-4a0f-abb6-6b0e7efd1118_2836x820.png 848w, https://substackcdn.com/image/fetch/$s_!xr4f!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf0d7cc-6f2e-4a0f-abb6-6b0e7efd1118_2836x820.png 1272w, https://substackcdn.com/image/fetch/$s_!xr4f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf0d7cc-6f2e-4a0f-abb6-6b0e7efd1118_2836x820.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Defining plugin targets</h3><p>Now, the rest is rather trivial. We can define all the plugin libraries depending on the LLVM versions available on the host OS:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!60pz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f11007-3d9b-444a-a721-5a2bee1feec6_2972x1772.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!60pz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f11007-3d9b-444a-a721-5a2bee1feec6_2972x1772.png 424w, https://substackcdn.com/image/fetch/$s_!60pz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f11007-3d9b-444a-a721-5a2bee1feec6_2972x1772.png 848w, https://substackcdn.com/image/fetch/$s_!60pz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f11007-3d9b-444a-a721-5a2bee1feec6_2972x1772.png 1272w, https://substackcdn.com/image/fetch/$s_!60pz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f11007-3d9b-444a-a721-5a2bee1feec6_2972x1772.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!60pz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f11007-3d9b-444a-a721-5a2bee1feec6_2972x1772.png" width="1456" height="868" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a2f11007-3d9b-444a-a721-5a2bee1feec6_2972x1772.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:868,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:281870,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://lowlevelbits.com/i/160324297?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f11007-3d9b-444a-a721-5a2bee1feec6_2972x1772.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!60pz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f11007-3d9b-444a-a721-5a2bee1feec6_2972x1772.png 424w, https://substackcdn.com/image/fetch/$s_!60pz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f11007-3d9b-444a-a721-5a2bee1feec6_2972x1772.png 848w, https://substackcdn.com/image/fetch/$s_!60pz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f11007-3d9b-444a-a721-5a2bee1feec6_2972x1772.png 1272w, https://substackcdn.com/image/fetch/$s_!60pz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f11007-3d9b-444a-a721-5a2bee1feec6_2972x1772.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Defining test targets</h3><p>Obviously, we must have tests for the plugin. This is also relatively trivial, we need to define a test case for each available LLVM versions as well, thus producing <code>NxM</code> tests where <code>N</code> is the number of tests and <code>M</code> is the number of LLVM versions.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!B0qk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd844df9-3ad3-4415-9cf7-5e8a758216f9_2996x2516.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!B0qk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd844df9-3ad3-4415-9cf7-5e8a758216f9_2996x2516.png 424w, https://substackcdn.com/image/fetch/$s_!B0qk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd844df9-3ad3-4415-9cf7-5e8a758216f9_2996x2516.png 848w, https://substackcdn.com/image/fetch/$s_!B0qk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd844df9-3ad3-4415-9cf7-5e8a758216f9_2996x2516.png 1272w, https://substackcdn.com/image/fetch/$s_!B0qk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd844df9-3ad3-4415-9cf7-5e8a758216f9_2996x2516.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!B0qk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd844df9-3ad3-4415-9cf7-5e8a758216f9_2996x2516.png" width="1456" height="1223" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fd844df9-3ad3-4415-9cf7-5e8a758216f9_2996x2516.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1223,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:481617,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://lowlevelbits.com/i/160324297?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd844df9-3ad3-4415-9cf7-5e8a758216f9_2996x2516.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!B0qk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd844df9-3ad3-4415-9cf7-5e8a758216f9_2996x2516.png 424w, https://substackcdn.com/image/fetch/$s_!B0qk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd844df9-3ad3-4415-9cf7-5e8a758216f9_2996x2516.png 848w, https://substackcdn.com/image/fetch/$s_!B0qk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd844df9-3ad3-4415-9cf7-5e8a758216f9_2996x2516.png 1272w, https://substackcdn.com/image/fetch/$s_!B0qk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd844df9-3ad3-4415-9cf7-5e8a758216f9_2996x2516.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Conclusion</h3><p>With all the little pieces above, the builds are now completely transparent and smooth for the end user:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6IVo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0361faf4-f510-4573-95ba-1a8876daf991_1774x854.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6IVo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0361faf4-f510-4573-95ba-1a8876daf991_1774x854.png 424w, https://substackcdn.com/image/fetch/$s_!6IVo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0361faf4-f510-4573-95ba-1a8876daf991_1774x854.png 848w, https://substackcdn.com/image/fetch/$s_!6IVo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0361faf4-f510-4573-95ba-1a8876daf991_1774x854.png 1272w, https://substackcdn.com/image/fetch/$s_!6IVo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0361faf4-f510-4573-95ba-1a8876daf991_1774x854.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6IVo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0361faf4-f510-4573-95ba-1a8876daf991_1774x854.png" width="1456" height="701" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0361faf4-f510-4573-95ba-1a8876daf991_1774x854.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:701,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:225392,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://lowlevelbits.com/i/160324297?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0361faf4-f510-4573-95ba-1a8876daf991_1774x854.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6IVo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0361faf4-f510-4573-95ba-1a8876daf991_1774x854.png 424w, https://substackcdn.com/image/fetch/$s_!6IVo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0361faf4-f510-4573-95ba-1a8876daf991_1774x854.png 848w, https://substackcdn.com/image/fetch/$s_!6IVo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0361faf4-f510-4573-95ba-1a8876daf991_1774x854.png 1272w, https://substackcdn.com/image/fetch/$s_!6IVo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0361faf4-f510-4573-95ba-1a8876daf991_1774x854.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Full working example can be found here: <a href="https://github.com/AlexDenisov/bazel-llvm-plugin">https://github.com/AlexDenisov/bazel-llvm-plugin</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://lowlevelbits.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Low Level Bits! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[How to learn Compilers (LLVM Edition)]]></title><description><![CDATA[A collection of resources to start learning compilers (with a focus on LLVM)]]></description><link>https://lowlevelbits.com/p/how-to-learn-compilers-llvm-edition</link><guid isPermaLink="false">https://lowlevelbits.com/p/how-to-learn-compilers-llvm-edition</guid><dc:creator><![CDATA[AlexDenisov]]></dc:creator><pubDate>Thu, 04 Nov 2021 20:56:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F055d9429-d0ae-4332-bf7a-edd8a49e3eee_411x411.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Compilers and Programming Languages is a huge topic. You cannot just take a learning path and finish it at some point. There are many different areas, each of which is endless.</p><p>Here, I want to share some links that would help to learn compilers.</p><p>The list could not be exhaustive - everyone is busy, and no one has time to read the <a href="https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools">Dragon Book</a>.</p><p>The main criteria behind each link:</p><ul><li><p>I can personally recommend the material as I went through it</p></li><li><p>each entry should be relatively short and can be consumed in a reasonable time</p></li></ul><p>I'm a big fan of learning through practicing. Thus the main focus is on LLVM, as you can go and do something cool with real-world programs!</p><p>The list consists of four groups: general theory, front-end, middle-end, and back-end.</p><p>At the first run, you can take the first item from each group, and it should put you on a solid ground.</p><h4><em>Disclaimer</em></h4><p><em>There are a lot of excellent resources out there!<br>Some of them are not on the list because of my subjective judgment, and the others are not here because I've never seen them!<br>Please, share your favourite resource in the comments.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://lowlevelbits.com/p/how-to-learn-compilers-llvm-edition/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://lowlevelbits.com/p/how-to-learn-compilers-llvm-edition/comments"><span>Leave a comment</span></a></p><h3>General Theory / Introduction</h3><ul><li><p><a href="http://aosabook.org/en/llvm.html">AOSA book: LLVM</a><br>This is a chapter from the <a href="http://aosabook.org/en/index.html">Architecture of Open Source Applications</a> book.<br>It is written by Chris Lattner and covers high-level LLVM design.</p></li><li><p><a href="https://online.stanford.edu/courses/soe-ycscs1-compilers">Compilers</a><br>The course is taught by Alex Aiken. In this course, you build a compiler for a real programming language from scratch. It covers the whole compilation pipeline: parsing, type-checking, optimizations, code generation. Besides practical parts, it also dives into the theory.</p></li><li><p><a href="https://online.stanford.edu/courses/soe-ycsautomata-automata-theory">Automata Theory</a><br>The course is taught by Jeffrey Ullman. This one is pretty heavy on theory. It starts with relatively simple topics like state machines and finite automata (deterministic and otherwise). It gradually moves on to more complex things like Turing-machines, computational complexity, famous P vs. NP, etc.</p></li></ul><p>or</p><ul><li><p><a href="https://ocw.mit.edu/courses/mathematics/18-404j-theory-of-computation-fall-2020/">Theory of Computation</a><br>This course is taught by Michael Sipser. It is similar to the one above but delivered in a different style. It goes into more details on specific topics.</p></li></ul><h3>Front-end</h3><p>The compiler front-end is where the interaction with the actual source code happens. The compiler parses the source code into an Abstract Syntax Tree (AST), does semantic analysis and type-checking, and converts it into the intermediate representation (IR).</p><p>The Compilers course from the above covers the general parts.</p><p>Here are some links specific to Clang:</p><ul><li><p><a href="https://jonasdevlieghere.com/understanding-the-clang-ast/">Understanding the Clang AST</a><br>This article is written by Jonas Devlieghere. It goes into detail and touches implementation details of Clang's AST. It also has a lot of excellent links to dive deeper into the subject.</p></li><li><p><a href="https://github.com/banach-space/clang-tutor">clang-tutor</a><br>This repository maintained by Andrzej Warzy&#324;ski. It contains several Clang plugins covering various topics, from simple AST traversals to more involved subjects such as automatic refactoring and obfuscation.</p></li></ul><h3>Middle-end</h3><p>The middle-end is a place where various optimizations happen. Typically, the middle-ends use some intermediate representation. The intermediate representation of LLVM is usually referred to as LLVM IR or LLVM Bitcode.</p><p>In a nutshell, it is a human-readable assembly language for a pseudo-machine (i.e., the IR does not target any specific CPU).</p><p>The LLVM IR maintains certain properties: it is in a Static Single Assignment (SSA) form organized as a Control-Flow Graph (CFG).</p><ul><li><p><a href="https://www.youtube.com/watch?v=m8G_S5LwlTo">LLVM IR Tutorial - Phis, GEPs and other things, oh my!</a><br>This is a great talk by Vince Bridgers and Felipe de Azevedo Piovezan.</p></li><li><p><a href="https://www.youtube.com/watch?v=J5xExRGaIIY">Introduction to LLVM</a><br>A one-hour-long talk/tutorial from LLVM Developers meeting given by Eric Christopher and Johannes Doerfert. Another great tutorial that better builds on top of the previous video.</p></li><li><p><a href="https://www.cs.cornell.edu/courses/cs6120/2020fa/self-guided">CS 6120: Advanced Compilers</a><br>The course is taught by Adrian Sampson. The title says "advanced," but it covers what one would expect in a modern production-grade compiler: SSA, CFG, optimizations, various analyses.</p></li><li><p><a href="https://lowlevelbits.org/bitcode-demystified">Bitcode Demystified</a><br>This one is from me. It gives a high-level description of what's the LLVM Bitcode/IR is.</p></li><li><p><a href="https://github.com/banach-space/llvm-tutor">llvm-tutor</a><br>This one is also from Andrzej Warzy&#324;ski. It covers LLVM plugins (so-called passes) that allow one to analyze and transform the programs in the LLVM IR form.</p></li></ul><h3>Back-end</h3><p>The last phase of the compilation is a back-end. This phase aims to convert the intermediate representation into a machine code (zeros and ones). The zeros and ones later can be run on the CPU. Therefore, to understand the back-end, you need to understand the machine code and how CPUs work.</p><ul><li><p><a href="https://www.coursera.org/learn/build-a-computer">Build a Modern Computer from First Principles: From Nand to Tetris</a><br>Taught by Shimon Schocken and Noam Nisan. This course starts backward: first, you build the logic gates (and, or, xor, etc.), then use the logic gates to construct Arithmetic-Logic Unit (ALU), and then use the ALU to build the CPU. Then you learn how to control the CPU with zeros and ones (machine code), and eventually, you develop your assembler to convert the human-readable assembly into the machine code.</p></li><li><p><a href="https://lowlevelbits.org/parsing-mach-o-files/">Parsing Mach-O files</a><br>This is a short article written by me. It shows how to parse object files on macOS (Mach-O). If you are on Linux or Windows, search for similar articles on `elf` and `PE/COFF` files, respectively.</p></li><li><p><a href="https://book.easyperf.net/perf_book">Performance Analysis and Tuning on Modern CPUs</a><br>The book by Denis Bakhvalov. While it is about performance, it gives an excellent introduction to how CPUs work.</p></li></ul><h3>Bonus points</h3><p>Here are some more LLVM related channels I recommend looking at:</p><ul><li><p><a href="https://www.youtube.com/channel/UCv2_41bSAa5Y_8BacJUZfjQ">LLVM's YouTube channel</a><br>Here you can find a lot of talks from developer meetings.</p></li><li><p><a href="https://llvmweekly.org">LLVM Weekl</a>y<br>A weekly newsletter run by Alex Bradbury. This is the single newsletter I am aware of that doesn't have ads!</p></li><li><p><a href="https://blog.llvm.org">LLVM Blog</a><br>This is, well, LLVM's blog.</p></li><li><p><a href="https://llvm.org/docs/tutorial/">LLVM Tutorials</a><br>Good starting points, even if you know nothing about compilers.</p></li><li><p><a href="https://blog.regehr.org/archives/category/compilers">Embedded in academia</a><br>John Regehr's blog has lots of goodies when it comes to LLVM and compilers!</p></li></ul><div><hr></div><h3><em>Strings attached</em></h3><p>As I mentioned in the beginning, Compilers is a huge field!</p><p>If you go through the material above, you will learn a lot, but you will still have a few knowledge gaps in the whole compilation pipeline (I certainly do).</p><p>But the good thing is - you'd know what the gaps are and how to address them!</p><p><strong>Good luck!</strong></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://lowlevelbits.com/p/how-to-learn-compilers-llvm-edition?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://lowlevelbits.com/p/how-to-learn-compilers-llvm-edition?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://lowlevelbits.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Low Level Bits! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Debugging DYLD]]></title><description><![CDATA[Short technical note on how to debug issues with macOS dynamic linker - dyld]]></description><link>https://lowlevelbits.com/p/debugging-dyld</link><guid isPermaLink="false">https://lowlevelbits.com/p/debugging-dyld</guid><dc:creator><![CDATA[AlexDenisov]]></dc:creator><pubDate>Tue, 13 Nov 2018 18:51:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134a5988-106b-4fdc-9802-a4b2921d5a98_491x491.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, I was debugging an interesting issue: a program crashes whenever it tries to call a particular function from a dynamic library. It was not clear how to debug this issue. Eventually, I did resolve the problem: the key was in the dynamic linker, dyld.</p><p>In this article, I want to make a short intro on where to start if you have a similar issue. It is by no means an exhaustive guide, but rather a starting point that could have saved me a few hours would I have known this information before.</p><h3>Inspect the dyld from inside</h3><ol><li><p>Source code<br>To understand what&#8217;s going on within DYLD you&#8217;d need to look at the source code, but also at the disassembly.<br>The source code is generally available <a href="https://github.com/apple-oss-distributions/dyld">on GitHub</a>, but might be slightly outdated if you are running the latest version of macOS.</p></li><li><p>Binaries<br>The binaries you are interested in are <code>/usr/bin/dyld</code> and <code>/usr/lib/system/libdyld.dylib</code>. Since macOS switched do dyld cache, you&#8217;d need to use <a href="https://github.com/keith/dyld-shared-cache-extractor">dyld-shared-cache-extractor</a> to extract all the binaries. Once you get the libraries you can disassemble them (<a href="https://www.hopperapp.com">Hopper</a> ftw) and start debugging.</p></li><li><p>LLDB<br>Run your binary and add a breakpoint based on a regex (e.g. `br set -r dyld`) and hit `run`</p></li></ol><p>During debugging, please be ready to jump a lot between the source code, <code>/usr/lib/dyld</code> and <code>/usr/lib/system/libdyld.dylib</code></p><h3>Inspect the dyld from the outside</h3><p>There are a few other options to observe the behavior of dyld without looking at the code, source or binary.<br>You will also need to disable <a href="https://en.wikipedia.org/wiki/System_Integrity_Protection">SIP</a> if you want to exercise it on systems apps.</p><p>All the options are controlled via environment variables. These are the ones I found the most useful:</p><ul><li><p><code>DYLD_PRINT_APIS</code>: documented, prints a nice trace of almost everything that is happening inside of dyld. Here is an example output:<br><br><code>_dyld_register_func_for_add_image(0x7fff7696ab92)</code></p><p><code>_dyld_get_image_slide(0x1000f1000)</code></p><p><code>_dyld_register_func_for_add_image(0x7fff7689cd98)</code></p><p><code>_dyld_get_image_slide(0x1000f1000)</code></p><p><code>_dyld_register_func_for_add_image(0x7fff76be67cb)</code></p><p><code>dyld_image_path_containing_address(0x7fff75221000)<br><br></code>It looks cryptic, but it greatly helps to understand the program execution flow.</p></li><li><p><code>DYLD_PRINT_LIBRARIES: </code>documented, prints all the dynamic libraries that are being loaded during the app startup. Here is an example output:<br><br><code>dyld: loaded: /usr/lib/libiconv.2.dylib</code></p><p><code>dyld: loaded: /System/Library/Frameworks/Security.framework/Versions/A/Security</code></p><p><code>dyld: loaded: /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation</code></p><p><code>dyld: loaded: /usr/lib/libz.1.dylib</code></p><p><code>dyld: loaded: /usr/lib/libSystem.B.dylib</code></p><p><code>dyld: loaded: /usr/lib/libresolv.9.dylib</code></p><p><code>dyld: loaded: /usr/lib/system/libcache.dylib</code></p><p><code>dyld: loaded: /usr/lib/system/libcommonCrypto.dylib</code></p><p><code>dyld: loaded: /usr/lib/system/libcompiler_rt.dylib<br></code></p></li><li><p><code>DYLD_*_PATH: </code>changes the order of directories where dyld will search for dynamic libraries. The nice side effect of using these variables is that their presence disables the dyld3 closure cache. So if your suspect is dyld3 closures, then export any of the <code>DYLD_*_PATH</code> variables to disable them. Some examples:<br><br><code>export DYLD_FRAMEWORK_PATH=</code></p><p><code>export DYLD_LIBRARY_PATH=</code><br></p></li></ul><p>For more info, please consult the dyld man page (<code>man dyld</code>) or dig through the code, source or binary.</p><h3>Summary</h3><p>Debugging such a thing as dyld is a nontrivial task, but it is indeed possible. If you know any other hints or tricks, please share them.</p><p>Happy debugging!<br><br></p>]]></content:encoded></item></channel></rss>