diff --git a/stb_howto.txt b/stb_howto.txt new file mode 100644 index 0000000..231d99a --- /dev/null +++ b/stb_howto.txt @@ -0,0 +1,184 @@ +Lessons learned about how to make a header-file library +V1.0 +September 2013 Sean Barrett + +Things to do in an stb-style header-file library, +and rationales: + + +1. #define LIBRARYNAME_IMPLEMENTATION + +Use a symbol like the above to control creating +the implementation. (I used a far-less-clear name +in my first header-file library; it became +clear that was a mistake once I had multiple +libraries.) + +Include a "header-file" section with header-file +guards and declarations for all the functions, +but don't guard the implementation. That way, +if client's header file X includes your header file for +declarations, they can still include header file X +in the source file that creates the implementation; +if you guard the implementation too, then the first +include (before the #define) creates the declarations, +and the second one (after the #define) does nothing. + + +2. AVOID DEPENDENCIES + +Don't rely on anything other than the C standard libraries. + +(If you're creating a library specifically to leverage/wrap +some other library, then obviously you can rely on that +library. But if that library is public domain, you might +be better off directly embedding the source, to reduce +dependencies for your clients. But of course now you have +to update whenever that library updates.) + +If you use stdlib, consider wrapping all stdlib calls in +macros, and then conditionally define those macros to the +stdlib function, allowing the user to replace them. + +For functions with side effects, like memory allocations, +consider letting the user pass in a context and pass +that in to the macros. (The stdlib versions will ignore +the parameter.) Otherwise, users may have to use global +or thread-local variables to achieve the same effect. + + +3. AVOID MALLOC + +You can't always do this, but when you can, embedded developers +will appreciate it. I almost never bother avoiding, as it's +too much work (and in some cases is pretty infeasible; +see http://nothings.org/gamedev/font_rendering_malloc.txt ). +But it's definitely something one of the things I've gotten +the most pushback on from potential users. + + +4. ALLOW STATIC IMPLEMENTATION + +Have a #define which makes function declarations and +function definitions static. This makes the implementation +private to the source file that creates it. This allows +people to use your library multiple times in their project +without collision. (This is only necessary if your library +has configuration macros or global state, or if your +library has multiple versions that are not backwards +compatible. I've run into both of those cases.) + + +5. MAKE ACCESSIBLE FROM C + +Making your code accessible from C instead of C++ (i.e. +either coding in C, or using extern "C") makes it more +straightforward to be used in C and in other languages, +which often only have support for C bindings, not C++. +(One of the earliest results I found in googling for +stb_image was a Haskell wrapper.) Otherwise, people +have to wrap it in another set of function calls, and +the whole point here is to make it convenient for people +to use, isn't it? (See below.) + +I prefer to code entirely in C, so the source file that +instantiates the implementation can be C itself, for +those crazy people out there who are programming in C. +But it's probably not a big hardship for a C programmer +to create a single C++ source file to instantiate your +library. + + +6. NAMESPACE PRIVATE FUNCTIONS + +Try to avoid having names in your source code that +will cause conflicts with identical names in client +code. You can do this either by namespacing in C++, +or prefixing with your library name in C. + +In C, generally, I use the same prefix for API +functions and private symbols, such as "stbtt_" +for stb_truetype; but private functions (and +static globals) use a second underscore as +in "stbtt__" to further minimize the chance of +additional collisions in the unlikely but not +impossible event that users write wrapper +functions that have names of the form "stbtt_". +(Consider the user that has used "stbtt_foo" +*successfully*, and then upgrades to a new +version of your library which has a new private +function named either "stbtt_foo" or "stbtt__foo".) + +Note that the double-underscore is reserved for +use by the compiler, but (1) there is nothing +reserved for "middleware", i.e. libraries +desiring to avoid conflicts with user symbols +have no other good options, and (2) in practice +no compilers use double-underscore in the middle +rather than the beginning/end. (Unfortunately, +there is at least one videogame-console compiler that +will warn about double-underscores by default.) + + +7. EASY-TO-COMPLY LICENSE + +I make my libraries public domain. You don't have to. +But my goal in releasing stb-style libraries is to +reduce friction for potential users as much as +possible. That means: + + a. easy to build (what this file is mostly about) + b. easy to invoke (which requires good API design) + c. easy to deploy (which is about licensing) + +I choose to place all my libraries in the public +domain, abjuring copyright, rather than license +the libraries. This has some benefits and some +drawbacks. + +Any license which is "viral" to modifications +causes worries for lawyers, even if their programmers +aren't modifying it. + +Any license which requires crediting in documentation +adds friction which can add up. Valve used to have +a page with a list of all of these on their web site, +and it was insane, and obviously nobody ever looked +at it so why would you care whether your credit appeared +there? + +Permissive licenses like zlib and BSD license are +perfectly reasonable, but they are very wordy and +have only two benefits over public domain: legally-mandated +attribution and liability-control. I do not believe these +are worth the excessive verbosity and user-unfriendliness +these licenses induce, especially in the single-file +case where those licenses tend to be at the top of +the file, the first thing you see. (To the specific +points, I have had no trouble receiving attribution +for my libraries; liability in the face of no explicit +disclaimer of liability is an open question.) + +However, public domain has frictions of its own, because +public domain declarations aren't necessary recognized +in the USA and some other locations. For that reason, +I recommend a declaration along these lines: + +// This software is in the public domain. Where that dedication is not +// recognized, you are granted a perpetual, irrevocable license to copy +// and modify this file as you see fit. + +I typically place this declaration at the end of the initial +comment block of the file and just say 'public domain' +at the top. + +I have had people say they couldn't use one of my +libraries because it was only "public domain" and didn't +have the additional fallback clause, who asked if +I could dual-license it under a traditional license. + +My answer: they can create a derivative work by +modifying one character, and then license that however +they like. (Indeed, *adding* the zlib or BSD license +would be such a modification!) Unfortunately, their +lawyers reportedly didn't like that answer. :(