LINUX.ORG.RU

Линковка библиотек с одинаковыми именами функций

 , ,


0

1

Не было печали, пока не решил еще одну библиотеку в проект засунуть и оказалось что имена функций повторяются

Как победить можно???

# make -j2 -B Recorder
rm -f Recorder
gcc -c RecorderFDisk.c -I./util-linux/ -Wall -pedantic -O3
gcc -c RecorderArchive.c -I./paho.mqtt.c/src/ -Wall -pedantic -O3
gcc -c RecorderFFmpeg.c -I./FFmpeg/ -Wall -pedantic -O3
gcc -c RecorderFFserver.c -I./FFmpeg/ -O3
g++ -o Recorder Recorder.cpp ./libcommon/Sys.cpp                                \
    RecorderFDisk.o RecorderArchive.o RecorderFFmpeg.o RecorderFFserver.o       \
    ./util-linux/libblkid/src/libblkid_la-probe.o                               \
    ./util-linux/libuuid/src/libuuid_la-parse.o                                 \
    ./util-linux/libuuid/src/libuuid_la-unparse.o                               \
    ./util-linux/libuuid/src/libuuid_la-gen_uuid.o                              \
    ./util-linux/disk-utils/fdisk-fdisk-list.o                                  \
    ./util-linux/.libs/libcommon.a                                              \
    ./util-linux/.libs/libsmartcols.a                                           \
    ./util-linux/.libs/libtcolors.a                                             \
    ./util-linux/.libs/libblkid.a                                               \
    ./util-linux/.libs/libuuid.a                                                \
    ./util-linux/.libs/libfdisk.a                                               \
    ./FFmpeg/libavdevice/libavdevice.a                                          \
    ./FFmpeg/libavfilter/libavfilter.a                                          \
    ./FFmpeg/libavformat/libavformat.a                                          \
    ./FFmpeg/libavcodec/libavcodec.a                                            \
    ./FFmpeg/libavutil/libavutil.a                                              \
    ./FFmpeg/libswscale/libswscale.a                                            \
    ./FFmpeg/libswresample/libswresample.a                                      \
    ./paho.mqtt.c/build/src/libpaho-mqtt3a.a                                    \
    -lpthread -ltinfo -lm -lx264 -lv4l2 -lasound -Wall -pedantic -O3
./paho.mqtt.c/build/src/libpaho-mqtt3a.a(WebSocket.c.o): In function `uuid_generate':
WebSocket.c:(.text+0x11): multiple definition of `uuid_generate'
./util-linux/libuuid/src/libuuid_la-gen_uuid.o:/root/utils/util-linux/libuuid/src/gen_uuid.c:551: first defined here
./paho.mqtt.c/build/src/libpaho-mqtt3a.a(WebSocket.c.o): In function `uuid_unparse':
WebSocket.c:(.text+0xc0): multiple definition of `uuid_unparse'
./util-linux/libuuid/src/libuuid_la-unparse.o:/root/utils/util-linux/libuuid/src/unparse.c:74: first defined here
collect2: error: ld returned 1 exit status
Makefile:39: ошибка выполнения рецепта для цели «Recorder»
make: *** [Recorder] Ошибка 1

★★★

Ответ на: комментарий от EXL

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

rootree
()
Ответ на: комментарий от wolverin

Смотрим https://github.com/eclipse/paho.mqtt.c

/** @brief converts a uuid to a string */
void uuid_unparse( uuid_t uu, char *out )
{
        int i;
        for ( i = 0; i < 16; ++i )
        {
                if ( i == 4 || i == 6 || i == 8 || i == 10 )
                {
                        *out = '-';
                        ++out;
                }
                out += sprintf( out, "%02x", uu[i] );
        }
        *out = '\0';
}

и util-linux/libuuid/src/unparse.c
https://github.com/util-linux/util-linux/


void uuid_unparse(const uuid_t uu, char *out)
{
#ifdef UUID_UNPARSE_DEFAULT_UPPER
        uuid_fmt(uu, out, hexdigits_upper);
#else
        uuid_fmt(uu, out, hexdigits_lower);
#endif
}

Гм.
Объявление параметров немного разное.
В одной функции: uuid_t uu в другой const uuid_t uu.

Как бы linker не должен был ругаться?

Forum0888
()
Ответ на: комментарий от EXL

Так объявление же параметров разнится.

А мамия, нужно при вызове функции в коде нужно, чтобы параметр был объявлен как const?

А так получается неоднозначность (проблема где-то здесь).
По идее linker должен уметь различить эти две функции.

Forum0888
()
Ответ на: комментарий от wolverin

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

Попробуйте (для эксперимента) аргумент при вызове передавать как const.

Forum0888
()
Ответ на: комментарий от Forum0888

Попробуйте (для эксперимента) аргумент при вызове передавать как const.

Компилятор при парсинге кода будет использовать ту функцию, которая больше соответствует аргументам.
А здесь уже нужно анализировать код, чтобы понять какую функцию нам нужно вызвать.

Forum0888
()
Ответ на: комментарий от wolverin

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

Forum0888
()
Ответ на: комментарий от Forum0888

К счастью

void uuid_unparse_upper(const uuid_t uu, char *out)
{
        uuid_fmt(uu, out, hexdigits_upper);
}
вызывает uuid_fmt()
static void uuid_fmt(const uuid_t uuid, char *buf, char const *restrict fmt)
{
        char *p = buf;
        int i;

        for (i = 0; i < 16; i++) {
                if (i == 4 || i == 6 || i == 8 || i == 10) {
                        *p++ = '-';
                }
                size_t tmp = uuid[i];
                *p++ = fmt[tmp >> 4];
                *p++ = fmt[tmp & 15];
        }
        *p = '\0';
}

которая выполняет ту же функциональность, что и


/** @brief converts a uuid to a string */
void uuid_unparse( uuid_t uu, char *out )
{
        int i;
        for ( i = 0; i < 16; ++i )
        {
                if ( i == 4 || i == 6 || i == 8 || i == 10 )
                {
                        *out = '-';
                        ++out;
                }
                out += sprintf( out, "%02x", uu[i] );
        }
        *out = '\0';
}

так что флажок --allow-multiple-definition «правильно помог».

А вот что линкеру не понравилось, мне не понятно.

Forum0888
()
Ответ на: комментарий от EXL

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

rootree
()
Ответ на: комментарий от rootree

А вообще у ТС проблема с архитектурой кода, раз у него линкуются две одинаковые функции в один бинарник.

В двух библиотеках (это не его код) встретились функции, имеющие одинаковое имя.

Forum0888
()
Ответ на: комментарий от Forum0888

Я это понял. Поэтому и говорю, что нужно как-то решать эту проблему на корню. Использовать allow-multiple-definition на постоянной основе плохая идея, если только это уже не законченный продукт. Подключит ТС ещё какую-то библиотеку, где будет ещё одна коллизия имён, вот только в этот раз логика в этой функции будет совсем иной (например, в этой библиотеке uuid_generate будет возвращать uuid_t вместо void). Или добавит свою функцию, имя которой пересекётся с именем функции из какой-нибудь библиотеки. И всё, привет долгая ловля ошибок в рантайме, потому что линкер это тихо проглотит.

rootree
()
Ответ на: комментарий от Forum0888

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

А вообще, до тех пор, пока ты играешься со своим кодом наедине, можешь делать что угодно. Никто не запрещает. Я лишь советую ;)

rootree
()
Ответ на: комментарий от Forum0888

Лучше все же разработчикам библиотек сообщить о коллизии имен.

Нет, лучше функцию поместить в какую-нибудь стандартную библиотеку.
Скорее всего она уже имеется в какой-то (функция то «типовая»).

Forum0888
()
Ответ на: комментарий от rootree

Никак не отменяет того, что можно расставить статики

Где? В исходниках чужих относительно проекта библиотек? Новая версия прилетает и снова всё разваливается. Тут лучше действительно зарепортить разработчику libpaho-mqtt3a случай коллизии c системной libuuid.

Глядишь там тоже не будут заниматься велосипедостроением, а возьмут системную libuuid, либо в static на своей стороне уже обернут.

Проблема с этим лишь одна – время. И пока ТС ждёт ответа на репорт и обновление либы, флажок --allow-multiple-definition ему поможет.

Но соглашусь, что это временное решение. И мне стоило написать о его опастности прежде чем советовать. Что поделать, в С не завезли namespace’ы.

EXL ★★★★★
()
Последнее исправление: EXL (всего исправлений: 1)
Ответ на: комментарий от Forum0888

И кстати, вот ты в код залез, а самого нужного почему-то не увидел.

А ведь там:

#if !(defined(_WIN32) || defined(_WIN64))
#if defined(LIBUUID)
#include <uuid/uuid.h>
#else /* if defined(USE_LIBUUID) */

https://github.com/eclipse/paho.mqtt.c/blob/eff2da4875725509fc97641b118d6badf3e3a08f/src/WebSocket.c#L92-L94

Следовательно наиболее оптимальным для TC решением проблемы будет убрать флажок -Wl,--allow-multiple-definition и добавить флажок -DLIBUUID, после чего ошибка должна уйти и «вредная» линковка тоже.

EXL ★★★★★
()
Последнее исправление: EXL (всего исправлений: 1)
Ответ на: комментарий от Forum0888

Подправить код не проблема

Проблема, когда этот код не твой, а в какой-то либе. Завтра ты забудешь что именно ты там подправлял, послезавтра прилетит обновление и начинай вспоминать и накладывать патчи по новой…

Подправить макросы не проблема

Так а не нужно ничего поправлять. Там уже в коде разработчиком либы предусмотрен вариант выкидывания этих функций uuid_generate() и uuid_parse() в том случае, если код этой библиотеки компилируется с флагом -DLIBUUID, видимо с этой проблемой уже сталкивались.

EXL ★★★★★
()
Последнее исправление: EXL (всего исправлений: 2)
Ответ на: комментарий от EXL

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

wolverin ★★★
() автор топика
Ответ на: комментарий от EXL

осталось разобраться как ее собрать с этим флагом

# cmake -DPAHO_BUILD_STATIC=TRUE -DPAHO_WITH_SSL=TRUE -DLIBUUID=TRUE
-- CMake version: 3.5.1
-- CMake system name: Linux
-- Timestamp is 2023-01-24T03:10:28Z
-- Configuring done
-- Generating done
CMake Warning:
  Manually-specified variables were not used by the project:

    LIBUUID

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

Ты определяешь этот дефайн для самого CMake, а не для кода. Попробуй:

cmake -DCMAKE_C_FLAGS=-DLIBUUID

И потом смотри на нормальный verbose-лог компиляции:

make VERBOSE=1

При сборке файла WebSocket.c флажок -DLIBUUID стоять должен обязательно.

EXL ★★★★★
()
Ответ на: комментарий от EXL

засунул #define LIBUUID прям в WebSocket.h, теперь очевидно нет динамической линковки библиотеки, хотя uuid-dev пакет поставил.. сейчас попробую ваш вариант

[ 60%] Building C object src/CMakeFiles/paho-mqtt3a-static.dir/MQTTAsyncUtils.c.o
../src/libpaho-mqtt3c.so.1.3.10: undefined reference to `uuid_generate'
collect2: error: ld returned 1 exit status
test/CMakeFiles/test_sync_session_present.dir/build.make:95: recipe for target 'test/test_sync_session_present' failed
make[2]: *** [test/test_sync_session_present] Error 1
CMakeFiles/Makefile2:805: recipe for target 'test/CMakeFiles/test_sync_session_present.dir/all' failed
make[1]: *** [test/CMakeFiles/test_sync_session_present.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....
[ 60%] Building C object test/CMakeFiles/test11.dir/test11.c.o
[ 61%] Linking C executable test_sync_session_present-static
../src/libpaho-mqtt3c.a(WebSocket.c.o): In function `WebSocket_connect':
WebSocket.c:(.text+0x5cc): undefined reference to `uuid_generate'
collect2: error: ld returned 1 exit status
test/CMakeFiles/test_sync_session_present-static.dir/build.make:95: recipe for target 'test/test_sync_session_present-static' failed
make[2]: *** [test/test_sync_session_present-static] Error 1
CMakeFiles/Makefile2:842: recipe for target 'test/CMakeFiles/test_sync_session_present-static.dir/all' failed
make[1]: *** [test/CMakeFiles/test_sync_session_present-static.dir/all] Error 2
[ 62%] Linking C executable test11
../src/libpaho-mqtt3a.so.1.3.10: undefined reference to `uuid_generate'
collect2: error: ld returned 1 exit status
test/CMakeFiles/test11.dir/build.make:95: recipe for target 'test/test11' failed
make[2]: *** [test/test11] Error 1
CMakeFiles/Makefile2:916: recipe for target 'test/CMakeFiles/test11.dir/all' failed
make[1]: *** [test/CMakeFiles/test11.dir/all] Error 2
[ 62%] Linking C static library libpaho-mqtt3a.a
[ 62%] Built target paho-mqtt3a-static
Makefile:160: recipe for target 'all' failed
make: *** [all] Error 2
wolverin ★★★
() автор топика
Ответ на: комментарий от EXL

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

# find / -name libuuid.so
/usr/lib/arm-linux-gnueabihf/libuuid.so
/opt/util-linux/.libs/libuuid.so

wolverin ★★★
() автор топика
Ответ на: комментарий от Siborgium

Более того, перегрузка это концепция языка, а здесь проблема линковки.

Так проблема и возникает от того, что в двух разных библиотеках
имеется функция с одинаковым именем и с почти одинаковыми
наборами параметров (в одной из функций параметр с const).

Для C++ это не проблема, а в Си - проблема (для линковки).

В логе правда еще имеется интересная строка

Makefile:39: ошибка выполнения рецепта для цели «Recorder»
make: *** [Recorder] Ошибка 1

Forum0888
()
Последнее исправление: Forum0888 (всего исправлений: 5)