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