repstosw 18 5 октября, 2023 Опубликовано 5 октября, 2023 · Жалоба Использую две библиотеки, самостоятельно собранные из исходников (исходники доступны): libcelt.a и libspeexdsp.a В обоих библиотеках есть модули - kiss_fft.c, функции которых отличаются: libcelt использует свой набор функций из своего модуля kiff_fft.c, а libspeex - соответственно свои. Объединить kiss_fft.c - не вариант: слишком разные реализации. При статической линковке я указываю соответственно -lcelt и -lspeexdsp. В итоге рождается нерабочий код, улетающий в исключение. Виной тому: линковщик берёт одну реализацию функций из одного модуля kiss_fft.c и применяет его к обоим библиотекам. Пока решил проблему - переименованием дублей функций во всех исходниках libspeex. Читал ещё про смену перфикса через objdump, но это муторно - нужно переправлять все хедеры функциям. Вопрос: как решить проблему более красиво? Надо чтобы функции в библиотеках работали только в пределах самой библиотеки и не распостранялись на другие библиотеки. Они static. Тулчейн - GCC. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 5 октября, 2023 Опубликовано 5 октября, 2023 · Жалоба 8 minutes ago, repstosw said: Вопрос: как решить проблему более красиво? самое простое и прямолинейное - исправить код в этих двух библиотеках, чтобы каждая использовала свои функции со своими уникальными префиксами, соотв. поменять названия в этих используемых конфликтных функциях 9 minutes ago, repstosw said: Они static static функции видны и доступны только в пределах файла компиляции, о каком static идет речь? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
arhiv6 18 5 октября, 2023 Опубликовано 5 октября, 2023 · Жалоба Если одно какое-то имя пересекается, можно попробовать одну эту функцию в обеих библиотеках пометить атрибутом __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() {}; // статическая функция, доступна только в пределах объектного файла Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 5 октября, 2023 Опубликовано 5 октября, 2023 (изменено) · Жалоба 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 Изменено 5 октября, 2023 пользователем repstosw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 235 5 октября, 2023 Опубликовано 5 октября, 2023 · Жалоба 4 часа назад, repstosw сказал: Вопрос: как решить проблему более красиво? Надо чтобы функции в библиотеках работали только в пределах самой библиотеки и не распостранялись на другие библиотеки. Они static. Тулчейн - GCC. namespace? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 173 5 октября, 2023 Опубликовано 5 октября, 2023 · Жалоба Результат быстрогугления дает нечто такое objcopy --redefine-sym old=new file Как обычно, базовые проблемы систем сборки не решены за прошедшие 100 лет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 5 октября, 2023 Опубликовано 5 октября, 2023 · Жалоба 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 С виду - эффективные. Попробую - результат напишу Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 173 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба 6 часов назад, repstosw сказал: А хедеры ручками переправлять? Если Вам нужно обращаться из своей программы то к функциям одной, то другой библиотеки, то, разумеется, функции должны иметь различные имена... А если экспортируемые (внешние) функции разных библиотек не имеют функций с одинаковым названием, то внутренние функции библиотек должны быть static. Но это Вам итак понятно, думаю. Мне не понятно: у Вас в разных модулях (каталогах) лежат libcelt.c и libspeexdsp.c, а рядом с ними лежат kiss_fft.c? Соответственно, в kiss_fft.c для разных модулей - разные реализции экспортируемых функций: для изолированной сборки библиотеки это не мешало, так? А когда обе библиотеки (скомпилированные) добавили в проект, линкер для библиотек подключал функции kiss_fft "не своего" модуля, так? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба 6 hours ago, repstosw said: Вот тут подсказали ещё пару решений: ага, но там же некий деятель заявил вот "это": Quote Понимаешь, что операции с целыми числами в си без плюсов и с плюсами разные? Без плюсов все обязано переводиться в инты и только так обрабатываться. На плюсах другие правила приведения типов. Наверняка еще различия найдутся, но этого достаточно, чтобы нельзя было переводить не глядя на каждую строчку кода. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 235 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба 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: Хотя конечно - применены презираемые тут многими макросы..... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 173 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба 1 час назад, jcxz сказал: Там в в заголовочном файле каждого модуля/кодека (в котором объявляются имена функций, используемых снаружи модуля), есть подобная конструкция: Ну там имена функций в библиотеках уже будут разными, т.к. препроцессором лишь приклеили префиксы. А тут речь, скорее, о создании независимых библиотек (модулей), каждая со своим набором (даже одинаковых по названиям) .c-файлов реализаций и даже функций внутри них. Вот только при использовании таких библиотек их "внутренности" (экспортируемые имена функций) будут видны всем. Это и пытается исправить ТС. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 235 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба 17 минут назад, Arlleex сказал: Вот только при использовании таких библиотек их "внутренности" (экспортируемые имена функций) будут видны всем. Это и пытается исправить ТС. "Внутренности" как раз и станут разными. На величину префикса. Это исправит проблему с конфликтами имён. Но в исходнике (.c-файле) они будут выглядеть одинаковыми. Вроде это как раз и нужно ТС. 17 минут назад, Arlleex сказал: А тут речь, скорее, о создании независимых библиотек Я так понял - ТС под "библиотеками" имеет в виду не "скомпилённые библиотеки", а "библиотеки в исходниках". В первом посте он это пишет. Поэтому моё решение вполне годное. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
yes 7 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба 10 hours ago, repstosw said: А хедеры ручками переправлять? sed -i 's/old/new/g' но там надо потренироваться в писании regexp-а old - чтоб он имена функций находил, а не фрагменты текста Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 6 октября, 2023 Опубликовано 6 октября, 2023 (изменено) · Жалоба Для ясности картины поясню: Либа 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"))) тоже не работает. Изменено 6 октября, 2023 пользователем repstosw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться