|
@@ -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. :(
|