【问题标题】:Python shared object module naming conventionPython 共享对象模块命名约定
【发布时间】:2011-09-13 05:54:01
【问题描述】:

我已经用 C++ 编写了一个 Python 模块并将其构建为一个共享对象库,它运行良好。但是在弄清楚这一切的同时,我注意到(通过 strace)Python 会寻找一些不同的变体 import 被调用。特别是,当我说import foo 时,Python 按顺序搜索:

  • foo(一个目录)
  • foo.so
  • foomodule.so
  • foo.py
  • foo.pyc

除了 foomodule.so 之外,这一切都很好理解。为什么 Python 会同时查找 name.so 和 namemodule.so 的所有内容?是不是什么历史文物?我进行了相当多的搜索,但根本没有给出任何解释,我想知道是否应该将我的模块命名为 foomodule.so 而不是 foo.so。我的系统似乎有一些遵循每个约定的现有 Python 模块,所以我不禁想知道不同的名称是否意味着什么。

【问题讨论】:

    标签: python module naming-conventions shared-libraries


    【解决方案1】:

    这实际上是平台相关的,Python 会根据操作系统尝试不同的后缀。这里是import.c中后缀表的初始化:

    #ifdef HAVE_DYNAMIC_LOADING
        memcpy(filetab, _PyImport_DynLoadFiletab,
               countD * sizeof(struct filedescr));
    #endif
        memcpy(filetab + countD, _PyImport_StandardFiletab,
               countS * sizeof(struct filedescr));
        filetab[countD + countS].suffix = NULL;
    
        _PyImport_Filetab = filetab;
    

    所以它加入了两个列表,_PyImport_DynLoadFiletab_PyImport_StandardFiletab。后者更简单,它在同一个文件中定义为[".py", ".pyw", ".pyc"](第二个条目仅存在于 Windows 上)。 _PyImport_DynLoadFiletab 在各种 dynload_<platform>.c 文件中定义。在基于 Unix 的系统上,它的值是 [".so", "module.so"],对于 CygWin,它定义为 [".dll", "module.dll"],而对于 OS/2,它是 [".pyd", ".dll"],对于 Windows,它只是 [".pyd"]

    我浏览了源代码历史,最终得出了自 1999 年以来的这一变化,显然添加了“module.so”作为可能的后缀:http://hg.python.org/cpython-fullhistory/diff/8efa37a770c6/Python/importdl.c。因此,这些更改最初是为 NeXTStep(最终成为 Mac OS X)添加的,仅用于特定的链接设置。我不知道这个操作系统,所以很难说出它为什么会这样做——我怀疑这只是为了防止命名冲突。例如。可能已经加载了框架库foo.so,并且操作系统不允许加载另一个同名的库。所以foomodule.so 是一种妥协,允许名称为foo 的Python 模块仍然存在。

    编辑:上面的段落是错误的 - 我没有深入了解历史,感谢 senderle 指出这一点。事实上,有趣的变化似乎是从 1994 年开始的 http://hg.python.org/cpython-fullhistory/diff/2230/Python/import.c,它添加了一个新的模块命名方案 (foo.so) 作为旧方案 (foomodule.so) 的替代方案。我猜想旧形式在某个时候已被弃用,因为在对该代码的众多重写之一中已删除了对某些平台(如 Windows)的支持。请注意,即使在首次引入时,也会首先列出短模块名称版本 - 这意味着它已经是首选变体。

    Edit2:我搜索了 1994 年的邮件列表/新闻组,看看是否在某个地方讨论过这个变化 - 看起来不像,Guido van Rossum 似乎在没有告诉任何人的情况下实现了它.

    【讨论】:

    • 有趣,我不知道那个全历史浏览器。那里有一些深刻的制度记忆。然而,#define LONG_EXT "module.so" 的定义——如果这就是你所指的——早在你所说的补丁之前就已经存在了。事实上,importdl.c 第一次创建时就在那里!
    • @senderle:谢谢,我确实犯了一个错误。 importdl.c 是在重写中创建的,原始代码可以在 import.c 中找到 - 我发现引入了两种命名方案的更改并更新了我的答案。太糟糕了,Python 的机构记忆不包括导致改变的讨论。
    【解决方案2】:

    这只是一个猜测,但我只能假设这与以下内容有关,来自Extending Python with C or C++

    首先创建一个文件 spammodule.c。 (从历史上看,如果一个模块被称为 spam,包含其实现的 C 文件称为 spammodule.c;如果模块名称很长,如 spammify,则模块名称可以只是 spammify.c。)

    我想这个约定扩展到.so 文件的名称。 the same 的第 1.5 节进一步支持了该猜想。


    基于弗拉基米尔的excellent discovery,我发现first referencemodule.so 作为后缀。它来自一个支持动态加载 SunOS 库的补丁,来自“Bill”。 (Bill Jansson?) 显然module-as-suffix 约定在使用.so 共享库之前就开始了,而当.so 库被采用时,该约定被简单地维护了。

    我认为 Wladimir 是对的——有趣的变化是采用了短模块名称约定。这证实了我的猜测,即长模块名称是早期的约定。

    【讨论】:

    • 我回去检查了 Python 查找各种文件的顺序。我注意到它在 foomodule.so 之前查找 foo.so,如果 foomodule.so 是首选形式,这似乎很奇怪。我会等待其他人加入,因为虽然我觉得你的回答是合理的,但它也有点摇摆不定(无意冒犯,我想我仍在寻找一些消息来源说“这就是我们有两种模式的原因”或类似的东西)。
    • 是的,毫无疑问,它是手摇的 :)。但我似乎很清楚,一定有一个早期的foomodule 约定不再受欢迎,但由于某种原因很难消除。我也很想听听这位老警卫关于这个问题的看法。
    • 甚至在添加module.so 之前,Python 已经加载了带有module.o 文件名后缀的模块-您链接到的更改仅添加了对SunOS 的支持。添加对动态加载的支持的补丁是hg.python.org/cpython-fullhistory/diff/609/Python/import.c,它已经使用module.o作为后缀——我猜这是遵循Amoeba的命名约定。
    • @Wladimir,是的,完全正确——这就是为什么我说“.so共享库”而不是“共享库”一般。此外,我很确定module.o 早在采用任何形式的动态加载之前就是常规后缀。我想我们可以通过查看 makefile 来确认这一点!
    猜你喜欢
    • 1970-01-01
    • 2019-01-14
    • 2012-07-20
    • 2013-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-10
    • 1970-01-01
    相关资源
    最近更新 更多