从同一项目中构建DLL和静态库

28

我有一些本地的C++库(Win32,没有MFC),在Visual Studio 2005下编译,并在许多解决方案中使用。

我想根据我使用它们的特定解决方案的需求,选择将它们编译和链接为静态库或DLL。

那么,最好的方法是什么?我考虑了以下几种方法:

1. 多个项目文件

  • 例如:“foo_static.vcproj”与“foo_dll.vcproj”
  • 优点:易于为新库生成,不需要太多手动操作vcproj文件。
  • 缺点:两个地方的设置、文件列表等很容易失去同步。

2. 单个项目文件,多个配置

  • 例如:“Debug | Win32” vs “Debug DLL | Win32”,等等。
  • 优点:文件列表更容易保持同步;编译选项也比较容易保持同步。
  • 缺点:我同时为Win32和智能设备目标构建,所以已经有多个配置了;我不想让我的组合爆炸变得更糟糕(“FooPhone | WinMobile 6 的静态库”,“FooPhone | WinMobile 6 的动态库”,“BarPda | WinMobile 6 的静态库”等)。
  • 更糟糕的缺点:VS 2005有一个坏习惯,认为如果您为平台“Foo”定义了配置,则您确实需要在解决方案中的所有其他平台上进行定义,并且无论是否有效,它都会随意地将所有配置/平台配置的排列组合插入到受影响的vcproj文件中。(已向MS提交错误报告;作为WONTFIX关闭。)

3. 单个项目文件,通过vsprops文件选择静态或动态

  • 例如:将适当的vcproj片段存储在属性表文件中,然后在需要静态库时将“FooApp静态库”属性表应用于config/platform组合,在需要DLL时将“FooApp DLL”属性表应用于相应组合。
  • 优点:这正是我想做的!
  • 缺点:看起来似乎不可能。 看起来可以在 .vsprops 文件中无法覆盖在静态和动态库之间切换的 .vcproj 属性(Configuration 元素的 ConfigurationType 属性)。 Microsoft 发布的这些文件的架构仅列出了<Tool>和<UserMacro>元素。
  • 编辑: 如果有人建议,我也尝试过更“聪明”的第3种方法,其中我定义了一个 .vsprops,其中包含一个名为“ModuleConfigurationType”的 UserMacro,其值为“2”(DLL)或“4”(静态库),并将 .vcproj 中的配置更改为 ConfigurationType="$(ModuleConfigurationType)"。 Visual Studio 会默默地且没有警告地删除该属性,并将其替换为 ConfigurationType="1"。非常有用!

    我是否错过了更好的解决方案?

    7个回答

    6
    我可能漏掉了一些东西,但是为什么不能定义没有文件的DLL项目,只需让它链接其他项目创建的lib文件呢? 而且,关于设置,您可以将其因素化在vsprop文件中...

    好主意——这可能是值得一试的东西,不过你需要使用一些诡计才能在所有情况下正确获取链接指令。至于.vsprop文件,我提到过我尝试过这样做,但配置类型是vsprop文件不支持的设置之一。 - Tim Lesher
    旧帖,但对于现在遇到此问题的任何人来说:不实施进一步的诡计,这实际上是行不通的。关于此问题,有一篇微软博客文章在这里:https://devblogs.microsoft.com/oldnewthing/20140321-00/?p=1433 但本质上:连接器会看到你实际上没有使用静态库中的任何内容,因此它不会将其包含在内。 - wheybags

    5

    有一种简单的方法可以在一个项目中创建静态和动态链接库版本。

    首先创建你的dll项目,然后按以下步骤执行:

    只需要创建一个nmake makefile或.bat文件来运行lib工具。 基本上就是这样:

    lib /NOLOGO /OUT:<your_lib_pathname> @<<
    <list_all_of_your_obj_paths_here>
    <<
    

    接下来,在您的项目中添加一个“后期构建事件”,其中命令只运行.bat文件(或nmake或perl)。然后,您将始终获得dll和静态库。

    我不会贬低Visual Studio,因为它不允许在链接器(在工具流程中)之前在项目中存在此工具。


    这在VS2010中非常容易。您可以向vcxproj文件添加一个目标,该目标可以使用已定义的编译文件列表'ClCompile'来生成.obj列表,然后在Exec任务中调用Lib。 - morechilli

    2

    我认为通常的做法是选择上述第二种方式。这也是我使用的方式,也是许多图书馆和公司所采用的方式。

    如果你发现这种方法对你不起作用,那么一定要使用其他方法。

    祝你好运。


    我们正在进行1)和2),每个都有一定的成功,但也有不同的缺点。我希望有一个4)... - Tim Lesher

    2
    我更喜欢两种配置方式。
    一种是通过项目属性窗口中的 “所有配置” 选项设置所有常见设置。然后分离设置。就这样,让我们开始编码吧。
    另外还有一个非常好的功能叫做“批量构建”,可以依次构建指定的配置。

    0

    多个项目是最佳选择 - 在我接触过的众多项目中,这是我最广泛见到的配置。

    话虽如此,也可能通过修改vcproj文件来实现第三个选项,这可以使用外部工具(如自定义vbscript)从外部调用。您可以使用shell变量来控制工具的行为。

    请注意,仍应该使用Visual Studio进行构建,makefile只在需要进行修改时启动外部工具,然后按照实际构建命令继续执行。


    0

    由于一些问题阻止我们迁移到VS2005或更新版本,我仍在使用Visual Studio 6.0。重建会导致严重问题(一切都会崩溃)......因此,我们中的许多人正在考虑通过有结构的方式游说迁移到GnuC++,最终使我们摆脱授权的Visual Studio产品并转向Eclipse和Linux。

    在Unix/Linux中,为所有配置构建很容易...所以我无法相信在Visual Studio中尝试完成同样的任务需要花费如此多的时间和生产力。对于VS6.0,我目前发现只有两个单独的项目似乎可行。我还没有尝试过多配置技术,但将在旧版的VS6.0中看看它是否有效。


    在VS 6.0中,多配置技术是区分平台差异的唯一方法,因为VS6没有像VS2005那样具有目标平台的概念。 - Tim Lesher

    -1
    为什么不选择版本1,并使用脚本或其他工具从第一个版本生成第二组项目文件。这样,您就可以确定差异仅限于构建dll或静态库所需的部分。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接