我正在尝试从命令行使用mex链接库,或者更确切地说,从makefile链接库。我是从我在这里发布的Makefile中做到的:
BDDM_MATLAB = @matlabhome@
MEXCC = $(BDDM_MATLAB)/bin/mex
MEXFLAGS = -v -largeArrayDims -O
MEXEXT = mexa64
TDIR = $(abs_top_srcdir)/test
IDIR = $(abs_top_srcdir)/src
LDIR = $(abs_top_srcdir)/lib
LOP1 = $(CUDA_LDFLAGS) $(LIBS)
SOURCES := $(wildcard *.cpp)
OBJS = $(SOURCES:.cpp=.o)
mTESTS = $(addprefix $(TDIR)/, $(SOURCES:.cpp=.$(MEXEXT)))
all: $(TDIR) $(mTESTS)
$(OBJS) : %.o : %.cpp
$(MEXCC) $(MEXFLAGS) -c -outdir ./ -output $@ $(CUDA_CFLAGS) -I$(IDIR) CFLAGS="\$$CFLAGS -std=c99" $^
$(mTESTS) : $(TDIR)/%.$(MEXEXT) : %.o
$(MEXCC) $(MEXFLAGS) -L$(LDIR) -outdir $(TDIR) $^ $(LOP1) -lmpdcm LDFLAGS="-lcudart -lcuda"
.PHONY = $(TDIR)
$(TDIR):
$(MKDIR_P) $@
clean:
$(RM) *.o
libmpdcm是一个静态库,包括对两个共享库libcuda和libcudart的调用。我的环境有
export LD_LIBRARY_PATH = / usr / local / cuda-7.0 / lib64:$ LD_LIBRARY_PATH:
我的制作规则产生
/usr/local/MATLAB/R2014a/bin/mex -v -largeArrayDims -O -L/home/eaponte/projects/test_cpp/lib -outdir /home/eaponte/projects/test_cpp/test test_LayeredEEG.o -L/usr/local/cuda/lib64 -lcudart -lcuda -lmpdcm LDFLAGS="-lcudart -lcuda"
这将生成以下g ++命令:
/usr/bin/gcc -lcudart -lcuda -shared -O -Wl,--version-script,"/usr/local/MATLAB/R2014a/extern/lib/glnxa64/mexFunction.map" test_LayeredEEG.o -lcudart -lcuda -lmpdcm -L/home/eaponte/projects/test_cpp/lib -L/usr/local/cuda/lib64 -L"/usr/local/MATLAB/R2014a/bin/glnxa64" -lmx -lmex -lmat -lm -lstdc++ -o /home/eaponte/projects/test_cpp/test/test_LayeredEEG.mexa64
问题是之后我在Matlab中遇到链接错误:
Invalid MEX-file '/home/eaponte/projects/test_cpp/test/test_Fmri.mexa64': /home/eaponte/projects/test_cpp/test/test_Fmri.mexa64: undefined symbol: cudaFree
我知道解决方案只是将cuda库放在g ++命令的末尾
/usr/bin/gcc -lcudart -lcuda -shared -O -Wl,--version-script,"/usr/local/MATLAB/R2014a/extern/lib/glnxa64/mexFunction.map" test_LayeredEEG.o -lmpdcm -L/home/eaponte/projects/test_cpp/lib -L/usr/local/cuda/lib64 -L"/usr/local/MATLAB/R2014a/bin/glnxa64" -lmx -lmex -lmat -lm -lstdc++ -lcudart -lcuda -o /home/eaponte/projects/test_cpp/test/test_LayeredEEG.mexa64
如何从命令行(或从Makefile)实现运行mex?
答案 0 :(得分:2)
只是为了阐明问题和解决方案,并提供一些避免类似的帮助:
与GNU链接器链接的基本规则 您的问题makefile被违反的是:在要链接的实体的命令行序列中, 需要 符号定义的实体 必须 之前 那些 提供 定义。
链接序列中的目标文件(.o
)将整个合并到输出可执行文件中,
无论它是否定义了可执行文件使用的任何符号。 库
另一方面,仅检查它是否提供符号的任何定义
因而至今未定义,只有它提供的这些定义被链接到
可执行文件(我有点简化)。因此,链接不会开始,直到看到某个目标文件,
并且任何库都必须出现在需要定义的所有内容之后。
违反这一原则通常是由于某些链接器标志选项的无效捆绑引起的
和一些库选项一起成为make
- 变量及其在连接配方中的位置,
结果是捆绑选项被插入到有效的位置
标志但对库无效。在您的问题makefile中就是这样,LOP1
坏捆绑。
在典型情况下,捆绑会导致所有库放在所有目标文件之前,
再也没有提过。因此,目标文件会产生未定义的符号错误,因为库
它们要求链接器在发现任何未定义的符号之前看到它们,并被忽略。
在您的非典型案例中,结果显示libcudart
和libcuda
晚于您的唯一身份
目标文件test_LayeredEEG.o
- 但它不需要它们的符号 - 但早于
唯一确实需要来自它们的符号,即libmpdcm
库。所以他们被忽略了,
并且您构建了一个尚未与它们链接的.mex64
共享库。
很久以前 - GCC之前的4.5版 - 共享库(如libcudart
和libcuda
)免除
根据他们应该需要的要求,在链接器看到它们时,
为了被联系起来。无论如何,它们都与目标文件相关联,并且相信它们
这是如此并没有完全消亡。不是这样。默认情况下,共享库和
当且仅当需要时才会链接静态库。
为了避免这种陷阱,理解规范的命名是非常有帮助的
编译和链接中涉及的make
变量及其语义,以及
它们在make
的编译和链接配方中的规范用法。梅克斯是一个
C / C ++ / Fortran编译器的操纵器,它添加了一些自己的命令行选项:
对于make
目的,它是另一个编译器。对于它继承的选项和
传递给底层编译器,您希望在make
recipes。
这些变量最重要的make
变量及其含义:
CC
=您的C编译器,例如gcc
FC
=您的Fortran编译器,例如gfortran
CXX
=您的C ++编译器,例如g++
。LD
=您的链接器,例如ld
。但是你应该知道这只适用于特殊用途
应该直接调用链接器。通常,在您的。上调用真正的链接器
代表编译器。它可以从您传递的选项中推断出您是否
想要编译完成或链接完成,并将调用适当的工具。当你
想要完成链接,它会悄悄地增加你传递的链接器选项
额外的那些指定非常令人厌烦,但确保
链接获取所有正确的标志和库的语言
程序你正在链接。因此几乎总是,将您的编译器指定为您的
接头 AR
=您的归档工具(静态库构建器)CFLAGS
= C编译选项FFLAGS
= Fortran编译的选项CXXFLAGS
= C ++编译选项CPPFLAGS
= C预处理器的选项,适用于使用它的任何编译器。 当你的意思CPPFLAGS
CXXFLAGS
的常见错误
LDFLAGS
=联系选项, N.B。不包括库选项,-l<name>
LDLIBS
=关联的图书馆选项,-l<name>
用于编译和链接的规范make
规则:
C源文件$<
到目标文件$@
:
$(CC) $(CPPFLAGS) $(CFLAGS) -c $@ $<
免费从Fortran文件$<
到目标文件$@
,并进行预处理:
$(FC) $(CPPFLAGS) $(FFLAGS) -c $@ $<
(无需预处理,删除$(CPPFLAGS)
)
C ++源文件$<
到目标文件$@
:
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $@ $<
将目标文件$ ^链接到可执行文件$ @:
$(<compiler>) $(LDFLAGS) -o $@ $^ $(LDLIBS)
如果你能尽可能多地编写makefile,以便a)你已经为正确的变量分配了正确的选项
这个词汇表,和b)使用规范的make
食谱,那么你的路径会更顺畅。
BTW ......
你的makefile有以下错误:
.PHONY = $(TDIR)
这显然是尝试$(TDIR)
成为phony target,
但语法错了。它应该是:
.PHONY: $(TDIR)
作业的作用就是创建名为make
的{{1}}变量,其值为.PHONY
,
并且不会使$(TDIR)
成为假目标。
哪个是幸运的,因为$(TDIR)
是你的输出目录,而不是假的
目标
您希望在需要输入任何内容之前确保$(TDIR)
创建make
它,但你不希望它成为那些文物的正常先决条件,这是必须的
只要触及$(TDIR)
的时间戳,就make
重建它们。大概是这样的
为什么你认为这是一个虚假的目标。
您真正想要的$(TDIR)
是order-only prerequsite
将在那里输出的$(TDIR)
。这样做的方法是将$(mTESTS)
规则修改为:
$(mTESTS)
如果需要,在$(mTESTS) : $(TDIR)/%.$(MEXEXT) : %.o | $(TDIR)
之前,这将导致$(TDIR)
,但是
但在确定$(mTESTS)
是否时,将不会考虑$(TDIR)
需要制作。
另一方面,目标$(mTESTS)
和all
是虚假的目标:没有这样的人工制品
要制作,所以你应该告诉clean
:
make
答案 1 :(得分:1)
正如评论中所指出的,问题是编译标志中动态库的顺序。在搜索了原因之后,我在SO中发现静态库需要在考虑依赖顺序的情况下进行链接。在我的例子中,库libmpdc依赖于libcuda和libcudart但是在左边。解决方案是交换makefile中的顺序:
$(mTESTS) : $(TDIR)/%.$(MEXEXT) : %.o
$(MEXCC) $(MEXFLAGS) -L$(LDIR) -outdir $(TDIR) $^ $(LOP1) -lmpdcm LDFLAGS="-lcudart -lcuda"
到
$(mTESTS) : $(TDIR)/%.$(MEXEXT) : %.o
$(MEXCC) $(MEXFLAGS) -L$(LDIR) -outdir $(TDIR) $^ -lmpdcm $(LOP1)