Xref 是一個交叉引用工具,通過分析定義的函數間的調用關系,用於查找函數、 模塊、 應用程序和版本之間的依賴關系。
通俗而言,Xref 可以檢查代碼中函數的調用關系。比如在 moduleA 中的 funA 調用了moduleB 中的funB, 但是moduleB 中並未定義funB,此錯誤在代碼編譯期間不能被發現,但是可以通過Xref 檢查。
栗子
使用reabr 創建一個application ,命名為xref_test,目錄結構如下:
1 $ tree 2 . 3 ├── ebin 4 │ ├── test.beam 5 │ ├── xref_test.app 6 │ ├── xref_test_app.beam 7 │ └── xref_test_sup.beam 8 ├── rebar 9 ├── src 10 │ ├── test.erl 11 │ ├── xref_test.app.src 12 │ ├── xref_test_app.erl 13 │ └── xref_test_sup.erl 14 └── xref.config 15 16 2 directories, 10 files
其中 test.erl 的代碼為:
1 $ cat ./src/test.erl 2 -module(test). 3 -export([start/0]). 4 start() -> 5 test_2:start().
在test module 中定義start/0 函數,其中調用了test_2:start/0 函數,但是此函數並沒有定義。這種情況,必然會引發錯誤,但是在編譯期間,並不能發現。
1 $ ./rebar com 2 ==> xref_test (compile) 3 Compiled src/xref_test_app.erl 4 Compiled src/test.erl 5 Compiled src/xref_test_sup.erl
OK,上述執行是順利完成的。但是在運行時,必然會發生錯誤。
1 1> test:start(). 2 ** exception error: undefined function test_2:start/0
那么,怎樣才能在運行之前發現這個錯誤呢?Xref 就應該隆重登場了。
rebar xref
在rebar 中,集成了xref 工具,相關的配置信息如下:
1 {xref_warnings, false}. 2 %% optional extra paths to include in xref:set_library_path/2. 3 %% specified relative location of rebar.config. 4 %% e.g. {xref_extra_paths,["../gtknode/src"]} 5 {xref_extra_paths,[]}. 6 %% xref checks to run 7 {xref_checks, [undefined_function_calls, undefined_functions, 8 locals_not_used, exports_not_used, 9 deprecated_function_calls, deprecated_functions]}. 10 %% Optional custom xref queries (xref manual has details) specified as 11 %% {xref_queries, [{query_string(), expected_query_result()},...]} 12 %% The following for example removes all references to mod:*foo/4 13 %% functions from undefined external function calls as those are in a 14 %% generated module 15 {xref_queries, 16 [{"(XC - UC) || (XU - X - B" 17 " - (\"mod\":\".*foo\"/\"4\"))",[]}]}.
在rebar.config 文件中,配置好這些信息,執行:
1 $ ./rebar xref 2 ==> xref_test (xref) 3 Warning: test_2:start/0 is undefined function (Xref) 4 src/test.erl:5: Warning: test:start/0 calls undefined function test_2:start/0 (Xref) 5 ERROR: xref failed while processing /Users/redink/erlang/test/xref_test: rebar_abort
這個時候,錯誤就能夠清晰的看出來了。
xref_runner
xref_runner 是獨立於rebar xref 的一個工具,支持在非rebar 組織的項目中使用xref ,友好度很高。
https://github.com/inaka/xref_runner
在rebar node 組織的Erlang release 中,可以使用xref_runner 方便的對apps 目錄下的application 進行xref 檢查。
xrefr.config 定義:
1 $ cat xrefr.config 2 [ 3 {xref, [ 4 {config, #{dirs => ["./apps/appname/ebin"], 5 extra_paths => [ 6 "./deps/***/ebin"]}}, 20 {checks, [ 21 undefined_functions 22 , undefined_function_calls 23 , locals_not_used 24 %%, exports_not_used 25 , deprecated_function_calls 26 , deprecated_functions 27 ]}, 28 {xref_default, {verbose}} 29 ] 30 } 31 ].
總結
Xref 非常有用,能幫我們在運行之前盡快的發現代碼的錯誤以及潛在的錯誤。
擴展閱讀:
http://www.erlang.org/doc/apps/tools/xref_chapter.html