openjpeg:解决静态链接时未定义引用错误:undefined reference to `__imp_opj_xxxxxxx'

解决办法

加入OPJ_STATIC宏定义。
1. 在#include "openjpeg-2.1/openjpeg.h"之前中加入OPJ_STATIC定义,如下

#ifndef OPJ_STATIC
#define OPJ_STATIC
#endif
#include "openjpeg-2.1/openjpeg.h"

2.如果你用cmake编译项目代码可以在CMakeLists.txt中加入OPJ_STATIC定义,类似如下

add_executable(testCImg ${SOURCE_LIST})
##指定使用openjpeg静态库
add_definitions(-DOPJ_STATIC)
target_link_libraries(testCImg "${OPENJP2_LIBRARY_STATIC}" )

=====================================================

问题溯源

如果你希望在项目中以静态库方式使用openjpeg,就要自己动手编译openjpeg的源码,关于如何生成openjpeg静态库参见我之前的博文《VS2015编译openjpeg(32/64位)》《mingw(gcc)编译openjpeg》

静态库(libopenjp2.a)生成好了,然后编译自己的代码时报错(openjpeg以动态库方式连接(libopenjp2.dll.a),则编译正常通过):

CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x110): undefined reference to __imp_opj_stream_destroy'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x11d): undefined reference to
__imp_opj_destroy_codec’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x156): undefined reference to __imp_opj_image_destroy'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x3a9): undefined reference to
__imp_opj_stream_create’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x3c8): undefined reference to __imp_opj_stream_set_user_data'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x3ec): undefined reference to
__imp_opj_stream_set_user_data_length’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x3fc): undefined reference to __imp_opj_stream_set_read_function'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x40c): undefined reference to
__imp_opj_stream_set_write_function’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x41c): undefined reference to __imp_opj_stream_set_skip_function'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x42c): undefined reference to
__imp_opj_stream_set_seek_function’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x4b8): undefined reference to __imp_opj_stream_create'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x4d7): undefined reference to
__imp_opj_stream_set_user_data’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x4fb): undefined reference to __imp_opj_stream_set_user_data_length'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x50b): undefined reference to
__imp_opj_stream_set_read_function’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x51b): undefined reference to __imp_opj_stream_set_write_function'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x52b): undefined reference to
__imp_opj_stream_set_skip_function’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x53b): undefined reference to __imp_opj_stream_set_seek_function'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x716): undefined reference to
__imp_opj_image_create’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0xa44): undefined reference to __imp_opj_set_default_encoder_parameters'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0xa60): undefined reference to
__imp_opj_create_compress’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0xa78): undefined reference to __imp_opj_set_info_handler'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0xa8d): undefined reference to
__imp_opj_set_warning_handler’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0xaa2): undefined reference to __imp_opj_set_error_handler'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0xab3): undefined reference to
__imp_opj_setup_encoder’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0xbc4): undefined reference to __imp_opj_start_compress'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0xbdc): undefined reference to
__imp_opj_encode’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0xbf4): undefined reference to __imp_opj_end_compress'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0xc9b): undefined reference to
__imp_opj_version’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0xfc7): undefined reference to __imp_opj_set_default_encoder_parameters'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x1158): undefined reference to
__imp_opj_set_default_encoder_parameters’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x128e): undefined reference to __imp_opj_create_compress'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x12a6): undefined reference to
__imp_opj_set_info_handler’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x12bb): undefined reference to __imp_opj_set_warning_handler'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x12d0): undefined reference to
__imp_opj_set_error_handler’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x12e1): undefined reference to __imp_opj_setup_encoder'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x12ee): undefined reference to
__imp_opj_stream_create’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x130d): undefined reference to __imp_opj_stream_set_user_data'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x131e): undefined reference to
__imp_opj_stream_set_user_data_length’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x132e): undefined reference to __imp_opj_stream_set_read_function'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x133e): undefined reference to
__imp_opj_stream_set_write_function’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x134e): undefined reference to __imp_opj_stream_set_skip_function'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x135e): undefined reference to
__imp_opj_stream_set_seek_function’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x145a): undefined reference to __imp_opj_start_compress'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x1472): undefined reference to
__imp_opj_encode’
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x148a): undefined reference to __imp_opj_end_compress'
CMakeFiles\testCImg.dir/objects.a(j2k_mem.cpp.obj):j2k_mem.cpp:(.text+0x15ac): undefined reference to
__imp_opj_version’

所有openjpeg的函数都找不到引用。。。。找不到引用的规律是所有的引用前都加了_imp_前缀,比如opj_stream_destroy变成了_img_opj_stream_destroy

满世界百度查资料,只有在这个贴子http://stackoverflow.com/questions/15726931/c-qt-undefined-reference-to-imp结尾处找到一点线索:
这里写图片描述
(IIRC是什么意思还没搞清楚,不去深究了)
编译器在连接的openjpeg时候错误地以连接动态库(DLL)的导入库(import library)的方式去连接静态库,在静态库中找不到具有_imp_前缀的函数名,就报错了.(编译器在生成导入库(import library)时,所有的函数名前都加了_imp_前缀,)
为了证实这个想法用UltraEdit打开openjpeg的动态库(DLL)的导入库(import library)libopenjp2.dll.a(或者别的不相关的导入库都行),以二进制方式查看,果然看到所有openjpeg.h中定义的函数都加了_imp_前缀。
这里写图片描述

现在的问题就是搞清楚,为什么编译器会以连接动态库(DLL)的导入库(import library)的方式去连接openjpeg的静态库,于是仔细研究openjpeg的CMakeLists.txt

发现BUILD_SHARD_LIBS开关控制了两个宏的定义

# Build the library
if(WIN32)
  if(BUILD_SHARED_LIBS)
    add_definitions(-DOPJ_EXPORTS)
  else()
    add_definitions(-DOPJ_STATIC)
  endif()
endif()

打开openjpeg.h找到了用到OPJ_STATICOPJ_EXPORTS的地方:

#if defined(OPJ_STATIC) || !defined(_WIN32)
/* http://gcc.gnu.org/wiki/Visibility */
#if __GNUC__ >= 4
#define OPJ_API    __attribute__ ((visibility ("default")))
#define OPJ_LOCAL  __attribute__ ((visibility ("hidden")))
#else
#define OPJ_API
#define OPJ_LOCAL
#endif
#define OPJ_CALLCONV
#else
#define OPJ_CALLCONV __stdcall
/*
The following ifdef block is the standard way of creating macros which make exporting 
from a DLL simpler. All files within this DLL are compiled with the OPJ_EXPORTS
symbol defined on the command line. this symbol should not be defined on any project
that uses this DLL. This way any other project whose source files include this file see 
OPJ_API functions as being imported from a DLL, wheras this DLL sees symbols
defined with this macro as being exported.
*/
#if defined(OPJ_EXPORTS) || defined(DLL_EXPORT)
#define OPJ_API __declspec(dllexport)
#else
#define OPJ_API __declspec(dllimport)
#endif /* OPJ_EXPORTS */
#endif /* !OPJ_STATIC || !_WIN32 */

上面的代码可以看出如果没有定义OPJ_STATIC,所有的OPJ_API 都会定义成(__declspec(dllexport)__declspec(dllimport)),openjpeg.h定义所有的函数定义都是OPJ_API 开头的,所以都会被定义被定义成DLL调用。

搞清楚原因,解决问题的办法就有了。于是就有了,本文开头的解决方法

发布了439 篇原创文章 · 获赞 365 · 访问量 160万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: Age of Ai 设计师: meimeiellie

分享到微信朋友圈

×

扫一扫,手机浏览