STB: Single-file public domain libraries for C/C++
github.com
github.com
STB-style is different from traditional C++ style 'header-only libraries' in that the implementation is not parsed and compiled each time the header is included, instead the implementation code sits inside a big ifdef/endif block which is only activated at a single include point across the whole project (meaning the implementation is compiled only once in a complete project rebuild, every other include only parses the API declarations at the top of the header and skips the implementation).
This means that STB-style libs don't suffer from the compile time explosion we are seeing for typical header-only C++ libraries (such as the C++ stdlib headers).
You still pay the raw IO cost for skipping the ifdef/endif section of course, but this comes down to a couple of seconds for including the file tens-of-thousands of times (which is rarely the case even in large projects since such libraries tend to be isolated in small areas of the projects, such as a single subsystem).
The actual problem are libraries with hundreds or thousands of source files in dozens of directories and a CMakeLists.txt file from hell.
A good C/C++ library should be easy to drop into a project, trivial to integrate with any build system (or no build system at all), and no need for a package manager. If configuration is necessary it should happen with a small number of defines.
...one arguable advantage of STB-style headers is that you can include all header-library implementations of a project in a single source file, which might actually speed up overall build time because this benefits from the same advantages as unity/jumbo builds (especially in case of C++ code when stdlib headers need to be included). But for C code - where the stdlib headers are just a couple of hundred lines of simple declarations instead of tens-of-thousands of lines of gnarly template code - the difference is also negligible.
PS: another advantage of STB-style headers is that you can build even non-trivial projects into a single source file and compile that with `cc main.c -o mytool`, e.g. no need for a build system at all (of course the same is possible by including .c files into the main.c file, even if that might look a bit icky).
Why is that a problem? If you have a large library, surely it's better to properly break it up into separate files?!
> no need for a package manager.
Well, yeah if you don't want even a build system, large projects in general become really difficult to maintain anyway. The solution seems to be like every programming language created after 1989? Have a package manager and make it irrelevant if the library contains 1 file or 1000. What's the reason C resists so much using a package manager, even when similarly low level languages like Rust and Zig have them and make them first class citizens?
That's at best good for developing the library (even that is debatable though), but definitely not when just using the source-distribution of the library in a project.
> What's the reason C resists so much using a package manager...
One important problem is that there are so many package managers and build systems for C and C++ projects. So the choice for a library author is either to support all package managers and build systems (not really a realistic option), or none specifically (much better but requires that the library source distribution is designed for simple integration into projects without esoteric build requirements).
Requiring a specific package manager and build system is hostile to users preferring other tools.
The problem doesn't lie with C or C++ users, but with the respective language committees saying "dependency management and build system standardization isn't our problem".
Sqlite solves this dilemma by providing both: regular source code repository with separate files for development and an "amalgamation" with everything in a single .c file. The latter makes it really easy to integrate.
> I still use MSVC 6 (1998) as my IDE because it has better human factors for me than later versions of MSVC.
This is really amusing to me. Does anyone know if the author has ever given more detail on why?
Also stb is a really great library to look at for those starting C development.
Of course, you also have a C++ compiler from 1998 that doesn't use correct for loop scoping, barely works with templates, can't understand any C++11 or later constructs, barfs a page of angle-bracket meatloaf diagnostics whenever an error occurs in the STL, has a single-threaded build, and only works with a Windows XP era version of the Windows SDK. I gave it up around Visual Studio 2005 when the IDE became tolerable again.
However not all is lost, for those that are deep into COM, the tooling has hardly changed, it is still mostly ATL as in 1998 (WRL, WIL, C++/WinRT still rely on the same VS 6 tooling).
My attempted summary: it's mostly a matter of the window layout in VC6 giving the most real estate to Just Code, and also the hotkeys for common workflows (e.g. show/hide debug output) are simple.
Commentary: Modern MSVC tends to be more difficult to customize, whereas e.g. Jetbrains IDEs are more straightforward to customize in such a way as stb would be familiar with -- but, both MSVC and Jetbrains suffer from such awful performance (e.g. input latency) that it detracts from their usefulness as IDEs.
“I just want to load an image. Thank you. Moving on…”
For instance here is the start of the implementation block in stb_image.h, above that is just "cheap" public API declarations:
https://github.com/nothings/stb/blob/f4a71b13373436a2866c5d6...
tinyengine is great but not supported for windows yet
And then you realize you need the official lib - libpng, etc.
E.g. it's not so simple.
> Primarily of interest to game developers and other people who can avoid problematic images and only need the trivial interface
The elephant in the room is the missing common build system, so folks engage in what's EASIEST - include just a header and you are done. This is awesome for initial development, gives you wings, but once your software has been deployed over and over - that header only library starts to show it's weakness - because it's header-only there are certain limitations - especially around how to handle singletons, initialization, and few other critical things.... And then compilation.
Some header-only libraries, realize that and simply asks the user to at least do this once somewhere:
#define SOME_HEADER_ONLY_LIB_IMPL 1 #include <some_header_only_lib.h>
and above gets code that needs to be compiled in exactly one compilation unit, and not multiple.
This is actually not so bad, if it was considered more... but it gets hairy when you have library that needs to use that header only library, and now up the tree of deps the top-most program has to do the above, and then it gets super messy.
Again, it's super easy, but not simple (long term). I've seen it happen with code that I work, I've also written tons of header-only libs - they are exciting!