Перейти к содержанию
    

Как изолировать и избежать наложения одинаковых имён функций в статических библиотеках?

Использую две библиотеки, самостоятельно собранные из исходников (исходники доступны): libcelt.a и libspeexdsp.a

В обоих библиотеках есть модули - kiss_fft.c, функции которых отличаются:  libcelt использует свой набор функций из своего модуля kiff_fft.c, а libspeex - соответственно свои.

Объединить kiss_fft.c - не вариант: слишком разные реализации.

При статической линковке я указываю соответственно -lcelt и -lspeexdsp.   В итоге рождается нерабочий код, улетающий в исключение.  Виной тому: линковщик берёт одну реализацию функций из одного модуля kiss_fft.c и применяет его к обоим библиотекам.

Пока решил проблему - переименованием дублей функций во всех исходниках libspeex.  Читал ещё про смену перфикса через objdump, но это муторно - нужно переправлять все хедеры функциям.

 

Вопрос: как решить проблему более красиво?  Надо чтобы функции в библиотеках работали только в пределах самой библиотеки и не распостранялись  на другие библиотеки.  Они static. Тулчейн - GCC.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 minutes ago, repstosw said:

Вопрос: как решить проблему более красиво?

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

соотв. поменять названия в этих используемых конфликтных функциях

 

9 minutes ago, repstosw said:

Они static

static функции видны и доступны только в пределах файла компиляции,

о каком static идет речь?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если одно какое-то имя пересекается, можно попробовать одну эту функцию в обеих библиотеках пометить атрибутом __attribute__((visibility("hidden"))). Но правильнее делать так: библиотеки собираются с ключом компилятора  -fvisibility=hidden, чтобы ограничить области видимости функций по-умолчанию. А те функции, которые нужно оставить доступными пользователю для вызова, пометить атрибутом __attribute__((visibility("default"))). Пример:

// lib.h - интерфейс библиотеки

#pragma once

void test1(); 
// lib.c

#include "test.h"

#define ACCESSIBLE __attribute__((visibility("default")))
  
ACCESSIBLE void test1() {}; // функция доступна для вызова из вне, этим макросом помечаем все доступные пользователю функции
           void test2() {}; // функция не-статическая, но доступна только внутри библиотеки, из-за -fvisibility=hidden
    static void test3() {}; // статическая функция, доступна только в пределах объектного файла

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Forger said:

о каком static идет речь?

Имелось в виду что они все в стоставе статической библиотеки.  Не о ключевом слове "static" перед именами.

41 minutes ago, arhiv6 said:

Но правильнее делать так: библиотеки собирается с ключом компилятора  -fvisibility=hidden,

Обе библиотеки собираю с ключом -fvisibility=hidden, очевидно тулчейн игнорирует этот флаг.

Тулчейн:   xtensa-hifi4-elf-...  Это GCC, собранный с помощью crosstool-ng.

Полный набор опций сборки библиотек:

set TOOLCHAIN=xtensa-hifi4-elf-
  
set OPTIONS=-Ofast -std=c99 -DNDEBUG -DHAVE_CONFIG_H -fmax-errors=1 -ffast-math -fno-math-errno -fno-exceptions -fno-unwind-tables \
  -fno-asynchronous-unwind-tables -fomit-frame-pointer -ftree-vectorize -ffunction-sections -fdata-sections -fvisibility=hidden -Wall -Wextra

del *.o
del *.a

:COMPILE
%TOOLCHAIN%gcc %OPTIONS% -c bands.c
%TOOLCHAIN%gcc %OPTIONS% -c celt.c
%TOOLCHAIN%gcc %OPTIONS% -c cwrs.c
%TOOLCHAIN%gcc %OPTIONS% -c entcode.c
%TOOLCHAIN%gcc %OPTIONS% -c entdec.c
%TOOLCHAIN%gcc %OPTIONS% -c entenc.c
%TOOLCHAIN%gcc %OPTIONS% -c header.c
%TOOLCHAIN%gcc %OPTIONS% -c kiss_fft.c
%TOOLCHAIN%gcc %OPTIONS% -c laplace.c
%TOOLCHAIN%gcc %OPTIONS% -c mathops.c
%TOOLCHAIN%gcc %OPTIONS% -c mdct.c
%TOOLCHAIN%gcc %OPTIONS% -c modes.c
%TOOLCHAIN%gcc %OPTIONS% -c pitch.c
%TOOLCHAIN%gcc %OPTIONS% -c plc.c
%TOOLCHAIN%gcc %OPTIONS% -c quant_bands.c
%TOOLCHAIN%gcc %OPTIONS% -c rangedec.c
%TOOLCHAIN%gcc %OPTIONS% -c rangeenc.c
%TOOLCHAIN%gcc %OPTIONS% -c rate.c
%TOOLCHAIN%gcc %OPTIONS% -c vq.c

:LIBRARY
%TOOLCHAIN%ar qc libcelt.a ^
bands.o ^
celt.o ^
cwrs.o ^
entcode.o ^
entdec.o ^
entenc.o ^
header.o ^
kiss_fft.o ^
laplace.o ^
mathops.o ^
mdct.o ^
modes.o ^
pitch.o ^
plc.o ^
quant_bands.o ^
rangedec.o ^
rangeenc.o ^
rate.o ^
vq.o

 

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 часа назад, repstosw сказал:

Вопрос: как решить проблему более красиво?  Надо чтобы функции в библиотеках работали только в пределах самой библиотеки и не распостранялись  на другие библиотеки.  Они static. Тулчейн - GCC.

namespace?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Результат быстрогугления дает нечто такое

objcopy --redefine-sym old=new file

Как обычно, базовые проблемы систем сборки не решены за прошедшие 100 лет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

12 hours ago, jcxz said:

namespace?

В C ?

 

6 hours ago, Arlleex said:

Результат быстрогугления дает нечто такое

objcopy --redefine-sym old=new file

А хедеры ручками переправлять?

 

6 hours ago, Arlleex said:

Как обычно, базовые проблемы систем сборки не решены за прошедшие 100 лет.

Не знаю...

Вот тут подсказали ещё пару решений: https://gamedev.ru/code/forum/?id=279603

С виду - эффективные. Попробую - результат напишу

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 часов назад, repstosw сказал:

А хедеры ручками переправлять?

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

А если экспортируемые (внешние) функции разных библиотек не имеют функций с одинаковым названием, то внутренние функции библиотек должны быть static.

Но это Вам итак понятно, думаю. Мне не понятно: у Вас в разных модулях (каталогах) лежат libcelt.c и libspeexdsp.c, а рядом с ними лежат kiss_fft.c?

Соответственно, в kiss_fft.c для разных модулей - разные реализции экспортируемых функций: для изолированной сборки библиотеки это не мешало, так?

А когда обе библиотеки (скомпилированные) добавили в проект, линкер для библиотек подключал функции kiss_fft "не своего" модуля, так?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 hours ago, repstosw said:

Вот тут подсказали ещё пару решений:

ага, но там же некий деятель заявил вот "это":

Quote

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

56 минут назад, Arlleex сказал:

А когда обе библиотеки (скомпилированные) добавили в проект, линкер для библиотек подключал функции kiss_fft "не своего" модуля, так?

Я так понял у ТС проблемы с вызовами функций извне модулей.

 

Для их решения можно попробовать способ, применённый в Helix-библиотеке. Внутри Helix-а тоже есть разные кодеки (mp3, aac, ...), внутри которых есть функции с одинаковыми именами. Файлы - *.c.  И тем не менее - собираются нормально.

Там в в заголовочном файле каждого модуля/кодека (в котором объявляются имена функций, используемых снаружи модуля), есть подобная конструкция:

#define STAT_PREFIX     xmp3

#ifdef STAT_PREFIX
#define STATNAME(func)  concatABC(STAT_PREFIX, _, func)
#else
#define STATNAME(func)  func
#endif

//these symbols are common to all implementations
#define UnpackFrameHeader  STATNAME(UnpackFrameHeader)
#define UnpackSideInfo     STATNAME(UnpackSideInfo)
#define DecodeHuffman      STATNAME(DecodeHuffman)
#define Dequantize         STATNAME(Dequantize)
#define Imdct              STATNAME(Imdct)
#define UnpackScaleFactors STATNAME(UnpackScaleFactors)
#define Subband            STATNAME(Subband)

#define hdrTab             STATNAME(hdrTab)
#define sfBandTab          STATNAME(sfBandTab)

Это в .mp3-модуле.

В AAC-модуле аналогично:

#define STAT_PREFIX     xaac

#ifndef ASMDEF

#ifdef STAT_PREFIX
#define STATNAME(func)  concatABC(STAT_PREFIX, _, func)
#else
#define STATNAME(func)  func
#endif

//these symbols are common to all implementations
#define AllocateBuffers         STATNAME(AllocateBuffers)
#define FreeBuffers             STATNAME(FreeBuffers)

#define SetRawBlockParams       STATNAME(SetRawBlockParams)
#define PrepareRawBlock         STATNAME(PrepareRawBlock)
#define FlushCodec              STATNAME(FlushCodec)

#define UnpackADTSHeader        STATNAME(UnpackADTSHeader)
#define GetADTSChannelMapping   STATNAME(GetADTSChannelMapping)
#define UnpackADIFHeader        STATNAME(UnpackADIFHeader)
#define DecodeNextElement       STATNAME(DecodeNextElement)
#define DecodeNoiselessData     STATNAME(DecodeNoiselessData)
#define Dequantize              STATNAME(Dequantize)
#define StereoProcess           STATNAME(StereoProcess)
#define Pns                     STATNAME(Pns)
#define TnsFilter               STATNAME(TnsFilter)
#define Imdct                   STATNAME(Imdct)

#define InitSBR                 STATNAME(InitSBR)
#define DecodeSBRBitstream      STATNAME(DecodeSBRBitstream)
#define DecodeSBRData           STATNAME(DecodeSBRData)
#define FreeSBR                 STATNAME(FreeSBR)
#define FlushCodecSBR           STATNAME(FlushCodecSBR)

//global ROM tables
#define sampRateTab             STATNAME(sampRateTab)
#define predSFBMax              STATNAME(predSFBMax)
#define channelMapTab           STATNAME(channelMapTab)
#define elementNumChans         STATNAME(elementNumChans)
#define sfBandTabShort          STATNAME(sfBandTabShort)
#define sfBandTabLong           STATNAME(sfBandTabLong)
#define atabsShort              STATNAME(atabsShort)
#define atabsLong               STATNAME(atabsLong)

Как видно - есть одинаковые имена. Эти .h-файлы подключаются только каждый для файлов своего модуля.

А снаружи функции этих модулей вызываются с присоединёнными суффиксами:

xmp3_Dequantize();

или

xaac_Dequantize();

 

PS: Хотя конечно - применены презираемые тут многими макросы..... :biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, jcxz сказал:

Там в в заголовочном файле каждого модуля/кодека (в котором объявляются имена функций, используемых снаружи модуля), есть подобная конструкция:

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

А тут речь, скорее, о создании независимых библиотек (модулей), каждая со своим набором (даже одинаковых по названиям) .c-файлов реализаций и даже функций внутри них.

Вот только при использовании таких библиотек их "внутренности" (экспортируемые имена функций) будут видны всем. Это и пытается исправить ТС.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

17 минут назад, Arlleex сказал:

Вот только при использовании таких библиотек их "внутренности" (экспортируемые имена функций) будут видны всем. Это и пытается исправить ТС.

"Внутренности" как раз и станут разными. На величину префикса. Это исправит проблему с конфликтами имён. Но в исходнике (.c-файле) они будут выглядеть одинаковыми.

Вроде это как раз и нужно ТС.

17 минут назад, Arlleex сказал:

А тут речь, скорее, о создании независимых библиотек

Я так понял - ТС под "библиотеками" имеет в виду не "скомпилённые библиотеки", а "библиотеки в исходниках". В первом посте он это пишет.

Поэтому моё решение вполне годное.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 hours ago, repstosw said:

А хедеры ручками переправлять?

sed -i 's/old/new/g'

но там надо потренироваться в писании regexp-а old - чтоб он имена функций находил, а не фрагменты текста

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для ясности картины поясню:

Либа 1: libcelt. Она должна использовать свои функции из kiff_fft.c : kiss_fft() и kiss_fft_alloc().
Либа 2: libspeex. Она должна использовать свои функции из kiff_fft.c : kiss_fft() и kiss_fft_alloc().

Так как внутренности  kiss_fft() и kiss_fft_alloc() - разные.  И использование только одного для этих двух либ - приводит к нерабочим вариантам (ключ    --allow-multiple-definition)

Решение найдено.  После построения библиотек, меняем в libspeex имена этой паре проблемных функций:

objcopy --redefine-sym kiss_fft=speex_kiss_fft --redefine-sym kiss_fft_alloc=speex_kiss_fft_alloc libspeexdsp.a

Всё!

Тоесть - меняем не все объекты через префикс (иначе задолбимся править хедеры, при компиляции основного проекта это вылезет!), а только те, на которые линковщик кричит, что они multiple.

Вместо Libspeex, поменять имена функций можно было у libcelt. Разницы нет.

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

P.S. Что есть статическая либа в C по сути? Это набор объектников.  При линковке основной программы, ликовщику фиолетово на библиотеки и принадлежность - он просто подсовывает список объектников и всё. А там уже и обнаруживались пары функций с одинаковыми именами.

 

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

И __attribute__((visibility("hidden"))) тоже не работает.

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...