第六章 编译并运行程序
Table of Contents
- 编译并运行程序
- 6.1 开启和停止Erlang shell
- 6.2 配置开发环境
- 6.2.1 为文件加载器设定搜索路径
- 6.2.2 在系统启动时批量执行命令
 
- 6.3 运行程序的几种不同方法
- 6.3.1 在Erlang shell中编译运行
- 6.3.2 在命令行提示符下编译运行
- 6.3.3 把程序当做escript脚本运行
- 6.3.4 用命令行参数编程
 
- 6.4 使用makefile进行自动编译
- 6.4.1 makefile模版
- 6.4.2 定制makefile模版
 
- 6.5 在Erlang shell中的命令编辑
- 6.6 解决系统死锁
- 6.7 如何应对故障
- 6.7.1 未定义/遗失代码
- 6.7.2 makefile不能工作
- 6.7.3 shell没有响应
 
- 6.8 获取帮助
- 6.9 调试环境
- 6.10 崩溃转储
 
第六章 编译并运行程序
6.1 开启和停止Erlang shell
使用*erl*命令开启Erlang shell, 在shell中调用*erlang:halt()*来停止系统运行, 调用*init:stop()*的别名*q()*来退出shell。
6.2 配置开发环境
在大型项目中, 代码分散在各个目录下, 需要进行相关设置使得Erlang加载器可以找到正确的调用模块和函数。
6.2.1 为文件加载器设定搜索路径
使用*code:get_path()获取当前系统的加载路径。
如果需要添加一个新目录到加载路径的开头, 可以使用*code:add_patha(Dir)*。
如果需要添加一个新目录到加载路径的末尾, 可以使用*code:add_pathz(Dir)*。
如果需要查看所有的已加载的模块, 可以使用*code:all_loaded()*。
如果需要查看发生冲突的模块名, 可以使用*code:clash()*。
以上函数皆可放置在用户目录下的*.erlang*文件中。
或者以以下形式启动shell:
erl -pa Dir1 -pz Dir2
-pa Dir1 表示把Dir1添加到代码搜索路径开头
-pz Dir2 表示把Dir2添加到代码搜索路径末尾
6.2.2 在系统启动时批量执行命令
因为*.erlang*文件的优先级比较高, 且可以在此文件中添加任意的Erlang代码, 因此可以通过此文件来定制不同行为的程序。
6.3 运行程序的几种不同方法
测试程序
-module(hello).
-export([start/0]).
start() ->
    io:format("Hello World~n").
6.3.1 在Erlang shell中编译运行
# 使用c(ModuleName)编译模块 
1> c(hello).
{ok,hello}
# 使用Module:Fun(Args)调用某个模块的某个函数 
2> hello:start().
Hello World
ok
6.3.2 在命令行提示符下编译运行
# 使用erlc编译模块 
$ erlc hello.erl
# -noshell 启动Erlang但关闭shell
# -s hello start 执行hello模块的start函数
# -s init stop 执行init模块的stop函数, 即退出Erlang 
$ erl -noshell -s hello start -s init stop
Hello World
# 加载指定路径并执行其所包含的模块中的函数
$ erl -noshell -pa path -s module fun
6.3.3 把程序当做escript脚本运行
#!/usr/bin/env escript
main(_) ->
    io:format("Hello World\n").
对文件添加可执行权限后执行, 即可达到与普通Erlang程序相同的结果。
6.3.4 用命令行参数编程
编写一个根据计算给定参数阶乘的程序。
-module(fac).
-export([main/1]).
%% 将参数转换成整数类型后调用阶乘函数
main([A]) ->
    I = list_to_integer(atom_to_list(A)),
    F = fac(I),
    io:format("factorial ~w = ~w~n", [I, F]),
    init:stop().
fac(0) ->1;
fac(N) ->N*fac(N-1).
运行结果:
$ erlc fac.erl 
$ erl -noshell -s fac main 25
factorial 25 = 15511210043330985984000000
6.4 使用makefile进行自动编译
6.4.1 makefile模版
# 声明涉及到的文件类型
.SUFFIXES: .erl .beam .yrl
# 依赖关系
# .beam文件依赖于.erl文件 
.erl.beam:
    erlc -W $<
.yrl.erl:
    erlc -W $<
# 定义变量 
ERL = erl -boot start_clean 
# 定义要编译的模块列表, 使用"\"来折行
# Edit the lines below
MODS = module1 module2 \
       module3 ... special1 ...\
       ...
       moduleN
# 定义默认的target
all: compile
compile: ${MODS:%=%.beam} subdirs
## 定义target的依赖关系及其执行命令
special1.beam: special1.erl    
    ${ERL} -Dflag1 -W0 special1.erl
## run an application from the makefile
application1: compile
    ${ERL} -pa Dir1  -s application1 start Arg1 Arg2 
# the subdirs target compiles any code in 
# sub-directories
subdirs:
    cd dir1; make
    cd dir2; make
    ...
# remove all the code
clean:  
    rm -rf *.beam erl_crash.dump
    cd dir1; make clean
    cd dir2; make clean
6.4.2 定制makefile模版
.SUFFIXES: .erl .beam
.erl.beam:
    erlc -W $<
ERL = erl -boot start_clean
MODS = module1 module2 module3
all: compile
    ${ERL} -pa 'codepath' -s module1 start
compile: ${MODS:%=%.beam}
clean:
    rm -rf *.beam erl_crash.dump
6.5 在Erlang shell中的命令编辑
| 命令 | 描述 | 
| ^A | 一行的开始 | 
| ^E | 一行的结尾 | 
| ^F或右箭头 | 前进一个字符 | 
| ^B或左箭头 | 后退一个字符 | 
| ^P或上箭头 | 前一行 | 
| ^N或下箭头 | 后一行 | 
| ^T | 颠倒两个字母顺序 | 
| Tab键 | 帮助扩展当前模块或函数名 | 
6.6 解决系统死锁
出现死锁的原因:
1、  shell没有响应
2、  Ctrl+C处理程序被禁止
3、  Erlang启动时带有-detached选项
4、  Erlang启动时带有-heart Cmd选项
5、  发生严重错误导致了僵尸进程
6.7 如何应对故障
6.7.1 未定义/遗失代码
1、  调用未经编译的模块中的函数
2、  调用不在代码搜索路径中的模块中的函数
3、  调用存在多个版本的同一模块中的函数
6.7.2 makefile不能工作
1、  makefile中的空格, 缩进应以tab字符开始
2、  缺失要编译的模块文件
6.7.3 shell没有响应
Eshell V5.9.1  (abort with ^G)
# 停止响应后通过Ctrl+G进入JCL模式
# 输入h查看帮助
# 输入s启动新shell
# 输入j查看任务列表
# 输入c nn 切换到指定的shell 
1> receive foo -> true end.
User switch command
 --> h
  c [nn]            - connect to job
  i [nn]            - interrupt job
  k [nn]            - kill job
  j                 - list all jobs
  s [shell]         - start local shell
  r [node [shell]]  - start remote shell
  q        - quit erlang
  ? | h             - this message
 --> j
   1* {shell,start,[init]}
 --> s
 --> j
   1  {shell,start,[init]}
   2* {shell,start,[]}
 --> c 2
Eshell V5.9.1  (abort with ^G)
1> init:stop().
ok
6.8 获取帮助
使用erl -man module 获取帮助
6.9 调试环境
系统自带的命令都包含在shell_default模块中, 如果要自定义命令, 可以创建一个user_default模块, 将其放在加载路径中即可直接使用其中的函数。
6.10 崩溃转储
Erlang崩溃后会产生erl_crash.dump文件, 分析此文件可以使用系统自带的基于Web的崩溃分析器。