Vendoring in C

3 Dec 2025

Vendoring in C

Vendoring means outsourcing writing part of your code to a 3rd party and including it in your project. When you run pip install matplotlib and write import matplotlib.pyplot as plt in your source file, you’re vendoring NumPy. Many modern programming languages incorporate a package manager to make this process more painless for you: pip for Python, Pkg for Julia, Cargo for Rust, etc.

In C, there is no common package manager that is tied to the language. This inherently represents a moderate barrier to entry for including other codebases in your work. In my opinion, just like everything in C, this is both a blessing and a curse. Some friction here is good: it forces you to choose what vendored libraries you use somewhat more carefully, as you have to work a bit harder to include them. It also encourages you to write a simple implementation of your own rather than add another large dependency to your project just for a single function (this, too, is a double-edged sword).

However, the lack of a package manager can be a real impediment to just getting things done. For example, writing your own gui library is just way, way outside the scope of most projects that simply just want to be a gui. This post is some of my notes on some basic practices with including external libraries in a C project. For this reason, I’m going to use a gui library as a demonstration: raygui.

raygui

raygui is a basic immediate-mode, cross-platform gui library built on top of raylib, which is a cross-platform gamedev library. I’m learning how to use it for my own projects, with the eventual goal of writing a thin shell library that sits on top of raygui, and allows the user to setup user interfaces for scientific software applications, including 2D plots of data.

raygui is a nice alternative to other, more comprehensive, gui libraries like Qt because it’s lightweight and easy to setup. You simply compile raylib and include two header files, raylib.h and raygui.h, in your project and you’re off to the races.

Environment and Setup

Generally, I’m working on either Linux or macOS. At the moment, I don’t have access to a Windows desktop environment, so I’m going to defer writing instructions for working on Windows.

I usually setup my C projects like this:

project/ 
    docs/           # I like manually written .md docs
    include/        # I keep both public and internal headers here
        internal/
        project.h
    src/            # All implementation code (.c files)
    tests/          # All tests
    vendor/         # Focus of this post
    Makefile        # Builds the entire project
    README.md       

Most of my projects are fairly small (we’re not talking about 100K’s of code), so I usually prefer to write manually written markdown documentation and keep that included in the codebase. I also keep public and internal headers in the same include/ directory because it feels cleaner to me; some might argue that only public headers should go there.

The focus of this posts is the vendor/ folder. This is where I keep external libraries; in this case, this is where raygui is going to go. In Python-land, this is the site-packages folder.

Getting raygui Setup