Это хорошая идея, чтобы сделать вариант обработки с использованием общей библиотеки? - PullRequest
1 голос
/ 15 октября 2019

Я определил интерфейс, используя абстрактный класс C ++. Я хочу создать его несколько раз для разных вариантов моего проекта (варианты могут быть аппаратными или ОС). Моя цель - создать совместно используемые библиотеки для каждого варианта и использовать правильные библиотеки для данного проекта без необходимости что-либо перекомпилировать.

Я приказываю получить требуемый экземпляр для данного варианта, я использую общедоступныефункция. В файле cpp каждого варианта я определяю функцию для возврата экземпляра для этого варианта. В основном коде я делаю внешнее объявление этой функции. Я намереваюсь вызвать метод интерфейса, используя возвращаемый объект.

// Interface.hpp
class Interface {
    public:
        virtual void routine() = 0;
};

// variantA.cpp
class variantA : public Interface {
    public:
        void routine() {
            printf( "We are in variantA\n" );
        }
} variant;

Interface& getVariant() {
    return variant;
}

// variantB.cpp
class variantB : public Interface {
    public:
        void routine() {
            printf( "We are in variantB\n" );
        }
} 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

Ответы [ 2 ]

0 голосов
/ 15 октября 2019

Во-первых, не делайте этого с объявлением перед использованием, которое принадлежит заголовку интерфейса, именно для этого и нужен заголовок.

Проблема

Но я боюсь, что у нас есть XY проблема здесь:

Я хочу создать его несколько раз для разных вариантов моегопроект (варианты могут быть аппаратными вариантами или вариантами ОС). Моя цель состоит в том, чтобы создать общие библиотеки для каждого варианта и использовать правильные библиотеки для данного проекта без необходимости что-либо перекомпилировать.

Это невозможно: видеть, что вы обычно не можете скомпилировать libvarianta для аппаратного обеспечения илиВариант ОС a скомпилировал libvariantb для аппаратного обеспечения или вариант ОС b и использовал все это вместе в одной программе, которая одновременно ссылается на a и b.

Проблема в том, что есть причина, по которой вам обычно приходится компилировать всеЕще раз: разное оборудование и разные операционные системы обычно требуют разного машинного кода. Даже вызов printf, который вы делаете, переводит на другой машинный код для разных компиляторов или операционных систем. Вот что означают стандарт и справочник C ++ под средой выполнения и реализацией.

Кроме того, вы часто даже не могли вызвать функцию, потому что при использовании разделяемой ссылки вы столкнулись с проблемами ABI (не API), что также означает, что даже для одной и той же версии компилятора Microsoft дляту же архитектуру вы должны скомпилировать один раз для отладки и один раз для сборки выпуска (, если не соблюдаются дополнительные меры предосторожности ).

Большинство библиотек даже имеют разную высокоуровневую компиляцию кода на разных платформах с использованием препроцессора.

Решение

Таким образом, вам придется собирать все необходимые версии для ваших библиотек. и потребитель вашей библиотеки, который будет нуждаться в сложной логике, чтобы знать, какой двоичный файл загрузить. Другими словами: вам нужно было бы найти один двоичный файл совместно используемой библиотеки, который вы бы получили, если бы вы все равно просто скомпилировали их. Так что было бы проще просто статически связать его и использовать один API, без необходимости абстрактного класса или интерфейсов, по крайней мере, во время выполнения. Вам может понадобиться делать разные вещи во время компиляции, поскольку у вас может не быть переносимого способа сделать что-либо. Затем вы можете использовать макросы препроцессора или полиморфизм времени компиляции . Это соответствует рекомендации, которую дал вам John3136.

Ответ

Итак, НЕТ , совместное использование ссылок не решит проблему, т.е. достигните того, что вы пытаетесь сделать, насколько я понимаю ваш вопрос. Это просто создаст более сложные проблемы. Совместное использование ссылок не является ни переносимым, ни даже вещью в соответствии с чистым стандартом C ++. Однако есть некоторые хитрости, как разные операционные системы пытаются добиться стабильности ABI (например, COM-объекты в Windows), но это все равно не решит проблему, если ваш код должен быть ориентирован на другое оборудование или среды выполнения.

0 голосов
/ 15 октября 2019

Неа. Кажется, это плохая идея, а не то, как все остальные делают совместные библиотеки C ++. Если это разные аппаратные средства или варианты ОС, то библиотеки, возможно, должны быть другого формата. Обычный подход - одна библиотека с одинаковым API, скомпилированным для каждого варианта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...