什么是MSVC dll,静态库和导入库的正确命名约定

时间:2010-01-26 14:51:37

标签: dll naming-conventions visual-c++ cmake static-libraries

MSVC库构建的标准或“最常用”命名约定是什么。

例如,对于以下平台,库foo具有以下约定:

Linux / gcc:

shared: libfoo.so
import: ---
static: libfoo.a

的Cygwin / GCC:

shared: cygfoo.dll
import: libfoo.dll.a
static: libfoo.a

视窗/ MinGW的:

shared: libfoo.dll
import: libfoo.dll.a
static: libfoo.a

MSVC buidls应该使用什么?据我所知,通常名称为foo.dllfoo.lib,但您通常如何区分导入库和静态库?

注意:我问,因为CMake在他们之间创建了非常unpleasant的冲突,将导入和静态库命名为foo.lib。见bug report。答案会 帮助我说服开发人员修复这个错误。

6 个答案:

答案 0 :(得分:5)

正如其他人所说,没有标准,但有流行的惯例。我不确定如何明确地判断什么是最受欢迎的惯例。除了你提到的静态与导入库的命名之外,Release库与Debug库的命名之间也有类似的区别,特别是在Windows上。

这两种情况(即静态与导入,调试与发布)都可以通过以下两种方式之一进行处理:不同的名称或不同的目录位置。我通常选择使用不同的名称,因为我觉得它可以最大限度地减少以后误读库类型的可能性,特别是在安装或其他文件移动活动之后。

我通常在Windows上使用foo.dllfoo.lib,在静态库中使用foo_static.lib,当我希望同时拥有共享和静态版本时。我见过其他人使用这个约定,所以它可能是“最受欢迎的”。

所以我建议你在桌子上添加以下内容:

视窗/ MSVC:

shared: foo.dll
import: foo.lib
static: foo_static.lib

然后在cmake,你可以

add_library(foo_static STATIC foo.cpp)

add_library(FooStatic STATIC foo.cpp)
set_target_properties(FooStatic PROPERTIES OUTPUT_NAME "foo_static") 

如果由于某种原因您不希望使用“foo_static”作为符号库名称。

答案 1 :(得分:4)

您可以通过扩展名区分库和.dll。但您可以通过 filename 区分导入库和静态库,而不是扩展名。

对于一组构建为静态库的代码,或者存在dll的静态库,不存在导入库的情况。这是两件不同的事情。

没有单一的MSVC标准文件名约定。通常,以“D”结尾的库名称通常是库代码msvcrtd.dll vs msvcrt.dll的调试版本,但除此之外,没有标准。

答案 2 :(得分:2)

据我所知,没有真正的“标准”,至少没有大多数软件符合的标准。

我的约定是将动态和静态.lib命名为,但如果项目恰好支持静态和动态链接,则将它们放在不同的目录中。例如:

foo-static
   foo.lib

foo
   foo.lib
   foo.dll

要链接的库取决于库目录的选择,因此它几乎完全与构建过程的其余部分分离(如果使用MSVC的#pragma comment(lib,"foo.lib")工具,它将不会出现在源代码中,并且它没有出现在链接器的导入库列表中。)

我已经看过很多次了。此外,我认为基于MSVC / Windows的项目倾向于更频繁地使用单一的官方链接类型 - 静态,动态。但这只是我个人的观察。

简而言之:   视窗/ MSVC

shared: foo.dll
import: foo.lib
static: foo.lib

您应该能够将此基于目录的模式与CMAKE一起使用(从未使用过它)。此外,我不认为这是一个'错误'。这只是缺乏标准化。如果每个人都喜欢不同的话,CMAKE会(imho)做正确的事情而不是来建立伪标准。

答案 3 :(得分:2)

库没有标准的命名约定。传统的库名称以lib为前缀。许多链接器可以选择在命令行中将lib添加到库名称。

静态和动态库通常通过文件扩展名来标识;虽然这不是必需的。因此libmath.a将是一个静态库,而libmath.solibmath.dll将是一个动态库。

常见的命名约定是将库的类别附加到名称。例如,调试静态数学库将是“libmathd.a”或Windows中的“lib_math_debug”。一些商店还将Unicode添加为文件名属性。

如果需要,可以将_msvc附加到库名称以指示库需要或由MSVC创建(以区分GCC和其他工具)。使用多个平台时,一种流行的约定是将对象和库放在特定于平台的文件夹中。例如,./linux/文件夹将包含Linux的对象和库,同样适用于Microsoft Windows平台的./msw/

这是一个风格问题。风格问题通常被视为宗教问题:没有一个是错的,没有普遍的风格,而且它们是个人偏好。你选择什么样的系统,只要保持一致。

答案 4 :(得分:2)

正如其他人所说,在Windows上没有单一的标准来命名文件。

对于我们完整的产品库,它涵盖了100个exes,dlls和static libs,我们已经成功使用了以下多年,它已经节省了很多混乱。它基本上是我多年来看到的几种方法的混合。

简而言之,我们所有的前缀和后缀文件(不包括扩展本身)。它们都以“om”(基于我们公司名称)开头,然后有一个或两个字符组合,大致标识代码区域。

后缀解释了它们是什么类型的构建文件,并且最多包含三个字母组合,具体取决于构建,包括Unicode,静态,调试(Dll构建是默认的,没有明确的后缀标识符)。当我们开始使用这个系统时,Unicode并不是那么普遍,我们不得不同时支持Unicode和非unicode构建(在Windows 2000操作系统之前),现在所有内容都是专门构建的unicode,但我们仍然使用相同的命名法。

因此典型的.lib“set”文件可能看起来像

omfThreadud.lib (Unicode/Debug/Dll)
omfThreadusd.lib (Unicode/Static/Debug)
omfThreadu.lib (Unicode/Release/Dll)
omfThreadus.lib (Unicode/static)

所有文件都内置在一个公共bin文件夹中,这为开发人员消除了很多dll-hell问题,也使得调整编译器/链接器设置变得更加简单 - 它们都指向使用相对路径的相同位置永远不需要手动(或自动)复制项目所需的库。拥有这些后缀还可以消除您可能拥有的文件类型的任何混淆,并保证您不会有混合方案,您将调试dll放在发行套件上,反之亦然。所有exes也使用类似的后缀(Unicode / Debug)并构建到相同的bin文件夹中。

同样有一个“include”文件夹,每个库在include文件夹中有一个头文件,与库/ dll的名称相匹配(例如omfthread.h)该文件本身#include所有其他项目由该图书馆曝光。如果你想要foo.dll中的功能你只需要#include“foo.h”,这就更简单了。我们的库被功能区域高度分割 - 实际上我们没有任何“瑞士军刀”dll,所以包括库整个功能都有意义。 (这些标头中的每一个还包括其他先决条件标头,无论它们是我们的内部库还是其他供应商SDK)

其中每个包含文件都在内部使用宏,这些宏使用#pramga将相应的库名称添加到链接器行,因此各个项目不需要关心。我们的大多数库都可以静态构建或作为DLL构建,并且#define OM_LINK_STATIC(如果已定义)用于确定单个项目想要的内容(我们通常使用DLL,但在某些情况下,内置于.exe make中的静态库)更有意义的部署或其他原因)

#if defined(OM_LINK_STATIC)
 #pragma comment (lib, OMLIBNAMESTATIC("OMFTHREAD"))
#else
 #pragma comment (lib, OMLIBNAME("OMFTHREAD"))
#endif

这些宏(OMLIBNAMESTATIC& OMLIBNAME)使用_DEBUG确定它是什么类型的构建,并生成适当的库名称以添加到链接器行。

我们在静态和放大器中使用通用定义。 dll版本的库,用于控制dll版本中类/函数的正确导出。从库中导出的每个类或函数都使用此宏进行修饰(其名称与库的基本名称相匹配,但这在很大程度上并不重要)

class OMUTHREAD_DECLARE CThread : public CThreadBase

在项目设置的DLL版本中,我们定义了OMFTHREAD_DECLARE = __ declspec(dllexport),在库的静态库版本中,我们将OMFTHREAD_DECLARE定义为 empty

在库头文件中,我们根据客户端尝试链接到它的方式来定义它

#if defined(OM_LINK_STATIC)
 #define OMFTHREAD_DECLARE
#else
 #define OMFTHREAD_DECLARE __declspec(dllimport)
#endif

一个想要使用我们的内部库的典型项目只是将相应的include添加到他们的stdafx.h(通常)并且它只是工作,如果他们需要链接静态版本他们只是将OM_LINK_STATIC添加到他们的编译器设置(或在stdafx.h中定义),它再次起作用。

答案 5 :(得分:1)

据我所知,目前还没有任何约定。以下是我如何做的一个例子:

(项目)的 {子模块} {平台} {架构} {编译器运行} _ {BuildType}的.lib / DLL

完整文件名应仅为小写,并且只包含带有预先指定的下划线的字母数字。子模块字段(包括其前导下划线)是可选的。

项目:保存项目名称/标识符。优选尽可能短。即" dna"

SubModule:可选。持有模块名称。优选尽可能短。即" dna_audio"

平台:标识二进制编译的平台。即" win32" (Windows)," winrt"," xbox"," android"。

架构:描述编译二进制文件的体系结构。 ie" x86"," x64"," arm"。对于各种位,架构名称相同的位置使用其名称后跟位数。即。 " name16"," name32"," name64"

CompilerRuntime:可选。并非所有二进制文件都链接到编译器运行时,但如果有,则包含在此处。即" vc90" (Visual Studio 2008)," gcc"。适用的公寓可以包括在内,即" vc90mt"

BuildType:可选。这可以包含字母(以任何所需的顺序),每个字母都可以说明构建特定的内容。 d = debug(如果发布则省略)t = static(如果是动态则省略)a = ansi(如果是unicode则省略)

示例(假设项目名为" DNA"): dna_win32_x86_vc90.lib / DLL dna_win32_x64_vc90_d.lib / DLL dna_win32_x86_vc90_sd.lib dna_audio_win32_x64_vc90.lib / DLL dna_audio_winrt_x64_vc110.lib / DLL