Matlab MEX文件的共享库位置:

10
我正在尝试编写一个使用libhdf5的matlab mex函数;我的Linux安装提供了libhdf5-1.8共享库和头文件。然而,我的Matlab版本r2007b提供了一个来自1.6版本的libhdf5.so。(显然,Matlab .mat文件引导了hdf5)。当我编译mex时,它在Matlab中会出现段错误。如果我将我的libhdf5版本降级到1.6(不是长期的解决方案),代码就可以编译并正常运行。
问题:我该如何解决这个问题?我该如何告诉mex编译过程链接到/usr/lib64/libhdf5.so.6而不是/opt/matlab/bin/glnxa64/libhdf5.so.0?当我尝试在编译中使用-Wl,-rpath-link,/usr/lib64时,会出现以下错误:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/../../../../x86_64-pc-linux-gnu/bin/ld: warning: libhdf5.so.0, needed by /opt/matlab/matlab75/bin/glnxa64/libmat.so, may conflict with libhdf5.so.6
/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: ld returned 1 exit status

    mex: link of 'hdf5_read_strings.mexa64' failed.

make: *** [hdf5_read_strings.mexa64] Error 1

如果没有其他办法,最后的救命稻草就是下载hdf5-1.6.5的本地头文件,但这并不具有未来性(我将来会升级Matlab版本)。有什么好的想法吗?

编辑:根据Ramashalanka的建议,我:

A)调用mex-v以获取3个gcc命令;最后一个是链接器命令;

B)使用-v调用该链接器命令以获取collect命令;

C)调用collect2 -v -t和其余标志。

我的输出中相关的部分:

/usr/bin/ld: mode elf_x86_64
/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/../../../../lib64/crti.o
/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/crtbeginS.o
hdf5_read_strings.o
mexversion.o
-lmx (/opt/matlab/matlab75/bin/glnxa64/libmx.so)
-lmex (/opt/matlab/matlab75/bin/glnxa64/libmex.so)
-lhdf5 (/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/../../../../lib64/libhdf5.so)
/lib64/libz.so
-lm (/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/../../../../lib64/libm.so)
-lstdc++ (/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/libstdc++.so)
-lgcc_s (/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/libgcc_s.so)
/lib64/libpthread.so.0
/lib64/libc.so.6
/lib64/ld-linux-x86-64.so.2
-lgcc_s (/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/libgcc_s.so)
/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/crtendS.o
/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/../../../../lib64/crtn.o

因此,实际上引用了位于/usr/lib64libhdf5.so。然而,我相信这被环境变量LD_LIBRARY_PATH覆盖了,我的Matlab版本在运行时会自动设置它,以便找到自己的版本,例如libmex.so等。
我认为crt_file.c示例要么不使用我正在使用的函数(H5DOpen在从1.6移动到1.8时有一个签名更改(是的,我正在使用-DH5_USE_16_API)),要么不太可能击中需要hdf5的Matlab内部部分。

在您的输出中,我看到了lib64/libhdf5.so这个动态库。您需要为静态库指定显式路径(带有.o后缀),而不是使用-lhdf5。如果还没有工作,请发布新的链接器输出。如果.so文件是列表中唯一的文件,则只包括该文件。如果您没有-lhdf5选项并且显式指定了静态库的路径(见下文),则LD_LIBRARY_PATH或任何其他路径(例如-L中的路径)都不应该成问题。我同意您对h5_crtfile.c的评论,但我们需要的所有信息都在上面的链接器输出中。 - Ramashalanka
وˆ‘و²،وœ‰libhdf5.oو–‡ن»¶ï¼›gentooçڑ„hdf5软ن»¶هŒ…وڈگن¾›ن؛†libhdf5.soم€پlibhdf5.aم€پlibhdf5.laن»¥هڈٹن¸€ن؛›Fortranه’ŒC++و–‡ن»¶م€‚وˆ‘需è¦پè‡ھه·±ç¼–译libhdf5هگ—ï¼ںè؟™وک¯ن¸€ن¸ھ选é،¹... - shabbychef
抱歉,我的意思是 .a 而不是 .o。你可以通过 strings libhdf5.a 等方式检查你拥有的 libhdf5.a 文件是否为正确版本。我在我的文件中看到了 HDF5 Version: 1.8.4。如果你无法获得正确的静态库作为二进制文件,那么编译也很容易。请参见我对你其他问题的评论。 - Ramashalanka
运行命令 strings /usr/lib64/libhdf5.a | grep 'library version' 将会输出以下内容:"HDF5 library version: 1.8.4 HDF5 library version: 1.8.4 ..." 我无法链接静态库,原因不明。同样的警告 -fPIC - shabbychef
好的。如果我关闭-bundle,我会发现与您遇到的相同的“undefined reference to 'main'”错误。因此,在调用mex时,您需要在系统上使用等效的-bundle。从手册中看来,似乎-fPIC(或-fpic)作为CFLAG和(也许)-shared作为LDFLAG。是的,您的头文件和库确实似乎是正确的版本。我怀疑您不需要重新编译hdf5以使用-fPIC,因为在我的系统上,使用-bundle一切都正常。 - Ramashalanka
2个回答

9
以下方法在我的系统上有效:
  1. Install hdf5 version 1.8.4 (you've already done this: I installed the source and compiled to ensure it is compatible with my system, that I get gcc versions and that I get the static libraries - e.g. the binaries offered for my system are icc specific).

  2. Make a target file. You already have your own file. I used the simple h5_crtfile.c from here (a good idea to start with this simple file first a look for warnings). I changed main to mexFunction with the usual args and included mex.h.

  3. Specify the static 1.8.4 library you want to load explicitly (the full path with no -L for it necessary) and don't include -lhdf5 in the LDFLAGS. Include a -t option so you can ensure that there is no dynamic hdf5 library being loaded. You also need -lz, with zlib installed. For darwin we also need a -bundle in LDFLAGS:

    mex CFLAGS='-I/usr/local/hdf5/include' LDFLAGS='-t /usr/local/hdf5/lib/libhdf5.a -lz -bundle' h5_crtfile.c -v
    

    For linux, you need an equivalent position-independent call, e.g. fPIC and maybe -shared, but I don't have a linux system with a matlab license, so I can't check:

    mex CFLAGS='-fPIC -I/usr/local/hdf5/include' LDFLAGS='-t /usr/local/hdf5/lib/libhdf5.a -lz -shared' h5_crtfile.c -v
    
  4. Run the h5_crtfile mex file. This runs without problems on my machine. It just does a H5Fcreate and H5Fclose to create "file.h5" in the current directory, and when I call file file.h5 I get file.h5: Hierarchical Data Format (version 5) data.

请注意,如果我在第三步中包含-lhdf5,那么当我尝试运行可执行文件时,Matlab会中止(因为它使用的是我的动态库版本1.6.5),所以这绝对解决了我的系统问题。
感谢您的问题。我上面的解决方案对我来说肯定比以前做的要容易得多。希望上述内容对您有用。

好的,我已经重写了这篇文章,请看看会有什么不同。 - Ramashalanka
我在shell中使用mex生成的gcc命令进行编译。因此,我尝试了您的解决方案,并跳过了步骤2和3;(顺便说一句,“-bundle”是特定于Darwin的)使用“h5_crtfile.c”,我收到了警告:“警告! 此应用程序包含的HDF5头文件与链接到该应用程序的HDF5库使用的版本不匹配。如果应用程序继续运行,可能会发生数据损坏或分段错误。 设置'HDF5_DISABLE_VERSION_CHECK'环境变量,则应用程序将继续运行。 头文件为1.8.4,库为1.6.5。” 然而,file.h5已经被创建!但是,在我的mex上使用这个技巧,它仍然会导致分段错误。 - shabbychef
警告!HDF5头文件等内容不会出现在Matlab窗口中,而是出现在调用Matlab的shell中。 (实际上,我认为它被管道传输到stderr)。这可能是您没有看到它的原因?仍在根据您的建议进行处理... - shabbychef
好的。像上面讨论的那样执行 strings /usr/lib64/libhdf5.a 来检查版本。还要检查您的头文件版本。在我的版本中,hdf5.h 没有信息,但是 H5public.h#define H5_VERS_INFO "HDF5 library version: 1.8.4"。如果您有不兼容的版本,最好下载并编译到单独的 /usr/local/hdf5 目录中,就像我一样,并将 -I 设置为我上面所述的方式。上面的输出可能更容易作为您问题中的 code 阅读(但是您不希望因为太多编辑而使自己成为社区 wiki)。 - Ramashalanka
执行命令 grep VERS_INFO /usr/include/H5public.h 会得到 "#define H5_VERS_INFO "HDF5 library version: 1.8.4"" 的输出,因此我认为这是合法的。 - shabbychef
显示剩余8条评论

3

我接受Ramashalanka的答案,因为它给了我确切的解决方案,现在我将在此处发布完整内容:

  1. 从hdf5网站下载hdf5-1.6.5库,并将头文件安装在本地目录中;
  2. 告诉mex查找“hdf5.h”在这个本地目录中,而不是标准位置(例如/usr/include);
  3. 告诉mex编译我的代码和matlab提供的共享对象库,并且不要在LDFLAGS中使用-ldfh5标志。

我使用的命令实际上是:

/opt/matlab/matlab_default/bin/mex -v CC#gcc CXX#g++ CFLAGS#"-Wall -O3 -fPIC -I./hdf5_1.6.5/src -I/usr/include -I/opt/matlab/matlab_default/extern/include" CXXFLAGS#"-Wall -O3 -fPIC -I./hdf5_1.6.5/src -I/usr/include -I/opt/matlab/matlab_default/extern/include " -O -lmwblas -largeArrayDims -L/usr/lib64 hdf5_read_strings.c /opt/matlab/matlab_default/bin/glnxa64/libhdf5.so.0

这将由我翻译成以下命令:

这将由我翻译成以下命令:

gcc -c -I/opt/matlab/matlab75/extern/include -DMATLAB_MEX_FILE -Wall -O3 -fPIC -I./hdf5_1.6.5/src -I/usr/include -I/opt/matlab/matlab_default/extern/include -O -DNDEBUG hdf5_read_strings.c
gcc -c -I/opt/matlab/matlab75/extern/include -DMATLAB_MEX_FILE -Wall -O3 -fPIC -I./hdf5_1.6.5/src -I/usr/include -I/opt/matlab/matlab_default/extern/include -O -DNDEBUG /opt/matlab/matlab75/extern/src/mexversion.c
gcc -O -pthread -shared -Wl,--version-script,/opt/matlab/matlab75/extern/lib/glnxa64/mexFunction.map -Wl,--no-undefined -o hdf5_read_strings.mexa64  hdf5_read_strings.o mexversion.o  -lmwblas -L/usr/lib64 /opt/matlab/matlab_default/bin/glnxa64/libhdf5.so.0 -Wl,-rpath-link,/opt/matlab/matlab_default/bin/glnxa64 -L/opt/matlab/matlab_default/bin/glnxa64 -lmx -lmex -lmat -lm -lstdc++

这个解决方案应该适用于我所有的目标机器,至少在我升级到matlab r2009a之前,我相信它使用的是hdf5-1.8。感谢您的所有帮助,对于这个问题我很抱歉——我认为我过于依赖打包版本的hdf5,而不是本地的一组头文件。

请注意,如果Mathworks在Matlab发行版中提供了一组头文件,这一切都将变得微不足道...


这是我处理需要链接boost-thread的多线程mex文件的方式。但一定有办法让它链接到系统库而不是Matlab内部的库,并且避免那种分段错误。被困在Matlab内置的任何boost中并不好。 - Chinasaur
关于Ramashalanka的有益建议,我也可以说,在我的boost-thread链接情况下,我不得不在Linux中进行这个解决方法,但在Mac中似乎mex命令不像在Linux中那样链接内部版本。 - Chinasaur
1
类似于这里的答案:https://dev59.com/t2LVa4cB1Zd3GeqPtBrA 可能会起作用(尽管问题有些不同)。如果我成功了,我会回报的。 - Chinasaur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接