A good example of that IMO is cJSON[1], it's a small self-contained single file implementation of a JSON reader and parser. It's easy to use, the code is pretty clean and easy to follow and I never ran into any obvious limitation. I very much recommend it.
There are also projects that are developed as multiple files but amalgamated into a single huge file before release. SQLite does that: https://sqlite.org/amalgamation.html
> Over 100 separate source files are concatenated into a single large files of C-code named "sqlite3.c" and called "the amalgamation". The amalgamation contains everything an application needs to embed SQLite. The amalgamation file is more than 220,000 lines long and over 7.5 megabytes in size (as of 2018-11-24).
> Combining all the code for SQLite into one big file makes SQLite easier to deploy — there is just one file to keep track of. And because all code is in a single translation unit, compilers can do better inter-procedure optimization resulting in machine code that is between 5% and 10% faster.
You can use includes to have "a single file to add to the project", and still split your code in smaller, readable files.
See https://github.com/jedisct1/libhydrogen for example. It's a single-file crypto library from an application perspective, but everything was not stored into a single, hard-to-navigate file.
#include "mycrypto.1.1.h"
Doesn't that have the same effect of being easy to include? The amalgamation may be better for the compiler but I'm not sure why.
But within a single object the compiler doesn't need to obey the ABI rule at all if that's faster.
Now, you obviously could imagine an object and more powerful linkers that had enough optimisation magic to produce the same output executable from the sixty object files, but just spitting out a single source code file is a LOT easier than making that optimisation work on every platform now and in the future.
The invocation above creates one object file for each C source file, as temporary files, (in a Unix system you can watch it do this with a suitably powerful syscall tracer, presumably something similar is possible on non-Unix systems but I don't know exactly how)
Then it links them and produces the output you've mistaken for an "object file", then it deletes the temporary files.
does this hold even when non-amalgated code uses `-flto` or equivalent flag?
Until one of the C/C++ package managers gets good and wins, this is the nicest alternative.
Note that people don't necessarily develop the libraries in one big file or don't have dependencies. Many newer libraries use a single C file as a distribution format.
The other nice thing about it is that if the code is small it can be more easily debugged and audited by humans. If it pulls in hundreds of thousands of lines of code, that can be a problem. Also, small code is a requirement on some projects because of speed or memory limitations.
The size of the code is independent of the number of files the code is in.
Eventually there will be a security vulnerability found and every app will be on some random version making it exploitable.
I think it's also people giving up on build systems and package managers.