3 ms·
Before the usual confusion starts flooding the comment section: STB-style is different from traditional C++ style 'header-only libraries' in that the implement
by flohofwoe 3y ago
Before the usual confusion starts flooding the comment section:
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).
- mort96 3y agoI don't really get the benefit tbh. I always end up with a stb_image.c file which only defines the necessary macro and includes stb_image.h. Wouldn't it be simpler if the project just provided a stb_image.c and an stb_image.h? It would have better compile-time performance, the header would have more readable API docs (which is important since the only API docs are in the headers), and it would be less work to integrate.
- flohofwoe 3y agoYeah, definitely debatable. IME the difference between a single STB-style header and a single .h/.c pair isn't really all that relevant in practice (not enough to waste much time discussing the pros and cons at least - especially the build time consequences are usually overblown, I benchmarked my own header libraries and it comes down to a couple of seconds at most for including the header in thousands of C source files - with the implementation skipped of course). 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).
- brabel 3y ago> The actual problem are libraries with hundreds or thousands of source files in dozens of directories and a CMakeLists.txt file from hell. 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?
- flohofwoe 3y ago> Why is that a problem? If you have a large library, surely it's better to properly break it up into separate files?! 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".
- tomovo 3y ago> If you have a large library, surely it's better to properly break it up into separate files?! 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.
- 3y ago
- lifthrasiir 3y agoIf there are multiple such libraries, I will probably put them into a single `deps.c` and forget. No need for individual `<library>.c`. Yes, upgrading one of dependencies will recompile `deps.c`, but that should be infrequent.