【问题标题】:something like preprocessors at runtime运行时的预处理器之类的东西
【发布时间】:2015-08-24 20:45:06
【问题描述】:

在我的应用程序中,我使用了 x2.0 库中的新函数,该函数在 x1.0 版本中没有,但我想保持向后兼容性。

我正在与该库动态链接,当我在执行新函数之前使用简单的 if 条件检查库版本时,它不起作用,因为在启动期间,exe 搜索并解析所有函数,就像我运行时一样链接到旧版本的应用程序给了我错误。

在运行时,我希望 exe 检查 lib 版本并执行新函数或不根据该版本执行它。

可以吗,如果可以,

我能做些什么来实现这个目标?

【问题讨论】:

  • 库是否太大而无法为您的应用程序创建包装器?
  • 我无法控制图书馆的开发,我是从互联网上得到的
  • 但是你可以控制它周围的包装器。
  • 好吧,你说的 wrapper 是什么意思? ..对不起,我无法得到它
  • @becks 通常的方法是声明某些合约(纯虚拟接口)并使用dynamic_cast<MyExtendedInterface>对其进行测试以进行验证。

标签: c++ linker shared-libraries


【解决方案1】:

我认为最好的答案是对同一个 dll 使用隐式和显式链接 默认情况下,加载程序将加载 dll,然后在您的代码中使用 LoadLibrary 和 GetProcAddress 来获取旧版本库中不存在的 API

  HINSTANCE hinstLib; //Handle to the DLL
    // MYPROC ProcAddress; //Pointer to the function

   hinstLib = LoadLibrary("x.dll");
   FOO3 myFunc = (FOO3) GetProcAddress(hinstLib, "foo3");

【讨论】:

    【解决方案2】:

    处理与第三方库的向后兼容性的一种方法是围绕它创建一个包装库/源文件,并确保您的应用程序永远不会从任何其他地方调用第三方库的任何函数。

    假设您依赖于提供两个头文件“foo.h”和“bar.h”的第三方库。在库的版本 1 中,文件可能如下所示:

    foo.h:

    void foo1();
    int foo2();
    

    bar.h:

    void bar1(int);
    int bar2(int);
    

    假设他们在第 2 版中扩展了界面,现在它们看起来像:

    foo.h:

    void foo1();
    int foo2();
    double foo3();
    

    bar.h:

    void bar1(int);
    int bar2(int);
    int bar3(double);
    

    在您的应用程序中,您希望能够在与库的版本 2 链接时使用 foo3()bar3(),但您希望能够优雅地处理库版本 1 中缺少这些功能.

    您可以使用以下方法来完成此操作。

    为库创建一个包装器 .h 文件。

    foo_bar_wrapper.h:

    namespace foo_bar_wrapper
    {
        void foo1();
        int foo2();
        double foo3();
        void bar1(int);
        int bar2(int);
        int bar3(double);
    }
    

    然后,将它们实现为传递到第三方库。

    foo_bar_wrapper.h:

    #include "foo.h"
    #include "bar.h"
    
    namespace foo_bar_wrapper
    {
        void foo1() { ::foo1(); }
        int foo2() { return ::foo2(); }
        double foo3() { return ::foo3(); }
        void bar1(int x) { return ::bar1(x); }
        int bar2(int x) { return ::bar2(x); }
        int bar3(double x) { return ::bar3(x); }
    }
    

    但是,由于库的版本 1 不支持 foo3bar3,您可以使用:

    namespace foo_bar_wrapper
    {
        void foo1() { ::foo1(); }
        int foo2() { return ::foo2(); }
    
        double foo3() 
        {
    #if FOO_LIBRARY_VERSION > 1
            return ::foo3();
    #else
            // Deal gracefully with version 1
    #endif
        }
    
        void bar1(int x) { return ::bar1(x); }
        int bar2(int x) { return ::bar2(x); }
    
        int bar3(double x)
        {
    #if FOO_LIBRARY_VERSION > 1
           return ::bar3(x);
    #else
            // Deal gracefully with version 1
    #endif
        }
    
    }
    

    确保在构建应用程序时正确定义 FOO_LIBRARY_VERSION

    【讨论】:

    • 嗯,首先,感谢您的回答。但我将在我的机器上构建应用程序,用户将根据他的环境使用 exe,因此#if 只会在编译期间工作。假设我安装了最新版本,所以它可以在我的机器上运行,但是如果用户使用旧版本,他会遇到链接错误,因为他只有我的 exe,你怎么看?
    • 选项1:要求用户下载最新版本的第三方库。选项 2:随 .exe 分发最新版本的第三方库。选项 3:构建您的 .exe 的两个版本,并确保您的每个用户都能够选择他们选择使用的版本。
    猜你喜欢
    • 1970-01-01
    • 2022-12-03
    • 2012-11-15
    • 1970-01-01
    • 2012-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多