使用共享库进行变体处理是个好主意吗?

Is it a good idea to do variant handling using shared library?

本文关键字:处理 好主意 共享      更新时间:2023-10-16

我用抽象类定义了一个接口C++。我想为项目的不同变体多次实例化它(变体可以是硬件变体或操作系统变体(。我的目标是为每个变体创建共享库,并为给定项目使用正确的库,而无需重新编译任何内容。

我为了检索给定变体所需的实例,我正在使用公共函数。在每个变体的 cpp 文件中,我定义了一个函数来返回该变体的实例。在主代码中,我正在对这个函数进行外部声明。我打算使用返回的对象调用接口的方法。

// Interface.hpp
class Interface {
public:
virtual void routine() = 0;
};
// variantA.cpp
class variantA : public Interface {
public:
void routine() {
printf( "We are in variantAn" );
}
} variant;
Interface& getVariant() {
return variant;
}
// variantB.cpp
class variantB : public Interface {
public:
void routine() {
printf( "We are in variantBn" );
}
} variant;
Interface& getVariant() {
return variant;
}
// main.cpp
#include "Interface.hpp"
extern Interface& getVariant();
int main() {
Interface& interface = getVariant();
interface.routine();
}
// build.sh
g++ -c -fPIC -O0 variantA.cpp
g++ -c -fPIC -O0 variantB.cpp
g++ variantA.o -shared -o libvariantA.so
g++ variantB.o -shared -o libvariantB.so
ln -s libvariantA.so libvariant.so
g++ -L. -lvariant main.cpp -o main

主要问题:我的方法在理论上正确吗?这样做是个好主意吗?或者,这种方法有什么明显的缺陷吗?如果是这样,任何人都可以推荐我更好的方法吗?

第二个问题:我可能可以通过一些试验自己弄清楚。但我仍然发布这个,因为这可能会使该方法无法使用。问题是编译错误:

In function `main':
main.cpp:(.text+0x9): undefined reference to `getVariant()'
collect2: error: ld returned 1 exit status

首先,不要在使用前使用声明这样做,它属于接口标头,这就是标头的用途。

问题

但我担心我们在这里遇到了一个 XY 问题:

我想为我的不同变体多次实例化它 项目(变体可以是硬件变体或操作系统变体(。我的目标是 为每个变体创建共享库,并将正确的库用于 一个给定的项目,无需重新编译任何内容。

这是不可能的:看到你通常不能为硬件或操作系统变体a编译libvarianta,而为硬件或操作系统变体b编译libvariantb,并在一个同时链接到a和b的程序中一起使用它们。

问题是你通常每次都必须重新编译是有原因的:不同的硬件和不同的操作系统通常需要不同的机器代码。甚至您所做的printf调用也会转换为不同编译器或操作系统的不同机器代码。这就是C++标准和参考对运行时和实现的意义。

此外,您通常甚至无法调用该函数,因为在使用共享链接时,您会遇到 ABI(不是 API(的问题,这也意味着即使对于相同架构的相同Microsoft编译器版本,您也必须编译一次用于调试,一次用于发布版本(除非遵循进一步的预防措施(。

大多数库甚至使用预处理器在不同的平台上编译不同的高级代码。

溶液

因此,您仍然必须为库和库的使用者编译所有需要的不同版本,这将需要一个复杂的逻辑才能知道要加载哪个二进制文件。换句话说:你必须找到一个共享库二进制文件,如果你只是简单地将它们编译在一起,你就会得到这个二进制文件。因此,简单地静态链接它并使用一个 API 会更容易,不需要抽象类或接口,至少在运行时明智。您可能需要在编译时执行不同的操作,因为您可能没有可移植的方式来执行操作。然后,可以使用预处理器宏或编译时多态性。这符合 John3136 给您的建议。

所以,共享链接不会解决问题,即据我理解你的问题,实现你尝试做的事情。它只会产生更复杂的问题。共享链接不是可移植的,甚至不是纯标准C++的东西。但是,有一些技巧可以尝试不同的操作系统如何实现 ABI 稳定性(如 Windows 上的 COM 对象(,但如果代码需要针对不同的硬件或运行时,这仍然无法解决问题。

不。这似乎是一个坏主意,而不是其他人C++共享库的方式。如果它们是不同的硬件或操作系统变体,则库可能必须采用不同的格式。一个为每个变体编译相同 API 的库是正常方法。