Почему я получаю ошибки "неопределенная ссылка на xxx", когда учтены все необходимые библиотеки и ссылки?

По сути, я пытаюсь использовать библиотеки redland rdf, но я не могу ссылаться на них. Когда я пробую простую базовую программу, использующую библиотеки Redland, я получаю следующие ошибки:

/usr/local/lib/librdf.a(rdf_init.o): In function `librdf_free_memory':
/home/ciaran/Software/redland/redland-1.0.17/src/rdf_init.c:671: undefined reference to `raptor_free_memory'
/usr/local/lib/librdf.a(rdf_init.o): In function `librdf_alloc_memory':
/home/ciaran/Software/redland/redland-1.0.17/src/rdf_init.c:689: undefined reference to `raptor_alloc_memory'
/usr/local/lib/librdf.a(rdf_init.o): In function `librdf_calloc_memory':
/home/ciaran/Software/redland/redland-1.0.17/src/rdf_init.c:707: undefined reference to `raptor_calloc_memory'

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

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

$ git clone git@github.com:CiaranWelsh/RedlandBuildTest.git

который содержит исходные файлы, необходимые для создания библиотек Redland, а также пример кода, который я использую (который ломается).

Для сборки библиотек вам также понадобится

    $ sudo apt install automake autoconf libtool gtk-doc-tools
    $ sudo apt install libxml2 libxml2-dev libxslt libxslt-dev libcurl4-openssl-dev libltdl-dev

Обратите внимание: я работаю над Ubuntu-18.04 в подсистеме Windows для Linux.

Чтобы получить, собрать и установить библиотеки, я использую следующие команды терминала:

#raptor2
wget "http://download.librdf.org/source/raptor2-2.0.15.tar.gz" 
tar -xvf raptor2-2.0.15.tar.gz
cd raptor2-2.0.15
./autogen.sh 
make
sudo make install
# redland (librdf)
wget "http://download.librdf.org/source/redland-1.0.17.tar.gz" 
tar -xvf redland-1.0.17.tar.gz
cd redland-1.0.17 
./autogen.sh
make
sudo make install
# rasqal
wget "http://download.librdf.org/source/rasqal-0.9.33.tar.gz" 
tar -xvf rasqal-0.9.33.tar.gz
cd rasqal-0.9.33
./autogen.sh 
make 
sudo make install

Которые доступны в репозитории github как сценарии оболочки (get-raptor.sh, get-rasqal.sh а также get-librdf.sh).

И мой минимальный скрипт CMake (тоже в репозитории):

cmake_minimum_required(VERSION 3.15)
project(RedlandBuildTest)

set(CMAKE_CXX_STANDARD 14)

find_library(RAPTOR2_STATIC_LIBRARY
        NAMES libraptor2.a
        PATHS /usr/local/lib
        )

find_path(RAPTOR2_INCLUDE_DIR
        NAMES raptor2.h
        PATHS /usr/local/include/raptor2
        )
find_library(RASQAL_STATIC_LIBRARY
        NAMES librasqal.a
        PATHS /usr/local/lib
        )

find_path(RASQAL_INCLUDE_DIR
        NAMES rasqal.h
        PATHS /usr/local/include/rasqal
        )

find_library(LIBRDF_STATIC_LIBRARY
        NAMES librdf.a
        PATHS /usr/local/lib
        )

find_path(LIBRDF_INCLUDE_DIR
        NAMES librdf.h
        PATHS /usr/local/include
        )

add_executable(RedlandBuildTest main.c)

target_include_directories(RedlandBuildTest PRIVATE
        ${RAPTOR2_INCLUDE_DIR}
        ${RASQAL_INCLUDE_DIR}
        ${LIBRDF_INCLUDE_DIR}
        )

target_link_libraries(RedlandBuildTest PRIVATE
        ${RAPTOR2_STATIC_LIBRARY}
        ${RASQAL_STATIC_LIBRARY}
        ${LIBRDF_STATIC_LIBRARY}
        curl
        xml2
        xslt
        ltdl
        )

get_target_property(LINK_LIBRARIES RedlandBuildTest LINK_LIBRARIES)
get_target_property(INCLUDE_DIRECTORIES RedlandBuildTest INCLUDE_DIRECTORIES)

message(STATUS "

LINK_LIBRARIES      ${LINK_LIBRARIES}
INCLUDE_DIRECTORIES ${INCLUDE_DIRECTORIES}

")

message(STATUS "

    RAPTOR2_STATIC_LIBRARY   ${RAPTOR2_STATIC_LIBRARY}
    RAPTOR2_INCLUDE_DIR      ${RAPTOR2_INCLUDE_DIR}

    RASQAL_STATIC_LIBRARY    ${RASQAL_STATIC_LIBRARY}
    RASQAL_INCLUDE_DIR       ${RASQAL_INCLUDE_DIR}

    LIBRDF_STATIC_LIBRARY    ${LIBRDF_STATIC_LIBRARY}
    LIBRDF_INCLUDE_DIR       ${LIBRDF_INCLUDE_DIR}

")

И вывод команды CMake:

#(looks good)
LINK_LIBRARIES      /usr/local/lib/libraptor2.a;/usr/local/lib/librasqal.a;/usr/local/lib/librdf.a;curl;xml2;xslt;ltdl 
INCLUDE_DIRECTORIES /usr/local/include/raptor2;/usr/local/include/rasqal;/usr/local/include


    RAPTOR2_STATIC_LIBRARY   /usr/local/lib/libraptor2.a
    RAPTOR2_INCLUDE_DIR      /usr/local/include/raptor2

    RASQAL_STATIC_LIBRARY    /usr/local/lib/librasqal.a
    RASQAL_INCLUDE_DIR       /usr/local/include/rasqal

    LIBRDF_STATIC_LIBRARY    /usr/local/lib/librdf.a
    LIBRDF_INCLUDE_DIR       /usr/local/include

Для сборки я использую CLion, который просто делает это в фоновом режиме:

mkdir build && cd build
CMake ..
make

Таким образом, давая мне ошибки компоновщика. Я копнул немного глубже, используяnm для проверки содержимого библиотек Redland.

$nm -A librdf.a > librdf.a.nmoutput.txt
$nm -A libraptor2.a > libraptor2.a.nmoutput.txt
$nm -A librasqal.a > librasqal.a.nmoutput.txt 

Первый обидный undfined reference ошибка

/usr/local/lib/librdf.a(rdf_init.o): In function `librdf_free_memory':
/home/ciaran/Software/redland/redland-1.0.17/src/rdf_init.c:671: undefined reference to `raptor_free_memory'

функционирует librdf_free_memory, который является определенной ссылкой внутри librdf.a

# librdf.a.nmoutput.txt
...
librdf.a:rdf_init.o:0000000000000740 T librdf_free_memory
...

Когда мы ищем неопределенную ссылку на raptor_free_memory, мы видим, что он действительно не определен внутри librdf.a..

#librdf.a.nmoutput.txt
...
librdf.a:rdf_init.o:                 U raptor_free_memory
...

Но это должно быть в libraptor2.a в любом случае, и если мы посмотрим, мы увидим, что это действительно есть и определено так, как должно быть:

# libraptor2.a.nmoutput.txt
...
libraptor2.a:raptor_general.o:0000000000000863 T raptor_free_memory
...

Я понимаю, что процесс связывания должен по существу заполнить неопределенную ссылку внутри librdf.a с определением внутри libraptor.a, но этого явно не происходит.

Почему это происходит?

1 ответ

Решение

Когда ваши статические библиотеки зависят друг от друга, порядок ссылок имеет значение (см. Этот ответ).

Если librdf зависит от libraptor библиотека (на что указывает ошибка ссылки), libraptorбиблиотека должна быть указана после librdfпри указании компоновщику. Попробуйте переупорядочить список библиотек в вашемtarget_link_libraries(), чтобы придерживаться этого порядка на основе зависимостей вашей библиотеки.

Другие вопросы по тегам