Почему я получаю ошибки "неопределенная ссылка на 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()
, чтобы придерживаться этого порядка на основе зависимостей вашей библиотеки.