工欲善其事,必先利其器。排查 erlang 系统问题时,肯定希望能有一个像 Unix top 一样的工具,entop 就是这么个东东。
---------- 我是三月份发版本天天加班的分隔线 -----------
(以下内容翻译自 entop 的 README.md 文件)
entop
如同 Unix 中 top 一样的 Erlang 节点信息查看工具。
简介
entop 是用来展示远端 Erlang 节点运行信息的工具,其信息显示的方式类似于 Unix 中的 top 命令。
若要保证 entop 的正常运行,在 pre-R15 环境下,需要使用 cecho 0.3.0 版本;在 R15 或更高版本的环境下需要 cecho 0.4.0 版本。
cecho 的 github 地址:这里 。
编译
清理和编译可以分别运行如下命令
用法
若想成功运行 entop ,首先要确保 Erlang 已经安装到你的系统之中,并且 cecho 库所在路径被 Erlang code path 所包含。 项目中默认提供的启动脚本(entop)假定了其在 entop 应用根目录下被执行,如果这与你的实际情况不符,请自行调整脚本的相应路径,或者直接确保 entop 的 ebin/ 目录包含在 Erlang code path 之中。详情请参考启动脚本具体内容。
entop 的运行示例
用户接口
entop 的接口允许用户定制化,所以本节描述的接口均为“内置”接口。
表头信息
第一行 主要展示了节点的静态信息,例如节点名、操作系统类型、指定的 erl flag 、当前所运行的 erlang 版本信息。
第二行 展示了(目标节点所在机器的)本地时间、目标节点已持续运行的时间(格式为 Days:Hours:Minutes:Seconds)、运行 entop 的节点与目标节点之间的网络延迟情况(即 net_adm:ping() 成功交互所需花费的时间)
第三行 展示了系统中每个进程的具体信息、进程的总数、运行队列中的进程数量(由调度器进行调度的待运行进程数量)、reductions per interval (RpI) 值(自从上一次 called the node 后系统已经 reduction 的次数)、以及每个进程占用的内存量。
第四行 展示了系统内存使用量、atom 内存占用量(当前使用量/总体分配量)、binary 内存占用量、code 内存占用量,以及 ets 内存占用量。
第五行 为空白,目前作为预留。
第六行 为和行内容展示相关的信息,例如信息获取时间间隔、信息展示排序方式,以及获取相关信息所耗费的时间。
在 entop 运行状态下可以使用的控制命令 :
[1-N]: 根据指定列编号进行输出内容排序。第一列编号为 1 ,其他列按顺序增加。
r: 在升序排序和降序排序之间进行切换。
q: 从 entop 中退出返回 shell 命令行。
Ctrl-C: 等价于 'q' 命令。
'<' 和 '>': 将当前排序列左移或者右移(注意:次数为小于和大于号,非箭头)
---------- 我是三月份发版本天天加班的分隔线 -----------
按照 README.md 中的说明 “entop 的正常运行在 pre-R15 情况下需要 cecho 0.3.0 的支持,在 R15 或更高版本的情况下需要 cecho 0.4.0 的支持” 做了如下配置变更。
可以看到,按照上面的操作,我们失败了,排查错误的原因,我 查看了 cecho 的代码。
在 cecho_srv.erl 中
查看手册,针对 erl_ddll/load/2 有如下说明
---------- 我是三月份发版本天天加班的分隔线 -----------
(以下内容翻译自 kernel-2.15.2)
load(Path, Name) -> ok | {error, ErrorDesc}
Types:
Path = path()
Name = driver()
ErrorDesc = term()
加载并链接名为 Name 的动态 driver 。Path 为包含该 driver 的目录。Name 指定的对象必须为共享对象或动态链接库。
若两个 driver 具有不同的 Path 参数(即在不同路径下),则无法通过相同的 Name 进行加载。
Name 的值对应 Path 目录下的动态加载对象文件,但是去除了扩展名(例如,移除了 .so 后缀)。
在 driver 初始化函数中指定的 driver 名字方式,在很大程度上,与指定对应了 .beam 文件的 erlang 模块名一样。
如果对 driver 执行了卸载动作,但由于 port 仍旧处于 open 状态,故此 driver 实际上仍旧存在,此时若调用 load/2 ,则会停止针对 driver 的卸载行为,使得该 driver 得以保留(只要 Path 没有发生过变更),并会返回 ok 。
如果确实打算重新加载对象代码(driver),则可以使用 reload/2 或者底层的接口 try_load/3 进行操作。
针对不同的场景下的加载/卸载行为描述请参考具体说明。
如果超过一个进程想要使用相同的 Path 加载一个已经加载过的 driver ,或者如果相同的进程想要加载同一个 driver 多次,该函数调用都会返回 ok 。
模拟器会跟踪 load/2 被调用的次数,以便在相同数量的 unload/2 被调用后才真正卸载该 driver 。
如此,才能保证一个应用安全的加载一个 driver ,无论该 driver 是在多 erlang 进程间共享,还是在多 erlang 应用间共享。同样能保证 driver 的安全卸载,而不会对系统的其他部分产生影响。
以相同的 Name 但不同的 Path 加载多个 driver 是不允许的;
注意:
需要注意的是,Path 参数的值是按字面量解析的,所以针对统一 driver 的多次加载都需要指定具有相同字面量的 Path 字符串,即使不同的路径表达均指向相同的文件系统目录也不行(比如使用相对路径或链接的情况)。
函数执行成功后返回 ok ;函数执行失败后返回 {error, ErrorDesc} ,其中 ErrorDesc 为 opaque term ,可以通过 format_error/1 翻译成人可读的格式。
若希望对错误处理有更多控制,则需要使用 try_load/3 接口。
该函数会在入口参数不符合要求的情况下,抛出 badarg 异常。
---------- 我是三月份发版本天天加班的分隔线 -----------
根据上述信息,查看源码目录 priv 下,会在编译 cecho 后生成的 cecho.so 文件
ok ,变回原始配置再再做一次挑战...
在没有其他思路的请款下,就让我们简单粗暴一点吧,直接拉下来 master 和 0.4.0 两个版本的代码进行比较~~
结果很明显,只有 rebar.config 中的不同才是问题关键。
回头再看依赖 cecho.so 的库依赖关系(之前少看了该信息,5555...)
---------- 我是三月份发版本天天加班的分隔线 -----------
(以下内容翻译自 entop 的 README.md 文件)
entop
如同 Unix 中 top 一样的 Erlang 节点信息查看工具。
简介
entop 是用来展示远端 Erlang 节点运行信息的工具,其信息显示的方式类似于 Unix 中的 top 命令。
若要保证 entop 的正常运行,在 pre-R15 环境下,需要使用 cecho 0.3.0 版本;在 R15 或更高版本的环境下需要 cecho 0.4.0 版本。
cecho 的 github 地址:这里 。
编译
清理和编译可以分别运行如下命令
./rebar clean
./rebar compile
注意:如果你遇到和 cecho 依赖相关的问题,可以手动创建符号链接到 deps/ 下的 cecho (如果你的 cecho 放在其他目录也可以进行类似操作),或者运行 ./rebar get-deps 以下载最新版本。当通过 rebar 获取到最新版本后,不要忘记重新编译整个应用。
用法
若想成功运行 entop ,首先要确保 Erlang 已经安装到你的系统之中,并且 cecho 库所在路径被 Erlang code path 所包含。 项目中默认提供的启动脚本(entop)假定了其在 entop 应用根目录下被执行,如果这与你的实际情况不符,请自行调整脚本的相应路径,或者直接确保 entop 的 ebin/ 目录包含在 Erlang code path 之中。详情请参考启动脚本具体内容。
Usage: ./entop <TARGETNODE> [-name <NAME>|-sname <SNAME>] [-setcookie <COOKIE>]
entop 的运行示例
> ./entop rmq_yoyo@YOYO -sname entop -setcookie yoyo
用户接口
entop 的接口允许用户定制化,所以本节描述的接口均为“内置”接口。
表头信息
第一行 主要展示了节点的静态信息,例如节点名、操作系统类型、指定的 erl flag 、当前所运行的 erlang 版本信息。
第二行 展示了(目标节点所在机器的)本地时间、目标节点已持续运行的时间(格式为 Days:Hours:Minutes:Seconds)、运行 entop 的节点与目标节点之间的网络延迟情况(即 net_adm:ping() 成功交互所需花费的时间)
第三行 展示了系统中每个进程的具体信息、进程的总数、运行队列中的进程数量(由调度器进行调度的待运行进程数量)、reductions per interval (RpI) 值(自从上一次 called the node 后系统已经 reduction 的次数)、以及每个进程占用的内存量。
第四行 展示了系统内存使用量、atom 内存占用量(当前使用量/总体分配量)、binary 内存占用量、code 内存占用量,以及 ets 内存占用量。
第五行 为空白,目前作为预留。
第六行 为和行内容展示相关的信息,例如信息获取时间间隔、信息展示排序方式,以及获取相关信息所耗费的时间。
在 entop 运行状态下可以使用的控制命令 :
[1-N]: 根据指定列编号进行输出内容排序。第一列编号为 1 ,其他列按顺序增加。
r: 在升序排序和降序排序之间进行切换。
q: 从 entop 中退出返回 shell 命令行。
Ctrl-C: 等价于 'q' 命令。
'<' 和 '>': 将当前排序列左移或者右移(注意:次数为小于和大于号,非箭头)
---------- 我是三月份发版本天天加班的分隔线 -----------
按照 README.md 中的说明 “entop 的正常运行在 pre-R15 情况下需要 cecho 0.3.0 的支持,在 R15 或更高版本的情况下需要 cecho 0.4.0 的支持” 做了如下配置变更。
[root@Betty entop]# vi rebar.config
{erl_opts, [fail_on_warning, debug_info]}.
{deps_dir, "deps"}.
{clean_files, ["ebin/*.beam"]}.
{deps, [{cecho, ".*", {git, "https://github.com/mazenharake/cecho.git", {tag, "0.4.0"}}}]}. -- 这里由原来的 "HEAD" 变更为 {tag, "0.4.0"}
{escript_name, "rebar_tmp"}.
编译
[root@Betty entop]# ./rebar compile
==> cecho (compile)
Compiled src/cecho.erl
Compiled src/cecho_srv.erl
Compiled src/cecho_example.erl
Compiling c_src/cecho.c
==> entop (compile)
Compiled src/entop_collector.erl
Compiled src/entop_net.erl
Compiled src/entop.erl
Compiled src/entop_format.erl
Compiled src/entop_view.erl
[root@Betty entop]#
通过 entop 连接到 RabbitMQ 进程进行查看
[root@Betty entop]# ./entop rmq_betty@Betty -sname entop
=INFO REPORT==== 9-Mar-2016::13:58:43 ===
application: cecho
exited: {{driver_error,"undefined symbol: scrollok"}, -- 问题出在这里
{cecho,start,[normal,[]]}}
type: temporary
^C^C^C^C^C -- Ctrl + c 也停止不了
^Z
[1]+ Stopped ./entop rmq_betty@Betty -sname entop
[root@Betty entop]#
通过挂起回到前台,查看 entop 相关进程运行情况,并强杀
[root@Betty entop]# ps aux|grep entop
root 31769 0.0 0.0 106092 1236 pts/2 T 13:58 0:00 /bin/bash ./entop rmq_betty@Betty -sname entop
root 31775 0.0 0.8 748760 33344 pts/2 Tl 13:58 0:00 /usr/local/lib/erlang/erts-6.0/bin/beam.smp -A 20 -Bc -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -noshell -noinput -hidden -pa ./ebin -pa ./deps/cecho/ebin -eval entop:start('rmq_betty@Betty') -sname entop
root 31919 0.0 0.0 103252 856 pts/2 S+ 14:04 0:00 grep entop
[root@Betty entop]#
[root@Betty entop]#
[root@Betty entop]# kill -9 31769 31775
可以看到,按照上面的操作,我们失败了,排查错误的原因,我 查看了 cecho 的代码。
在 cecho_srv.erl 中
init(no_args) ->
process_flag(trap_exit, true),
case load_driver() of
ok ->
Port = erlang:open_port({spawn, "cecho"}, [binary]),
ok = do_call(Port, ?INITSCR),
ok = do_call(Port, ?WERASE, 0),
ok = do_call(Port, ?REFRESH),
{ok, #state{ port = Port }};
{error, ErrorCode} ->
exit({driver_error, erl_ddll:format_error(ErrorCode)}) -- 可以看出,上面的错误信息来自这里
end.
...
load_driver() ->
Dir = case code:priv_dir(cecho) of
{error, bad_name} ->
filename:dirname(code:which(?MODULE)) ++ "/../priv";
D ->
D
end,
erl_ddll:load(Dir, "cecho"). -- 其他代码都不会出错,只能是这里
查看手册,针对 erl_ddll/load/2 有如下说明
---------- 我是三月份发版本天天加班的分隔线 -----------
(以下内容翻译自 kernel-2.15.2)
load(Path, Name) -> ok | {error, ErrorDesc}
Types:
Path = path()
Name = driver()
ErrorDesc = term()
加载并链接名为 Name 的动态 driver 。Path 为包含该 driver 的目录。Name 指定的对象必须为共享对象或动态链接库。
若两个 driver 具有不同的 Path 参数(即在不同路径下),则无法通过相同的 Name 进行加载。
Name 的值对应 Path 目录下的动态加载对象文件,但是去除了扩展名(例如,移除了 .so 后缀)。
在 driver 初始化函数中指定的 driver 名字方式,在很大程度上,与指定对应了 .beam 文件的 erlang 模块名一样。
如果对 driver 执行了卸载动作,但由于 port 仍旧处于 open 状态,故此 driver 实际上仍旧存在,此时若调用 load/2 ,则会停止针对 driver 的卸载行为,使得该 driver 得以保留(只要 Path 没有发生过变更),并会返回 ok 。
如果确实打算重新加载对象代码(driver),则可以使用 reload/2 或者底层的接口 try_load/3 进行操作。
针对不同的场景下的加载/卸载行为描述请参考具体说明。
如果超过一个进程想要使用相同的 Path 加载一个已经加载过的 driver ,或者如果相同的进程想要加载同一个 driver 多次,该函数调用都会返回 ok 。
模拟器会跟踪 load/2 被调用的次数,以便在相同数量的 unload/2 被调用后才真正卸载该 driver 。
如此,才能保证一个应用安全的加载一个 driver ,无论该 driver 是在多 erlang 进程间共享,还是在多 erlang 应用间共享。同样能保证 driver 的安全卸载,而不会对系统的其他部分产生影响。
以相同的 Name 但不同的 Path 加载多个 driver 是不允许的;
注意:
需要注意的是,Path 参数的值是按字面量解析的,所以针对统一 driver 的多次加载都需要指定具有相同字面量的 Path 字符串,即使不同的路径表达均指向相同的文件系统目录也不行(比如使用相对路径或链接的情况)。
函数执行成功后返回 ok ;函数执行失败后返回 {error, ErrorDesc} ,其中 ErrorDesc 为 opaque term ,可以通过 format_error/1 翻译成人可读的格式。
若希望对错误处理有更多控制,则需要使用 try_load/3 接口。
该函数会在入口参数不符合要求的情况下,抛出 badarg 异常。
---------- 我是三月份发版本天天加班的分隔线 -----------
根据上述信息,查看源码目录 priv 下,会在编译 cecho 后生成的 cecho.so 文件
[root@Betty priv]# ll
总用量 132
-rwxr-xr-x 1 root root 135113 3月 9 13:57 cecho.so
[root@Betty priv]# nm -C cecho.so |grep scrollok
00000000000042ed T do_scrollok
U scrollok
[root@Betty priv]#
我擦,果然其中没有定义 scrollok 符号……Erlang 果不欺我~~~
ok ,变回原始配置再再做一次挑战...
[root@Betty entop]# vi rebar.config
{erl_opts, [fail_on_warning, debug_info]}.
{deps_dir, "deps"}.
{clean_files, ["ebin/*.beam"]}.
%%{deps, [{cecho, ".*", {git, "https://github.com/mazenharake/cecho.git", {tag, "0.4.0"}}}]}.
{deps, [{cecho, ".*", {git, "https://github.com/mazenharake/cecho.git", "HEAD"}}]}.
{escript_name, "rebar_tmp"}.
[root@Betty entop]# ll
总用量 141
drwxr-xr-x 1 root root 0 3月 9 13:56 deps
drwxr-xr-x 1 root root 4096 3月 9 13:57 ebin
-rwxr-xr-x 1 root root 1723 3月 9 10:16 entop
-rwxr-xr-x 1 root root 10175 3月 9 10:16 LICENSE
-rwxr-xr-x 1 root root 132 3月 9 10:16 NOTICE
-rwxr-xr-x 1 root root 3410 3月 9 13:53 README.md
-rwxr-xr-x 1 root root 114109 3月 9 10:16 rebar
-rwxr-xr-x 1 root root 302 3月 9 14:48 rebar.config
drwxr-xr-x 1 root root 4096 3月 9 10:18 src
[root@Betty entop]#
[root@Betty entop]#
[root@Betty entop]# rm -rf deps/
[root@Betty entop]# ll
总用量 141
drwxr-xr-x 1 root root 4096 3月 9 13:57 ebin
-rwxr-xr-x 1 root root 1723 3月 9 10:16 entop
-rwxr-xr-x 1 root root 10175 3月 9 10:16 LICENSE
-rwxr-xr-x 1 root root 132 3月 9 10:16 NOTICE
-rwxr-xr-x 1 root root 3410 3月 9 13:53 README.md
-rwxr-xr-x 1 root root 114109 3月 9 10:16 rebar
-rwxr-xr-x 1 root root 302 3月 9 14:48 rebar.config
drwxr-xr-x 1 root root 4096 3月 9 10:18 src
[root@Betty entop]#
[root@Betty entop]#
[root@Betty entop]# ./rebar get-deps
==> entop (get-deps)
Pulling cecho from {git,"https://github.com/mazenharake/cecho.git","HEAD"}
正克隆到 'cecho'...
==> cecho (get-deps)
[root@Betty entop]#
[root@Betty entop]# ./rebar clean
==> cecho (clean)
==> entop (clean)
[root@Betty entop]#
[root@Betty entop]# ./rebar compile
==> cecho (compile)
Compiled src/cecho.erl
Compiled src/cecho_srv.erl
Compiled src/cecho_example.erl
Compiling c_src/cecho.c
==> entop (compile)
Compiled src/entop_collector.erl
Compiled src/entop_net.erl
Compiled src/entop.erl
Compiled src/entop_format.erl
Compiled src/entop_view.erl
[root@Betty entop]#
[root@Betty entop]# ll deps/cecho/priv/
总用量 132
-rwxr-xr-x 1 root root 135145 3月 9 14:51 cecho.so
[root@Betty entop]#
[root@Betty entop]#
[root@Betty entop]# nm -C deps/cecho/priv/cecho.so |grep scrollok
00000000000042fd T do_scrollok
U scrollok
[root@Betty entop]#
[root@Betty entop]# ./entop
Usage: ./entop <TARGETNODE> [-name <NAME>|-sname <SNAME>] [-setcookie <COOKIE>]
[root@Betty entop]# ./entop rmq_betty@Betty -sname entop
{error_logger,{{2016,3,9},{14,53,0}},"Protocol: ~tp: the name entop@Betty seems to be in use by another Erlang node",["inet_tcp"]}
{error_logger,{{2016,3,9},{14,53,0}},crash_report,[[{initial_call,{net_kernel,init,['Argument__1']}},{pid,<0.21.0>},{registered_name,[]},{error_info,{exit,{error,badarg},[{gen_server,init_it,6,[{file,"gen_server.erl"},{line,322}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]}},{ancestors,[net_sup,kernel_sup,<0.10.0>]},{messages,[]},{links,[#Port<0.190>,<0.18.0>]},{dictionary,[{longnames,false}]},{trap_exit,true},{status,running},{heap_size,376},{stack_size,27},{reductions,735}],[]]}
{error_logger,{{2016,3,9},{14,53,0}},supervisor_report,[{supervisor,{local,net_sup}},{errorContext,start_error},{reason,{'EXIT',nodistribution}},{offender,[{pid,undefined},{name,net_kernel},{mfargs,{net_kernel,start_link,[[entop,shortnames]]}},{restart_type,permanent},{shutdown,2000},{child_type,worker}]}]}
{error_logger,{{2016,3,9},{14,53,0}},supervisor_report,[{supervisor,{local,kernel_sup}},{errorContext,start_error},{reason,{shutdown,{failed_to_start_child,net_kernel,{'EXIT',nodistribution}}}},{offender,[{pid,undefined},{name,net_sup},{mfargs,{erl_distribution,start_link,[]}},{restart_type,permanent},{shutdown,infinity},{child_type,supervisor}]}]}
{error_logger,{{2016,3,9},{14,53,0}},crash_report,[[{initial_call,{application_master,init,['Argument__1','Argument__2','Argument__3','Argument__4']}},{pid,<0.9.0>},{registered_name,[]},{error_info,{exit,{{shutdown,{failed_to_start_child,net_sup,{shutdown,{failed_to_start_child,net_kernel,{'EXIT',nodistribution}}}}},{kernel,start,[normal,[]]}},[{application_master,init,4,[{file,"application_master.erl"},{line,133}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]}},{ancestors,[<0.8.0>]},{messages,[{'EXIT',<0.10.0>,normal}]},{links,[<0.8.0>,<0.7.0>]},{dictionary,[]},{trap_exit,true},{status,running},{heap_size,376},{stack_size,27},{reductions,117}],[]]}
{error_logger,{{2016,3,9},{14,53,0}},std_info,[{application,kernel},{exited,{{shutdown,{failed_to_start_child,net_sup,{shutdown,{failed_to_start_child,net_kernel,{'EXIT',nodistribution}}}}},{kernel,start,[normal,[]]}}},{type,permanent}]}
{"Kernel pid terminated",application_controller,"{application_start_failure,kernel,{{shutdown,{failed_to_start_child,net_sup,{shutdown,{failed_to_start_child,net_kernel,{'EXIT',nodistribution}}}}},{kernel,start,[normal,[]]}}}"}
Crash dump was written to: erl_crash.dump
Kernel pid terminated (application_controller) ({application_start_failure,kernel,{{shutdown,{failed_to_start_child,net_sup,{shutdown,{failed_to_start_child,net_kernel,{'EXIT',nodistribution}}}}},{k
Something wrong. Code: 1
[root@Betty entop]#
[root@Betty entop]#
[root@Betty entop]# ps aux|grep entop
root 463 0.0 0.0 103252 840 pts/2 S+ 14:53 0:00 grep entop
root 32043 0.0 0.0 106092 1236 pts/2 T 14:06 0:00 /bin/bash ./entop rmq_betty@Betty -sname entop
root 32049 0.0 0.9 748760 34824 pts/2 Tl 14:06 0:00 /usr/local/lib/erlang/erts-6.0/bin/beam.smp -A 20 -Bc -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -noshell -noinput -hidden -pa ./ebin -pa ./deps/cecho/ebin -eval entop:start('rmq_betty@Betty') -sname entop
[root@Betty entop]#
[root@Betty entop]#
[root@Betty entop]# kill -9 32043 32049
[root@Betty entop]#
[1]+ 已杀死 ./entop rmq_betty@Betty -sname entop
[root@Betty entop]#
[root@Betty entop]#
[root@Betty entop]#
[root@Betty entop]#
[root@Betty entop]#
[root@Betty entop]# ps aux|grep entop
root 467 0.0 0.0 103252 844 pts/2 S+ 14:53 0:00 grep entop
[root@Betty entop]#
[root@Betty entop]#
[root@Betty entop]# ./entop rmq_betty@Betty -sname entop
Node: rmq_betty@Betty (Connected) (17/6.0) unix (linux 2.6.32) CPU:4 SMP +A:30 +K
Time: local time 14:53:34, up for 000:22:27:49, 3ms latency,
Processes: total 189 (RQ 0) at 124011 RpI using 13860.0k (13892.3k allocated)
Interval 1000ms, Sorting on "Reductions" (Descending), Retrieved in 4ms 1170.1k
Pid Registered Name Reductions MQueue HSize SSize HTot <0.179.0> vm_memory_monitor 77427487 06772 97382
<0.230.0> background_gc 59304009 0233 7233
<0.282.0> rabbit_mgmt_db 44805986 02586 74184
<0.208.0> rabbit_memory_monito 31871301 04185 74561
<0.243.0> rabbit_mgmt_external 31362904 06772 913544
<0.256.0> rabbit_web_dispatch_ 14034430 010958 921916
<0.182.0> rabbit_disk_monitor 752889602586 94184
<0.25.0> file_server_2 70139900376 9752
<0.3.0> erl_prim_loader42681980987 6987
<0.7.0> application_controll 282319702586 76771
<0.180.0> timer_server 228609901598 91974
<0.276.0> - 13847170376 13 752
<0.273.0> - 13844820376 13 752
<0.275.0> - 13842510376 13 752
<0.266.0> - 13838640376 13 752
<0.265.0> - 13837490376 13 752
<0.268.0> - 13837340376 13 752
<0.262.0> - 13836540376 13 752
<0.261.0> - 13836280376 13 752
<0.267.0> - 13836160376 13 752
<0.264.0> - 13835610376 13 752
<0.263.0> - 13834900376 13 752
<0.270.0> - 13834830376 13 752
<0.271.0> - 13828050376 13 752
<0.272.0> - 13825730376 13 752
<0.269.0> - 13824750376 13 752
<0.274.0> - 13823870376 13 752
<0.0.0> init 12066000987 2987
<0.184.0> os_cmd_port_creator 8509590610 1986
<0.148.0> file_handle_cache 8355150610 7986
<0.12.0> rex 8075230610 9986
<0.26.0> code_server 804759017731 317731
<0.173.0> rabbit_event 76952902586 82962
<0.177.0> rabbit_alarm 3456710376 8752
<0.66.0> mnesia_recover2134950233 9233
<0.187.0> rabbit_node_monitor 1169900376 9376
<0.21.0> net_kernel 99217 0376 9376
<0.145.0> rabbit 77518 0233 5233
<0.8965.0> - 68682 0233 11 233
<0.11.0> kernel_sup 67885 0376 9376
[root@Betty entop]# ogger 55368 0610 8610
[root@Betty entop]#
整个过程下来,没发现有啥具体区别啊!!如何破?!
在没有其他思路的请款下,就让我们简单粗暴一点吧,直接拉下来 master 和 0.4.0 两个版本的代码进行比较~~
结果很明显,只有 rebar.config 中的不同才是问题关键。
{port_envs, [{"LDFLAGS", "$LDFLAGS -lncurses"}]}.
这条配置信息从字面上就可以理解,LDFLAGS 是用来设置 link 选项的,所以上面是指定了对 ncurses 库的链接依赖。
回头再看依赖 cecho.so 的库依赖关系(之前少看了该信息,5555...)
[root@Betty priv]# ldd cecho.so
linux-vdso.so.1 => (0x00007fff10eee000)
libncurses.so.5 => /lib64/libncurses.so.5 (0x00007fa6c1aef000)
libc.so.6 => /lib64/libc.so.6 (0x00007fa6c175b000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fa6c1556000)
libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007fa6c1335000)
/lib64/ld-linux-x86-64.so.2 (0x000000388c400000)
[root@Betty priv]#
而在引用 0.4.0 版本的 cecho 时,信息如下
[root@Betty entop]# ldd deps/cecho/priv/cecho.so
linux-vdso.so.1 => (0x00007fff8f0c5000)
libc.so.6 => /lib64/libc.so.6 (0x00007f4fb65bd000)
/lib64/ld-linux-x86-64.so.2 (0x000000388c400000)
[root@Betty entop]#
果然存在差别!这也就解释了为何 scrollok 符号在两次结果中虽然都是 U 状态,但基于 master 的编译却可用的原因,因为 scrollok 符号在 libncurses.so.5 中~~
[root@Betty entop]# nm -D /lib64/libncurses.so.5.7 | grep scrollok
000000389940a9b0 T is_scrollok
0000003899412980 T scrollok
[root@Betty entop]#
手动在 0.4.0 版本的 cecho 的 rebar.config 文件中添加 {port_envs, [{"LDFLAGS", "$LDFLAGS -lncurses"}]}. 后,重新编译运行,一切正常~~