android导入本地图书

I’m obsessed with nice APIs. Not just APIs however, also in making the overall experience of using a library as good as possible. For Python there are quite a few best practices around by now but it feels like there is not really a lot of information available about how to properly structure a native library. What do I mean by native library? Essentially a dylib/DLL/so.

我迷上了不错的API。 但是,不仅要使用API​​,还应尽可能提高使用库的整体体验。 对于Python来说,目前有很多最佳实践,但是似乎没有足够的有关如何正确构建本机库的信息。 我的原生库是什么意思? 本质上是dylib / DLL / so。

Since I’m currently spending more time on C and C++ than Python at work I figured I might take the opportunity and collect my thoughts on how to write proper shared libraries that do not annoy your users.

由于我目前在C和C ++上花费的时间比在工作上花费的时间多,所以我想我可以借此机会并收集有关如何编写适当的共享库的想法,这些共享库不会惹恼用户。

共享还是静态? (Shared or Static?)

This post almost entirely assumes that you are building a DLL or shared library and not something you link statically. While it sounds like a statically and dynamically linked library are essentially the same thing where the only difference is how you link against it, there is much more to it.

这篇文章几乎完全假设您正在构建DLL或共享库,而不是静态链接的东西。 听起来静态和动态链接的库本质上是相同的东西,唯一的区别是链接的方式不同,但还有更多。

With a dynamically linked library you have much better control over your symbols. Dynamically linked libraries also work much better between different programming languages. Nothing stops you from writing a library in C++ and then using it in Python. In fact, that’s exactly how I recommend doing unittests against such libraries. More about that later.

使用动态链接库,您可以更好地控制符号。 动态链接库在不同的编程语言之间也可以更好地工作。 没有什么可以阻止您使用C ++编写库,然后在Python中使用它。 实际上,这正是我建议对此类库进行单元测试的方式。 以后再说。

哪种语言? (Which Language?)

So you want to write a library that compiles into a DLL or something of that sort and it should be somewhat platform independent. Which languages can you actually use there? Right now you can pick between C and C++ and soon you might also be able to add Rust to that list. Why not others? C is easy: because that’s the only language that actually defines a somewhat stable ABI. Strictly speaking it’s not the language that defines it, it’s the operating system, but in one way or another, C is the language of choice for libraries and the C calling conventions is the lingua franca of shared libraries.

因此,您想编写一个可编译为DLL或类似文件的库,并且该库应在某种程度上与平台无关。 您在那里实际上可以使用哪些语言? 现在,您可以在C和C ++之间进行选择,并且很快您也可以将Rust添加到该列表中。 为什么不别人呢? C很容易:因为这是唯一定义某种程度上稳定的ABI的语言。 严格说来,它不是定义它的语言,它是操作系统,但是从某种程度上来说,C是库选择的语言,而C调用约定是共享库的通用语言。

“The greatest trick that C ever pulled was convince the world that it does not have a runtime”. I’m not sure where I heard the quote first, but it’s incredibly appropriate when talking about libraries. Essentially C is so commonplace that everything can assume that some basic functionality is provided by the C standard library. That’s the one thing that everybody agreed on that exists. For C++ the situation is more complicated. C++ needs a bunch of extra functionality that is not provided by the C standard library. Primarily it needs support for exception handling. C++ however degrades otherwise nicely to C calling conventions so it’s very easy to still write libraries in it, that completely hide the fact that there is C++ behind the scenes.

“ C曾经拉过的最大诀窍就是让世界相信它没有运行时”。 我不确定首先在哪里听到报价,但这在谈论库时非常合适。 本质上,C非常普遍,以至于所有东西都可以假定C标准库提供了一些基本功能。 那是所有人都同意存在的一件事。 对于C ++,情况更加复杂。 C ++需要一堆C标准库未提供的额外功能。 首先,它需要支持异常处理。 但是,C ++可以很好地降级为C调用约定,因此仍然很容易在其中编写库,这完全掩盖了C ++在幕后的事实。

For other languages that’s not so easy however. Why for instance is it not a good idea to write a library in Go? The reason for this is that Go for needs quite a heavy runtime that does garbage collection and provides a scheduler for it’s coroutines. Rust is getting closer to not having any runtime requirements besides the C standard library which will make it possible to write libraries in it.

对于其他语言,这并不是那么容易。 例如,为什么在Go中编写一个库不是一个好主意? 原因是Go for需要大量的运行时来执行垃圾回收并为其协同程序提供调度程序。 除了C标准库之外,Rust几乎没有任何运行时要求,这使得可以在其中编写库。

Right now however, C++ is most likely the language you want to use. Why not C? The reason for this is that Microsoft’s C compiler is notoriously bad at receiving language updates and you would otherwise be stuck with C89. Obviously you could just use a different compiler on Windows but that causes a whole bunch of problems for the users of your library if they want to compile it themselves. Requiring a tool chain that is not native to the operating system is an easy way to alienate your developer audience.

但是,现在,C ++很可能是您要使用的语言。 为什么不C? 原因是众所周知,Microsoft的C编译器在接收语言更新方面很差,否则您将被C89所困扰。 显然,您可以在Windows上使用其他编译器,但是如果库用户希望自己编译它,则会给您带来很多问题。 要求不是操作系统本身的工具链是疏远开发人员受众的一种简便方法。

I would however generally recommend to a very C like subset of C++: don’t use exceptions, don’t use RTTI, don’t build crazy constructors. The rest of the post assumes that C++ is indeed the language of choice.

但是,我通常会向非常像C的C ++子集推荐:不要使用异常,不要使用RTTI,不要构建疯狂的构造函数。 文章的其余部分假定C ++确实是首选语言。

公共标题 (Public Headers)

The library you’re building should ideally have exactly one public header file. Internally go nuts and create as many headers as you want. You want that one public header file to exist, even if you think your library is only ever going to be linked against something that is not C. For instance Python’s CFFI library can parse header files and build bindings out of that. People of all languages know how headers work, they will have a look at them to build their own bindings.

理想情况下,您正在构建的库应该只有一个公共头文件。 内部发疯,并根据需要创建任意数量的标题。 您希望存在一个公共头文件,即使您认为您的库只会与非C的东西链接。例如,Python的CFFI库可以解析头文件并从中建立绑定。 各种语言的人都知道标题是如何工作的,他们将研究标题以建立自己的绑定。

What rules are there to follow in headers?

标头中应遵循哪些规则?

标头护卫 (Header Guards)

Each public header that other people use should have sufficiently unique header guards to make sure they can be included multiple times safely. Don’t get too creative with the guards, but also don’t be too generic with them. It’s no fun including a header that has a super generic include guard at the top (like UTILS_H and nothing else). You also want to make sure that there are extern "C" markers for C++.

他人使用的每个公共标头应具有足够独特的标头防护,以确保可以安全地多次包含它们。 不要对守卫太有创造力,但也不要对他们太宽泛。 包含在顶部具有超级通用包含保护的标头(例如UTILS_H等)没什么好玩的 。 您还想确保C ++有外部“ C”标记。

This would be your minimal header:

这将是您的最小标头:

#ifndef YOURLIB_H_INCLUDED
#ifndef YOURLIB_H_INCLUDED
#define YOURLIB_H_INCLUDED
#define YOURLIB_H_INCLUDED
#ifdef __cplusplus
#ifdef __cplusplus
extern extern "C" "C" {{#endif#endif/* code goes here *//* code goes here */#ifdef __cplusplus
#ifdef __cplusplus
}
}
#endif
#endif
#endif
#endif

出口标记 (Export Markers)

Because you yourself will probably include your header file as well you will need to make sure that there are macros defined that export your functions. This is necessary on Windows and it’s a really good idea on other platforms as well. Essentially it can be used to change the visibility of symbols. I will go into that later, for the time being just add something that looks like this:

因为您自己也可能包含头文件,所以需要确保定义了一些宏来导出您的函数。 在Windows上这是必需的,在其他平台上也是一个好主意。 本质上,它可用于更改符号的可见性。 我将在稍后讨论,暂时添加如下所示的内容:

On Windows it will set YL_API (I used YL as short version for “Your Library” here, pick a prefix that fits you) for DLLs appropriately depending on what flag is set. Whoever includes the header without doing anything fancy before will automatically get __declspec(dllimport) in its place. This is a really good default behavior on Windows. For other platforms nothing is set unless a somewhat recent GCC/clang version is used in which case the default visibility marker is added. As you can see some macros can be defined to change which branch is taken. For instance when you build the library you would tell the compiler to also defined YL_BUILD_SHARED.

在Windows上,它将根据设置的标志适当地为DLL设置YL_API (我在这里将YL用作“ Your Library”的简称,选择适合您的前缀)。 谁在不做任何花哨的情况下包含标头的人都会自动获得__declspec(dllimport)的位置。 这是Windows上非常好的默认行为。 对于其他平台,除非使用了较新的GCC / clang版本,否则不会进行任何设置,在这种情况下,将添加默认可见性标记。 如您所见,可以定义一些宏来更改采用哪个分支。 例如,当您构建库时,您将告诉编译器也定义了YL_BUILD_SHARED

On Windows the default behavior for DLLs has always been: all symbols are not exported default unless marked with __declspec(dllexport). On other platforms unfortunately the behavior has always been to export everything. There are multiple ways to fix that, one is the visibility control of GCC 4. This works okay, but there are some extra things that need to be considered.

在Windows上,DLL的默认行为始终是:默认情况下不会导出所有符号,除非标记为__declspec(dllexport) 。 不幸的是,在其他平台上,行为始终是导出所有内容。 有多种解决方法,一种是GCC 4的可见性控制。这可以正常工作,但是还需要考虑一些其他事项。

The first is that the in-source visibility control is not the silver bullet. For a start the marker will do nothing unless the library is compiled with -fvisibility=hidden. More important than that however is that this will only affect your own library. If you statically link anything against your library, that library might expose symbols you do not want to expose. Imagine for instance you write a library that depends on another library you want to statically link in. This library’s symbols will also be exported from your library unless you prevent that.

首先是源内可见性控件不是灵丹妙药。 首先,除非使用-fvisibility = hidden编译库,否则标记将不执行任何操作。 比这更重要的是,这只会影响您自己的库。 如果您将任何内容静态链接到您的库,则该库可能会公开您不想公开的符号。 例如,假设您编写了一个库,该库依赖于要静态链接的另一个库。该库的符号也将从库中导出,除非您禁止这样做。

This works differently on different platforms. On Linux you can pass --exclude-libs ALL to ld and the linker will remove those symbols automatically. On OS X it’s tricker because there is no such functionality in the linker. The easiest solution is to have a common prefix for all functions. For instance if all your functions start with yl_ it’s easy to tell the linker to hide everything else. You do this by creating a symbols file and then pointing the linker to it with -exported_symbols_list symbols.txt. The contents of this file can be the single line _yl_*. Windows we can ignore as DLLs need explicit export markers.

这在不同平台上的工作方式有所不同。 在Linux上,您可以将--exclude-libs ALL传递给ld ,链接器将自动删除这些符号。 在OS X上,这很麻烦,因为链接器中没有这样的功能。 最简单的解决方案是为所有功能使用通用前缀。 例如,如果您所有的函数都以yl_开头,则很容易告诉链接器隐藏其他所有内容。 为此,您可以创建一个符号文件,然后使用-exported_symbols_list symbol.txt将链接器指向该文件。 该文件的内容可以是_yl_ *单行 。 由于DLL需要明确的导出标记,因此我们可以忽略Windows。

小心包含和定义 (Careful with Includes and Defines)

One thing to be careful about is that your headers should not include too many things. Generally I believe it’s fine for a header to include things like stdint.h to get some common integer types. However what you should not do is being clever and defining types yourself. For instance msgpack had the brilliant idea to define int32_t and a few other types for Visual Studio 2008 because it lacks the stdint.h header. This is problematic as only one library can define those types then. Instead the better solution is to ask the user to provide a replacement stdint.h header for older Visual Studio versions.

要注意的一件事是标题不应该包含太多内容。 通常,我相信标头包含stdint.h之类的东西来获取一些常见的整数类型就可以了。 但是,您不应该做的是聪明并自己定义类型。 例如,msgpack有一个绝妙的主意,因为它缺少stdint.h标头,所以为Visual Studio 2008定义了int32_t和其他一些类型。 这是有问题的,因为那时只有一个库可以定义这些类型。 相反,更好的解决方案是要求用户为旧版本的Visual Studio提供替换的stdint.h标头。

Especially do not ever include windows.h in a library header. That header pulls in so much stuff that Microsoft added extra defines to make it leaner (WINDOWS_LEAN_AND_MEAN, WINDOWS_EXTRA_LEAN and NOMINMAX). If you need windows.h included, have a private header file that’s only included for your .cpp files.

特别是永远不要在库头文件中包含windows.h 。 该标头引入了很多东西,Microsoft添加了额外的定义以使其更精简( WINDOWS_LEAN_AND_MEANWINDOWS_EXTRA_LEANNOMINMAX )。 如果需要包含windows.h ,请使用仅包含.cpp文件的专用头文件。

稳定的ABI (Stable ABI)

Do not put any structs into public headers unless you are 100% sure that you will never change them. If you do want to expose structs and you do want to add extra members later, make sure that the user does not have to allocate that header. If the user does have to allocate that header, add a version or size information as first member into the struct.

除非您100%确保不会更改它们,否则请勿将任何结构放入公共头文件中。 如果确实要公开结构,并且以后确实要添加额外的成员,请确保用户不必分配该标头。 如果用户必须分配该标头,则将版本或大小信息作为第一个成员添加到结构中。

Microsoft generally puts the size of structs into the structs to allow adding members later, but this leads to APIs that are just not fun to use. If you can try to avoid having too many structs in the headers, if you can’t at least try to come up with alternative methods to make the API suck less.

Microsoft通常将结构的大小放入结构中,以允许以后添加成员,但这会导致API使用起来很不好玩。 如果可以避免在标头中包含太多结构,则至少不能尝试提出其他方法来减少API的负担。

With structs you also run into the issue that alignments might differ between different compilers. Unfortunately there are cases where you are dealing with a project that forces the alignment to be different for the whole project and that will obviously also affect the structs in your header file. The fewer structs the better

android导入本地图书_美丽的本地图书馆相关推荐

  1. vscode安装本地服务器_如何用本地的VSCode连接极链AI的GPU服务器

    最近参加比赛可能要用云GPU比较多,但是网页打开notebook太麻烦了,没法像本地编译器一样.于是搞了一下本地VSCode连接极链AI的云主机,可以愉快地本地码代码,云端跑程序.方法如下: l 打开 ...

  2. 拉取远程分支到本地分支_保险公司在本地没有分支机构可以投保吗?异地投保会影响理赔吗?...

    保姐经常看到客户提出类似"我住的地方不在保险的销售区域,是不是不能投保这款保险?"."异地投保会不会被拒赔?"的问题,可见消费者对于"保险的销售区域是 ...

  3. 有了商城源码如何部署到本地服务器_怎么将本地做好的网站部署到服务器上?...

    例如自己自在本地开发好了一个web网站,如何部署到云服务器上,让别人访问?请大神指教 网站如果在本地已经配置好后,需要发布到服务器里的话,具体要怎么做呢! 首先在本地配置的话,只需要配置ip地址就可以 ...

  4. git 怎么备份本地分支_同步管理本地git仓库和github仓库上的分支

    参考文章 分支管理策略 在实际开发中,我们应该按照几个基本原则进行分支管理: 首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活 那在哪里干活呢?干活都在 dev分支上 ...

  5. 哪个读书app可以导入txt_QQ阅读iphone版怎么导入电子书 三种手机QQ阅读器导入本地图书图文教程...

    QQ阅读iphone版是一款比较方便的移动终端阅读软件,除了从电子书城下载或者购买电子书外,我们也可以把自己电脑中的电子书上传到QQ阅读软件中,不过果粉们都知道苹果手机没有文件管理器,无法使用qq阅读 ...

  6. 如何将免费的本地图书导入到掌阅iReader中去

    掌阅iReader是一款功能强大的手机阅读学习软件,个性时尚.界面简约,是小说阅读爱好者的首选阅读软件之一.虽然掌阅iReader书库中的资源非常丰富,但是也有一定的下载局限性,那么如何将本地图书导入 ...

  7. Android 入门第九讲01-音频(本地音乐播放,暂停,继续播放,获取播放时间,快进到指定位置,变速播放,播放data/data/目录下的音频文件,播放网络歌曲)

    Android 入门第九讲01-音频(本地音乐播放,暂停,继续播放,获取播放时间,快进到指定位置,变速播放,播放data/data/目录下的音频文件,播放网络歌曲) 准备 1.储存在raw文件夹 2. ...

  8. 本地图书管理:通过calibre-web打造个人在线书城

    导语 上一期,跟大家介绍了本地音乐管理,今天带来的是本地图书管理--打造个人在线书城. 其实与其说是教程,这篇文章更像是作者打造方案的一个记录.虽然可能硬件环境和作者不同,但配置方面还是有很大的参考价 ...

  9. Android Studio同步远程Git代码到本地

    前一篇文件说如何将本地代码同步到远程Git服务器(将代码同步到远程Git服务器),这篇说说如何在Android Studio中将远程代码同步到本地. 环境说明: 1.本地需要安装有git环境 2.An ...

最新文章

  1. 项目管理协作软件,打造超强执行力团队!
  2. 日记20190416
  3. Spring中BeanPostProcessor
  4. [基础题]2.(*)利用接口做参数,写个计算器,能完成加减乘除运算。
  5. 基于DDDLite的权限管理OpenAuth.net 1.0版正式发布
  6. 使用Jersey跨服务器上传图片 报405 Method Not Allowed错误
  7. java 在底图上绘制线条_使用底图和geonamescache绘制k表示聚类
  8. php字符串和数组基本方法,PHP字符串和数组
  9. Vue v-for生成DOM元素
  10. Win7如何禁用无线网卡
  11. 图像压缩算法动态规划c语言,动态规划算法实现数字图像压缩的研究.pdf
  12. 深入解读Linux进程调度系列(总览)
  13. 使用NOPI做Excepl导入导出
  14. C++后台开发学习路线
  15. 用DrRacket写scheme语言的hello world
  16. win10任务管理器禁用_如何在Windows 10的文件资源管理器中禁用广告和通知
  17. python取省边界_提取行政区边界经纬度坐标(高德+百度)
  18. 《Linux操作系统-系统移植》第12章 5G模组移植-第1节 中移物联5G移植(PPP拨号)
  19. 【转载】发一篇能激励大家拼搏的文章,文中内容属实
  20. [Linux-网络性能测试] -- netperf测试

热门文章

  1. 特殊纸张如何设置打印格式
  2. h5给标签添加自定义属性
  3. 厦门 服务器管理系统,厦门erp电商管理系统排行榜
  4. 个人信息安全事件应急处理和报告
  5. 荣耀linux版笔记本换硬盘,存储不够?小白首次拆机,荣耀MagicBook Pro升级硬盘记...
  6. 用python写生日快乐说说_抖音生日快乐祝福语说说大全 抖音热门生日句子致自己...
  7. 要合理的宣泄自己的压力
  8. 【一本通】1136:密码翻译
  9. 历年奥斯卡获奖影片(1927—2013)
  10. [转]nbsp;有刷、有感和无刷…