<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Isabella Muerte</title>
    <description>The latest articles on DEV Community by Isabella Muerte (@bruxisma).</description>
    <link>https://dev.to/bruxisma</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F148379%2Fa440105d-dca5-4117-a2f3-69d496343098.jpeg</url>
      <title>DEV Community: Isabella Muerte</title>
      <link>https://dev.to/bruxisma</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bruxisma"/>
    <language>en</language>
    <item>
      <title>How To Find Packages With CMake: The Basics</title>
      <dc:creator>Isabella Muerte</dc:creator>
      <pubDate>Mon, 14 Sep 2020 18:34:54 +0000</pubDate>
      <link>https://dev.to/bruxisma/how-to-find-packages-with-cmake-the-basics-ikk</link>
      <guid>https://dev.to/bruxisma/how-to-find-packages-with-cmake-the-basics-ikk</guid>
      <description>&lt;p&gt;Whether we want to or not, many folks have to interact with CMake at least once in their life. If they are unlucky, they might have to find dependencies using &lt;code&gt;find_package&lt;/code&gt;. If they are extremely unlucky, they might have to write a file to work with &lt;code&gt;find_package&lt;/code&gt;. At the end of this, they might have a file that kind of works, but most likely is based off of a tutorial from 2008. A lot of things have changed since then. There's an easier way to do it these days!&lt;/p&gt;

&lt;p&gt;In a previous post, I alluded to a project I've been working on since 2018. It's called IXM, and while it's not ready for general use, it is where I realized there is a common set of operations for finding packages, their components, and setting their correct properties. We'll be using some of what I've learned and figured out over the past two years to understand how &lt;code&gt;find_package&lt;/code&gt; files work and how to make them useful for your projects and the folks who depend on them.&lt;/p&gt;

&lt;p&gt;This tutorial is written for CMake 3.14 and later, though I personally recommend using CMake 3.16 as it is the version installed with the most recent Ubuntu LTS release, 20.04.&lt;/p&gt;

&lt;p&gt;Additionally, this tutorial isn't meant to discuss how to write a &lt;code&gt;&amp;lt;package-name&amp;gt;-config.cmake&lt;/code&gt; file. Those have a different set of options but also tend to be smaller in practice. Instead I'll be showing how to write what's known as a &lt;code&gt;find_package&lt;/code&gt; &lt;code&gt;MODULE&lt;/code&gt; file. That said, we will eventually tackle how to handle writing a usable &lt;code&gt;find_package&lt;/code&gt; file that can be used in &lt;code&gt;cmake --find-package&lt;/code&gt; mode, in the so-called &lt;a href="https://cmake.org/cmake/help/latest/manual/cmake.1.html#run-a-script"&gt;Script Mode&lt;/a&gt; or with &lt;code&gt;cpack&lt;/code&gt; for the &lt;a href="https://cmake.org/cmake/help/latest/cpack_gen/external.html"&gt;External Generator&lt;/a&gt;. For now, however, we'll focus on the most common workflow for CMake: Configure and Build.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Basics
&lt;/h1&gt;

&lt;p&gt;Within CMake, there are several commands that are used when writing a &lt;code&gt;find_package&lt;/code&gt; file. The most &lt;em&gt;important&lt;/em&gt; ones are &lt;a href="https://cmake.org/cmake/help/latest/command/find_program.html"&gt;find_program&lt;/a&gt;, &lt;a href="https://cmake.org/cmake/help/latest/command/find_library.html"&gt;find_library&lt;/a&gt;, &lt;a href="https://cmake.org/cmake/help/latest/command/find_path.html"&gt;find_path&lt;/a&gt;, and lastly &lt;a href="https://cmake.org/cmake/help/latest/command/find_file.html"&gt;find_file&lt;/a&gt;. Each of these has a purpose, but we will not always use them. Depending on &lt;em&gt;what&lt;/em&gt; you are trying to find, you might also find yourself using &lt;a href="https://cmake.org/cmake/help/latest/command/execute_process.html"&gt;execute_process&lt;/a&gt;, &lt;a href="https://cmake.org/cmake/help/latest/command/file.html#read"&gt;file(READ)&lt;/a&gt;, &lt;a href="https://cmake.org/cmake/help/latest/command/file.html#strings"&gt;file(STRINGS)&lt;/a&gt;, &lt;a href="https://cmake.org/cmake/help/latest/command/string.html#regex-match"&gt;string(REGEX MATCH)&lt;/a&gt;, and &lt;a href="https://cmake.org/cmake/help/latest/command/mark_as_advanced.html"&gt;mark_as_advanced&lt;/a&gt;. Additionally, 99.9% of the time, you'll want to use the CMake provided module &lt;a href="https://cmake.org/cmake/help/latest/module/FindPackageHandleStandardArgs.html"&gt;FindPackageHandleStandardArgs&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Before we can use &lt;code&gt;find_package&lt;/code&gt;, however, we need to make sure CMake can find it in the first place. The most common place to put your cmake scripts is inside the project's root directory under a &lt;code&gt;cmake/&lt;/code&gt; directory. We can then add this path to our &lt;code&gt;CMAKE_MODULE_PATH&lt;/code&gt; variable so CMake knows where to find us.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This is the bare minimum we need for CMake to find our following &lt;code&gt;find_package&lt;/code&gt; files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Commands
&lt;/h2&gt;

&lt;p&gt;The commands most typically used have a &lt;em&gt;very large&lt;/em&gt; amount of documentation and thus it can be a bit overwhelming. Worry not. &lt;em&gt;Most of the time&lt;/em&gt; you don't need to worry about these additional parameters. We can cover them in detail in later posts.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;find_program&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is used to find the path to a file that the system considers &lt;em&gt;executable&lt;/em&gt;. Whether it is a script or an actual executable is actually irrelevant. As long as you could execute it via something like &lt;code&gt;exec&lt;/code&gt; (or &lt;code&gt;CreateProcess&lt;/code&gt; on Windows), it can be used as an executable.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;find_library&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is used to find &lt;em&gt;both&lt;/em&gt; shared and static libraries. The form for this is a bit odd, as languages with custom static library formats (e.g., Rust's &lt;code&gt;.rlib&lt;/code&gt;) won't ever be found, however we &lt;em&gt;can&lt;/em&gt; find &lt;code&gt;.so&lt;/code&gt;, &lt;code&gt;.dylib&lt;/code&gt;, &lt;code&gt;.dll&lt;/code&gt;, &lt;code&gt;.a&lt;/code&gt;, and &lt;code&gt;.lib&lt;/code&gt; files by default. on macOS, &lt;code&gt;.framework&lt;/code&gt;s are also searched for first. Users can configure this with the &lt;a href="https://cmake.org/cmake/help/latest/variable/CMAKE_FIND_FRAMEWORK.html"&gt;CMAKE_FIND_FRAMEWORK&lt;/a&gt; variable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding an Executable
&lt;/h2&gt;

&lt;p&gt;Finding executables in packages is one of the easiest things, compared to finding libraries. Executables can be made into imported targets, much like libraries, and they can then be used in the &lt;code&gt;add_custom_command&lt;/code&gt; and &lt;code&gt;add_custom_target&lt;/code&gt; commands with their imported name.&lt;/p&gt;

&lt;p&gt;A popular tool that we can use as an example here is &lt;code&gt;sphinx-build&lt;/code&gt;, the actual "compiler" for the &lt;a href="https://sphinx-doc.org"&gt;sphinx documentation framework&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Inside of a file named &lt;code&gt;FindSphinx.cmake&lt;/code&gt;, we have&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You'll notice that, unlike what you might be used to, we use &lt;code&gt;Sphinx_EXECUTABLE&lt;/code&gt; and not &lt;code&gt;SPHINX_EXECUTABLE&lt;/code&gt;. This will make more even more sense in later posts, but it's consider "good behavior" to prefix your variables with the &lt;em&gt;package name&lt;/em&gt;, and not an upper cased version of said package name. This also prevents a theoretical &lt;code&gt;find_package(SPHINX)&lt;/code&gt; and a &lt;code&gt;find_package(Sphinx)&lt;/code&gt; having a variable collision.&lt;/p&gt;

&lt;p&gt;That's the basics of it! We can now let &lt;code&gt;find_package_handle_standard_args&lt;/code&gt; take care of business for us, and then hide our cache variable if it's been found.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Seems simple enough, right? Well, we still need to &lt;em&gt;import&lt;/em&gt; this executable so it's usable by the build system. To do that we're going to create what's known as an &lt;em&gt;imported executable&lt;/em&gt; and set the &lt;code&gt;IMPORTED_LOCATION&lt;/code&gt; property to the value stored in &lt;code&gt;Sphinx_EXECUTABLE&lt;/code&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Of course, it's &lt;em&gt;not enough&lt;/em&gt; to just do this. We need to guard our sphinx target creation. What if we never found it in the first place? The file would error for users and that's &lt;em&gt;no bueno&lt;/em&gt;!&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Additionally, what if someone wants to name their target &lt;code&gt;Sphinx&lt;/code&gt;? It's best to try to stay out of their way, or our simple documentation generator might interfere with someone's actual dependency or project! We can do this by &lt;em&gt;namespacing&lt;/em&gt; the &lt;code&gt;Sphinx&lt;/code&gt; target, which is only permitted for &lt;em&gt;imported&lt;/em&gt; targets. &lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;But wait! What if multiple projects in our build tree depend on &lt;code&gt;find_package(Sphinx)&lt;/code&gt;? Then it will fail to work because &lt;code&gt;Sphinx::Sphinx&lt;/code&gt; is already a target! We should fix that by only creating the target if we've found Sphinx &lt;em&gt;and&lt;/em&gt; it hasn't been created yet.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;While this might seem simple, once we move into later posts in this tutorial, we will expand on this and get it to its &lt;em&gt;proper&lt;/em&gt; state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding a Library
&lt;/h2&gt;

&lt;p&gt;Finding libraries in CMake is deceptively simple. It should just be as easy as finding the path to a single file, setting a variable, and calling it a day... right?&lt;/p&gt;

&lt;p&gt;If only that were the case. Remember, we have access to imported targets, and this can be used to provide more information to CMake when generating the build system, and prevents typos for variables. Even more important, we can create dependency lists of libraries and their components so that users can follow the "YOLO" principle (i.e., &lt;em&gt;You Only Link Once&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Worse, sometimes these libraries provide &lt;code&gt;&amp;lt;Library&amp;gt;Config.cmake&lt;/code&gt;/&lt;code&gt;&amp;lt;library&amp;gt;-config.cmake&lt;/code&gt; files which might not create imported targets and simply export cache variables. One such library is &lt;a href="https://libsdl.org"&gt;SDL2&lt;/a&gt;. SDL2 is a wonderfully neat library, but it's CMake experience leaves a lot to be desired. Sounds like a perfect way to create our own &lt;code&gt;FindSDL2.cmake&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Using what we've learned above regarding &lt;code&gt;find_package&lt;/code&gt; for executable based packages, we can start with a basic skeleton file that's eerily similar to what we did before.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Try to use this however, and you'll quickly find there is no way to &lt;code&gt;#include &amp;lt;SDL2/SDL.h&amp;gt;&lt;/code&gt; 😱! That just won't do! We need to &lt;em&gt;find the path&lt;/em&gt; where this file is found. This is where &lt;a href="https://cmake.org/cmake/help/latest/command/find_path.html"&gt;&lt;code&gt;find_path&lt;/code&gt;&lt;/a&gt; comes into play to find the &lt;code&gt;SDL2_INCLUDE_DIR&lt;/code&gt;. It's a requirement for us to use SDL2 at all, so it'll be added to the &lt;code&gt;REQUIRED_VARS&lt;/code&gt; parameter to &lt;code&gt;find_package_handle_standard_args&lt;/code&gt;. Because it's a cache variable, we'll also mark it as &lt;code&gt;ADVANCED&lt;/code&gt; if we found SDL2, and finally add it to the &lt;code&gt;INTERFACE_INCLUDE_DIRECTORIES&lt;/code&gt; property for &lt;code&gt;SDL2::SDL2&lt;/code&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Awesome! We can now just call &lt;code&gt;target_link_libraries(&amp;lt;my-target&amp;gt; PRIVATE SDL2::SDL2)&lt;/code&gt; and we've got full access to its headers and automatically link against the library itself.&lt;/p&gt;

&lt;p&gt;That... should be it right? Unfortunately, no. On Windows, we must sometimes link against &lt;code&gt;SDL2main&lt;/code&gt; (other platforms are permitted to as well), because SDL2 sometimes overrides the &lt;code&gt;main&lt;/code&gt; function with a redefinition. We can ask that &lt;code&gt;find_package&lt;/code&gt; search for &lt;code&gt;SDL2main&lt;/code&gt; by declaring a component called &lt;code&gt;SDL2::Main&lt;/code&gt;. Ideally, we will always search for all components, and let &lt;code&gt;find_package&lt;/code&gt; and &lt;code&gt;find_package_handle_standard_args&lt;/code&gt; take care of the details. However we need to (of course) do some extra work.&lt;/p&gt;

&lt;p&gt;Firstly, we need to find the &lt;code&gt;SDL2main&lt;/code&gt; library itself. CMake's &lt;code&gt;find_package&lt;/code&gt; cares less about how variables are named, but &lt;em&gt;does&lt;/em&gt; care about how the &lt;code&gt;_FOUND&lt;/code&gt; variables are named. Effectively, for each component in a package, &lt;code&gt;find_package_handle_standard_args&lt;/code&gt; considers a component found if &lt;code&gt;&amp;lt;package&amp;gt;_&amp;lt;component&amp;gt;_FOUND&lt;/code&gt; is true or false. Generally, you'll want to stick to a consistent naming convention, so we'll name our &lt;code&gt;_LIBRARY&lt;/code&gt; variable &lt;code&gt;SDL2_Main_LIBRARY&lt;/code&gt;, and if it's set &lt;em&gt;at all&lt;/em&gt;, we'll just set &lt;code&gt;SDL2_Main_FOUND&lt;/code&gt; to &lt;code&gt;YES&lt;/code&gt; (one of the strings CMake considers to be a boolean)&lt;/p&gt;

&lt;p&gt;We then pass &lt;code&gt;HANDLE_COMPONENTS&lt;/code&gt; as a flag to &lt;code&gt;find_package_handle_standard_args&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Next we'll need to also mark the variable as advanced but &lt;em&gt;only&lt;/em&gt; if its found and ONLY if &lt;code&gt;find_package_handle_standard_args&lt;/code&gt; didn't return early. This might seem counter-intuitive, but that's CMake for ya! We might as well also import the library and make it depend on &lt;code&gt;SDL2::SDL2&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;That should be it, right? Again, things are not as simple as they may seem. SDL2 introduces bug fixes, new APIs, etc. in minor point releases. How do we know for sure we're building with SDL2 2.15? We need to check the version. How does SDL2 express this? Inside of the &lt;code&gt;SDL2/SDL_version.h&lt;/code&gt; header. This, here, is the part where things will become very painful. The only solution we have is to... use a regex 😱😭.&lt;/p&gt;

&lt;p&gt;SDL2 has the following C preprocessor defines declared:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SDL_MAJOR_VERSION&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SDL_MINOR_VERSION&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SDL_PATCHLEVEL&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Luckily, these are fairly simple to find, so we can just get a list of matching lines via &lt;a href="https://cmake.org/cmake/help/latest/command/file.html#strings"&gt;&lt;code&gt;file(STRINGS)&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;OK, but that doesn't actually get us the data right? So we need to extract it further, and this is where it &lt;em&gt;really&lt;/em&gt; does get messy. We'll also pass it to &lt;code&gt;find_package_handle_standard_args&lt;/code&gt; as the &lt;code&gt;VERSION_VAR&lt;/code&gt; and then set the &lt;code&gt;VERSION&lt;/code&gt; property of &lt;code&gt;SDL2::SDL2&lt;/code&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And that's all we need to do! We're done 🎉 (for now 😱)&lt;/p&gt;

&lt;p&gt;Exhausting wasn't it? Luckily, once you write a file like these you rarely need to ever touch them again... At least, until the next entry in this series. 😈&lt;/p&gt;

</description>
      <category>cmake</category>
      <category>buildsystems</category>
      <category>cpp</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Everything You Never Wanted To Know About CMake</title>
      <dc:creator>Isabella Muerte</dc:creator>
      <pubDate>Sat, 23 Mar 2019 12:59:27 +0000</pubDate>
      <link>https://dev.to/slurpsmadrips/everything-you-never-wanted-to-know-about-cmake-4mgg</link>
      <guid>https://dev.to/slurpsmadrips/everything-you-never-wanted-to-know-about-cmake-4mgg</guid>
      <description>&lt;p&gt;This post was originally posted to my personal site. It has been reposted here for visibility.&lt;/p&gt;

&lt;p&gt;Just hearing the word CMake is typically enough to make a shiver run down my spine. I've been deep in the muck of its behavior and tooling the last few weeks as I finish up a CMake library titled &lt;a href="https://github.com/ixm-one/ixm"&gt;IXM&lt;/a&gt;. While the various minutiae of how IXM works, why I wrote it, and all the nice little usage details are definitely for another post, the quick summary is that it abstracts away a majority of common  needs from CMake users, thus allowing you to write &lt;em&gt;even less&lt;/em&gt; CMake (and I think we can all agree that's a good thing). After writing a small ranty post in the YOSPOS subforum on Something Awful about all the gross and disgusting things I've learned about CMake in recent weeks, I decided I'd write up a more in-depth description. Without further ado, let's get into teaching you, the average user, everything you never wanted to know about CMake.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Introduction
&lt;/h2&gt;

&lt;p&gt;Rather than explaining what CMake is, what it does, how it works in extreme&lt;br&gt;
detail, or what have you, I'm going to quickly describe the various steps CMake&lt;br&gt;
takes during the entire build process. Effectively, the workflow of CMake is as&lt;br&gt;
follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;configure&lt;/li&gt;
&lt;li&gt;generate&lt;/li&gt;
&lt;li&gt;build&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Within these steps we can do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;configure

&lt;ul&gt;
&lt;li&gt;copy files&lt;/li&gt;
&lt;li&gt;execute processes&lt;/li&gt;
&lt;li&gt;read/write to files&lt;/li&gt;
&lt;li&gt;check host system state&lt;/li&gt;
&lt;li&gt;create, import, and modify build targets&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;generate

&lt;ul&gt;
&lt;li&gt;write to files&lt;/li&gt;
&lt;li&gt;run generator expressions&lt;/li&gt;
&lt;li&gt;... that's about it&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;build

&lt;ul&gt;
&lt;li&gt;post-build commands&lt;/li&gt;
&lt;li&gt;pre-build commands&lt;/li&gt;
&lt;li&gt;execute processes&lt;/li&gt;
&lt;li&gt;generate files for consumption in later build stages, but &lt;em&gt;only&lt;/em&gt; if CMake
was able to prove that it could consume the files via the DAG.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the many criticisms of CMake is that it is not immediately obvious as to&lt;br&gt;
what commands will run at what stage. Some commands execute, and then create&lt;br&gt;
steps to execute at the &lt;code&gt;generate&lt;/code&gt; step, others run during the &lt;code&gt;configure&lt;/code&gt;&lt;br&gt;
step, and still others will finally execute during the &lt;code&gt;build&lt;/code&gt; itself.&lt;/p&gt;

&lt;p&gt;IXM itself is mostly concerned with the configure and generation step. Because we cannot specify to the user the stage that executes at what time, we try to hide the &lt;code&gt;generate&lt;/code&gt; operations behind &lt;code&gt;configure&lt;/code&gt; step command calls. This means that while we rely on the user performing work in the configure stage, they have less work to do as we simply setup &lt;em&gt;generator expressions&lt;/em&gt; to execute in the background later. The nice thing about this is that we can figure out at the generation stage if our DAG is actually safe and correct and not just "hope for the best" during the configure stage.&lt;/p&gt;
&lt;h2&gt;
  
  
  Cursed and Custom Variables
&lt;/h2&gt;

&lt;p&gt;Variables in CMake are just cursed eldritch terrors, lying in wait to scare the &lt;em&gt;absolute&lt;/em&gt; &lt;strong&gt;piss&lt;/strong&gt; out of anyone that isn't expecting it. Luckily, I drink a lot of coffee and I take a dieuretic so this isn't anything &lt;em&gt;new&lt;/em&gt; for me.&lt;/p&gt;

&lt;p&gt;Beginning with CMake 3.0, there was a change in the way CMake treats variables. Effectively, an "unquoted" argument can be any character except whitespace or one of &lt;code&gt;(&lt;/code&gt;, &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;#&lt;/code&gt;, &lt;code&gt;\&lt;/code&gt;, &lt;code&gt;"&lt;/code&gt;, or &lt;code&gt;&amp;gt;&lt;/code&gt;. Yes, this means CMake variables can contain emoji! How's &lt;em&gt;that&lt;/em&gt; for a modern programming language?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="c1"&gt;# In awe at the byte size of this lad.&lt;/span&gt;
&lt;span class="c1"&gt;# What an absolute code unit.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;🙃 &lt;span class="s2"&gt;"Why would you do this?"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But there is a caveat. When dereferencing a variable &lt;em&gt;explicitly&lt;/em&gt; (i.e., &lt;code&gt;${🙃}&lt;/code&gt;), one must escape any non-alphanumeric character or the characters &lt;code&gt;_&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;.&lt;/code&gt;, and &lt;code&gt;/&lt;/code&gt;. Except, it's not the characters you're escaping, but the &lt;em&gt;bytes themselves&lt;/em&gt;! Thus, we can never &lt;em&gt;actually&lt;/em&gt; dereference the value stored in 🙃, unless CMake does it for us. This is done in the &lt;code&gt;if()&lt;/code&gt;, &lt;code&gt;elseif()&lt;/code&gt;, &lt;code&gt;else()&lt;/code&gt;, &lt;code&gt;while()&lt;/code&gt;, and &lt;code&gt;foreach(IN LISTS)&lt;/code&gt; commands.&lt;/p&gt;

&lt;p&gt;Additionally, because &lt;code&gt;function()&lt;/code&gt; and &lt;code&gt;macro()&lt;/code&gt; can take an &lt;em&gt;unquoted argument&lt;/em&gt;, this means we can &lt;em&gt;also&lt;/em&gt; name functions and macros with &lt;em&gt;literally anything&lt;/em&gt;. The hard part, in this case, is how we can call a command. The only valid characters in this case are alphanumeric and the character &lt;code&gt;_&lt;/code&gt;. Why would CMake let us create functions that can't be called? Hell if I know! 🤣&lt;/p&gt;

&lt;p&gt;This brings us to the very last bit of information regarding variables in CMake.  You can, with a little bit of magic, create your own variable namespaces.  So, CMake's current set of variables exist in the following dereference "spaces".  There is &lt;code&gt;$&lt;/code&gt;, which is the default lookup rules. Additionally, there is also &lt;code&gt;$CACHE&lt;/code&gt; and &lt;code&gt;$ENV&lt;/code&gt;. Both of these look into the &lt;code&gt;CMakeCache.txt&lt;/code&gt; file and system environment variables respectively. This style of variable dereferencing has spread to other parts of CMake. The most explicitly obvious module would be &lt;code&gt;ExternalData&lt;/code&gt;, which provides special &lt;code&gt;DATA{}&lt;/code&gt; variable references. &lt;/p&gt;

&lt;p&gt;In IXM's case, we go a step beyond this, and created a custom syntax to permit the fetching of content via various "provider" variable references. In this syntax, one can specify packages much like other build system/package manager combos. As an example, to get extremely popular Catch2 C++ library, you can specify it via &lt;code&gt;HUB{catchorg/catch2@v2.6.0}&lt;/code&gt;. This name can then be passed around, and it will eventually be use to construct parameters to the &lt;code&gt;FetchContent&lt;/code&gt; module. Yes, it's painful, terrifying, and I'm not going to show you how to do it because it involves abusing CMake's regex engine, ad-hoc string replacements, and an arrogance not seen since moments before Icarus plummeted to his death.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Dict-ion
&lt;/h2&gt;

&lt;p&gt;CMake's current builtin data type is the string. However lurking behind this string data type is an actual type system. How else, then, would CMake know what is a library and what is a source file? One major thing it is lacking however is for a basic key-value system. As it turns out, we can abuse the current library type system to create our own dictionary type. The way this is done is to simply create an &lt;code&gt;INTERFACE IMPORTED&lt;/code&gt; library. Then we simply add functions that automatically add &lt;code&gt;INTERFACE_&lt;/code&gt; to any keys passed in.  Because the interface target is imported, anything that might &lt;em&gt;depend&lt;/em&gt; on this library masquerading as a dictionary will not require that the target be exported during the install step. Thus, we &lt;em&gt;can&lt;/em&gt; get properties via the &lt;code&gt;$&amp;lt;TARGET_PROPERTY&amp;gt;&lt;/code&gt; generator expression, however it is up to us to make sure the &lt;code&gt;INTERFACE_&lt;/code&gt; portion is prepended. I would love to see an alternative to this, but oh well.&lt;/p&gt;

&lt;p&gt;The only downside to this approach is that, due to scoping rules within CMake, dictionaries are faux-global. In other words, they are available to CMake scripts from the directory they were created in and any child directories. They cannot, sadly, be local to function scopes. Perhaps this might change in the future, and we'll get a real honest to god dictionary type, but don't hold your breath. I'd rather see the CMake language go away entirely than get a dictionary type. 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  Improper Properties
&lt;/h2&gt;

&lt;p&gt;Remember moments ago when we were talking about "valid" strings and UTF-8? Well, I lied. As it turns out you just have bytes on your system. This means we can make &lt;em&gt;invalid&lt;/em&gt; UTF-8 character sequences. One value that will never exist in a valid UTF-8 sequence is the &lt;code&gt;C0&lt;/code&gt; byte. Well, as it happens, we can just dump that into a property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;ASCII 192 C0&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;set_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;TARGET &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; PROPERTY INTERFACE_&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;C0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; value&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Behold! CMake gives us the ability to have invalid properties and it doesn't even come to close giving a &lt;em&gt;shit&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Coincidentally, the above property name is used to keep track of keys that were added to a &lt;code&gt;dict()&lt;/code&gt; via the IXM interface. This comes into play when we serialize our dictionary types to disk, as knowing the exact keys to save comes in handy. This is especially true because we want to serialize them minus their &lt;code&gt;INTERFACE_&lt;/code&gt; prepended strings.&lt;/p&gt;

&lt;p&gt;Additionally, there is a curious approach to handling cache variables in CMake. Cache variables effectively live in their own scope. This is why we can have &lt;code&gt;$CACHE{VAR}&lt;/code&gt; to skip the typical variable lookup. In addition to setting the value of a cache variable via &lt;code&gt;set()&lt;/code&gt;, we can also set them via &lt;code&gt;set_property&lt;/code&gt;. After all, cache variables have &lt;em&gt;properties&lt;/em&gt;, one of which is &lt;code&gt;VALUE&lt;/code&gt;. Which we&lt;br&gt;
can get or set as desired. No need to call &lt;code&gt;set(... FORCE)&lt;/code&gt; or&lt;br&gt;
&lt;code&gt;-DVAR:TYPE=VALUE&lt;/code&gt; the variable.&lt;/p&gt;
&lt;h2&gt;
  
  
  Serialization and Custom File Formats
&lt;/h2&gt;

&lt;p&gt;CMake's "treat everything as a string" approach to scripting means that we have interesting side effects. Specifically, CMake does not (at the time of this writing) have any way of performing IO on binary data.  Instead, you must either use a pre-existing language or tool to make sure that you can extract binary data. This is, to be quite frank, frustrating as hell.  &lt;em&gt;However&lt;/em&gt;, we can cheat and make our own file formats. If you recall, ASCII (and by extension Unicode), have what are known as the C0 control codes. While many of these, such as the &lt;code&gt;SOH&lt;/code&gt; (&lt;em&gt;Start Of Header&lt;/em&gt;) or &lt;code&gt;STX&lt;/code&gt; (&lt;em&gt;Start of Text&lt;/em&gt;) control codes have become superfluous thanks to the existence of TCP/IP, we can still use 4 specific control codes for separating our data into hierarchical structures. Specifically, the File Separator, Group Separator, Record Separator, and Unit Separator control codes are easily within our grasp. This means we can have a fairly extensive amount of data split up.&lt;/p&gt;

&lt;p&gt;CMake treats all strings separated by a &lt;code&gt;;&lt;/code&gt; as a list. This means having lists of lists is difficult. But with the magic of the above separators, we simply have to perform a &lt;code&gt;string(REPLACE)&lt;/code&gt; call. The downside is we have to do it at least &lt;em&gt;once&lt;/em&gt; per level of depth, but that is simple enough. Effectively, encoding looks like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;ASCII 31 unit-separator&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;REPLACE &lt;span class="s2"&gt;";"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;unit-separator&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; data &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;APPEND output &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Of course the reverse is to simply switch the location of the &lt;code&gt;;&lt;/code&gt; and &lt;code&gt;${unit-separator}&lt;/code&gt; when extracting from output.&lt;/p&gt;

&lt;p&gt;The actual &lt;code&gt;dict(SAVE)&lt;/code&gt; function in IXM looks like the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="nb"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;ixm_dict_save name&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARGN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; @ARGS=1 INTO&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;NOT INTO&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"dict(SAVE) missing 'INTO' parameter"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;endif&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nf"&gt;ixm_dict_noop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;KEYS &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; keys&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;ASCII 29 group&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;ASCII 30 record&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;ASCII 31 unit&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;key IN LISTS keys&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;GET &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; value&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;value&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;REPLACE &lt;span class="s2"&gt;";"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;unit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; value &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;APPEND output &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;record&lt;/span&gt;&lt;span class="si"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;endif&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nb"&gt;endforeach&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;JOIN output &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;group&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; output&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;ixm_dict_filepath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;INTO &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INTO&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;ASCII 1 SOH&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;ASCII 2 STX&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;ASCII 3 ETX&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;ASCII 25 EM&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;ASCII 30 RS&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;ASCII 31 US&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;WRITE &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INTO&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SOH&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;IXM&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;STX&lt;/span&gt;&lt;span class="si"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;RS&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;version&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;US&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ETX&lt;/span&gt;&lt;span class="si"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;output&lt;/span&gt;&lt;span class="si"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;EM&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;endfunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Yes, we are writing various &lt;code&gt;STX&lt;/code&gt; and &lt;code&gt;EM&lt;/code&gt; values to the file as well (even&lt;br&gt;
thought &lt;em&gt;technically&lt;/em&gt; that's not what they're meant for), however that's to&lt;br&gt;
future proof this file for its versioning, as the actual layout of the file may&lt;br&gt;
change in the future, especially since IXM is &lt;em&gt;currently&lt;/em&gt; not even at a stable&lt;br&gt;
alpha version. &lt;/p&gt;

&lt;p&gt;This 'streaming' format from the tape drive days&lt;sup id="fnref1"&gt;1&lt;/sup&gt; works well for CMake, as we lack fine grained byte access into strings. We cannot simply jump around willy nilly. We either must rely on content being stored in a CMake safe format, regexes, or reading one byte at a time in the CMake language (No thank you! 🙅). By treating CMake content as a "stream" of data, we can stitch the entire serialized format back into a state within CMake, as well as write it back out with little to no issue.&lt;/p&gt;

&lt;p&gt;Currently the IXM 'database' format looks something to the effect of the&lt;br&gt;
following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;␁IXM␂␞version␟1␞additional␟key␟value␟pairs␃␜&amp;lt;filename&amp;gt;␝&amp;lt;dict-name&amp;gt;␞key␟value
␟list␞another␟key␟pair␞OPTIONS␟BUILD_TESTING␟OFF[␜&amp;lt;filename&amp;gt;␝&amp;lt;dict-name&amp;gt;...]␙
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The above text formatting might be a bit hard to follow, but let's walk through it anyhow. First, we use the &lt;em&gt;start-of-header&lt;/em&gt; control code. This is so multiple &lt;em&gt;database files&lt;/em&gt; can be concatenated together without issue, or possibly even embedded into another text file altogether. This is then followed by the &lt;em&gt;start-of-text&lt;/em&gt; control code. This is used to terminate the &lt;em&gt;start-of-header&lt;/em&gt; control code. We then treat the &lt;em&gt;record separator&lt;/em&gt; and &lt;em&gt;unit separator&lt;/em&gt; as a single depth way of setting key-value pairs in the database header. Currently, we just set the date, but in the future additional metadata could possibly be stored.&lt;/p&gt;

&lt;p&gt;Next, we store a "file". This representation is technically superfluous. As of right now, we only ever have the one file, unless other files were written to and are being concatenated. Regardless, it's nice to have it be forward compatible. Each &lt;em&gt;group&lt;/em&gt; is separated by the name of the target, followed by its key-value pairs. These are separated by &lt;em&gt;record&lt;/em&gt; and &lt;em&gt;unit&lt;/em&gt; respectively. A &lt;em&gt;unit&lt;/em&gt; separator might not appear if the values for a key are a single value. Keys that have no value are never written to disk. &lt;code&gt;dict()&lt;/code&gt; instances with no keys are never written to disk either.&lt;/p&gt;

&lt;p&gt;So, why do this in the first place? Well, it gives us a bit more flexibility. Instead of polluting the CMake cache for storing previous runs (and then having to sometimes delete the cache just to fix some broken state), we can instead store previous runs for expensive operations. Want to work around the &lt;code&gt;try_compile&lt;/code&gt; way of things and increase &lt;code&gt;check()&lt;/code&gt; throughput? While not yet implemented, this approach of serializing data in the way people are used to allows us to side step some of CMake's anachronisms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Events and The Nightmares Held Within
&lt;/h2&gt;

&lt;p&gt;Remember above how I said we can't call commands that don't meet the calling convention? Sorry, but I lied again! There is only &lt;em&gt;one&lt;/em&gt; way this works, and that's by way of events. Yes, &lt;em&gt;CMake has events&lt;/em&gt;. No, they are &lt;em&gt;not&lt;/em&gt; documented, and the order of operations is fickle and can change because some user "did a thing" you weren't expecting. With the exception of &lt;em&gt;one&lt;/em&gt; operation. The hidden and not so well known &lt;em&gt;post-configure&lt;/em&gt; step.&lt;/p&gt;

&lt;p&gt;CMake has a very interesting command, typically meant for debugging. It is called &lt;code&gt;variable_watch&lt;/code&gt; and it takes the name of a variable and a command. Because it is a parameter, this command name can be an unquoted argument. The same type of unquoted argument that allows us to have emoji or invalid UTF-8 byte sequences in our function names.&lt;/p&gt;

&lt;p&gt;When CMake is finished with its configuration step, the &lt;code&gt;CMAKE_CURRENT_LIST_DIR&lt;/code&gt; variable is set to an empty string. This means that, for all intents and purposes, we can execute destructors. Yes. &lt;em&gt;We can force CMake to have RAII&lt;/em&gt;. We can even check the current stack to see where we are when executing. This makes the following possible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="nb"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;ixm::exit variable access value current stack&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="cm"&gt;#[[Do whatever your heart desires here]]&lt;/span&gt;
&lt;span class="nb"&gt;endfunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nb"&gt;variable_watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;CMAKE_CURRENT_LIST_DIR ixm::exit&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is, I should note, &lt;em&gt;extremely useful&lt;/em&gt; if you're trying to break CMake to not do its normal thing of crushing your soul everytime you want to start a new project.&lt;/p&gt;

&lt;h2&gt;
  
  
  file(GENERATE)
&lt;/h2&gt;

&lt;p&gt;Last on our list is the very powerful and &lt;em&gt;very terrifying&lt;/em&gt; &lt;code&gt;file(GENERATE)&lt;/code&gt; command. This command allows us to feed generation expressions to CMake that will then be used to generate a file at the &lt;code&gt;generate&lt;/code&gt; step. These are, in effect, the closest analogy to a &lt;em&gt;post-generate&lt;/em&gt; step we can get. What this allows us to do, essentially, is generate any kind of file that can depend on content that was created during the configure step. To save your sanity, I'm not going to be posting all of the massive amounts of code I've written to get the behaviors discussed below. You're more than free to peruse the project itself if you're curious.&lt;/p&gt;

&lt;p&gt;For instance, this is how you can generate a response file for your C or C++&lt;br&gt;
compiler based off of a target.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="nb"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;ixm_generate_response_file target&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARGN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; @ARGS=? LANGUAGE&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;get_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;rsp TARGET &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; PROPERTY RESPONSE_FILE&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;NOT rsp&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;output &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_CURRENT_BINARY_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/IXM/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.rsp"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;set_target_properties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    PROPERTIES
      RESPONSE_FILE &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;output&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;endif&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c1"&gt;# This function generates the actual generator expressions. They're not&lt;/span&gt;
  &lt;span class="c1"&gt;# shown here for brevity.&lt;/span&gt;
  &lt;span class="nf"&gt;ixm_generate_response_file_expressions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;JOIN &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; content
    &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;Default&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;Release&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;Debug&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INCLUDE_DIRECTORIES&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;COMPILE_DEFINITIONS&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;COMPILE_OPTIONS&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;COMPILE_FLAGS&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;GENERATE
    OUTPUT $&amp;lt;TARGET_PROPERTY:&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;,RESPONSE_FILE&amp;gt;
    CONTENT &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;endfunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Essentially, this gives you a way to get all the flags given to a specific target without having to manually track all the possible flags. Sadly, we cannot get the property granularity on a &lt;em&gt;directory&lt;/em&gt; or &lt;em&gt;source file&lt;/em&gt; level scope. Regardless, generating a response file means we can do things, like, generate a precompiled header in a cross platform way. No need for &lt;a href="https://github.com/sakra/cotire"&gt;cotire&lt;/a&gt;'s approach to PCH generation, nor do we have to add a custom language as seen in the &lt;a href="https://github.com/nanoant/CMakePCHCompiler"&gt;CMakePCHCompiler&lt;/a&gt;. Even better, we can use &lt;code&gt;file(GENERATE)&lt;/code&gt; to &lt;em&gt;conditionally&lt;/em&gt; create &lt;em&gt;unity builds&lt;/em&gt; on a per-target basis. If we create our library target with &lt;code&gt;add_library(&amp;lt;name&amp;gt; OBJECT)&lt;/code&gt;, then we've recreated the ability to do per-directory unity builds as found in game engines like Unreal.  Combine this with &lt;a href="https://ninja-build.org/"&gt;ninja&lt;/a&gt; and your build will see a considerable speed up.&lt;/p&gt;

&lt;p&gt;Finally, a few things we can do with &lt;code&gt;file(GENERATE)&lt;/code&gt; also include, but are not limited to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generating files for services like AppImage, systemd, or launchd without    requiring a user to leave CMake, or using &lt;code&gt;configure_file&lt;/code&gt;. Want to generate a file to automatically turn your executable into a Windows service as well? You can do that too.&lt;/li&gt;
&lt;li&gt;Write a &lt;code&gt;CPackConfig.cmake&lt;/code&gt; file that is created at generation time, removing the need to &lt;code&gt;include(CPack)&lt;/code&gt; after all your calls to &lt;code&gt;install()&lt;/code&gt;, and setting various global variables.&lt;/li&gt;
&lt;li&gt;Generate a &lt;code&gt;CTestConfig.cmake&lt;/code&gt; file, or ignore that altogether so you can have a decent unit test runner for once.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Welcome To H*ck
&lt;/h2&gt;

&lt;p&gt;Now that I've shared the dark terrifying secrets that lie within CMake, I hope you, the reader, can internalize the nightmares that are sitting quietly waiting to unleash themselves. Perhaps you might lose this information one day, but you'll always &lt;em&gt;know&lt;/em&gt; you once knew it, and that is a fate worse than most. Regardless, one thing is true after I have stared into the depths of CMake:&lt;/p&gt;

&lt;p&gt;I͠ K̸no͜w ͝Too̢ ͡Muc͘ḩ&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Yes, I am aware that tape drives still exist. Chill. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>cpp</category>
      <category>cmake</category>
      <category>buildsystems</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
