Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
itdan3344
stb
提交
d4f114ad
S
stb
项目概览
itdan3344
/
stb
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
stb
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
d4f114ad
编写于
5月 25, 2014
作者:
S
Sean Barrett
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
advice for how to make your own stb-style library
上级
38c36fa0
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
184 addition
and
0 deletion
+184
-0
stb_howto.txt
stb_howto.txt
+184
-0
未找到文件。
stb_howto.txt
0 → 100644
浏览文件 @
d4f114ad
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. :(
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录