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.
This is also the approach used by this library, see:
https://github.com/jeremycw/httpserver.h#example
This approach also doesn't have the 'build time problems', since the (expensive to compile) implementation code is only seen once by the compiler (unlike many C++ header-only libs, which rely on inline code)
An additional technical downside in this case is the code complexity in the client code, from the required modal preprocessor flags.
I know C and C++ since 1992, used them across multiple OSes, hardly seen anything that would motivate the fashion of header only files.
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`.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.
// 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.
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