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
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`. #define HTTPSERVER_IMPL
prior to the inclusion, then the header provides the implementation too, otherwise only the interface. Obviously, you must have this HTTPSERVER_IMPL followed by #include "httpserver.h" in only one file in your program.If someone doesn't like it, they can split the file into two: the header proper and the "impl" part in a .c file.
Just look for the part starting with #ifdef HTTPSERVER_IMPL. Take that out through to the closing #ifdef and put it into a httpserver.c file. Then put #include "httserver.h" into the top of that file, and remove all *_IMPL preprocessor cruft from httpserver.c. Now you have a proper single-header, single C file module.
As noted above, it avoids version incompatibility by essentially forcing static linking. But most developers would statically link a small two-file library anyway, so it’s a moot point. C isn’t supposed to have training wheels.
What "module system"? The alternative would be one .c file and one .h file. It's negligible effort to add these to any project that already has more than one .c file.
Long term technical debt
Header only works for some things (particularly things that require no globals, singletons, etc) and that's a valid concern. Saying header-only = long term technical debt always (or even most of the time) feels like an assertion because I've only heard hypotheticals around why it is bad.
Header only is nice and easy, dump file in the project, #include and your job is done.
That technique is used in sqlite. https://www.sqlite.org/amalgamation.html
> 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.
This header-only containing implementations adds its code to every compilation unit and the linker has to be smart enough to deduplicate identical symbols across many compilation units. Linkers (ld command) are provided either by the platform vendor or the compiler vendor, so they may or may not be able to do this. Binutils on Linux is able to do so IIRC.
It's a terrible practice that promotes cowboy coding. It should just use two files, which would cause less problems in the real world.
You can also write C without headers or newlines. IOCCC may welcome it but why would you ship it or encourage people to use it?
That's not how this works. It's actually a pretty clever trick, and it effectively behaves as a .h / .c pair of files. See https://github.com/nothings/stb/blob/master/docs/stb_howto.t...
It's a symptom of the tooling that this is even a thing.
Shudder
Or even plain old tarball with any sort of build script.
And vcpkg, cargo are already good options for those that need cross-os package manager.
says who? care to elaborate?
It is soon 2020, there is no reasons to use C in new code. Because of security and also convenience.
Maybe it is a nice mental exercise (also try brainfuck and malbolge), but not something for production.
It also defines some buffer size names that are likely also declared in other libraries, like `BUF_SIZE`, and will need to be `#undef`ed.
No chunked support. Well, if ever I use this (and... I do have a pressing use for something like this), that will be a PR I'll send in, probably using async.h[0] to allow handlers to be asynchronous.
Also, it's no fair to compare this server's performance to nginx if this server has no TLS support: you'll have to setup a reverse proxy, and then what will that be?
The lack of URI parsing is not a big deal for me, but it'd be nice.
I like the idea. Keep it up. The "some things" that are missing are really the basics of any HTTP server. Now it's more like something you could build a minimal REST API on. (With the need of a "real" server as proxy)
I've gone as far as compiling Go from my Android phone.
Edit here's someone else running Termux with Go:
http://rafalgolarz.com/blog/2017/01/15/running_golang_on_and...
I would also love if someone wanted to contribute fuzz testing or other static analysis to the project. PRs are welcome.
I thought it was poor form to have a lot of code in headers. This seems like it'd be better served as a small C http library.
It would be better if it was namespace'd in some way, at least by using a common unusual prefix for all of the non-local symbols. It wouldn't be hard to clash with the chosen names.
It is mostly because it makes it harder to reuse compiled objects when you make a change and rebuild. For a drop-in library that you're probably not editing, this shouldn't be an issue.
Also I find no handling of slow connections.
This is definitely a toy.
. C (could have been C++... embedded MCU platform)
. compiles cleanly out of the box
. demo is simple, works out of the box, simple to verify
I contrast this with my experience a few days ago with the "Space Invaders in C" post (too lazy to reference it or find the exact title). I do development on my Mac all the time (command-line, C++, clang/gcc). Tried building Space Invaders. One problem after the next. Gave up after about 20-25 minutes.
Cliché as it is, the importance of the "out of box" experience is so important. Especially for a commercial product, which I realize this isn't.
I then went back to using plain C for awhile, and after the complexity of C++, C was so much fun to use.
Anyway, I enjoyed reading through this C header file, and it took me back. But, I am sticking with Lisp because for me it is such a higher productivity language.
Pointer arithmetic and pointers to ephemeral objects is what sucks.
You can get a 3-for-1 with this kind of library by having a libuv implementation.
Honestly I dislike them because they're a redundant pain in the ass. I tried other solutions before (at one job I had 15 years ago we had automatic header code generation, ooof), and although modules are not that ready for primetime [3] (dependency resolution need to be done by an external program), I think they'll be the bees knees.
[1] https://en.wikipedia.org/wiki/Include_guard
[2] (some people will be quick to note that can be solved by pragmas)
[3] https://vector-of-bool.github.io/2019/01/27/modules-doa.html (but he wrote a follow up: https://vector-of-bool.github.io/2019/03/04/modules-doa-2.ht... )
Trying to get multiple C packages from third parties all working together is rough compared to other languages. Rust has me a little spoiled, I guess.
Meanwhile, in C/C++ world, build systems are a mess. You have so many tools. Some folks just use what IDE provides, e.g. MSVC solutions. Some people use CMake. Some people have their handcrafted Makefile solutions. Sure, it works on their platforms, but it's very hard to make it portable. With Cargo and similar, you just go "cargo get" (don't know the exact command, don't use Rust) and you can expect the packages to download and build as needed.
Header files work. They've worked for many decades. Yes, they require software authors to _do more work_, but they also help to eliminate a lib/ directory with 10,000 interdependent libraries that quickly becomes untrusted and frankly, ridiculous.
I don't care for the deep dependency chains of npm, but integrating C libraries which use a mix of different build systems, and making sure your complete project cross-compiles cleanly with different toolchains for different arches is just irritating and time consuming. I don't think the situation is ideal.
Arguably, you can attest some of those issues to JavaScript’s immense popularity but if even Python can manage it, others can too.