2015-11-06 66 views
2

我想從命令行使用mex,或者更確切地說,從makefile鏈接庫。我做這從一個Makefile我張貼在這裏:用g ++從命令行控制mex鏈接選項

BDDM_MATLAB = @[email protected] 

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 [email protected] $(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) [email protected] 

clean: 
    $(RM) *.o 

libmpdcm是包括兩個共享庫libcuda和libcudart調用靜態庫。我的環境有

出口LD_LIBRARY_PATH =在/ usr /本地/ 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庫在++命令

/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 

如何實現這一運行從命令行MEX(或從生成文件)的克的結束?

+0

這是在運行時,對不對?你可能只需要調整你的LD_LIBRARY_PATH或者LD_RUN_PATH(參見['setenv'](http://www.mathworks.com/help/matlab/ref/setenv.html)以在MATLAB內部完成)到包括CUDA運行時的位置。或者,如果您想鏈接靜態CUDA運行時,您可以在'mex'命令末尾列出.a文件。只是一個猜測,所以我沒有發佈答案。 – chappjc

+0

儘管我可以看到最後一個可能如何解決連接錯誤,但這三條命令行都沒有從鏈接 的角度完全有意義。請在您的問題中發佈makefile,以及用於運行失敗make的 命令行以及失敗make的完整 控制檯輸出(來自clean)。此外,什麼是 'libmpdcm'庫,它來自哪裏? –

+0

@chappjc我已經解決了您的意見。 – eaponte

回答

2

只是爲了說明問題和解決方案,並提供一些幫助避免類似:

的基本規則與GNU鏈接程序 鏈接,表明您的問題makefile文件已超越:在要鏈接的實體的命令行序列中,需要需要符號定義 必須出現以前的那些提供定義

鏈接序列中的目標文件(.o)將被整合到輸出可執行文件 中,而不管它是否定義了可執行文件使用的任何符號。一個 只是檢查,看看它是否提供了任何定義的符號 ,因此是未定義的,只有它提供的這樣的定義鏈接到可執行文件(我在某種程度上簡化) 。因此,直到一些目標文件被看到, 和任何庫必須出現在需要從其定義的所有東西之後,鏈接纔開始。這一原則

違反通常由一些連接器參數選項 和一些庫選項無能捆綁在一起出現成make -variable及其聯動配方,其結果是捆綁的選項在插入位置, 對於 標誌有效的位置,但對庫無效。這是在你的問題makefile中,LOP1和 不好的包。

在典型情況下,捆綁導致所有庫都放置在所有對象文件之前,並且從未再次提及。因此,目標文件會產生未定義的符號錯誤,因爲它們需要的庫 在鏈接器發現任何未定義的符號之前就被看到,並且被忽略。 在你的非典型的情況下,導致libcudartlibcuda被後來見過比你唯一 對象文件test_LayeredEEG.o - 然而這不需要從他們的符號 - 但早於 這也需要從他們的符號唯一,圖書館libmpdcm。所以他們被忽略, 和你建立了一個.mex64共享庫,但沒有與他們鏈接。

很久以前 - 預GCC 4.5 - 共享庫(如libcudartlibcuda)爲免除 從他們應該需要,在點,當連接器以鏈接看到他們, 的要求。無論如何,它們都被鏈接在一起,就像對象文件一樣,並且認爲這是如此並不完全消失。不是這樣。默認情況下,當且僅當需要的時候,共享庫和靜態庫纔會鏈接。

爲了避免這種陷阱是大大有助於瞭解 參與編譯和鏈接及其語義make變量的規範命名,並在編譯和鏈接的食譜 它們的規範使用了make。 Mex是C/C++/Fortran編譯器的一個操縱器,它增加了一些自己的命令行選項: 用於make的目的,它是另一種編譯器。對於它繼承的選項,並且 傳遞給底層編譯器,您希望遵守該編譯器在make配方中的用法。

這些都是make變量最有可能關係到你和它們的含義:

  • CC = C編譯器,例如gcc
  • FC =您的Fortran編譯器,例如gfortran
  • CXX =您的C++編譯器,例如g++
  • LD =您的鏈接器,例如ld。但是你應該知道,只有在專門用途 應該直接調用鏈接器。通常,編譯器會以您的 的名義調用真正的鏈接器。它可以從選項中推斷出您是否通過 編譯完成或鏈接完成,並且會調用相應的工具。當你想要鏈接完成時,它會悄悄地增加你通過 附加的鏈接器選項,它會非常煩人的指定,但確保 鏈接獲取所有正確的標誌和庫的語言您正在鏈接的程序爲 。因此,幾乎總是,將您的編譯器指定爲您的 鏈接器
  • AR =您的歸檔工具(靜態庫構建)的C語言編譯
  • FFLAGS =選項Fortran語言編譯
  • CXXFLAGS =爲C選++編譯
  • CPPFLAGS =爲C預處理器選項
  • CFLAGS =選項,任何使用它的編譯器。 避免當您的意思爲CXXFLAGS
  • LDFLAGS = N.B.B的選項時,編寫CPPFLAGS的常見錯誤。排除庫選項-l<name>
  • LDLIBS =進行聯動庫選項,-l<name>

和規範make規則編譯和鏈接:

C源文件$<到目標文件[email protected]

$(CC) $(CPPFLAGS) $(CFLAGS) -c [email protected] $< 

免提Fortran文件$<到目標文件[email protected],與預處理:

$(FC) $(CPPFLAGS) $(FFLAGS) -c [email protected] $< 

(無預處理,除去$(CPPFLAGS)

C++源文件$<到對象文件[email protected]

$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c [email protected] $< 

鏈接對象文件$ ^成可執行$ @:

$(<compiler>) $(LDFLAGS) -o [email protected] $^ $(LDLIBS) 

如果您可以儘可能多地編寫makefile以便a)您已將正確的選項從 這個詞彙表中分配給正確的變量,並且b)使用規範的make食譜,那麼您的路徑將會更平滑。

而BTW ...

Makefile中有以下錯誤:

.PHONY = $(TDIR) 

這顯然是企圖使$(TDIR)一個phony target, 但語法是錯誤的。它應該是:

.PHONY: $(TDIR) 

什麼這個分配是簡單地創建一個.PHONY變量make叫,隨着$(TDIR), 的價值,不會使$(TDIR)假目標。

這是幸​​運的,因爲$(TDIR)是您的輸出目錄,而不是假目標 。

你希望確保make創建$(TDIR)你需要輸出任何東西之前到 它,但你不希望它那些文物的正常prequisite,這將迫使 make重建他們時的$(TDIR)時間戳是感動。這大概是 爲什麼你認爲它是一個虛假的目標。

你實際上想要的$(TDIR)order-only prerequsite$(mTESTS)將在那裏輸出。做到這一點的方法是修改$(mTESTS)規則是:

$(mTESTS) : $(TDIR)/%.$(MEXEXT) : %.o | $(TDIR) 

這將導致$(TDIR)來進行,如果需要的話,$(mTESTS)作出之前,但 仍然$(TDIR)不會在確定被視爲是否$(mTESTS)需要製作

在另一方面,目標allclean僞目標:沒有這樣的文物 要作出,所以你應該告訴make所以用:

.PHONY: all clean 
+0

感謝您的詳盡解答,建議和指出錯誤。我發現我的makefile文件很臃腫,但我寫的文件還不夠高效。 – eaponte

1

正如評論中指出的那樣,問題出現在編譯標誌中動態庫的順序上。在找到這個原因之後,我發現在靜態庫需要鏈接時要考慮到依賴關係的順序。在我的情況下,庫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) 
+0

我很高興你找到了你的答案。在Linux中查找正確的庫列表順序可能會很痛苦。但是我仍然希望你在看到「無效的MEX文件」時澄清。當你試圖運行它時,對嗎?我一直在運行時看到這一點,而不是編譯時間。 – chappjc

+0

@chappjc沒錯,鏈接沒有產生錯誤,但是在運行期間它報告了缺失的庫。 – eaponte