Как использовать 2 библиотеки C, которые экспортируют одни и те же имена функций [дублировать]

StackOverflow https://stackoverflow.com/questions/681200

  •  22-08-2019
  •  | 
  •  

Вопрос

Дубликат следующего вопроса: Конфликт функций C


Привет, в моем текущем проекте я должен использовать какую-то библиотеку интерфейса.Имена функций задаются этим интерфейсом, то, что делают эти функции, - выбор разработчиков.Насколько я могу судить, проект должен использовать эти функции, и когда дело доходит до компиляции, вы выбираете библиотеку, а вместе с ней и функциональность.То, что я пытаюсь сделать, это использовать существующую библиотеку и мою библиотеку одновременно, обернув другую и вызвав ее в mein functions:

другой файл:

int function1 (int a) {
// do something
}

мой брат:

int function1 (int a) {
//my code here
    otherlib::function1(a);
}

Проблема в том, что у меня нет доступа к другой библиотеке, а в другой библиотеке нет никаких пространств имен.Я уже пытался

namespace old {
    #include "otherlib.h"
}

а затем вызовите старую функцию с помощью old::function1 в моей функции.Это работает до тех пор, пока это всего лишь заголовочный файл.Библиотека экспортирует свой символ обратно в глобальное пространство.Также что-то вроде

namespace new {
    function1 (int a) {
        ::function1(a);
    }
}

не сработало.И последнее, но не менее важное: я попробовал ifdefs и предложил defines здесь

но я не добился успеха.

Есть какие-нибудь идеи, как это решить?Заранее благодарю.

Редактировать:У меня нет доступа ни к старой библиотеке, ни к проекту, в котором должны использоваться обе библиотеки.

РЕДАКТИРОВАТЬ 2:по крайней мере, старая библиотека является статичной

Это было полезно?

Решение

Пространства имен в C решаются с использованием префиксов имен библиотек, таких как:

libfoo --> foo_function1
библиотека -> bar_function1

Эти префиксы являются реальными пространствами имен.итак, если вы напишете libbar

int bar_function1(int a) {
     function1(a);
}

Это способ решать проблемы.

C имеет пространства имен --- они просто называются префиксами ;)

Другой вариант - проделывать различные грязные трюки с динамической загрузкой библиотек, таких как:

h1=dlopen("libfoo.so")
foo_function1=dlsym(h1,"function1")

h2=dlopen("libbar.so")
bar_function1=dlsym(h2,"function1")

Другие советы

Кажется, что другая библиотека - C, а ваш код - C ++.Вы можете столкнуться с проблемой искажения (компиляторы C ++ искажают символы - добавляют дополнительные элементы в имя символа, дифференцируют перегрузки и тому подобное).

Если библиотека является чистым C, вы можете попробовать:

extern "C" { // disable mangling of symbol names in the block
#include "otherlib.h"
}

namespace new_lib { // new is a reserved word
   int function1( int a ) {
      ::function1(a);
   }
}

Я этого еще не пробовал.Также рассмотрите возможность предоставления сообщений об ошибках, которые вы получаете.

Другим вариантом была бы (если библиотека динамическая) динамическая загрузка библиотеки и вызов функции.В Linux (я не знаю о Windows) вы можете использовать dlopen, чтобы открыть библиотеку, dlsym, чтобы получить символ и вызвать его:

// off the top of my head, not tried:
int function1( int a )
{
   int (*f)(int); // define the function pointer
   void * handle = dlopen( "library.so" );
   f = dlsym( handle, "function1" );
   f( a ); // calls function1(a) in the dynamic library
}

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

Обновить

Если ваши пользователи не будут использовать 'otherlib' напрямую (они не будут включать свои заголовки) и они будут использовать только C ++, тогда возможен первый подход (даже если он ужасен для чтения):

// newlib.h
namespace hideout {
   int f( int a );
}
using namespace hideout; // usually I would not put this on the header

// newlib.cpp
extern "C" { // if otherlib is C, else remove this line
#include "otherlib.h"
}
namespace hideout {
   int f( int a ) { return ::f( a*2 ); }
}

// main.cpp
#include "newlib.h"
int main()
{
   std::cout << f( 5 ) << std::endl;
}

Как это работает?Пользовательский код увидит только объявление function1 (в примере f()), поскольку они не включают otherlib.h.Внутри вашего модуля компиляции вы видите два объявления, но вы различаете их за счет использования пространства имен.Оператор using в заголовке вас не беспокоит, поскольку вы полностью соответствуете своему cpp.Пользователь main.cpp будет включать только ваш заголовок, поэтому компилятор будет видеть только убежище::f, и увидит это в любом месте благодаря оператору using.У компоновщика не возникнет проблем, поскольку символ C ++ искажен, идентифицируя реальное пространство имен:

// g++ 4.0 in macosx:
00002dbe T __ZN7hideout9function1Ei // namespace hideout, function1 takes int, returns int
00002db0 T _function1

Если пользовательский код будет включать как ваш заголовок, так и otherlib.h затем ему нужно будет указать, какую функцию он хочет вызвать.

Если вы действительно в отчаянии, вы могли бы написать библиотеку-оболочку, которая использует пространства имен или префиксы или допускает трюк dlsym.Эта библиотека-оболочка должна быть динамически связана (чтобы избежать конфликтов символов).Затем динамическая библиотека могла бы безопасно использовать старую статическую библиотеку, встроенную в нее.Просто убедитесь, что вы не экспортируете символы из статической библиотеки при создании динамической библиотеки-оболочки.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top