使用OpenCV+CMake开发检测应用时,DLL中类出现未解析外部符号错误
使用OpenCV和CMake开发检测应用,定义了抽象类Detector及其派生类FaceDetector。项目包含一个可执行文件和两个DLL,但在main.cpp中调用DLL内类的构造函数或方法时,出现未解析外部符号链接错误:
unresolved external symbol "public: __cdecl FaceDetector::FaceDetector(struct detectorProperties)" (??0FaceDetector@@QEAA@UdetectorProperties@@@Z) referenced in function main
目前能正常创建detectorProperties结构体实例、调用drawLabel函数,但类无法正常使用——哪怕是如下的简单Test类,也无法在main中初始化:
class Test { public: Test() {} }
相关代码与配置
ObjectDetection.h
#pragma once #include <opencv2/opencv.hpp> #ifdef OBJECTDETECTION_EXPORTS #define OBJECTDETECTION_API __declspec(dllexport) #else #define OBJECTDETECTION_API __declspec(dllimport) #endif extern OBJECTDETECTION_API void drawLabel(cv::Mat & image, std::string label, int left, int top); extern OBJECTDETECTION_API struct detectorProperties { // some variables }; extern OBJECTDETECTION_API class Detector { protected: std::string modelPath; bool shouldSwapRB = false; bool active = false; bool shouldDrawRect = true; public: virtual void detect(cv::Mat& image) = 0; }; extern OBJECTDETECTION_API class FaceDetector : public Detector { private: cv::CascadeClassifier cs; std::vector<cv::Rect> facesInFrame; public: FaceDetector(detectorProperties props); void detect(cv::Mat& image); };
ObjectDetection.cpp
#include "ObjectDetection.h" #include <iostream> #include <fstream> #include <opencv2/opencv.hpp> using namespace std; void drawLabel(cv::Mat & image, string label, int left, int top) { // function code } FaceDetector::FaceDetector(detectorProperties props) { // constructor code } // code
main.cpp
#include "ObjectDetection.h" int main() { detectorProperties props; props.modelPath = "some/path"; FaceDetector det = FaceDetector(props); }
CMake构建输出
Selecting Windows SDK version 10.0.22000.0 to target Windows 10.0.22623. The C compiler identification is MSVC 19.35.32216.1 The CXX compiler identification is MSVC 19.35.32216.1 Detecting C compiler ABI info Detecting C compiler ABI info - done Check for working C compiler: C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.35.32215/bin/Hostx64/x64/cl.exe - skipped Detecting C compile features Detecting C compile features - done Detecting CXX compiler ABI info Detecting CXX compiler ABI info - done Check for working CXX compiler: C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.35.32215/bin/Hostx64/x64/cl.exe - skipped Detecting CXX compile features Detecting CXX compile features - done OpenCV ARCH: x64 OpenCV RUNTIME: vc16 OpenCV STATIC: OFF Found OpenCV 4.7.0 in C:/OpenCV/build/x64/vc16/lib You might need to add C:\OpenCV\build\x64\vc16\bin to your PATH to be able to run your applications. Could NOT find WrapVulkanHeaders (missing: Vulkan_INCLUDE_DIR) Configuring done (4.5s) Generating done (0.2s)
顶层CMake文件
# Qt 6.2.4 uses CMake 3.16, so that should be our minimum CMake version cmake_minimum_required(VERSION 3.16) # Set the name for the project project(DetectionApp) # Specify where should the executables and libraries created # This helps us avoid copying the files manually or using a post-build command set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMALE_PREFIX_PATH $ENV{Qt6_DIR}) set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_AUTOUIC_SEARCH_PATHS} src/Application) find_package(OpenCV REQUIRED) find_package(Qt6 REQUIRED COMPONENTS Gui Core Widgets) # Add the subdirectories for the different parts of the application add_subdirectory(src/Application) add_subdirectory(src/CameraInteraction) add_subdirectory(src/ObjectDetection) add_subdirectory(src/CameraInteraction_v2) add_subdirectory(src/ObjectDetection_v2) add_subdirectory(src/WebCam) set(CMAKE_VERBOSE_MAKEFILE ON)
Application CMake文件
# Set the project name project(Application) # Add the executable file(GLOB SOURCE_FILES "*.cpp") file(GLOB UI_FILES "*.ui") file(GLOB HEADER_FILES "*.h") add_executable(${PROJECT_NAME} ${HEADER_FILES} ${SOURCE_FILES} ${UI_FILES}) # Add the libraries add_dependencies(${PROJECT_NAME} CameraInteraction ObjectDetection ) # Allow the headers to be included in main.cpp target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_SOURCE_DIR}/src/CameraInteraction" "${CMAKE_SOURCE_DIR}/src/ObjectDetection" ${OpenCV_INCLUDE_DIRS} ) #Link this project with te runtime output dir target_link_directories(${PROJECT_NAME} PUBLIC ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ) target_link_libraries(${PROJECT_NAME} CameraInteraction ObjectDetection Qt6::Core Qt6::Widgets ${OpenCV_LIBS} ) set_target_properties(${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE ON MACOSX_BUNDLE ON )
ObjectDetection库CMake文件
# Set the project name project(ObjectDetection) # Take every header and source in the directory file(GLOB HEADER_FILES "*.h") file(GLOB SOURCE_FILES "*.cpp") # Add the library add_library(${PROJECT_NAME} SHARED ${HEADER_FILES} ${SOURCE_FILES}) # Link against OpenCV target_include_directories(${PROJECT_NAME} PUBLIC ${OpenCV_INCLUDE_DIRS}) target_link_libraries(${PROJECT_NAME} PUBLIC ${OpenCV_LIBS})
解决方案
核心问题:类的导出方式错误
Windows下,extern仅适用于全局函数和变量,不能用来导出类。__declspec(dllexport)需要直接修饰类定义,而非搭配extern使用,这是导致链接错误的根本原因。
修复步骤:
修正头文件中的类/结构体导出写法
移除类和结构体前的extern,直接用OBJECTDETECTION_API修饰,同时补充detectorProperties缺失的modelPath成员(否则main中访问该成员会编译错误):// 修正后的结构体定义 OBJECTDETECTION_API struct detectorProperties { std::string modelPath; // 补充缺失成员 // 其他变量 }; // 修正后的抽象类定义 OBJECTDETECTION_API class Detector { protected: std::string modelPath; bool shouldSwapRB = false; bool active = false; bool shouldDrawRect = true; public: virtual void detect(cv::Mat& image) = 0; }; // 修正后的派生类定义 OBJECTDETECTION_API class FaceDetector : public Detector { private: cv::CascadeClassifier cs; std::vector<cv::Rect> facesInFrame; public: FaceDetector(detectorProperties props); void detect(cv::Mat& image); };补充缺失的类方法实现
当前ObjectDetection.cpp中缺少FaceDetector::detect的实现,会引发新的链接错误,需补充:void FaceDetector::detect(cv::Mat& image) { // 实现检测逻辑 }优化CMake链接配置(可选)
移除Application CMake中的target_link_directories——CMake会自动管理通过add_library创建的库的路径,无需手动指定。
验证修复
修改完成后重新构建项目,链接错误应消失,FaceDetector可正常初始化并调用方法。
内容的提问来源于stack exchange,提问作者Feri Carnu

