1. 起因
心血来潮,想要编一个人脸库VOSM,感觉应该很容易,最近的版本还算新,有linux和windows版本。想在mac上跑一下,顺便把Xcode,CMake,LLVM都理一下
2. 麻烦
过程不细说了。回头看看,断断续续两天时间,头一天把LLVM和gcc,clang的关系搞懂了,cmake复习一下(其实从来没认真学过)。主要问题是昨天,先是link opencv和boost始终有undefined reference的错误,尽管这两个库都是通过MacPorts安装的。boost是因为MacPorts是多线程版本,库名多了个-mt,比如libboost_filesystem-mt,libboost_system-mt等。
另外很多建议改用libstdc++而不是libc++(clang)
Linking libraries OpenCV 2.4.2 on xcode 4.5.1
Under Build Settings>Apple LLVM compiler 4.1 - Language>C++ Standard Library: Change from libc++ (LLVM ...) to libstdc++ (GNU C++ ...).
Undefined symbols for architecture x86_64 error when linking OpenCV in Xcode
不过在最终解决的环境下好像并没用到。而且有人的解释也没看懂---跟标准库有什么关系???
@BRabbit27 "nm" command revealed that libc++ has a different symbol naming convention compared to libstdc++. So, we must choose the same C++ library that OpenCV was compiled with, otherwise the linker will fail to resolve symbols. Here is a screenshot showing different naming between libc++ & libstdc++
3. 大麻烦
真正的麻烦是在整个过程中慢慢发现(慢慢还是把整个库的结构理出来了,本来开始懒得看,只想编译成功就好)module之间有循环依赖(circular dependency)。主要是cvcommon和smbuilding。在*nix下没有问题,但好像mac就不行。
On Unix, it's possible to link a shared library that contains an unresolved symbol that the linker has never seen; in this situation, any other code that pulls in this shared library must provide that symbol, or the program will fail to load. Windows doesn't allow this sort of laxity.
最接近的问题是 Ignoring an undefined symbol in a dynamic library from Xcode,从答案中又查到各种ld的option可以做lazy symbol binding,
--allow-shlib-undefined --no-allow-shlib-undefined
The default behaviour is to report errors for any undefined symbols referenced in shared libraries if the linker is being used to create an executable, but to allow them if the linker is being used to create a shared library.
The reasons for allowing undefined symbol references in shared libraries specified at link time are that:
• There are some operating systems, eg BeOS and HPPA , where undefined symbols in shared libraries are normal.
--no-undefined -z defs
Normally the linker will generate an error message for each reported unresolved symbol but the option --warn-unresolved-symbols can change this to a warning.
4. 解决
睡了4个小时,本以为会难受的很,反而一点感觉都没有---跑步真是有用处,有大用处!
早上起来还是不服气,到office继续战斗--虽然已经下了决心“放下”,本不是必须要做的事情,通过这个过程也理解了不少东西。。。。
原来应该是linker的option不同吧。Mac肯定用的是dyld,上面那些options都是gcc ld的。。。其实上面已经提到-undefined dynamic_lookup,不过我用时提示unrecognized link option,没有往ld和dyld上想---当时人都木了,再次下决心绝不在一个问题上纠缠超过2小时!!
Easy check for unresolved symbols in shared libraries?
dyld: lazy symbol binding failed: Symbol not found
5. 小结
一度以为是Xcode里某些未知的设置改变了CMakeLists.txt里设定的行为。看起来不是,尽管也看到很多确实属于这种情况的---或者说某个Xcode版本的bug。
无论怎样,现在觉得*nix的东西确实还是少用GUI的好,再长的编译命令也只是个命令行,要添加什么选项都很容易。
unix make版本的调通了,xcode马上也build succeeded。想想今天凌晨不停的在GUI里变换测试各种选项,真是折磨
gcc -shared -fPIC ... -Wl,-z,defs
nm -C -U
otool -L build/Release/puzzle.node
otool -l build/Release/puzzle.node
-static-libstdc++
-Wl,
option
再次下决心绝不在一个问题上纠缠超过2小时!!