связывание сторонних статических библиотек в библиотеке cgo

У меня есть библиотека Go, которая предоставляет привязки для библиотеки C++ OpenImageIO (OpenImageiGO). Я с удовольствием создавал свои привязки с помощью стандартной динамической привязки к libOpenImageIO, но теперь пытаюсь привязать статически. Я столкнулся с проблемой, когда независимо от того, какую комбинацию флагов я пробовал, внешний компоновщик терпит неудачу с кучей ошибок «неопределенная ссылка». Кажется, я припоминаю, что видел, как этот вопрос поднимался в прошлом, говоря, что была проблема с порядком, в котором компоновщик видел символы. Но я не могу найти эту информацию снова.

Вот краткий пример моей последней попытки сборки, пытаясь связать ее со статическими сборками boost, OpenColorIO и OpenImageIO:

$ export CGO_CPPFLAGS="\
-I/path/to/boost/include \
-I/path/to/OpenColorIO/include \
-I/path/to/OpenImageIO/include"

$ export CGO_LDFLAGS="\
-L/path/to/boost/lib -lboost_thread_static -lboost_system_static \
-L/path/to/OpenColorIO/lib -lopencolorio \
-L/path/to/OpenImageIO/lib -lOpenImageIO"

$ go build -v -x --ldflags '-extldflags "-static"'  github.com/justinfx/openimageigo
...
CGO_LDFLAGS="/path/to/boost/lib/libboost_system_static.a" "/path/to/boost/lib/libboost_thread_static.a" "/path/to/OpenColorIO/lib/libopencolorio.a" "/path/to/OpenImageIO/lib/libOpenImageIO.a" "-lstdc++" /vol/apps/go/1.3.0/pkg/tool/linux_amd64/cgo -objdir $WORK/github.com/justinfx/openimageigo/_obj/ -- -I/path/to/boost/include -I/path/to/OpenColorIO/include -I/path/to/OpenImageIO/include -I./cpp -I $WORK/github.com/justinfx/openimageigo/_obj/ -I/path/to/boost/include -I/path/to/OpenColorIO/include -I/path/to/OpenImageIO/include color.go imagebuf.go imagebufalgo.go imagecache.go imageinput.go imageoutput.go imagespec.go oiio.go roi.go
...
/usr/bin/g++ -I . -fPIC -m64 -pthread -fmessage-length=0 -I/path/to/boost/include -I/path/to/OpenColorIO/include -I/path/to/OpenImageIO/include -I./cpp -I $WORK/github.com/justinfx/openimageigo/_obj/ -g -O2 -o $WORK/github.com/justinfx/openimageigo/_obj/all.cpp.o -c ./all.cpp

/usr/bin/g++ -I . -fPIC -m64 -pthread -fmessage-length=0 -o $WORK/github.com/justinfx/openimageigo/_obj/_cgo_.o $WORK/github.com/justinfx/openimageigo/_obj/_cgo_main.o $WORK/github.com/justinfx/openimageigo/_obj/_cgo_export.o $WORK/github.com/justinfx/openimageigo/_obj/color.cgo2.o $WORK/github.com/justinfx/openimageigo/_obj/imagebuf.cgo2.o $WORK/github.com/justinfx/openimageigo/_obj/imagebufalgo.cgo2.o $WORK/github.com/justinfx/openimageigo/_obj/imagecache.cgo2.o $WORK/github.com/justinfx/openimageigo/_obj/imageinput.cgo2.o $WORK/github.com/justinfx/openimageigo/_obj/imageoutput.cgo2.o $WORK/github.com/justinfx/openimageigo/_obj/imagespec.cgo2.o $WORK/github.com/justinfx/openimageigo/_obj/oiio.cgo2.o $WORK/github.com/justinfx/openimageigo/_obj/roi.cgo2.o $WORK/github.com/justinfx/openimageigo/_obj/all.cpp.o /path/to/boost/lib/libboost_system_static.a /path/to/boost/lib/libboost_thread_static.a /path/to/OpenColorIO/lib/libopencolorio.a /path/to/OpenImageIO/lib/libOpenImageIO.a -lstdc++

И вот некоторые из выбранных ошибок, так как это был очень длинный фрагмент вывода:

/path/to/OpenImageIO/lib/libOpenImageIO.a(OpenImageIO_dist^src^libOpenImageIO^color_ocio.cpp.o): In function `ColorConfig':
/path/to/OpenImageIO/OpenImageIO_dist/src/libOpenImageIO/color_ocio.cpp:141: undefined reference to `OpenColorIO::v1::SetLoggingLevel(OpenColorIO::v1::LoggingLevel)'
...
/path/to/OpenImageIO/lib/libOpenImageIO.a(OpenImageIO_dist^src^libOpenImageIO^imagebufalgo_copy.cpp.o): In function `boost::shared_mutex::lock()':
/path/to/boost/include/boost/thread/pthread/shared_mutex.hpp:138: undefined reference to `boost::this_thread::disable_interruption::~disable_interruption()'

OpenImageIO не может найти ссылки на OpenColorIO. И OpenImageIO не может найти ссылки для повышения. Похоже, что порядок, в котором все происходит во время связывания, не делает символы OpenColorIO или boost доступными для OpenImageIO, поэтому я получаю кучу ошибок символов.

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

Обновление №1

Ответ, данный @james-henstridge, был правильным, и я почти полностью готов, за исключением одного последнего сбоя. Я получаю ошибочные ссылки для yaml-cpp, необходимые для OpenColorIO, хотя кажется, что у меня правильный порядок.

Вот мой последний env, в котором я проработал все явные статические библиотеки, которые нужно было добавить:

$ export CGO_CPPFLAGS="-I/usr/local/include -I/usr/include"

$ export CGO_LDFLAGS="\
-L/usr/local/lib \
-L/usr/lib \
-L/usr/lib/x86_64-linux-gnu \
-lOpenImageIO \
-lHalf -lIex -lfreetype -lIlmThread -lImath -lIlmImf -lIlmThread \
-lOpenColorIO \
-lyaml-cpp -ltinyxml \
-lboost_regex -lboost_filesystem -lboost_thread -lboost_system \
-ltiff -lgif -lpng -ljpeg -lz \
-lrt -ldl"

$ go test -v -x --ldflags '-extldflags "-static"' github.com/justinfx/openimageigo
...
/home/justin/src/OpenColorIO/src/core/OCIOYaml.cpp:329: undefined reference to `YAML::Node::begin() const'
...
/home/justin/src/OpenColorIO/build/ext/dist/include/yaml-cpp/nodereadimpl.h:79: undefined reference to `YAML::Node::GetScalar(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&) const'
...
/usr/local/lib/libOpenColorIO.a(OCIOYaml.cpp.o): In function `_FindFromNodeAtIndex':
/home/justin/src/OpenColorIO/build/ext/dist/include/yaml-cpp/nodeutil.h:53: undefined reference to `YAML::Node::FindAtIndex(unsigned long) const'
collect2: ld returned 1 exit status

Обновление №2

Не говоря уже об обновлении №1. Это было конкретно связано с OpenColorIO, а не общей проблемой.


person jdi    schedule 12.07.2014    source источник


Ответы (1)


Порядок флагов -l имеет значение при компоновке статических библиотек. Если вы связываете с помощью -lfoo -lbar -lbaz, любые символы, необходимые для libbar.a, будут искаться только в libbar.a и libbaz.a. Даже если libfoo.a содержит нужные вам символы, компоновщик их не найдет.

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

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

person James Henstridge    schedule 12.07.2014
comment
Ооо, так что, если бы я сначала перечислил OpenImageIO, затем OpenColorIO (который нужен первому), а затем boost (который нужен другим), это могло бы скомпилироваться? Проверю и отчитаюсь! - person jdi; 12.07.2014
comment
Большое спасибо. Кажется, это проблема. Не возражаете ли вы в последний раз взглянуть на мое обновление исходного вопроса? Кажется, у меня все еще возникают проблемы с одной последней ссылкой перед успешной компоновкой, но это немного отличается, так как я думаю, что здесь у меня правильный порядок. - person jdi; 13.07.2014
comment
Как был собран libyaml-cpp.a? Был ли ranlib запущен полученный архив как часть процесса сборки? Без этого вы можете столкнуться с проблемами при разрешении зависимостей символов внутри архива. - person James Henstridge; 13.07.2014
comment
Знаешь что? Наверное, не обращайте внимания на мою проблему с yaml-cpp. По-видимому, OpenColorIO (зависимость) имеет какую-то неэкспортированную настройку с yaml-cpp и tinyxml. У меня та же проблема на работе, что и дома. Скорее всего, это связано с этим: github.com/imageworks/OpenColorIO/issues/318 - person jdi; 14.07.2014
comment
Старое, но хорошее. Это справедливо и для библиотек Visual Studio. - person soulsabr; 06.06.2019