在cgo库中链接第三方静态库

I have a Go library that provides bindings for the C++ OpenImageIO library (OpenImageiGO). I've been happily building my bindings via the standard dynamic linking to libOpenImageIO, but am now trying to link statically. I'm running into an issue where no matter which combination of flags I try, the external linker fails with a ton of "undefined reference" errors. I seem to recall seeing this issue raised in the past, saying that there was an issue regarding the order in which the linker saw the symbols. But I can't seem to find this information again.

Here is a brief example of my most recent build attempt, trying to get it to link against static builds of boost, OpenColorIO, and 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++

And here are some of the cherry-picked errors, since it was a very long bit of output:

/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 can't seem to find references for OpenColorIO. And, OpenImageIO can't seem to find references for boost. It appears like the order in which things are happening during the linking isn't making the OpenColorIO or boost symbols available to OpenImageIO, so I get a bunch of symbol errors.

I'm hoping I am doing something simple and stupid that can be corrected in my build process. But the cgo static linking with external libs does seem a touch more complicated than the default dynamic linking approach.

Update #1

The answer given by @james-henstridge was right on, and I am almost fully built, except for one last hiccup. I'm getting failing references for yaml-cpp, needed by OpenColorIO, even though it seems I have the correct order.

Here is my latest env, where I have worked through all of the explicit static libs that had to be added:

$ 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

Update #2

Nevermind about update #1. It was specifically related to OpenColorIO and not a general issue.

1个回答



与静态库链接时, -l <​​/ code>标志的顺序很重要。 如果您使用 -lfoo -lbar -lbaz </ code>进行链接,则 libbar.a </ code>所需的任何符号都只会在 libbar.a </ code>和< 代码> libbaz.a </代码>。 即使 libfoo.a </ code>包含了您想要的符号,链接器也不会找到它们。</ p>

对于每个库,发生的情况是链接器 解压缩档案,并添加包含以前所引用符号的目标文件。 如果不需要存档中的特定对象文件,则将其忽略。</ p>

解决方法是确保在链接器标志所依赖的所有库之前列出每个库。 如果有任何依赖关系循环(不应存在),则可能有必要列出一个库两次。</ p>
</ div>

展开原文

原文

The order of the -l flags matters when you are linking with static libraries. If you link using -lfoo -lbar -lbaz, any symbols required by libbar.a will only be searched for in libbar.a and libbaz.a. Even if libfoo.a contains the symbols you're after, the linker won't find them.

What is happening is that for each library, the linker unpacks the archive and adds the object files that contain symbols referenced by whatever came before. If a particular object file in the archive isn't needed, it is ignored.

The fix is to make sure every library is listed before any it depends on in the linker flags. If there are any dependency loops (which there shouldn't be), it may be necessary to list a library twice.

dongpo4197
dongpo4197 虽然过时但好用。 Visual Studio库也是如此。
一年多之前 回复
dongqiang2069
dongqiang2069 你知道吗? 可能不理会yaml-cpp的问题。 显然,OpenColorIO(依赖项)具有使用yaml-cpp和tinyxml进行的某种未导出的设置。 我在工作中遇到的问题与在家中遇到的问题相同。 最有可能与此相关:github.com/imageworks/OpenColorIO/issues/318
6 年多之前 回复
doutu7123
doutu7123 libyaml-cpp.a是如何构建的? ranlib是否在构建过程中在生成的存档上运行? 否则,您可能会遇到无法解决归档文件中的符号依赖性的问题。
6 年多之前 回复
dongyi1996
dongyi1996 非常感谢。 这似乎是问题所在。 如果您不介意最后看一下我对原始问题的更新? 在成功链接之前,最后一个参考似乎仍然给我带来麻烦,但是由于我认为这里的顺序正确,因此这有点不同。
6 年多之前 回复
dongpalou5352
dongpalou5352 糟糕,如果我先列出了OpenImageIO,然后列出了OpenColorIO(前者需要),然后列出boost(其他人需要),则可能已经编译了吗? 将进行测试并回报!
6 年多之前 回复
立即提问