<?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: Richard</title>
    <description>The latest articles on DEV Community by Richard (@vanderoost).</description>
    <link>https://dev.to/vanderoost</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4134053%2F5e09adce-7039-4d1b-b766-d6ef17275e88.jpg</url>
      <title>DEV Community: Richard</title>
      <link>https://dev.to/vanderoost</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vanderoost"/>
    <language>en</language>
    <item>
      <title>Why 95% of company AI projects fail</title>
      <dc:creator>Richard</dc:creator>
      <pubDate>Sun, 20 Sep 2026 13:26:17 +0000</pubDate>
      <link>https://dev.to/vanderoost/why-95-of-company-ai-projects-fail-1614</link>
      <guid>https://dev.to/vanderoost/why-95-of-company-ai-projects-fail-1614</guid>
      <description>&lt;p&gt;It's an interesting time to be alive. The "AI transformation" is happening.&lt;/p&gt;

&lt;p&gt;Many business owners feel FOMO on AI adoption. Yet, allegedly 95% of AI projects in companies fail, according to an MIT report. Why is this?&lt;/p&gt;

&lt;p&gt;I've talked to business owners and AI automation agencies. This is what I found.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenge: GenAI is non-deterministic
&lt;/h2&gt;

&lt;p&gt;This is the big one. If you think like a software engineer, AI is finicky / fuzzy compared to cold hard code. LLM's use a literal random number generator to produce their outputs.&lt;/p&gt;

&lt;p&gt;So if you use LLM's for automation, you will have unexpected things happening.&lt;/p&gt;

&lt;p&gt;Most of the risk surfaces when you're using &lt;strong&gt;AI Agents&lt;/strong&gt; to automate tasks. But there is a more boring and deterministic approach to automation: &lt;strong&gt;AI workflows&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Agents vs. AI Workflows
&lt;/h2&gt;

&lt;p&gt;These are the two main approaches to AI automation.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Agents
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Agents&lt;/strong&gt; [] are systems where LLMs dynamically direct their own processes and tool usage, maintaining control over how they accomplish tasks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is currently the most hyped up version of automation:&lt;/p&gt;

&lt;p&gt;Trigger an LLM, and let it run wild with tools.&lt;/p&gt;

&lt;p&gt;And by "let it run wild with tools" I mean:&lt;/p&gt;

&lt;p&gt;Give it a sense of which tools it can use, and let the LLM decide which tools it wants to call, and how.&lt;/p&gt;

&lt;p&gt;Tools can be: reading / writing files on your computer, using a calculator, doing web search. Anything you might be able to do with a computer that could be useful for the task at hand.&lt;/p&gt;

&lt;p&gt;The flexible "blank canvas" approach here makes it quite interesting, but every little mistake adds up, and over time, results can get wild. This is not what you want in a company procedure.&lt;/p&gt;

&lt;p&gt;So it currently requires a lot of babysitting to be productive with agents, which kind of defeats the purpose of automation.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Workflows
&lt;/h3&gt;

&lt;p&gt;Less flashy, more simple and deterministic.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Workflows&lt;/strong&gt; are systems where LLMs and tools are orchestrated through predefined code paths.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;AI workflows are simple software procedures, with deterministic logic. The are "set in stone" and designed upfront with a lot of care.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Being predefined makes them less flexible, but that's exactly what you want in a company with SOP's. Only where it makes sense, LLM calls are made.&lt;/p&gt;

&lt;p&gt;This way, you keep the automation in check, and things don't spiral out of control by a hallucinating model.&lt;/p&gt;

&lt;p&gt;Every LLM call has guardrails with enforced checks and fallbacks. So even if an LLM model completely shits the bed, your workflow can still move on in a reasonable way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recipes for failure
&lt;/h2&gt;

&lt;p&gt;The common patterns of AI projects that fail are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;One system trying to automate everything&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automating workflows that still need human feedback&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Architecting high level production systems&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  One system trying to automate everything
&lt;/h3&gt;

&lt;p&gt;The man who chases two rabbits, catches none. If you try to automate too much with a single system, the chances of failure increase geometrically. And that is why it so often fails.&lt;/p&gt;

&lt;p&gt;The better approach is to take one procedure at a time, something that is done manually so you know exactly what needs to be done. You know the exceptions, you know the intricate details. Then it's a lot easier to start building an automation for this.&lt;/p&gt;

&lt;p&gt;Don't "automate the marketing" for your company, but automate budgeting your google ads account for example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automating workflows that still need human feedback
&lt;/h3&gt;

&lt;p&gt;If you try to fully automate a workflow where you should be checking things before moving to the next step, you're gonna have a bad time.&lt;/p&gt;

&lt;p&gt;For example, sending emails. If you think your agent can read incoming emails, figure out a reply, and send them off. This might work well for 90% of the cases. But unexpected situations can cause massive disasters.&lt;/p&gt;

&lt;p&gt;Solution: Automate 95% of the process, but have a human give the final green light before moving on. So let the AI draft a reply, you're the one to send it off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecting high level production systems&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI models wrapped up in coding harnesses are getting extremely good at software engineering. But when architecting high level production systems, AI currently just lacks some of the awareness, company history, that's required to lead this to a good outcome.&lt;/p&gt;

&lt;p&gt;Solution: Human / agent collaboration. Have a senior engineer go back and forth with the coding agent to come to a good outcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  What works well
&lt;/h2&gt;

&lt;p&gt;As we'll see, the non-deterministic nature of genAI explains why it so often fails to automate a business procedure.&lt;/p&gt;

&lt;p&gt;The common theme is that typically the more boring automations, that don't look exciting or flashy, are working the best.&lt;/p&gt;

&lt;p&gt;This agrees with Anthropic's take on the matter:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;we recommend finding the simplest solution possible, and only increasing complexity when needed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After talking to business owners, these are some AI project areas that are either working well or failing miserably.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data analytics
&lt;/h3&gt;

&lt;p&gt;Most companies are collecting data. And LLM's are fantastic at pulling data from a database, and drawing conclusion.&lt;/p&gt;

&lt;p&gt;Especially if you give it the proper context of what they have access to, and all the relations between entities.&lt;/p&gt;

&lt;p&gt;This can be a great way to answer business questions with subtle nuances that are different every time. For example, a question like: "What was last quarter's revenue from returning European customers?" and "How many of them spent over $1,000?".&lt;/p&gt;

&lt;p&gt;This used to take a MySQL (or Tableau/Power BI) expert and a complicated query for every single question.&lt;/p&gt;

&lt;p&gt;Now, most state of the art LLM's are smart enough to connect the dots, and pull the correct data out.&lt;/p&gt;

&lt;p&gt;Pro tip: Give the LLM read-only access to your database. For analytics there's no need to change the database. We've all heard the horror stories of "the AI wiped out production".&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Specialised translation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;LLM's are pretty good at language. So if you have a specific translation job to do, where context matters a lot, they can do a great job.&lt;/p&gt;

&lt;p&gt;If context matters a lot, you do have to make sure to give that context to the LLM, obviously.&lt;/p&gt;

&lt;p&gt;Examples of this could be: Translating restaurant menu's into different languages. Here, it's important to not translate everything literally, but now that everything is food related. And if a menu item says "Margarita" it's important to know whether it's under the pizza's or the cocktails section.&lt;/p&gt;

&lt;p&gt;Another example could be: Translating subtitles for technical tutorial videos. Having the context of the technical topic, and jargon is important here. But once you give it this context, LLMs can be great.&lt;/p&gt;

&lt;p&gt;This is a perfect example of where a workflow performs a lot better than agents.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Research&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;LLMs are great at processing large amounts of text. If you need to do research on a certain topic, you can let LLMs search the internet for sources, and cross reference different findings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;AI projects tend to fail because companies try to hastily adopt new workflows out of fear of missing out, and by nature, LLMs are non-deterministic.&lt;/p&gt;

&lt;p&gt;The approach that works reliably is: keeping it simple.&lt;/p&gt;

&lt;p&gt;When building applications with LLMs, use the simplest solution possible, and only increase complexity when needed.&lt;/p&gt;

&lt;p&gt;This might mean not building "agentic" systems at all, but just stick to workflows.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://vanderoost.com/articles/2026/09/13/why-company-ai-projects-fail/" rel="noopener noreferrer"&gt;vanderoost.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Plotting histograms in the terminal</title>
      <dc:creator>Richard</dc:creator>
      <pubDate>Sun, 20 Sep 2026 13:26:16 +0000</pubDate>
      <link>https://dev.to/vanderoost/plotting-histograms-in-the-terminal-4hkg</link>
      <guid>https://dev.to/vanderoost/plotting-histograms-in-the-terminal-4hkg</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/aLNlyBNU0tw" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I was generating some random numbers the other day. And I really felt the urge to visualize them. Just to get an intuition, like, what's the shape of the distribution? Is it noisy or smooth?&lt;/p&gt;

&lt;p&gt;When in Python, I would usually bust out &lt;code&gt;pip install matplotlib&lt;/code&gt; for this kind of tech. But what are the options when you're in C?&lt;/p&gt;

&lt;p&gt;I ended up writing a plot library from scratch of course :) &lt;a href="https://github.com/vanderoost/plt.c" rel="noopener noreferrer"&gt;plt.c on github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wanted to keep it super simple, so I chose to plot in the terminal, using unicode block characters. No need for external graphics or imaging libraries.&lt;/p&gt;

&lt;p&gt;This is what it looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqkhlw3tul0t1338m9ox9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqkhlw3tul0t1338m9ox9.png" alt="Terminal plot example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the rest of this article, we'll walk through the process of writing this library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating test data
&lt;/h2&gt;

&lt;p&gt;Before we can plot anything, we need something to plot. I want my utility to work with simple float arrays. If we need other datatypes later we can always do this.&lt;/p&gt;

&lt;p&gt;So let's generate some random floats:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#define SAMPLE_COUNT 16
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SAMPLE_COUNT&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;SAMPLE_COUNT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;RAND_MAX&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Histogram buckets
&lt;/h2&gt;

&lt;p&gt;To take a list of random numbers, and turn it into a histogram, we need to decide on our "buckets".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxz5l0jbh593fpgj4ond6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxz5l0jbh593fpgj4ond6.png" alt="Histogram buckets"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's say all the little green dots are our random numbers, or samples. The buckets are drawn as columns, and we just have to count how many samples fall in each bucket. Those counts will correspond to the bar heights of our histogram.&lt;/p&gt;

&lt;p&gt;We can do that by looping over all samples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define COLS 10
&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

  &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;COLS&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;SAMPLE_COUNT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;bucket_ix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;COLS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;bucket_ix&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We initialize our &lt;code&gt;buckets&lt;/code&gt; as a &lt;code&gt;size_t&lt;/code&gt; array, initialized to zero with the &lt;code&gt;= {}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then we loop over all samples, and for each decide which bucket it belongs to. Since we're working with samples from 0.0 to 1.0, it's a simple multiply with the number of columns &lt;code&gt;COLS&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  First ugly plot
&lt;/h2&gt;

&lt;p&gt;Now that we have bucket counts, we can try to plot them. Since we have &lt;em&gt;columns&lt;/em&gt;, we should also introduce the concept of &lt;em&gt;rows&lt;/em&gt;. Rows and columns refer to the terminal characters we can print. So plotting a 2D figure is simply a double loop over rows and columns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define ROWS 5
&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We hit every cell with our doubly nested loop. Then in each cell we decide whether we're above or below the height/count of the bucket. If we're above, we print a space, if we're below, we print a pound sign. Just an arbitrary character that fills up the cell.&lt;/p&gt;

&lt;p&gt;This spits out:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7evf565nk0ka3hdqr1l3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7evf565nk0ka3hdqr1l3.png" alt="First ugly plot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you squint your eyes, it kind of looks like a histogram..&lt;/p&gt;

&lt;p&gt;But we can do better :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Autoscaling the Y-axis
&lt;/h2&gt;

&lt;p&gt;One big problem with this approach is that we're not scaling the Y-axis at all. So when our sample count increases, we end up plotting a full block where all bars max out.&lt;/p&gt;

&lt;p&gt;This is what it looks like with &lt;code&gt;SAMPLE_COUNT&lt;/code&gt; set to 100:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F08fifacpbpcnhzq9asto.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F08fifacpbpcnhzq9asto.png" alt="Overflowing Y-axis"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can fix this by keeping track of the maximum bucket count:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;bucket_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;COLS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bucket_max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;bucket_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this &lt;code&gt;bucket_max&lt;/code&gt; and &lt;code&gt;ROWS&lt;/code&gt;, we can scale the buckets to the right size for our canvas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;COLS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ROWS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;bucket_max&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multiplying by &lt;code&gt;ROWS&lt;/code&gt;, so increasing our rows will make the bars scale up. Dividing by &lt;code&gt;bucket_max&lt;/code&gt; so the highest bar will always be exactly &lt;code&gt;ROWS&lt;/code&gt; high.&lt;/p&gt;

&lt;p&gt;Now the height of the histogram automatically scales:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2kum4vb3vkldf769c6yj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2kum4vb3vkldf769c6yj.png" alt="Autoscaling the Y-axis"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the full terminal width
&lt;/h2&gt;

&lt;p&gt;We've set our &lt;code&gt;COLS&lt;/code&gt; to an arbitrary 10. We could make the tool really fancy and auto-detect the width of the terminal, but I usually don't change my terminal width much, so I'm ok with just hard-coding it.&lt;/p&gt;

&lt;p&gt;But we can find out our width of the terminal using the &lt;code&gt;$COLUMNS&lt;/code&gt; variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;% echo $&lt;/span&gt;COLUMNS
&lt;span class="go"&gt;72
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So I'll be using 72 from now on. And while we're at it, let's set &lt;code&gt;ROWS&lt;/code&gt; to 16 and also increase the number of samples to 1000:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define SAMPLE_COUNT 1000
#define ROWS 16
#define COLS 72
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now our histogram starts to get a bit more "definition":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9m3z69t5tkc7fml5p4m3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9m3z69t5tkc7fml5p4m3.png" alt="Full-width histogram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Unicode block elements
&lt;/h2&gt;

&lt;p&gt;Instead of the arbitrary pound signs, we can do a lot better. By using &lt;a href="https://en.wikipedia.org/wiki/Block_Elements" rel="noopener noreferrer"&gt;unicode block elements&lt;/a&gt; we can 8x our vertical resolution (without increasing rows).&lt;/p&gt;

&lt;p&gt;We have 8 different block elements, going from 1/8 height (&lt;code&gt;U+2581&lt;/code&gt;), all the way to a full block (&lt;code&gt;U+2588&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;▁ ▂ ▃ ▄ ▅ ▆ ▇ █
1 2 3 4 5 6 7 8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All we have to do now is figure out some logic that prints out the correct unicode characters at the correct spot.&lt;/p&gt;

&lt;p&gt;We will still print one character at a time, so the number of rows and columns doesn't change. But we can now deal with 8 times more height levels.&lt;/p&gt;

&lt;p&gt;And then there are 3 different situations for a character. The column height can either be:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Under the current character: print a space&lt;/li&gt;
&lt;li&gt;Above the current character: print a full block&lt;/li&gt;
&lt;li&gt;Inside the current character: print one of the sub-blocks&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnvtz419wkb7un6zo7clv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnvtz419wkb7un6zo7clv.png" alt="Three different block situations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The three situations are drawn in yellow here.&lt;/p&gt;

&lt;p&gt;If we represent all 8 block characters in an array, we can use the index as the "sub-block-height" and we prevent having to write a lot of if-else statements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"\u2581"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"\u2582"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"\u2583"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"\u2584"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"\u2585"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"\u2586"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"\u2587"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"\u2588"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;block_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, I've also added the space character in there. So we have a total of 9 elements in our array. I still want to do the math with 8 levels though. So when I calculate &lt;code&gt;block_count&lt;/code&gt; I subtract 1.&lt;/p&gt;

&lt;p&gt;Then when we're autoscaling, we don't want to set the max bucket height equal to &lt;code&gt;ROWS&lt;/code&gt;, but to 8 times &lt;code&gt;ROWS&lt;/code&gt;, so we multiply it by &lt;code&gt;block_count&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;block_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;bucket_max&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then it's time for the plot loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;block_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;block_ix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;block_ix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block_ix&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;block_ix&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;block_ix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block_ix&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;block_count&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;block_count&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;block_ix&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;block_ix&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our &lt;code&gt;height&lt;/code&gt; is now also multiplied by the &lt;code&gt;block_count&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And then we calculate the index &lt;code&gt;block_ix&lt;/code&gt; which we then have to clamp betwen 0 and 8 to make sure everything works.&lt;/p&gt;

&lt;p&gt;And when we run it like this, we're plotting something that looks like a real histogram:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8dn5uphyybpnc784beat.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8dn5uphyybpnc784beat.png" alt="Plotting with block elements"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And maybe we should change the distribution a bit to really appreciate the extra resolution this has bought us. We can take the square root of each random number, and increase the sample count to 10,000:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;math.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#define SAMPLE_COUNT 10000
&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SAMPLE_COUNT&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;SAMPLE_COUNT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sqrtf&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;RAND_MAX&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;sqrtf&lt;/code&gt; (square root for floats) from &lt;code&gt;math.h&lt;/code&gt; we're getting a more interesting distribution:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3e9aol0pxrdq4m8ykpc7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3e9aol0pxrdq4m8ykpc7.png" alt="Square root distribution"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A plot like this would have never been possible with spaces and pound signs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Autoscaling the X-axis
&lt;/h2&gt;

&lt;p&gt;We're almost done, but there still is one issue: If our random floats go outside the 0.0 - 1.0 range, we have a problem.&lt;/p&gt;

&lt;p&gt;Let's go back to a uniform distribution, but subtract 0.5 to center the numbers around 0.0:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;  &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SAMPLE_COUNT&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;SAMPLE_COUNT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;RAND_MAX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That results in the following abomination:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5ogbhirc6wlrlrbdbyrs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5ogbhirc6wlrlrbdbyrs.png" alt="Not scaling the X-axis"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We could either manually specify the range we want to plot our histogram at, or let it auto-scale the x-axis as well. I prefer the latter. This allows us to just throw anything at it, and the plot function will just figure it out.&lt;/p&gt;

&lt;p&gt;So in order to do this, we need to keep track of the x-range (the minimum and maximum value of our samples):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;  &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;x_min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;x_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;SAMPLE_COUNT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;x_min&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;x_min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x_max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;x_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;x_range&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x_max&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x_min&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have &lt;code&gt;x_min&lt;/code&gt;, &lt;code&gt;x_max&lt;/code&gt; and &lt;code&gt;x_range&lt;/code&gt;. And we're going to do some basic math to scale and shift the samples back into a 0.0 - 1.0 range, after which we can multiply them with the number of columns &lt;code&gt;COLS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First we calculate the x-scale. And we guard against a range of 0.0 to avoid dividing by zero:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;  &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;x_scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x_range&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;COLS&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;x_range&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, we can shift and scale each sample, before calculating which bucket it goes into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;  &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;COLS&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;bucket_ix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x_min&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x_scale&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;bucket_ix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bucket_ix&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;COLS&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;COLS&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;bucket_ix&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;bucket_ix&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Subtracting &lt;code&gt;x_min&lt;/code&gt; makes sure we shift the entire range to start from 0.0. Then multiplying by &lt;code&gt;x_scale&lt;/code&gt; scales it up to our number of columns.&lt;/p&gt;

&lt;p&gt;After this, we make sure we don't exceed &lt;code&gt;COLS - 1&lt;/code&gt; which would mean we access elements outside of our &lt;code&gt;buckets&lt;/code&gt; array.&lt;/p&gt;

&lt;p&gt;This gets us back to a properly scaled histogram of our uniform distribution:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvza1vmltkj8aijhlrh29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvza1vmltkj8aijhlrh29.png" alt="Autoscaling the X-axis"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Splitting the code into a library
&lt;/h2&gt;

&lt;p&gt;Up until this point we've been cluttering up our &lt;code&gt;main&lt;/code&gt; function. I'd like to clean it up and end up with something like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;main.c&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"plt/plt.h"&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#define SAMPLE_COUNT 10000
#define ROWS 16
#define COLS 72
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SAMPLE_COUNT&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;SAMPLE_COUNT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;roll_a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;RAND_MAX&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;roll_b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;RAND_MAX&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;roll_a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;roll_b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;plt_hist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SAMPLE_COUNT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ROWS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;COLS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lot cleaner. Our plot functionality is now just one &lt;code&gt;plt/plt.h&lt;/code&gt; include, and one &lt;code&gt;plt_hist()&lt;/code&gt; call.&lt;/p&gt;

&lt;p&gt;Note that we also do two random rolls, and add them together. This gives quite an interesting distribution:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flx08fy93tqwjw0tuq76o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flx08fy93tqwjw0tuq76o.png" alt="Two random numbers added"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And our &lt;code&gt;plt&lt;/code&gt; library looks like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;plt/plt.h&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#ifndef _PLT_H
#define _PLT_H
&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;plt_hist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cp"&gt;#endif // _PLT_H
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;plt/plt.c&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"plt.h"&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;plt_hist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Get the x range&lt;/span&gt;
  &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;x_min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;x_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;x_min&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;x_min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x_max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;x_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;x_range&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x_max&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x_min&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;x_scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x_range&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;cols&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;x_range&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Keep track of bucket counts&lt;/span&gt;
  &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;bucket_ix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x_min&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x_scale&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;bucket_ix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bucket_ix&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cols&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;cols&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;bucket_ix&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;bucket_ix&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Find the max count&lt;/span&gt;
  &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;bucket_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bucket_max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;bucket_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// clang-format off&lt;/span&gt;
  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"\u2581"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"\u2582"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"\u2583"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"\u2584"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"\u2585"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"\u2586"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"\u2587"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"\u2588"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="c1"&gt;// clang-format on&lt;/span&gt;
  &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;block_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Scale heights&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;block_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;bucket_max&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Plotting&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;block_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;block_ix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;block_ix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block_ix&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;block_ix&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;block_ix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block_ix&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;block_count&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;block_count&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;block_ix&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;block_ix&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;That's it! Thanks for reading.&lt;/p&gt;

&lt;p&gt;I'm maintaining it on github as &lt;a href="https://github.com/vanderoost/plt.c" rel="noopener noreferrer"&gt;plt.c&lt;/a&gt; so feel free to grab it from there.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://vanderoost.com/articles/2026/09/11/histogram-plotting-in-the-terminal/" rel="noopener noreferrer"&gt;vanderoost.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vanderoost.com/articles/2026/08/05/levels-of-effective-makefile-cheatsheet/" rel="noopener noreferrer"&gt;The 7 levels of highly effective Makefiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/vanderoost/plt.c" rel="noopener noreferrer"&gt;plt.c on Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>coding</category>
      <category>github</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
    <item>
      <title>The 7 levels of highly effective Makefiles</title>
      <dc:creator>Richard</dc:creator>
      <pubDate>Sun, 20 Sep 2026 13:26:13 +0000</pubDate>
      <link>https://dev.to/vanderoost/the-7-levels-of-highly-effective-makefiles-758</link>
      <guid>https://dev.to/vanderoost/the-7-levels-of-highly-effective-makefiles-758</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/PPDyWuWz9VE" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Rumor has it that all Makefiles in use today were written in a time when dinosaurs roamed the earth. Nobody &lt;em&gt;actually&lt;/em&gt; writes new Makefiles anymore, right?&lt;/p&gt;

&lt;p&gt;Right. Makefiles cause a lot of anxiety, but in this article, I will walk you through the humbling experience of writing a Makefile from scratch. To automate a C build system.&lt;/p&gt;

&lt;p&gt;If you don't know what I'm talking about, Make is a tool for &lt;em&gt;making files&lt;/em&gt; based on certain &lt;em&gt;rules&lt;/em&gt;. It can be abused to do more, and to automate other terminal shenanigans. Think of running your tests, deploying, building Docker images, etc.&lt;/p&gt;

&lt;p&gt;Once you find yourself running certain commands repeatedly in a codebase, your first instinct might be to stash them away in some bash script.&lt;/p&gt;

&lt;p&gt;This works, but Makefiles give you some extra tech: &lt;code&gt;make&lt;/code&gt; automatically creates a dependency graph of all the files you want to "make", and then uses the last modification timestamps of each file to determine what actually has to be made.&lt;/p&gt;

&lt;p&gt;So it's more efficient, and it has some other cool tricks that we'll dive into.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; (spoiler alert): this is the final Makefile we'll end up with:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nv"&gt;NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; main
&lt;span class="nv"&gt;BIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; bin
&lt;span class="nv"&gt;OBJ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; obj
&lt;span class="nv"&gt;SRC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; src

&lt;span class="nv"&gt;EXEC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;BIN&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="p"&gt;$(&lt;/span&gt;NAME&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;BIN_SRCS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;LIB_SRCS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;ALL_SRCS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;BIN_SRCS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;LIB_SRCS&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;BINS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;patsubst &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/%.c,&lt;span class="p"&gt;$(&lt;/span&gt;BIN&lt;span class="p"&gt;)&lt;/span&gt;/%,&lt;span class="p"&gt;$(&lt;/span&gt;BIN_SRCS&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nv"&gt;OBJS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;patsubst &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/%.c,&lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;/%.o,&lt;span class="p"&gt;$(&lt;/span&gt;LIB_SRCS&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nv"&gt;DEPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;patsubst &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/%.c,&lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;/%.d,&lt;span class="p"&gt;$(&lt;/span&gt;ALL_SRCS&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(BINS)&lt;/span&gt;

&lt;span class="nl"&gt;$(BINS)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(BIN)/%: $(OBJ)/%.o $(OBJS)&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;@D&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;CC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;LDFLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$^&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;LDLIBS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt;

&lt;span class="nl"&gt;$(OBJ)/%.o&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(SRC)/%.c&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;@D&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;CC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;CFLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-MMD&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;$&amp;lt;&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(EXEC)&lt;/span&gt;
    &lt;span class="nv"&gt;$&amp;lt;&lt;/span&gt;

&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    find &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f | entr &lt;span class="nt"&gt;-c&lt;/span&gt; make run

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;BIN&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;-include&lt;/span&gt;&lt;span class="sx"&gt; $(DEPS)&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all run watch clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this looks a bit intimidating, not to worry. We'll start from zero with only a &lt;code&gt;main.c&lt;/code&gt; file and build it up step by step, to multiple &lt;code&gt;.c&lt;/code&gt; and &lt;code&gt;.h&lt;/code&gt; files in a proper project setup with subdirectories. I use this post myself as a Makefile cheatsheet.&lt;/p&gt;

&lt;p&gt;All the code can also be found in my &lt;a href="https://github.com/vanderoost/c-makefile-template" rel="noopener noreferrer"&gt;C Makefile template&lt;/a&gt; repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 0 - Nothing
&lt;/h2&gt;

&lt;p&gt;Literally no Makefile at all, so this one doesn't count. But even without a Makefile, we can already start using &lt;code&gt;make&lt;/code&gt; because it has a bunch of default rules.&lt;/p&gt;

&lt;p&gt;So without a Makefile, our project directory contains only a single file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;└── main.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before we knew about &lt;code&gt;make&lt;/code&gt;, we would compile it into a &lt;code&gt;main&lt;/code&gt; executable like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% cc main.c -o main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But with &lt;code&gt;make&lt;/code&gt;, we can simply run &lt;code&gt;make main&lt;/code&gt; to do the same:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make main
cc     main.c   -o main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That output on the last line shows the command that &lt;code&gt;make&lt;/code&gt; runs for us.&lt;/p&gt;

&lt;p&gt;It compiles &lt;code&gt;main.c&lt;/code&gt; into an executable called &lt;code&gt;main&lt;/code&gt; which we can run to verify it's all working:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% ./main
hello world
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that works, but how did &lt;code&gt;make&lt;/code&gt; know what to do without a Makefile?&lt;/p&gt;

&lt;p&gt;There are some default pattern matching rules, and &lt;code&gt;make&lt;/code&gt; magically figures it out.&lt;/p&gt;

&lt;p&gt;You don't need to understand this right now, but the rule that applies here looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;%&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;%.c&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;LINK.c&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$^&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;LOADLIBES&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;LDLIBS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;%&lt;/code&gt; picks up the target we want to make, &lt;code&gt;main&lt;/code&gt; in this case. The &lt;code&gt;%.c&lt;/code&gt; means it has a prerequisite of &lt;code&gt;main.c&lt;/code&gt; where the &lt;code&gt;%&lt;/code&gt; is the pattern. We happen to have a &lt;code&gt;main.c&lt;/code&gt;, which is why this works. Then the actual "recipe" for making it is a bunch of variables that end up running &lt;code&gt;cc     main.c   -o main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can see all the implicit rules and default variables with &lt;code&gt;make -p&lt;/code&gt; if you're curious.&lt;/p&gt;

&lt;p&gt;If your file is called &lt;code&gt;program.c&lt;/code&gt; instead, you can run &lt;code&gt;make program&lt;/code&gt;, and it spits out the file &lt;code&gt;program&lt;/code&gt; as the executable.&lt;/p&gt;

&lt;p&gt;Making without a Makefile is a bit of a party trick, but would I ever use this in practice? Actually, yes. Every time I quickly write a &lt;code&gt;main.c&lt;/code&gt; to test something, all I have to do is type &lt;code&gt;make main&lt;/code&gt; and it's compiled.&lt;/p&gt;

&lt;p&gt;What if you want to change the compiler, or add flags? No problem. The default behavior of &lt;code&gt;make&lt;/code&gt; is to compile with whatever is set in the &lt;code&gt;CC&lt;/code&gt; environment variable, and it uses the flags from &lt;code&gt;CFLAGS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So if you want to compile with &lt;code&gt;gcc&lt;/code&gt; instead of &lt;code&gt;cc&lt;/code&gt;, you can run it like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% CC=gcc make main
gcc     main.c   -o main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding flags can be done with the &lt;code&gt;CFLAGS&lt;/code&gt; variable:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% CC=gcc CFLAGS="-Wall -Wextra" make main
gcc -Wall -Wextra    main.c   -o main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But at this point it's easier to just use a Makefile. So let's check out the next level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 1 - Bare minimum
&lt;/h2&gt;

&lt;p&gt;Now we actually write a Makefile, the configuration for &lt;code&gt;make&lt;/code&gt;. For our "bare minimum" level I want to add three features:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Automatically run after compiling&lt;/li&gt;
&lt;li&gt;Configure compile flags&lt;/li&gt;
&lt;li&gt;Cleanup to get back to the initial state&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The filename is just Makefile so our project directory looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── Makefile
└── main.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A filename of &lt;code&gt;makefile&lt;/code&gt; also works, but Makefile is the convention I'm sticking to.&lt;/p&gt;

&lt;p&gt;A Makefile mainly consists of a bunch of &lt;em&gt;rules&lt;/em&gt;. This is what a rule looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;target&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;prerequisites&lt;/span&gt;
    recipe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we have a &lt;code&gt;target&lt;/code&gt; that's typically a file, like &lt;code&gt;main&lt;/code&gt;. It can have prerequisites which are typically other files, but can also be other non-file targets. And finally the &lt;code&gt;recipe&lt;/code&gt; which is the command to build the &lt;code&gt;target&lt;/code&gt;, like a &lt;code&gt;cc&lt;/code&gt; compile command.&lt;/p&gt;

&lt;p&gt;One thing to watch out for: that indentation before the recipe has to be a literal tab character. Spaces will get you &lt;code&gt;Makefile:2: *** missing separator.  Stop.&lt;/code&gt;, which is the most common way to break a fresh Makefile.&lt;/p&gt;

&lt;p&gt;To automatically run our program, feature 1, I'm going to add a target called &lt;code&gt;run&lt;/code&gt;, with a prerequisite &lt;code&gt;main&lt;/code&gt; because we need the main executable to run it. And the action of running it is just calling &lt;code&gt;./main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
    ./main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can run &lt;code&gt;make run&lt;/code&gt;, and this is what happens:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make run
cc     main.c   -o main
./main
hello world
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First it gets compiled, then it runs &lt;code&gt;./main&lt;/code&gt;. How does &lt;code&gt;make&lt;/code&gt; know that it needs to compile? Because we said that &lt;code&gt;main&lt;/code&gt; is a prerequisite of &lt;code&gt;run&lt;/code&gt; (i.e. &lt;code&gt;run&lt;/code&gt; depends on &lt;code&gt;main&lt;/code&gt;). So it will try to &lt;code&gt;make main&lt;/code&gt; first, before running it. And since &lt;code&gt;make main&lt;/code&gt; already worked without a Makefile, this still works.&lt;/p&gt;

&lt;p&gt;But even better, when we run it a second time:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make run
./main
hello world
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it only runs &lt;code&gt;main&lt;/code&gt;, without compiling. Why? Because &lt;code&gt;make&lt;/code&gt; is smart enough to look at the prerequisites of our &lt;code&gt;run&lt;/code&gt; target, &lt;code&gt;main&lt;/code&gt;. And since it already exists, it's not going to "make" it again.&lt;/p&gt;

&lt;p&gt;We know that the targets in a Makefile are usually files, but &lt;code&gt;run&lt;/code&gt; is not supposed to be a file. What if there is a file in our project directory that's literally called &lt;code&gt;run&lt;/code&gt;? Let's see what happens:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make main
cc     main.c   -o main
% touch run
% make run
make: `run' is up to date.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;code&gt;make run&lt;/code&gt; doesn't do anything, because the target &lt;code&gt;run&lt;/code&gt; is "up to date". That happens because the target file &lt;code&gt;run&lt;/code&gt; is newer than the prerequisite file &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To tell make that our &lt;code&gt;run&lt;/code&gt; target is not really referencing a file, we can mark it with &lt;code&gt;.PHONY&lt;/code&gt; like so:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
    ./main

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;code&gt;make run&lt;/code&gt; works again, regardless of our accidental &lt;code&gt;run&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make run
./main
hello world
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though we'll probably never have a &lt;code&gt;run&lt;/code&gt; file in the root of our project directory, it's good practice to mark all the non-file targets with &lt;code&gt;.PHONY&lt;/code&gt; to clarify intent.&lt;/p&gt;

&lt;p&gt;Feature 2 is adding custom compiler flags, easy:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
    ./main

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all. Because we're using the default rule to make &lt;code&gt;main&lt;/code&gt;, the flags will be picked up automatically:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make main
cc -Wall -Wextra    main.c   -o main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feature 3 is adding a cleanup shortcut to undo everything. I'll call it &lt;code&gt;clean&lt;/code&gt; and you see this in 9 out of 10 Makefiles, so we're just sticking to the convention. This target is, like &lt;code&gt;run&lt;/code&gt;, not supposed to be a file, so we mark it as &lt;code&gt;.PHONY&lt;/code&gt;, and all I want it to do is remove our &lt;code&gt;main&lt;/code&gt; executable:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
    ./main

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;rm &lt;/span&gt;main

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;run clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the target is &lt;code&gt;clean&lt;/code&gt;, it has no prerequisites, and all it does is run &lt;code&gt;rm main&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make clean
rm main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what if we run &lt;code&gt;make clean&lt;/code&gt; and &lt;code&gt;main&lt;/code&gt; doesn't exist?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make clean
rm main
rm: main: No such file or directory
make: *** [clean] Error 1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's an error. It doesn't really matter, but for good measure we can change the recipe to &lt;code&gt;rm -f main&lt;/code&gt; or use the &lt;code&gt;$(RM)&lt;/code&gt; variable that &lt;code&gt;make&lt;/code&gt; has for us:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
    ./main

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; main

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;run clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;code&gt;make clean&lt;/code&gt; runs without errors, even if there is nothing to clean:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make clean
rm -f main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before we go to the next level, I want to add one finishing touch here to change the behavior of running just &lt;code&gt;make&lt;/code&gt; without anything else.&lt;/p&gt;

&lt;p&gt;When you have a Makefile, running &lt;code&gt;make&lt;/code&gt; will run the first rule specified in the file, which is &lt;code&gt;run&lt;/code&gt; in our case.&lt;/p&gt;

&lt;p&gt;That's a bit confusing. I want to run the program with &lt;code&gt;make run&lt;/code&gt;, but when I type &lt;code&gt;make&lt;/code&gt;, it makes more sense to only compile (make) it, without running it.&lt;/p&gt;

&lt;p&gt;A common pattern to achieve this is using an &lt;code&gt;all&lt;/code&gt; target at the top of the Makefile:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
    ./main

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; main

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all run clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We give it a prerequisite of &lt;code&gt;main&lt;/code&gt; just like we did for &lt;code&gt;run&lt;/code&gt;, so running it will make sure that &lt;code&gt;main.c&lt;/code&gt; is compiled into &lt;code&gt;main&lt;/code&gt;. But then the recipe is empty, so it doesn't do anything else:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make
cc -Wall -Wextra    main.c   -o main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It just "makes" our program, which is the most intuitive thing to do after typing &lt;code&gt;make&lt;/code&gt; (or &lt;code&gt;make all&lt;/code&gt;). And again, &lt;code&gt;all&lt;/code&gt; is not referring to a file, so it's added to the &lt;code&gt;.PHONY&lt;/code&gt; list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 2 - Immediate feedback
&lt;/h2&gt;

&lt;p&gt;For me, programming is more productive and fun with a tight feedback loop. So when I make an edit, I want it to instantly compile and run (or crash).&lt;/p&gt;

&lt;p&gt;To do this, we can use a "file watcher" utility. I always use &lt;a href="https://github.com/eradman/entr" rel="noopener noreferrer"&gt;&lt;code&gt;entr&lt;/code&gt;&lt;/a&gt; for this, and set it up as a new rule in the Makefile.&lt;/p&gt;

&lt;p&gt;So let's add a &lt;code&gt;watch&lt;/code&gt; rule to the Makefile, because it "watches" our source files for changes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
    ./main

&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.c | entr make run

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; main

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all run watch clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is what happens when we run &lt;code&gt;make watch&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make watch
ls *.c | entr make run
cc -Wall -Wextra    main.c   -o main
./main
hello world
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first part, &lt;code&gt;ls *.c&lt;/code&gt; just lists out all &lt;code&gt;.c&lt;/code&gt; files in our project directory. All we have is &lt;code&gt;main.c&lt;/code&gt; for now.&lt;/p&gt;

&lt;p&gt;Then it pipes that list of files to &lt;code&gt;entr&lt;/code&gt;, which starts watching the file names that got passed in. When a file changes, it runs the command &lt;code&gt;make run&lt;/code&gt; which compiles and runs our &lt;code&gt;main&lt;/code&gt; executable.&lt;/p&gt;

&lt;p&gt;After running &lt;code&gt;make watch&lt;/code&gt;, it stays "active", waiting for changes. So if we edit &lt;code&gt;main.c&lt;/code&gt; and add some punctuation, we instantly see this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make watch
ls *.c | entr make run
cc -Wall -Wextra    main.c   -o main
./main
hello world
cc -Wall -Wextra    main.c   -o main
./main
Hello, world!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is super useful. One thing I usually like to pass to &lt;code&gt;entr&lt;/code&gt; is the &lt;code&gt;-c&lt;/code&gt; flag which clears the screen before it updates:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
    ./main

&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.c | entr &lt;span class="nt"&gt;-c&lt;/span&gt; make run

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; main

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all run watch clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents the terminal from cluttering up too much.&lt;/p&gt;

&lt;p&gt;Now, whenever we mess up, there is instant feedback. Like a subtle slap on the wrist that instantly catches errors and bugs.&lt;/p&gt;

&lt;p&gt;It also allows for faster experimentation: just try something, hit save, and the instant compile + run shows you the result.&lt;/p&gt;

&lt;p&gt;Also good to know when using &lt;code&gt;entr&lt;/code&gt;: Hitting Space re-runs the command. Hitting Q will quit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 3 - Compiling multiple files
&lt;/h2&gt;

&lt;p&gt;So far we've just been using &lt;code&gt;main.c&lt;/code&gt; as our source file. This is great for quick tools or testing some new concept. But most projects are organized across multiple files.&lt;/p&gt;

&lt;p&gt;Let's say I want to implement some tools for generating random numbers. I have an &lt;code&gt;rng.h&lt;/code&gt; header file, and an implementation in &lt;code&gt;rng.c&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To keep it simple, I'm still storing everything in the root of our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── Makefile
├── main.c
├── rng.c
└── rng.h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our &lt;code&gt;main.c&lt;/code&gt; file now has an &lt;code&gt;#!c #include "rng.h"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We could compile this by hand like so:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% cc main.c rng.c -o main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Integrating this into the Makefile looks like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;

&lt;span class="nl"&gt;main&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main.c rng.c&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
    ./main

&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.c | entr &lt;span class="nt"&gt;-c&lt;/span&gt; make run

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; main

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all run watch clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All we did was specify our target &lt;code&gt;main&lt;/code&gt; and give it the prerequisites &lt;code&gt;main.c&lt;/code&gt; and &lt;code&gt;rng.c&lt;/code&gt;. We don't give it a recipe, because we can still rely on the implicit recipe that &lt;code&gt;make&lt;/code&gt; comes with by default. So this now works:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make run
cc -Wall -Wextra    main.c rng.c   -o main
./main
random float: 0.633477
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But there is a way to simplify this even more. We don't need to write out the &lt;code&gt;main.c&lt;/code&gt; prerequisite, because that's also implied by &lt;code&gt;make&lt;/code&gt; already. So the more compact version of the rule looks like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;

&lt;span class="nl"&gt;main&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;rng.c&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
    ./main

&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.c | entr &lt;span class="nt"&gt;-c&lt;/span&gt; make run

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; main

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all run watch clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And everything still works:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make run
cc -Wall -Wextra    main.c rng.c   -o main
./main
random float: 0.503928
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Level 4 - Source directory
&lt;/h2&gt;

&lt;p&gt;Let's take the first step into organizing our project a bit more, by moving our source code into a &lt;code&gt;src&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── Makefile
└── src
    ├── main.c
    ├── rng.c
    └── rng.h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That breaks our build, because &lt;code&gt;make&lt;/code&gt; can't find our source files anymore:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make run
make: *** No rule to make target `rng.c', needed by `main'.  Stop.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fixing this in our Makefile is surprisingly simple. We just have to tell it about the new &lt;code&gt;src&lt;/code&gt; directory by adding it to the &lt;code&gt;VPATH&lt;/code&gt; variable:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nv"&gt;VPATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; src

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;

&lt;span class="nl"&gt;main&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;rng.c&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
    ./main

&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;ls &lt;/span&gt;src/&lt;span class="k"&gt;*&lt;/span&gt;.c | entr &lt;span class="nt"&gt;-c&lt;/span&gt; make run

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; main

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all run watch clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On line 13 we're also fixing our &lt;code&gt;watch&lt;/code&gt; rule and letting it know about the new &lt;code&gt;src&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;And that fixes the build:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make run
cc -Wall -Wextra    src/main.c src/rng.c   -o main
./main
random float: 0.621248
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're starting to see a bit of repetition in our Makefile, so let's take a moment to add some variables to DRY things up:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nv"&gt;EXEC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; main
&lt;span class="nv"&gt;SRC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; src

&lt;span class="nv"&gt;VPATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(EXEC)&lt;/span&gt;

&lt;span class="nl"&gt;$(EXEC)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;rng.c&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(EXEC)&lt;/span&gt;
    ./&lt;span class="p"&gt;$(&lt;/span&gt;EXEC&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.c | entr &lt;span class="nt"&gt;-c&lt;/span&gt; make run

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;EXEC&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all run watch clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have an &lt;code&gt;EXEC&lt;/code&gt; variable for our final executable. If we ever need to change this name, we can do it in one place. Same for our source code directory, stored in &lt;code&gt;SRC&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We've already seen the syntax for referencing a &lt;code&gt;make&lt;/code&gt; variable before when we used &lt;code&gt;#!makefile $(RM)&lt;/code&gt;, and we use it to reference &lt;code&gt;EXEC&lt;/code&gt; and &lt;code&gt;SRC&lt;/code&gt; as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 5 - Separate compilation
&lt;/h2&gt;

&lt;p&gt;Right now we're taking all our &lt;code&gt;.c&lt;/code&gt; source files, and compiling them in a single command. For this toy example that's totally fine and probably the fastest way, but for larger projects it could make sense to split this into multiple steps.&lt;/p&gt;

&lt;p&gt;This way, when you make an edit to one source file, you only have to recompile that source file, and then link all compiled object files together, instead of compiling all source files on every edit.&lt;/p&gt;

&lt;p&gt;There's a second payoff too: because every &lt;code&gt;.o&lt;/code&gt; file becomes an independent target with no dependencies on the others, &lt;code&gt;make -j&lt;/code&gt; can compile them in parallel across multiple CPU cores.&lt;/p&gt;

&lt;p&gt;Manually, you can compile your &lt;code&gt;.c&lt;/code&gt; files into object &lt;code&gt;.o&lt;/code&gt; files, and then link them to get the final executable:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;cc main.c -c -o main.o
cc rng.c -c -o rng.o
cc main.o rng.o -o main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's also possible to only compile the &lt;code&gt;rng&lt;/code&gt; library into an &lt;code&gt;.o&lt;/code&gt; file, and then link that in while compiling &lt;code&gt;main.c&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;cc rng.c -c -o rng.o
cc main.c rng.o -o main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see what that would look like in our Makefile. There is one super simple tweak we can make:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nv"&gt;EXEC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; main
&lt;span class="nv"&gt;SRC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; src

&lt;span class="nv"&gt;VPATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(EXEC)&lt;/span&gt;

&lt;span class="nl"&gt;$(EXEC)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;rng.o&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(EXEC)&lt;/span&gt;
    ./&lt;span class="p"&gt;$(&lt;/span&gt;EXEC&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.c | entr &lt;span class="nt"&gt;-c&lt;/span&gt; make run

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;EXEC&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all run watch clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's almost too small to spot, but we've changed &lt;code&gt;rng.c&lt;/code&gt; to &lt;code&gt;rng.o&lt;/code&gt;. So we're telling &lt;code&gt;make&lt;/code&gt; our &lt;code&gt;main&lt;/code&gt; executable doesn't depend on &lt;code&gt;rng.c&lt;/code&gt; anymore, but &lt;code&gt;rng.o&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And &lt;code&gt;make&lt;/code&gt; happens to know how to compile &lt;code&gt;.c&lt;/code&gt; files into &lt;code&gt;.o&lt;/code&gt; files by using another standard pattern matching rule. So this works perfectly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make run
cc -Wall -Wextra   -c -o rng.o src/rng.c
cc -Wall -Wextra    src/main.c rng.o   -o main
./main
random float: 0.143407
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We went from a single &lt;code&gt;cc&lt;/code&gt; command to two. So if we now make an edit to &lt;code&gt;main.c&lt;/code&gt; to change the message, and run &lt;code&gt;make run&lt;/code&gt; again, it will skip compiling &lt;code&gt;rng.c&lt;/code&gt; because its &lt;code&gt;.o&lt;/code&gt; file is already up to date:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make run
cc -Wall -Wextra    src/main.c rng.o   -o main
./main
the chance is: 0.226574
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a project with two &lt;code&gt;.c&lt;/code&gt; files and fewer than 20 lines of code, this sort of optimization is kind of silly over-engineering. But as the project grows it starts to make sense.&lt;/p&gt;

&lt;p&gt;You might have noticed that we have an &lt;code&gt;rng.o&lt;/code&gt; file sitting in our project directory now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── Makefile
├── main
├── rng.o
└── src
    ├── main.c
    ├── rng.c
    └── rng.h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows us to avoid recompiling the &lt;code&gt;rng&lt;/code&gt; library, but when we run &lt;code&gt;make clean&lt;/code&gt; we should clean it up:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nv"&gt;EXEC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; main
&lt;span class="nv"&gt;SRC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; src

&lt;span class="nv"&gt;VPATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(EXEC)&lt;/span&gt;

&lt;span class="nl"&gt;$(EXEC)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;rng.o&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(EXEC)&lt;/span&gt;
    ./&lt;span class="p"&gt;$(&lt;/span&gt;EXEC&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.c | entr &lt;span class="nt"&gt;-c&lt;/span&gt; make run

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;EXEC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.o

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all run watch clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we might add more than one library, we'll use &lt;code&gt;*.o&lt;/code&gt; to remove all object files on cleanup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 6 - Detect source files
&lt;/h2&gt;

&lt;p&gt;Our Makefile is in great shape, but one thing I don't like is that every time we decide to write a new library in our project, we have to also remember to edit the Makefile. Wouldn't it be great if &lt;code&gt;make&lt;/code&gt; could dynamically detect all source files?&lt;/p&gt;

&lt;p&gt;To make this work, we're going to use some new Makefile features like &lt;code&gt;wildcard&lt;/code&gt; and &lt;code&gt;patsubst&lt;/code&gt; to find files using pattern matching.&lt;/p&gt;

&lt;p&gt;We're also going to reorganize our source files one more time to make a better distinction between entrypoint &lt;code&gt;.c&lt;/code&gt; files and library &lt;code&gt;.c&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;I've added a new sample library called &lt;code&gt;vec&lt;/code&gt;, to show how our build system can automatically detect multiple libraries.&lt;/p&gt;

&lt;p&gt;The new project structure looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── Makefile
└── src
    ├── main.c
    ├── rng
    │&amp;nbsp;&amp;nbsp; ├── rng.c
    │&amp;nbsp;&amp;nbsp; └── rng.h
    └── vec
        ├── vec.c
        └── vec.h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the convention is: Entrypoints that turn into an executable go directly under &lt;code&gt;src&lt;/code&gt;, and all libraries in a subdirectory of &lt;code&gt;src&lt;/code&gt;. By sticking to this rule, we can configure the Makefile to detect these files properly.&lt;/p&gt;

&lt;p&gt;We also have to change any &lt;code&gt;#!c #include "rng.h"&lt;/code&gt; in our &lt;code&gt;main.c&lt;/code&gt; to &lt;code&gt;#!c #include "rng/rng.h"&lt;/code&gt; after this reorganization.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;.o&lt;/code&gt; files can be organized in their own dedicated directory &lt;code&gt;obj&lt;/code&gt; to reduce clutter in the root of the project.&lt;/p&gt;

&lt;p&gt;Our first step will be to detect all library source files based on a wildcard pattern. To do that, we use the &lt;code&gt;wildcard&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;LIBS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function just expands all files that match the wildcard. So in our case, it will match &lt;code&gt;src/rng/rng.c&lt;/code&gt; and &lt;code&gt;src/vec/vec.c&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, we use the function &lt;code&gt;patsubst&lt;/code&gt; to derive file names of the &lt;code&gt;.o&lt;/code&gt; files we want to keep track of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;OBJ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; obj
&lt;span class="nv"&gt;OBJS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;patsubst &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/%.c,&lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;/%.o,&lt;span class="p"&gt;$(&lt;/span&gt;LIBS&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one is a bit more complicated: It takes three parameters. The first one is the pattern to match, the second one is the new pattern to turn it into, and the third is a list of paths to do this with.&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;OBJS&lt;/code&gt; is created out of &lt;code&gt;LIBS&lt;/code&gt;, and transforms them like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/rng/rng.c -&amp;gt; obj/rng/rng.o
src/vec/vec.c -&amp;gt; obj/vec/vec.o
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we're going to use &lt;code&gt;OBJS&lt;/code&gt; as the prerequisites of our &lt;code&gt;EXEC&lt;/code&gt; target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;$(EXEC)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(OBJS)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of listing the &lt;code&gt;.o&lt;/code&gt; files of each library manually, we now have the &lt;code&gt;#!makefile $(OBJS)&lt;/code&gt; variable that dynamically updates.&lt;/p&gt;

&lt;p&gt;This is what the second rule looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;$(OBJ)/%.o&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(SRC)/%.c&lt;/span&gt;
    &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;@D&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;CC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;CFLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;$&amp;lt;&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a lot more going on. The target is dynamic due to the &lt;code&gt;%&lt;/code&gt;, so it matches all &lt;code&gt;.o&lt;/code&gt; files in the &lt;code&gt;obj&lt;/code&gt; directory and dynamically creates a corresponding &lt;code&gt;.c&lt;/code&gt; prerequisite for each one in the &lt;code&gt;src&lt;/code&gt; directory. So &lt;code&gt;obj/rng/rng.o&lt;/code&gt; will match with &lt;code&gt;src/rng/rng.c&lt;/code&gt; for example.&lt;/p&gt;

&lt;p&gt;The recipe of this rule has two commands. The first one just ensures that the directory of the target exists. The variable &lt;code&gt;#!makefile $(@D)&lt;/code&gt; magically references the directory of the target.&lt;/p&gt;

&lt;p&gt;The second command is just compiling the &lt;code&gt;.c&lt;/code&gt; file into the &lt;code&gt;.o&lt;/code&gt; file. Again, it uses two magic variables: &lt;code&gt;#!makefile $&amp;lt;&lt;/code&gt; to match the first prerequisite, and &lt;code&gt;#!makefile $@&lt;/code&gt; to match the target.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;watch&lt;/code&gt; rule has to look for source files recursively in &lt;code&gt;src&lt;/code&gt;, so we can use &lt;code&gt;find&lt;/code&gt; for this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    find &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f | entr &lt;span class="nt"&gt;-c&lt;/span&gt; make run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our &lt;code&gt;clean&lt;/code&gt; rule also has to be updated to match the new directory structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;EXEC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're removing the executable, and the entire &lt;code&gt;obj&lt;/code&gt; directory. Because we have the &lt;code&gt;mkdir -p&lt;/code&gt; recipe, we make sure we always rebuild these &lt;code&gt;obj&lt;/code&gt; directories when needed.&lt;/p&gt;

&lt;p&gt;If we add all of this to our Makefile, we get this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nv"&gt;EXEC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; main
&lt;span class="nv"&gt;SRC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; src
&lt;span class="nv"&gt;OBJ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; obj

&lt;span class="nv"&gt;LIBS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;OBJS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;patsubst &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/%.c,&lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;/%.o,&lt;span class="p"&gt;$(&lt;/span&gt;LIBS&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nv"&gt;VPATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(EXEC)&lt;/span&gt;

&lt;span class="nl"&gt;$(EXEC)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(OBJS)&lt;/span&gt;

&lt;span class="nl"&gt;$(OBJ)/%.o&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(SRC)/%.c&lt;/span&gt;
    &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;@D&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;CC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;CFLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;$&amp;lt;&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(EXEC)&lt;/span&gt;
    ./&lt;span class="p"&gt;$(&lt;/span&gt;EXEC&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    find &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f | entr &lt;span class="nt"&gt;-c&lt;/span&gt; make run

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;EXEC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all run watch clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we can run &lt;code&gt;make&lt;/code&gt; to see what happens:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make
mkdir -p obj/rng
cc -Wall -Wextra -c src/rng/rng.c -o obj/rng/rng.o
mkdir -p obj/vec
cc -Wall -Wextra -c src/vec/vec.c -o obj/vec/vec.o
cc -Wall -Wextra    src/main.c obj/rng/rng.o obj/vec/vec.o   -o main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And it seems to work. First we make sure we have an &lt;code&gt;obj/rng&lt;/code&gt; directory. Then we're compiling &lt;code&gt;src/rng/rng.c&lt;/code&gt; into &lt;code&gt;obj/rng/rng.o&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We do the same thing for &lt;code&gt;obj/vec/vec.o&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And finally we compile &lt;code&gt;main.c&lt;/code&gt; and link &lt;code&gt;rng.o&lt;/code&gt; and &lt;code&gt;vec.o&lt;/code&gt; into the final executable &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After running &lt;code&gt;make&lt;/code&gt;, the project directory looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── Makefile
├── main
├── obj
│&amp;nbsp;&amp;nbsp; ├── rng
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; └── rng.o
│&amp;nbsp;&amp;nbsp; └── vec
│&amp;nbsp;&amp;nbsp;     └── vec.o
└── src
    ├── main.c
    ├── rng
    │&amp;nbsp;&amp;nbsp; ├── rng.c
    │&amp;nbsp;&amp;nbsp; └── rng.h
    └── vec
        ├── vec.c
        └── vec.h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So everything is working as expected.&lt;/p&gt;

&lt;p&gt;One thing I'd like to clean up is those &lt;code&gt;mkdir&lt;/code&gt; commands. I don't really want to see this in the &lt;code&gt;make&lt;/code&gt; output. We can prevent any recipe commands from being printed by prepending an &lt;code&gt;@&lt;/code&gt; like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nv"&gt;EXEC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; main
&lt;span class="nv"&gt;SRC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; src
&lt;span class="nv"&gt;OBJ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; obj

&lt;span class="nv"&gt;LIBS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;OBJS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;patsubst &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/%.c,&lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;/%.o,&lt;span class="p"&gt;$(&lt;/span&gt;LIBS&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nv"&gt;VPATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(EXEC)&lt;/span&gt;

&lt;span class="nl"&gt;$(EXEC)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(OBJS)&lt;/span&gt;

&lt;span class="nl"&gt;$(OBJ)/%.o&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(SRC)/%.c&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;@D&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;CC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;CFLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;$&amp;lt;&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(EXEC)&lt;/span&gt;
    ./&lt;span class="p"&gt;$(&lt;/span&gt;EXEC&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    find &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f | entr &lt;span class="nt"&gt;-c&lt;/span&gt; make run

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;EXEC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all run watch clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it looks a bit cleaner:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make
cc -Wall -Wextra -c src/rng/rng.c -o obj/rng/rng.o
cc -Wall -Wextra -c src/vec/vec.c -o obj/vec/vec.o
cc -Wall -Wextra    src/main.c obj/rng/rng.o obj/vec/vec.o   -o main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the great thing is: There is no trace of the word &lt;code&gt;rng&lt;/code&gt; or &lt;code&gt;vec&lt;/code&gt; anywhere in the Makefile, it's fully dynamic. So if we add more libraries later, they will be picked up and compiled automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 7 - Header dependencies
&lt;/h2&gt;

&lt;p&gt;There is one flaw in our current Makefile: When you edit a header (&lt;code&gt;.h&lt;/code&gt;) file, &lt;code&gt;make&lt;/code&gt; doesn't know it has to recompile that particular library.&lt;/p&gt;

&lt;p&gt;A simple way to test this is just updating the modification timestamp of one of the &lt;code&gt;.h&lt;/code&gt; files with &lt;code&gt;touch&lt;/code&gt; and running &lt;code&gt;make&lt;/code&gt; again:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make
cc -Wall -Wextra -c src/rng/rng.c -o obj/rng/rng.o
cc -Wall -Wextra -c src/vec/vec.c -o obj/vec/vec.o
cc -Wall -Wextra    src/main.c obj/rng/rng.o obj/vec/vec.o   -o main
% touch src/rng/rng.h
% make
make: Nothing to be done for `all'.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It says "Nothing to be done", but we could have completely changed the header file.&lt;/p&gt;

&lt;p&gt;This is actually to be expected. We're not mentioning &lt;code&gt;.h&lt;/code&gt; files in the Makefile. All we do is say that the final executable depends on its corresponding &lt;code&gt;.c&lt;/code&gt; file, and all &lt;code&gt;.o&lt;/code&gt; files. Every &lt;code&gt;.o&lt;/code&gt; file only depends on its corresponding &lt;code&gt;.c&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Fortunately, compilers and &lt;code&gt;make&lt;/code&gt; can work together to fix this.&lt;/p&gt;

&lt;p&gt;When you compile, say, &lt;code&gt;main.c&lt;/code&gt; to &lt;code&gt;main.o&lt;/code&gt;, you can pass the &lt;code&gt;-MMD&lt;/code&gt; flag to let the compiler spit out not just the object file &lt;code&gt;main.o&lt;/code&gt; but also a dependency file &lt;code&gt;main.d&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% cc src/main.c -MMD -c
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It spits out two files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── Makefile
├── main.d
├── main.o
└── src
    ├── main.c
    ├── rng
    │&amp;nbsp;&amp;nbsp; ├── rng.c
    │&amp;nbsp;&amp;nbsp; └── rng.h
    └── vec
        ├── vec.c
        └── vec.h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that &lt;code&gt;main.d&lt;/code&gt; file is nothing complicated at all, it's just plain text:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;main.d&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;main.o&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;src/main.c src/rng/rng.h src/vec/vec.h&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks like a &lt;code&gt;make&lt;/code&gt; rule. And it specifies that &lt;code&gt;main.o&lt;/code&gt; depends on &lt;code&gt;src/main.c&lt;/code&gt; but also the two header files &lt;code&gt;src/rng/rng.h&lt;/code&gt; and &lt;code&gt;src/vec/vec.h&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The way the compiler "knows" this is by looking at the &lt;code&gt;main.c&lt;/code&gt; file, which specifies things like &lt;code&gt;#!c #include "rng/rng.h"&lt;/code&gt; and &lt;code&gt;#!c #include "vec/vec.h"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;-MMD&lt;/code&gt; flag actually has a few variations. Plain &lt;code&gt;-M&lt;/code&gt; prints the dependency list to stdout and doesn't compile anything. &lt;code&gt;-MD&lt;/code&gt; writes it to a &lt;code&gt;.d&lt;/code&gt; file &lt;em&gt;and&lt;/em&gt; compiles as usual. And &lt;code&gt;-MMD&lt;/code&gt; does the same as &lt;code&gt;-MD&lt;/code&gt;, but leaves out system headers. So that's the one we want, system headers are irrelevant in this case since we just want to know which files to recompile after we change one of our own header files.&lt;/p&gt;

&lt;p&gt;So now we want take those &lt;code&gt;.d&lt;/code&gt; files, and treat them like rules in our Makefile. And guess what, we can &lt;em&gt;include&lt;/em&gt; other files in our Makefile using the (you guessed it) &lt;code&gt;include&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I'd also like to make the final executable files a bit more flexible, allowing multiple final executables. And I want to store them in a subdirectory called &lt;code&gt;bin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So this is the first thing I want to add:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; main
&lt;span class="nv"&gt;BIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; bin
&lt;span class="nv"&gt;OBJ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; obj
&lt;span class="nv"&gt;SRC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; src

&lt;span class="nv"&gt;EXEC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;BIN&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="p"&gt;$(&lt;/span&gt;NAME&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of specifying the &lt;code&gt;#!makefile EXEC&lt;/code&gt; directly, we derive it from &lt;code&gt;#!makefile $(BIN)&lt;/code&gt; and &lt;code&gt;#!makefile $(NAME)&lt;/code&gt;. The &lt;code&gt;main&lt;/code&gt; executable will now be located at &lt;code&gt;bin/main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Instead of only keeping track of the library &lt;code&gt;.c&lt;/code&gt; files, I want to keep track of the entrypoint &lt;code&gt;.c&lt;/code&gt; files as well in a variable:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;BIN_SRCS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;LIB_SRCS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now distinguish between the entrypoint source files with &lt;code&gt;#!makefile $(BIN_SRCS)&lt;/code&gt;, and library source files with &lt;code&gt;#!makefile $(LIB_SRCS)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we have to modify the &lt;code&gt;patsubst&lt;/code&gt; line, and we'll add another one:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;BINS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;patsubst &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/%.c,&lt;span class="p"&gt;$(&lt;/span&gt;BIN&lt;span class="p"&gt;)&lt;/span&gt;/%,&lt;span class="p"&gt;$(&lt;/span&gt;BIN_SRCS&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nv"&gt;OBJS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;patsubst &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/%.c,&lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;/%.o,&lt;span class="p"&gt;$(&lt;/span&gt;LIB_SRCS&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's happening here with &lt;code&gt;BINS&lt;/code&gt; is pretty much: Take all &lt;code&gt;BIN_SRCS&lt;/code&gt; (only &lt;code&gt;src/main.c&lt;/code&gt;) and substitute pattern &lt;code&gt;src/%.c&lt;/code&gt; to &lt;code&gt;bin/%&lt;/code&gt;. So &lt;code&gt;src/main.c&lt;/code&gt; becomes &lt;code&gt;bin/main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Similar for &lt;code&gt;OBJS&lt;/code&gt;: Take all &lt;code&gt;LIB_SRCS&lt;/code&gt; (for example &lt;code&gt;src/vec/vec.c&lt;/code&gt;) and substitute pattern &lt;code&gt;src/%.c&lt;/code&gt; to &lt;code&gt;obj/%.o&lt;/code&gt;. So now the &lt;code&gt;%&lt;/code&gt; spans multiple directory levels. So &lt;code&gt;src/vec/vec.c&lt;/code&gt; becomes &lt;code&gt;obj/vec/vec.o&lt;/code&gt; because &lt;code&gt;%&lt;/code&gt; matches &lt;code&gt;vec/vec&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With these variables we can create some &lt;code&gt;make&lt;/code&gt; rules.&lt;/p&gt;

&lt;p&gt;First of all, the &lt;code&gt;all&lt;/code&gt; rule can now mean: Build all &lt;code&gt;BINS&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(BINS)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is currently only one file, &lt;code&gt;src/main.c&lt;/code&gt;, but if we add more &lt;code&gt;.c&lt;/code&gt; files directly under &lt;code&gt;src&lt;/code&gt; they will be considered entrypoints and they will be compiled to binaries.&lt;/p&gt;

&lt;p&gt;Because we're explicitly listing our source files like this, we don't have to specify &lt;code&gt;#!makefile VPATH = $(SRC)&lt;/code&gt; anymore.&lt;/p&gt;

&lt;p&gt;Now we're going to be a bit more explicit about how to link all &lt;code&gt;.o&lt;/code&gt; files into the final binary.&lt;/p&gt;

&lt;p&gt;Previously, we were relying heavily on the implicit rules that &lt;code&gt;make&lt;/code&gt; comes with. But now we've customized things enough such that we have to spell it out:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;$(BINS)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(BIN)/%: $(OBJ)/%.o $(OBJS)&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;@D&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;CC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$^&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is some new exotic syntax we haven't seen before, called a &lt;em&gt;static pattern rule&lt;/em&gt;. We have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;targets&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;target-pattern: prerequisites&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows us to explicitly spell out which exact target files we're gonna make, based on variable &lt;code&gt;#!makefile $(BINS)&lt;/code&gt;. Each target is then matched against the &lt;em&gt;target-pattern&lt;/em&gt; to extract a part of the target name (called the &lt;em&gt;stem&lt;/em&gt;). This stem is substituted into each of the prerequisites that have a pattern (like &lt;code&gt;#!makefile $(OBJ)/%.o&lt;/code&gt;) to get the prerequisite names.&lt;/p&gt;

&lt;p&gt;For example: target &lt;code&gt;bin/main&lt;/code&gt;, matched with &lt;code&gt;bin/%&lt;/code&gt; creates stem &lt;code&gt;main&lt;/code&gt;. Substitute stem &lt;code&gt;main&lt;/code&gt; into pattern &lt;code&gt;obj/%.o&lt;/code&gt; creates prerequisite &lt;code&gt;obj/main.o&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The recipe of this rule should look familiar. Just making sure the target's directory exists, and then linking all the &lt;code&gt;.o&lt;/code&gt; files into the final binary executable.&lt;/p&gt;

&lt;p&gt;Since we now store everything we make in either the &lt;code&gt;bin&lt;/code&gt; or &lt;code&gt;obj&lt;/code&gt; directories, we can update the &lt;code&gt;clean&lt;/code&gt; rule to just remove those directories entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;BIN&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full Makefile now looks like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nv"&gt;NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; main
&lt;span class="nv"&gt;BIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; bin
&lt;span class="nv"&gt;OBJ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; obj
&lt;span class="nv"&gt;SRC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; src

&lt;span class="nv"&gt;EXEC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;BIN&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="p"&gt;$(&lt;/span&gt;NAME&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;BIN_SRCS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;LIB_SRCS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;BINS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;patsubst &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/%.c,&lt;span class="p"&gt;$(&lt;/span&gt;BIN&lt;span class="p"&gt;)&lt;/span&gt;/%,&lt;span class="p"&gt;$(&lt;/span&gt;BIN_SRCS&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nv"&gt;OBJS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;patsubst &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/%.c,&lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;/%.o,&lt;span class="p"&gt;$(&lt;/span&gt;LIB_SRCS&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(BINS)&lt;/span&gt;

&lt;span class="nl"&gt;$(BINS)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(BIN)/%: $(OBJ)/%.o $(OBJS)&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;@D&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;CC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$^&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt;

&lt;span class="nl"&gt;$(OBJ)/%.o&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(SRC)/%.c&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;@D&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;CC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;CFLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;$&amp;lt;&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(EXEC)&lt;/span&gt;
    ./&lt;span class="p"&gt;$(&lt;/span&gt;EXEC&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    find &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f | entr &lt;span class="nt"&gt;-c&lt;/span&gt; make run

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;BIN&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all run watch clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running make works as expected:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make
cc -Wall -Wextra -c src/main.c -o obj/main.o
cc -Wall -Wextra -c src/rng/rng.c -o obj/rng/rng.o
cc -Wall -Wextra -c src/vec/vec.c -o obj/vec/vec.o
cc obj/main.o obj/rng/rng.o obj/vec/vec.o -o bin/main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First we're compiling the three source files to object files. Then we link them together into the final executable. But what about the &lt;code&gt;.d&lt;/code&gt; files?&lt;/p&gt;

&lt;p&gt;We haven't done anything about them, &lt;em&gt;yet&lt;/em&gt;. We just needed this foundation to be able to pattern match all files. Let's add the final pieces.&lt;/p&gt;

&lt;p&gt;We will create a &lt;code&gt;.d&lt;/code&gt; file for every &lt;code&gt;.c&lt;/code&gt; file, so let's make a list of all &lt;code&gt;.c&lt;/code&gt; files called &lt;code&gt;ALL_SRCS&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;ALL_SRCS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;BIN_SRCS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;LIB_SRCS&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's pretty simple, just concatenating the &lt;code&gt;#!makefile $(BIN_SRCS)&lt;/code&gt; with the &lt;code&gt;#!makefile $(LIB_SRCS)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we use those for another &lt;code&gt;patsubst&lt;/code&gt; to get a list of &lt;code&gt;.d&lt;/code&gt; files that we'll store in &lt;code&gt;DEPS&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;DEPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;patsubst &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/%.c,&lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;/%.d,&lt;span class="p"&gt;$(&lt;/span&gt;ALL_SRCS&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The substitution is exactly the same as the one we have for the &lt;code&gt;.o&lt;/code&gt; files, except we change the extension to &lt;code&gt;.d&lt;/code&gt;. This is because the dependency files will be placed next to their corresponding object files under the &lt;code&gt;obj&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;Now we need to tell the compiler to actually create those &lt;code&gt;.d&lt;/code&gt; files. Specifying the list doesn't do anything (it just helps us import them later).&lt;/p&gt;

&lt;p&gt;All we need to do is add the &lt;code&gt;-MMD&lt;/code&gt; flag to our &lt;code&gt;.o&lt;/code&gt; compilation rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;$(OBJ)/%.o&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(SRC)/%.c&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;@D&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;CC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;CFLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-MMD&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;$&amp;lt;&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we're creating the &lt;code&gt;.d&lt;/code&gt; files. You can see it by running make and checking the &lt;code&gt;obj&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── Makefile
├── bin
│&amp;nbsp;&amp;nbsp; └── main
├── obj
│&amp;nbsp;&amp;nbsp; ├── main.d
│&amp;nbsp;&amp;nbsp; ├── main.o
│&amp;nbsp;&amp;nbsp; ├── rng
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; ├── rng.d
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; └── rng.o
│&amp;nbsp;&amp;nbsp; └── vec
│&amp;nbsp;&amp;nbsp;     ├── vec.d
│&amp;nbsp;&amp;nbsp;     └── vec.o
└── src
    ├── main.c
    ├── rng
    │&amp;nbsp;&amp;nbsp; ├── rng.c
    │&amp;nbsp;&amp;nbsp; └── rng.h
    └── vec
        ├── vec.c
        └── vec.h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can include them into the Makefile with this syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="k"&gt;-include&lt;/span&gt;&lt;span class="sx"&gt; $(DEPS)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's why we created that &lt;code&gt;#!makefile $(DEPS)&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;We're using &lt;code&gt;-include&lt;/code&gt; here instead of &lt;code&gt;include&lt;/code&gt;. This is so that when one of the &lt;code&gt;.d&lt;/code&gt; files doesn't exist, it's silently ignored. If you use &lt;code&gt;include&lt;/code&gt;, you might encounter something like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make
Makefile:37: obj/main.d: No such file or directory
Makefile:37: obj/rng/rng.d: No such file or directory
Makefile:37: obj/vec/vec.d: No such file or directory
make: *** No rule to make target `obj/vec/vec.d'.  Stop.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now, lo and behold, we can make everything with &lt;code&gt;make&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% make
cc -Wall -Wextra -MMD -c src/main.c -o obj/main.o
cc -Wall -Wextra -MMD -c src/rng/rng.c -o obj/rng/rng.o
cc -Wall -Wextra -MMD -c src/vec/vec.c -o obj/vec/vec.o
cc obj/main.o obj/rng/rng.o obj/vec/vec.o -o bin/main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when we modify one of the header files, &lt;code&gt;make&lt;/code&gt; knows we need to recompile:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;% touch src/rng/rng.h
% make
cc -Wall -Wextra -MMD -c src/main.c -o obj/main.o
cc -Wall -Wextra -MMD -c src/rng/rng.c -o obj/rng/rng.o
cc obj/main.o obj/rng/rng.o obj/vec/vec.o -o bin/main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It recompiled &lt;code&gt;src/main.c&lt;/code&gt; and &lt;code&gt;src/rng/rng.c&lt;/code&gt; because they both include &lt;code&gt;src/rng/rng.h&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;watch&lt;/code&gt; rule also works properly now. It was already running &lt;code&gt;make run&lt;/code&gt; on a change of any file inside the &lt;code&gt;src&lt;/code&gt; directory, so that was already working. But now, when a &lt;code&gt;.h&lt;/code&gt; file is the one that's being edited, it will trigger &lt;code&gt;entr&lt;/code&gt; and properly run a recompile.&lt;/p&gt;

&lt;p&gt;A few final tweaks before we sign off.&lt;/p&gt;

&lt;p&gt;If your build needs linker flags, the convention is to split them across two variables. &lt;code&gt;LDFLAGS&lt;/code&gt; holds linker options like &lt;code&gt;-L/opt/lib&lt;/code&gt; and goes &lt;em&gt;before&lt;/em&gt; the object files. &lt;code&gt;LDLIBS&lt;/code&gt; holds the libraries themselves, like &lt;code&gt;-lm&lt;/code&gt;, and goes &lt;em&gt;after&lt;/em&gt; them, because the linker resolves symbols in the order it sees them. That's the same ordering &lt;code&gt;make&lt;/code&gt; uses in its own implicit link rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;$(BINS)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(BIN)/%: $(OBJ)/%.o $(OBJS)&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;@D&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;CC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;LDFLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$^&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;LDLIBS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can simplify our &lt;code&gt;run&lt;/code&gt; target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(EXEC)&lt;/span&gt;
    &lt;span class="nv"&gt;$&amp;lt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is very optional, but the magic variable &lt;code&gt;$&amp;lt;&lt;/code&gt; refers to the first prerequisite, which is &lt;code&gt;$(EXEC)&lt;/code&gt;, which is &lt;code&gt;bin/main&lt;/code&gt;. So &lt;code&gt;bin/main&lt;/code&gt; is executed as a command, which runs the main executable.&lt;/p&gt;




&lt;p&gt;And that's it. We've finished our Makefile!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt;

&lt;span class="nv"&gt;NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; main
&lt;span class="nv"&gt;BIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; bin
&lt;span class="nv"&gt;OBJ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; obj
&lt;span class="nv"&gt;SRC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; src

&lt;span class="nv"&gt;EXEC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;BIN&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="p"&gt;$(&lt;/span&gt;NAME&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;BIN_SRCS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;LIB_SRCS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;ALL_SRCS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;BIN_SRCS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;LIB_SRCS&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;BINS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;patsubst &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/%.c,&lt;span class="p"&gt;$(&lt;/span&gt;BIN&lt;span class="p"&gt;)&lt;/span&gt;/%,&lt;span class="p"&gt;$(&lt;/span&gt;BIN_SRCS&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nv"&gt;OBJS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;patsubst &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/%.c,&lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;/%.o,&lt;span class="p"&gt;$(&lt;/span&gt;LIB_SRCS&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nv"&gt;DEPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;patsubst &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt;/%.c,&lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;/%.d,&lt;span class="p"&gt;$(&lt;/span&gt;ALL_SRCS&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(BINS)&lt;/span&gt;

&lt;span class="nl"&gt;$(BINS)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(BIN)/%: $(OBJ)/%.o $(OBJS)&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;@D&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;CC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;LDFLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$^&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;LDLIBS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt;

&lt;span class="nl"&gt;$(OBJ)/%.o&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(SRC)/%.c&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;@D&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;CC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;CFLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-MMD&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;$&amp;lt;&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$(EXEC)&lt;/span&gt;
    &lt;span class="nv"&gt;$&amp;lt;&lt;/span&gt;

&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    find &lt;span class="p"&gt;$(&lt;/span&gt;SRC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f | entr &lt;span class="nt"&gt;-c&lt;/span&gt; make run

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;$(&lt;/span&gt;RM&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;BIN&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;OBJ&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;-include&lt;/span&gt;&lt;span class="sx"&gt; $(DEPS)&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all run watch clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically compile everything with &lt;code&gt;make&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Compile and run with &lt;code&gt;make run&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Recompile and run on edits with &lt;code&gt;make watch&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Clean up our mess with &lt;code&gt;make clean&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the Makefile automatically detects our source files.&lt;/p&gt;

&lt;p&gt;Thanks for reading. I hope this gives you the courage to go out into your codebase, whip up a new Makefile from scratch, and automate some of those repetitive commands.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://vanderoost.com/articles/2026/08/05/levels-of-effective-makefile-cheatsheet/" rel="noopener noreferrer"&gt;vanderoost.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/vanderoost/c-makefile-template" rel="noopener noreferrer"&gt;C Makefile template on Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>automation</category>
      <category>cli</category>
      <category>devops</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
