8 ms·
"header only" is C-speak for "up and running in 15 seconds" more or less. One major concern with integrating a new dependency in C land is how much of a pain in
by slovenlyrobot 7y ago
"header only" is C-speak for "up and running in 15 seconds" more or less. One major concern with integrating a new dependency in C land is how much of a pain in the ass it makes your build, especially considering a large chunk of C projects do not target typical desktop environments. After the first time you lost a day trying to get some batshit custom build tool to emit the correct link flags for your exotic ARM board, "header only" carries a lot of weight.
On the intermixing of source and header files, it doesn't quite work the way you mentioned. It's not possible to just cut-paste any old public object definition into a header file without at least applying 'static' to it, and that only works where the object truly is private to each translation unit. It's not so easy e.g. to instantiate a global variable shared across the whole program this way, so 'header only' also implies 'almost certainly free of globals', which is a good sign of hygiene
edit: yikes, in this case, the implication is totally invalid
- megous 7y agoWell, you can do: int a; int a; static int b; static int b; And it's a valid way to define a single global/static symbol called `a`/`b`.
- arcticbull 7y agoThey have different semantics. The static one can only be referenced in the current translation unit, whereas the non-static one is a global which can be referenced from any translation unit. The problem is that in the header-only case defining "int a" means you can only import the header from a single source file. With "static int a" the visibility is wrong. And if you did "extern int a" linking would fail because the symbol is never assigned to a translation unit.
- tomjakubowski 7y agoHeader-only libraries sometimes require you to define those externs in exactly one "impl" file, which you compile and link to your artifact. Something like this: // libfoo_impl.c // or in some other translation unit, such as main.c #define LIBFOO_IMPL #include "vendor/libfoo.h" // main.c #include "vendor/libfoo.h" int main() { foo_inc(); printf("%d\n", foo_count); return 0; } // vendor/libfoo.h #pragma once extern int foo_count; void foo_inc() { foo_count += 1; } #ifdef LIBFOO_IMPL int foo_count = 0; #endif main.c and libfoo_impl.c both include libfoo.h, which declares foo_count with the right linkage, but the variable is only defined once, in whichever translation unit defines LIBFOO_IMPL. Occasionally you'll find a header library which supports this _IMPL paradigm as an option to avoid inlining its functions in every translation unit that calls them.
- megous 7y agoYou're misunderstanding. I'm saying you can have multiple identical `int a;` across multiple translation units and it will point by default to a single global variable across the program. So you can include a single header from multiple places, and you just get a single shared global variable, if the header contains `int a`.
- noobermin 7y agoHijacking your comment to ask my question below. Apart from the possibility you can't do header-only for everything (like something that requires a singleton for example) and the other known issues (build times, ballooning of object files and thus executables) is the only other reason you don't see as many header-only libraries in C (like you do in C++ where they are ubiquitous) is that people merely don't do it in C? That is, a social landscape reason, not a technical reason.
- fulafel 7y agoYes, the social reasons are the only ones, besides the technical reasons :) An additional technical downside in this case is the code complexity in the client code, from the required modal preprocessor flags.
- Fronzie 7y agoIt's partly a historical reason as well. There are many projects with very complex Makefiles. Those are hard to integrate into your own project. Header-only is the other extreme: No makefile at all. With package managers like Conan and vcpkg, using a build-system like e.g. CMake, it's possible to have very simple and short project files which are easy to integrate. In this regard, C and C++ are a bit behind the times compared to other languages.
- tonyedgecombe 7y agoIsn't C++ supposed to be getting proper namespaces soon?
- throwaway8941 7y agoI am not an expert in C++, but there exists an opinion that it will not help as much as you might think. https://cor3ntin.github.io/posts/modules/ https://cor3ntin.github.io/posts/modules/
- nestorD 7y agoThe fact that you cannot define templates out of headers also explains why C++ has a lot of header-only libraries. : if you use templates and have no global references, you are most likely already header-only.
- pjmlp 7y ago"header only" is more like "I don't want to learn"-speak in regards to deal with native language toolchains.
- bluGill 7y agoThe native toolchain on my embedded board is a mess. You don't want to learn to deal with it if you don't have to. This comment applies to every embedded toolchain I've ever worked with. Even doing embedded linux with yocto is a mess of a toolchain and it is the best attempt I've ever seen at creating a good embedded toolchain. The problem is just messy.
- pjmlp 7y agoUsually that boils down to "we don't want to bother with the vendors IDE", e.g. MPLAB. I know C and C++ since 1992, used them across multiple OSes, hardly seen anything that would motivate the fashion of header only files.
- slovenlyrobot 7y agoYou've never in 28 years lost a single day to a compiler/linker flags/version mismatch and some random tool? I find that difficult to imagine. The horrifying alternative would be that such situations had been encountered but considered justifiable productive work
- pjmlp 7y agoNo, because I either used what was provided by the OS vendor, or library providers that were selling libraries for the deployment we wanted to do.