使用Emscripten编译C++版OpenFace出现未解析符号警告求助
我在使用Emscripten编译C++编写的OpenFace项目时,遇到了“unresolved symbol”(未解析符号)警告。执行命令em++ FaceLandmarkVid.cpp -std=c++11 -o OpenFace.bc将代码编译为bitcode时无任何警告;但执行em++ OpenFace.bc source.bc -o OpneFace.js将bitcode编译为JavaScript时,出现如下警告:
warning: unresolved symbol: _ZN12GazeAnalysis12EstimateGazeERKN16LandmarkDetector4CLNFERN2cv7Point3_IfEEffffb warning: unresolved symbol: _ZN16LandmarkDetector19FaceModelParametersC1ERNSt3__26vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEE warning: unresolved symbol: _ZN16LandmarkDetector22DetectLandmarksInVideoERKN2cv4Mat_IhEERNS_4CLNFERNS_19FaceModelParametersE warning: unresolved symbol: _ZN16LandmarkDetector23Calculate3DEyeLandmarksERKNS_4CLNFEdddd warning: unresolved symbol: _ZN16LandmarkDetector24CalculateAllEyeLandmarksERKNS_4CLNFE warning: unresolved symbol: _ZN16LandmarkDetector4CLNF5ResetEv warning: unresolved symbol: _ZN16LandmarkDetector4CLNFC1ENSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE warning: unresolved symbol: _ZN16LandmarkDetector7GetPoseERKNS_4CLNFEffff warning: unresolved symbol: _ZN2cv12VideoCaptureC1Ev warning: unresolved symbol: _ZN2cv12VideoCaptureD1Ev warning: unresolved symbol: _ZN2cv17CascadeClassifierD1Ev warning: unresolved symbol: _ZN2cv3Mat10deallocateEv warning: unresolved symbol: _ZN2cv8fastFreeEPv warning: unresolved symbol: _ZN5boost6system15system_categoryEv warning: unresolved symbol: _ZN5boost6system16generic_categoryEv warning: unresolved symbol: _ZN9Utilities10FpsTracker6GetFPSEv warning: unresolved symbol: _ZN9Utilities10FpsTracker8AddFrameEv warning: unresolved symbol: _ZN9Utilities10FpsTrackerC1Ev warning: unresolved symbol: _ZN9Utilities10Visualizer15ShowObservationEv warning: unresolved symbol: _ZN9Utilities10Visualizer18SetObservationGazeERKN2cv7Point3_IfEES5_RKNSt3__26vectorINS1_6Point_IdEENS6_9allocatorIS9_EEEERKNS7_INS2_IdEENSA_ISF_EEEEd warning: unresolved symbol: _ZN9Utilities10Visualizer18SetObservationPoseERKN2cv3VecIdLi6EEEd warning: unresolved symbol: _ZN9Utilities10Visualizer23SetObservationLandmarksERKN2cv4Mat_IdEEdRKNS2_IiEE warning: unresolved symbol: _ZN9Utilities10Visualizer6SetFpsEd warning: unresolved symbol: _ZN9Utilities10Visualizer8SetImageERKN2cv3MatEffff warning: unresolved symbol: _ZN9Utilities10VisualizerC1Ebbb warning: unresolved symbol: _ZN9Utilities15SequenceCapture12GetGrayFrameEv warning: unresolved symbol: _ZN9Utilities15SequenceCapture12GetNextFrameEv warning: unresolved symbol: _ZN9Utilities15SequenceCapture4OpenERNSt3__26vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEE warning: unresolved symbol: _ZN9Utilities15SequenceCaptureD1Ev warning: unresolved symbol: _ZNK16LandmarkDetector4CLNF15GetVisibilitiesEv
请问这种情况是否意味着存在仅有声明但无定义的函数?
没错,这些“unresolved symbol”警告完全对应了你代码中只存在函数/类声明,但没有提供具体实现(定义)的情况,我来帮你拆解下原因和解决思路:
为什么第一步编译没问题,第二步链接出问题?
- 执行
em++ FaceLandmarkVid.cpp -std=c++11 -o OpenFace.bc时,Emscripten只做了**编译(Compile)**阶段:它只需要确认代码里用到的函数/类有合法的声明(比如头文件里的定义),就能生成单个文件的bitcode,不需要知道这些函数的具体实现。 - 而第二步
em++ OpenFace.bc source.bc -o OpenFace.js是**链接(Link)**阶段:Emscripten需要把所有用到的符号(函数、类构造/析构函数等)的实现都找齐,才能生成完整的JavaScript/WebAssembly文件。如果某个符号只有声明没有实现,就会抛出这类警告。
这些未解析符号对应的缺失模块
从这些被混淆(mangled)的符号名可以看出,你缺失了几类关键实现:
- OpenFace自身模块的实现:比如
_ZN16LandmarkDetector4CLNFC1...是LandmarkDetector::CLNF类的构造函数,说明你没把OpenFace项目中LandmarkDetector、GazeAnalysis、Utilities这些子模块的bitcode文件加入链接命令。 - OpenCV库的实现:比如
_ZN2cv12VideoCaptureC1Ev是cv::VideoCapture的构造函数,说明你没有把用Emscripten交叉编译好的OpenCV库的bitcode加入链接。 - Boost库的实现:比如
_ZN5boost6system15system_categoryEv是Boost System库的符号,同理,Boost库的Emscripten编译版本也没被包含进来。
解决步骤
补全OpenFace子模块的bitcode:
先把OpenFace项目中所有依赖的子模块(比如LandmarkDetector.cpp、GazeAnalysis.cpp、Utilities/*.cpp等)都编译成bitcode文件,然后把它们全部加入链接命令。比如:em++ OpenFace.bc source.bc LandmarkDetector.bc GazeAnalysis.bc Utilities.bc -o OpenFace.js(另外注意你之前的命令里打错了
OpneFace.js,应该是OpenFace.js)添加第三方库的bitcode:
确保你已经用Emscripten交叉编译了OpenCV和Boost库(普通的桌面版库不能直接用),然后把它们的库文件(比如libopencv_core.bc、libboost_system.bc等)也加入到链接命令中。辅助工具:还原混淆的符号名
可以用c++filt工具把这些晦涩的符号转换成可读的函数名,方便你定位缺失的代码。比如执行:c++filt _ZN16LandmarkDetector4CLNFC1ENSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE会输出:
LandmarkDetector::CLNF::CLNF(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)这样你就能清楚知道是哪个类的哪个函数缺失了实现。
内容的提问来源于stack exchange,提问作者JaDoLo

