如何设计一个C / C ++库可以在许多客户端语言中使用? [英] How to design a C / C++ library to be usable in many client languages?

查看:248
本文介绍了如何设计一个C / C ++库可以在许多客户端语言中使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在计划编写一个应用于广泛平台上的大量人员可以使用的图书馆。我必须考虑如何设计它是正确的?为了使这个问题更加具体,最终有四个提问。

I'm planning to code a library that should be usable by a large number of people in on a wide spectrum of platforms. What do I have to consider to design it right? To make this questions more specific, there are four "subquestions" at the end.

考虑到所有已知的要求和细节,我得出结论,用C或C ++编写的图书是要走的路。我认为我的图书馆的主要用途将是用 C,C ++和Java SE 编写的程序,但是我也可以想到使用Java ME,PHP,.NET,目标C,Python,Ruby,bash scrips等... 也许我无法定位所有这些,但如果可能,我会这样做。

Considering all the known requirements and details, I concluded that a library written in C or C++ was the way to go. I think the primary usage of my library will be in programs written in C, C++ and Java SE, but I can also think of reasons to use it from Java ME, PHP, .NET, Objective C, Python, Ruby, bash scrips, etc... Maybe I cannot target all of them, but if it's possible, I'll do it.

在这里描述我的图书馆的完整目的非常多,但有一些方面可能对这个问题很重要:

It would be to much to describe the full purpose of my library here, but there are some aspects that might be important to this question:


  • 图书馆本身将开始小,但肯定会增加到巨大的复杂性,所以不是并行维护多个版本的选择。 >
  • 尽管

  • 该库将构建一个内部严格使用的对象图形,大部分复杂性将被隐藏在库中。

  • 客户端可能会更改对象,并且库必须被通知,这些库的某些客户端将只对特定对象的特定属性感兴趣,而其他客户端必须以某种方式遍历对象图。

  • 图书馆可能会更改对象,如果客户端已经具有该对象的句柄,则必须通知客户。

  • 库必须是多线程的,因为它将保持与其他几个主机的网络连接

  • 虽然可能会同步处理对库的一些请求,但是其中许多请求将花费太长时间,并且必须在背景,并通知客户成功(或失败)

  • The library itself will start out small, but definitely will grow to enormous complexity, so it is not an option to maintain several versions in parallel.
  • Most of the complexity will be hidden inside the library, though
  • The library will construct an object graph that is used heavily inside. Some clients of the library will only be interested in specific attributes of specific objects, while other clients must traverse the object graph in some way
  • Clients may change the objects, and the library must be notified thereof
  • The library may change the objects, and the client must be notified thereof, if it already has a handle to that object
  • The library must be multi-threaded, because it will maintain network connections to several other hosts
  • While some requests to the library may be handled synchronously, many of them will take too long and must be processed in the background, and notify the client on success (or failure)

当然,欢迎答复,无论他们是否解决我的具体要求,或者他们以更广泛的受众重要的一般方式回答问题!

所以这里有一些我的假设和c在过去的几个月里我收集到的内容:

So here are some of my assumptions and conclusions, which I gathered in the past months:


  • 在内部我可以使用任何我想要的,例如C ++与运算符重载,多继承,模板元编程...只要有一个便携式编译器来处理它(想到gcc / g ++)

  • 但是我的界面必须是干净的C接口,不涉及名称调整

  • 另外,我认为我的接口应该只包括功能,基本/原始数据类型(也可能是指针)作为参数传递返回值

  • 如果我使用指针,我认为我只应该使用它们将它们传递回库,而不是直接在引用的内存上操作

  • 在C ++应用程序中使用,我也可能会提供一个面向对象的界面(其中也容易出现名称变动,所以应用程序必须使用相同的编译器,或者以源代码形式包含库)

  • 对于C#中的使用,这也是正确的。

  • 对于Java SE / Java EE中的使用,Java本机接口(JNI)适用。我有一些基本的知识,但我一定要仔细检查一下。

  • 并不是所有的客户端语言都很好地处理多线程,所以应该有一个线程与客户端交谈

  • 对于在Java ME中的使用,没有JNI这样的东西,但是我可以使用嵌套虚拟机

  • 对于Bash脚本中的使用,必须有一个带有命令行界面的可执行文件

  • 对于其他客户端语言,不了解

  • 对于大多数客户端语言,使用该语言编写的适配器接口很好。我认为有一些工具可以为Java和其他一些软件自动生成。

  • 对于面向对象的语言,可能会创建一个面向对象的适配器,它隐藏了库的接口是基于功能的 - 但我不知道它是否值得的努力

  • Internally I can use whatever I want, e.g. C++ with operator overloading, multiple inheritance, template meta programming... as long as there is a portable compiler which handles it (think of gcc / g++)
  • But my interface has to be a clean C interface that does not involve name mangling
  • Also, I think my interface should only consist of functions, with basic/primitive data types (and maybe pointers) passed as parameters and return values
  • If I use pointers, I think I should only use them to pass them back to the library, not to operate directly on the referenced memory
  • For usage in a C++ application, I might also offer an object oriented interface (Which is also prone to name mangling, so the App must either use the same compiler, or include the library in source form)
  • Is this also true for usage in C# ?
  • For usage in Java SE / Java EE, the Java native interface (JNI) applies. I have some basic knowledge about it, but I should definitely double check it.
  • Not all client languages handle multithreading well, so there should be a single thread talking to the client
  • For usage on Java ME, there is no such thing as JNI, but I might go with Nested VM
  • For usage in Bash scripts, there must be an executable with a command line interface
  • For the other client languages, I have no idea
  • For most client languages, it would be nice to have kind of an adapter interface written in that language. I think there are tools to automatically generate this for Java and some others
  • For object oriented languages, it might be possible to create an object oriented adapter which hides the fact that the interface to the library is function based - but I don't know if its worth the effort

  • 这可能是可管理的努力,还是只是太多的可移植性?

  • 有没有关于这种设计的好书/网站标准?

  • 我的任何假设都是错误的?

  • 哪些开源库值得研究从他们的设计/界面/ souce学习? li>
  • meta:这个问题是相当长的,你有没有办法把它分成几个较小的?

  • is this possible with manageable effort, or is it just too much portability?
  • are there any good books / websites about this kind of design criteria?
  • are any of my assumptions wrong?
  • which open source libraries are worth studying to learn from their design / interface / souce?
  • meta: This question is rather long, do you see any way to split it into several smaller ones? (If you reply to this, do it as a comment, not as an answer)

推荐答案

主要是正确的。直接的程序界面是最好的。 (这不是完全相同的C btw(**),但足够接近)

Mostly correct. Straight procedural interface is the best. (which is not entirely the same as C btw(**), but close enough)

我将DLL很多(*),开源和商业,这里有一些我从日常实践中记得的几点,请注意,这些是更多的推荐研究领域,而不是基本的真理:

I interface DLLs a lot(*), both open source and commercial, so here are some points that I remember from daily practice, note that these are more recommended areas to research, and not cardinal truths:


  • 注意用于装饰和类似的次要管理方案,特别是如果您使用MS编译器。最引人注目的是,stdcall约会有时导致VB的装饰生成(装饰是像函数符号名后面的@ 6)

  • 并不是所有的编译器都可以实际布局各种结构:


    • ,以免过度使用工会。

    • 避免打包

    • ,最好包装记录。虽然速度较慢,但​​至少所有编译器都可以访问打包记录afaik

    • Watch out for decoration and similar "minor" mangling schemes, specially if you use a MS compiler. Most notably the stdcall convention sometimes leads to decoration generation for VB's sake (decoration is stuff like @6 after the function symbol name)
    • Not all compilers can actually layout all kinds of structures:
      • so avoid overusing unions.
      • avoid bitpacking
      • and preferably pack the records. While slower, at least all compilers can access packed records afaik

      • 宏由于其不真实而难以自动转换。使用函数

      • 为每个指针类型定义单独的类型,不要在函数声明中使用复合类型(xtype **)。

      • 尽可能地遵循定义使用前的定义,这将避免用户翻译头来重新排列它们,如果他们的语言通常需要在使用前定义,并使一个更容易 - 通过解析器来翻译它们。或者如果他们需要上下文信息来自动翻译。

      (**)
      这是因为什么C意味着二进制仍然依赖于使用的C编译器,特别是如果没有真正的通用系统ABI。想想这样的东西:

      (**) This is because what "C" means binary is still dependant on the used C compiler, specially if there is no real universal system ABI. Think of stuff like:


      • C在一些二进制格式(a.out,Coff?)上添加下划线前缀

      • 有时不同的C编译器对于通过价值传递的小结构有什么不同的看法。正式地,他们不应该在所有的afaik支持,但大多数。

      • 结构打包有时会有所不同,调用约定的细节(如跳过
        整数寄存器或不是如果参数可在FPU寄存器中注册)

      =====自动标题转换====

      ===== automated header conversions ====

      虽然我不太了解SWIG,但我知道并使用了一些特定于Delphi的头文件工具(h2pas,Darth / headconv等)。

      While I don't know SWIG that well, I know and use some delphi specific header tools( h2pas, Darth/headconv etc).

      然而,我从来没有在全自动模式下使用它们,因为更多的是输出不好。注释更改行或被剥离,并且不保留格式。

      However I never use them in fully automatic mode, since more often then not the output sucks. Comments change line or are stripped, and formatting is not retained.

      我通常会制作一个小脚本(在Pascal中,但是您可以使用任何具有体面字符串支持)一个标题,然后在相对均匀的部分(例如只有结构或仅定义等)上尝试一个工具。

      I usually make a small script (in Pascal, but you can use anything with decent string support) that splits a header up, and then try a tool on relatively homogeneous parts (e.g. only structures, or only defines etc).

      然后我检查我是否喜欢自动转换输出,并使用它,或尝试自己制作一个特定的转换器。由于它是一个子集(像只有结构),所以通常比制作一个完整的标头转换器更容易。当然这取决于我的目标是什么。 (漂亮,可读的标题或快速和脏)。在每个步骤中,我可能会做一些替换(使用sed或编辑器)。

      Then I check if I like the automated conversion output, and either use it, or try to make a specific converter myself. Since it is for a subset (like only structures) it is often way easier than making a complete header converter. Of course it depends a bit what my target is. (nice, readable headers or quick and dirty). At each step I might do a few substitutions (with sed or an editor).

      我为Winapi commctrl和ActiveX / comctl头文件最复杂的方案。在那里,我结合了IDL和C头(接口的IDL,C中是一堆不可扩展的宏,其余的是C头),并设法获取大约80%的宏类型(通过在sendmessage中传播类型转换宏返回宏声明,具有合理的(wparam,lparam,lresult)默认值)

      The most complicated scheme I did for Winapi commctrl and ActiveX/comctl headers. There I combined IDL and the C header (IDL for the interfaces, which are a bunch of unparsable macros in C, the C header for the rest), and managed to get the macros typed for about 80% (by propogating the typecasts in sendmessage macros back to the macro declaration, with reasonable (wparam,lparam,lresult) defaults)

      半自动化方式的缺点是声明的顺序不同(例如,常数,然后结构然后函数声明),这有时使维护变得痛苦。因此,我始终保持原始标题/ sdk与。

      The semi automated way has the disadvantage that the order of declarations is different (e.g. first constants, then structures then function declarations), which sometimes makes maintenance a pain. I therefore always keep the original headers/sdk to compare with.

      Jedi winapi转换项目可能有更多的信息,他们将大约一半的Windows标头翻译成Delphi,因此具有巨大的经验。

      The Jedi winapi conversion project might have more info, they translated about half of the windows headers to Delp and thus have enormous experience.

      这篇关于如何设计一个C / C ++库可以在许多客户端语言中使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆