You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
		
		
		
		
		
			
		
			
				
					
					
						
							185 lines
						
					
					
						
							6.9 KiB
						
					
					
				
			
		
		
	
	
							185 lines
						
					
					
						
							6.9 KiB
						
					
					
				| 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 only guard the implementation with LIBRARYNAME_IMPLEMENTATION, | |
| not the header-file guard. 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. :(
 | |
| 
 |