rebar工具使用备忘录

http://cryolite.iteye.com/blog/1159448html

rebar是一个开源的erlang应用自动构建工具。 bashotuncer开发。它其实是一个erlang脚本(escript)的工具,所以在不一样平台间迁移起来比较方便。 

1.安装 

能够去github下载源代码编译 
Bash代码   收藏代码
  1. git clone git://github.com/basho/rebar.git  


构建rebar工具 
Bash代码   收藏代码
  1. cd rebar  
  2. make  


把编译好的rebar放到系统目录中完成安装: 
Bash代码   收藏代码
  1. sudo mv rebar /usr/local/bin  


查看rebar的版本检查一下安装: 
Bash代码   收藏代码
  1. $ rebar -V  

rebar version: 2 date: 20110827_060830 vcs: git 8376693 

不过经过源代码获得的是不稳定的版本,使用时会出现些小问题。 
也有现成的稳定rebar下载: 
Bash代码   收藏代码
  1. curl -o rebar http://cloud.github.com/downloads/basho/rebar/rebar  



2. 使用 

2.0 rebar的帮助文档 

最基本的文档是README。 
有段rebar做者的 rebar使用介绍视频, fxxk墙浏览。 

rebar的官方文档不是很全,并且rebar的进化也很快,因此最好从rebar自己的帮助开始:经过rebar -h查看rebar帮助。 

一个诀窍:在使用rebar时加上-v参数能够详细的打印出rebar构建过程时的相关命令和参数,这有助于咱们查看构建工程过程的细节,从而判断rebar.config文件的配置是否正确。-vv会打印稍多信息,而-vvv参数会打印出最罗嗦的调试信息。 


2.1 自动补全 

rebar版本库中有提供实现自动补全的脚本(在目录priv/shell-completion/bash/下),而后在.bashrc(或者.bash_profile)添加一行: 
Bash代码   收藏代码
  1. source $rebar_home/priv/shell-completion/bash/rebar  


之后在命令行窗口中输入rebar命令连按两次tab键会自动列出可用的rebar子命令。固然也能够经过rebar -c 查看每一个子命令的详细解释。 

在rebar安装目录的priv/templates目录下有全部缺省模板的源代码,查看这些模板的源码有时候能帮助咱们理解rebar所作的工做。 

固然也能够订阅 rebar的邮件列表得到在线帮助 

2.3 rebar管理的工程目录结构 

rebar管理的erlang工程应该遵循 erlang OTP的约定,项目的文件结构以下,子目录src, include下分别放置erlang源代码和hrl包含文件,priv和ebin目录分别放置编译好的lib库共享文件(或可执行文件)和beam文件(和其余文件例如app文件),这两个目录由rebar自动生成并清理,不要把重要的代码放在这两个目录下,虽然不会被rebar clean自动删掉,(不过编译好的beam文件都会删掉),可是也影响很差哈。 

此外对port drive和nif的开发,它们的c源程序应该放在c_src目录下。目前port driver和nif是被rebar无区别对待,所以有着一样的rebar控制参数。 

总结:源代码应该组织到src, include和c_src三个目录结构中,此外,eunit单元测试代码放在test目录下。rebar控制priv和ebin目录,源码或文档不要在这两个目录下。 

实际上,即便没有rebar工程配置文件(rebar.config),只要符合上述目录结构的erlang工程都能自动被rebar编译。 

2.4 rebar的工程配置文件 

要想更好的使用rebar,通常须要一个rebar工程配置文件(rebar.config)对工程进行管理。 

如何写rebar.config配置 

rebar安装路径下有一个rebar.config.sample的文件,基本照抄就好了。 
此外研究这个文件能够发现许多rebar的使用诀窍。例如这句 
Rebar.config代码   收藏代码
  1. {pre_hooks, [{clean, "./prepare_package_files.sh"},  
  2.      {compile, "escript generate_headers"}]}.  

这显然是用来控制rebar子命令的前置钩子,也就是说在rebar clean子命令执行以前执行prepare_package_files.sh脚本;在compile子命令执行以前执行escript generate_headers脚本。 

固然相应的还有post_hooks后置钩子 


2.5 rebar模板的使用 

erlang/OTP的3个著名模式都有着各自的程序骨架,每次写一个srv或者fsm的模块,咱们都得重复写许多固定的骨架代码,rebar提供了模板帮咱们省下了这些重复工做,咱们用rebar模版自动生产相应的模版程序估计,而后只管往里面填应用的逻辑的实现代码就好了。 

rebar list-templates 子命令能够查看rebar缺省提供的工程模板(固然也能够建立本身的模板) 

显然,simplesrv,simplefsm,simpleapp这三个模板是用来建立OTP的服务器模式,有限状态机模式和app应用模式的。 

注意在rebar中,这三个模式的约定名称:srv, fsm和app 
相应的,这些模板都有一个约定的控制变量,分别是srvid, fsmid和appid 


下面作些实验看看 
能够试试建立一个application: 
Bash代码   收藏代码
  1. $ rebar create template=simpleapp  

也能够建立一个fsm的模块: 
Bash代码   收藏代码
  1. $ rebar create template=simplefsm  

再来一个server模块: 
Bash代码   收藏代码
  1. $ rebar create template=simplesrv  


而后在src查看这些自动生成的代码就能理解所谓的rebar 自动生成模板是怎么回事了。 

每类模板都有它们本身的生成控制变量,没有这些变量,一切都是默认的。例如上面的实验里,都没有指定模块的控制变量,因此生成的模块都是叫myxxx之类的缺省名字。 

在rebar源代码目录的priv/templates目录下有全部缺省模板的源程序,查阅这些模板的源码能够帮助咱们理解rebar的这些模板建立命令的变量是如何工做的: 
A) simplefsm.template模板 
Simplefsm.template代码   收藏代码
  1. {variables, [{fsmid, "myfsm"}]}.  
  2. {template, "simplefsm.erl", "src/{{fsmid}}.erl"}.  


这说明fsm模板提供了一个fsmid的变量控制着fsm模块的生成,自定义一个: 
Bash代码   收藏代码
  1. rebar create template=simplefsm fsmid=cat  


就在src下建立了一个fsm的cat模块 

B) simplemod.tempalte模板 
Simplemod.tempalte代码   收藏代码
  1. {variables, [{modid, "mymod"}]}.  
  2. {template, "simplemod.erl", "src/{{modid}}.erl"}.  
  3. {template, "simplemod_tests.erl", "test/{{modid}}_tests.erl"}.  


能够经过这个模板建立一个普通的erlang模块,同时它会自动生成该模块的单元测试代码: 
该模板提供的控制变量是modid 

下面建立一个叫fish的erlang模块: 
Bash代码   收藏代码
  1. rebar create template=simplemod modid=fish  


C)basicnif.template模板 
Basicnif.template代码   收藏代码
  1. {variables, [{module, "mymodule"}]}.  
  2. {template, "basicnif.erl", "src/{{module}}.erl"}.  
  3. {template, "basicnif.c", "c_src/{{module}}.c"}.  


这个模板是用来生成nif模块的,它提供了一个叫module的控制变量 
试着生成一个叫dragon的nif模块看看: 
Bash代码   收藏代码
  1. rebar create template=basicnif module=dragon  


nif的c代码和erl代码分别放在c_src和src目录下了。 

D) simpleapp.template模板 
Simpleapp.template代码   收藏代码
  1. {variables, [{appid, "myapp"}]}.  
  2. {template, "simpleapp.app.src", "src/{{appid}}.app.src"}.  
  3. {template, "simpleapp_app.erl", "src/{{appid}}_app.erl"}.  
  4. {template, "simpleapp_sup.erl", "src/{{appid}}_sup.erl"}.  


这说明simpleapp模板提供了一个叫appid的变量, 
下面自定义一个叫anmial的应用: 
Bash代码   收藏代码
  1. rebar create template=simpleapp appid=anmial  

而后发现src下多了3个和dog application相关的erl源代码 

实际上,rebar提供了一个直接建立application的子命令create-app: 
Bash代码   收藏代码
  1. rebar create-app appid=anmial  

效果同样。不过命令更短,帮助也详细(至少告诉咱们模板变量名是 appid) 


下面是以上例子建立了的文件: 
Bash代码   收藏代码
  1. find .  


./c_src 
./c_src/dragon.c 
./src 
./src/anmial_app.erl 
./src/cat.erl 
./src/anmial_sup.erl 
./src/anmial.app.src 
./src/fish.erl 
./src/myfsm.erl 
./src/dragon.erl 
./test 
./test/fish_tests.erl 


用rebar自动编译一下: 
Bash代码   收藏代码
  1. rebar compile  

能够发现源代码分别编译到ebin和priv两个目录下了,erlang是跨平台的,这没什么好说的。神奇的是nif(包括port driver)的动态共享库(so文件)也自动编译好了,并且对linux,mac 等自动跨平台支持。全部这些编译都由rebar compile一个命令搞定了。 

咱们能够经过加个-v参数详细查看编译过程当中rebar都作了什么: 
Bash代码   收藏代码
  1. rebar compile -v  

控制台上会详细打印出编译过程当中用到的命令和参数,还有相关的环境变量。 

如前所述,这些命令参数咱们能够经过rebar.config进行指定。例如生成nif动态共享库的连接参数,若是动态共享库还须要连接第三方库,那么须要为连接器指定相关连接参数 

比较坑爹的是,若是上面的例子中没有建立applicaton,compile默认是没法编译fsm,server或nif等模块的。整个工程必须有一个application 
Bash代码   收藏代码
  1. rebar create-app appid=animal  

对于nif模块也是如此。 

能够在rebar.config中经过为port_envs设置环境变量CFLAGS和LDFLAGS指定编译或连接的参数: 

在port_envs哪些变量能够定制,彷佛没有什么在线文档,因此直接看rebar的源代码程序:rebar_port_compiler.erl。开头的注释中就说明了能够定制哪些参数,有编译的也有连接的。 

举个例子,我最近写的一个nif模块c代码用到了c99的一些特性,还使用到了一个第三方共享库gdal。linux下nif动态库的编译并连接的命令是这样的: 
Bash代码   收藏代码
  1. gcc -std=c99 -fPIC -shared -o gdal_nifs.so gdal_nifs.c -I$ERL_HOME/usr/include -lgdal  

mac下的的编译连接命令是这样: 
Bash代码   收藏代码
  1. gcc -std=c99 -fPIC -bundle -undefined suppress -flat_namespace -o gdal_nifs.so gdal_nifs.c -I$ERL_HOME/usr/include -lgdal  


rebar已经考虑了跨平台编译连接的不一样参数问题,我还须要定制如下两个参数: 
1) 指定 c99 标准编译; -std=c99 
2) 指定gdal动态库的连接: -lgdal 

所以,个人rebar.config定制文件就是 
Rebar.config代码   收藏代码
  1. {port_specs, [{"priv/xxxx.so", ["c_src/*.c"}]}.  
  2. {port_env, [  
  3.     {"CFLAGS", "$CFLAGS -std=c99"},  
  4.     {"LDFLAGS", "$LDFLAGS -lgdal"}  
  5.     ]}.  


之后就能够经过rebar compile跨各类平台编译了。 


清理编译好的文件: 
Bash代码   收藏代码
  1. rebar clean  

刚才rebar自动编译好的目标文件(beam和so)都会自动删掉。 

注:该命令不会清除全部目标文件,它只清除由rebar生成的文件。 

模板是针对某种有着固定模式或结构的代码的,实际上咱们也能够本身写模版。本身的代码模板能够放在工程的 priv/templates目录下。rebar list-templates会自动列出该目录和当前目录下的全部模板,模板格式看一下官方提供的例子,简单的说就是模板变量的字符串替换,也没啥高深的。 

要是以为本身的模板不错也能够提交上去有可能会成为官方模板哦。 


3.依赖的管理 

较大的应用会依赖其它应用,rebar提供了对这些依赖的管理。在erlang工程的目录结构上,rebar对此有所扩展,全部的其余依赖应用都放在deps目录下,这是rebar工程比较独特的地方。 

工程依赖的其余应用都会放在deps目录下。在rebar.config配置,一个例子: 
{deps, [ 
  {lager, ".*", {git, "git://github.com/basho/lager", {branch, "master"}}}, 
  {poolboy, ".*", {git, "git://github.com/basho/poolboy", {branch, "master"}}}, 
  {webmachine, ".*", {git, "git://github.com/basho/webmachine", 
                              {branch, "master"}}} 
       ]}. 

项目的目录结构: 
tree -L 2 

├── deps 
│   ├── lager 
│   ├── poolboy 
│   ├── mochiweb 
│   └── webmachine 
├── ebin 
├── priv 
├── rebar.config 
└── src 
    ├── xxx_app.erl 
    ├── xxx.app.src 
    └── xxx_sup.erl 

(其中mochiweb又是webmachine依赖的应用) 

一个问题是依赖的应用还依赖其它应用,这时要注意deps配置参数中这些应用的顺序,例如若是上述配置中(举个例子)可能许多其它应用都依赖lager这个应用,这时,lager的配置就应该放在它们以前。 



5.常见问题 

1) 
rebar有着erlang的并行处理能力,缺省状况下每一个子命令有3个job worker并行处理,能够经过-j参数控制并行处理的worker数量。 

不过因为这种并行处理能力,有时候发现会出现灵异现象,好比有次我想同时清理而后编译: 
Barh代码   收藏代码
  1. rebar clean; rebar compile  

发现新的改写代码没有起做用,改为 
Bash代码   收藏代码
  1. rebar clean  
  2. rebar compile  

就没有问题了。 

如今个人用法是: 
rebar clean compile 

2。若是有如下状况: 
  • 某个应用没有启动;
  • lib下没有某个应用;
  • lib下某个应用对应的目录没有版本信息;
  • lib下某个应用对应的目录没有编译好的beam文件

这是由于对应的应用没有编译,就直接rebar generate的原故。 

依赖的第三方应用,包括本应用没有编译过,(即每一个应用ebin目录下没有beam文件),则rebar generate生成的发布目录中的时候就不会有对应的应用(能够看到该应用实际上是一个空壳:对应的目录不带版本信息,并且没有beam文件),即便在reltool.config中指定了这些应用也没用。 

3. 若是但愿系统启动时,某个应用随之启动 
第三方应用可能并不保证在系统初始化时启动,要想让其在初始化时启动,能够在reltool.config文件的修改'rel'项,增长对应的应用,例如想让lager初始化时自动启动: 
{rel, "xxx", "1.0", [kernel, stdlib,sasl, lager, xxx]} 


由于rebar文档不全,并且几乎天天都有代码修改,处于不断的快速进化中,早期的文档如今看来有的陈旧了,好比网上许多文档都提到了rebar的dialyzer静态分析,实际上最新的rebar已经再也不有这个子命令了。 

遇到问题通常能够去翻翻rebar.config.sample,这个配置模板提供了rebar.config的几乎全部配置变量及其说明。好比个人需求中须要写好几个nif模块,每一个nif模块都有本身对应的so.在rebar.config.sample中找到这几行代码: 
Rebar.config.sample代码   收藏代码
  1. %% so_specs - useful for building multiple *.so files  
  2. %%            from one or more object files  
  3. {so_specs, [{"priv/so_name.so", ["c_src/object_file_name.o"]}]}.  
相关文章
相关标签/搜索