rebar2构建工具学习

安装

1git clone git://github.com/basho/rebar.git  
2cd rebar
3make
4sudo cp rebar /usr/local/bin

或使用稳定的版本:

1curl -o rebar http://cloud.github.com/downloads/basho/rebar/rebar  

使用

rebar作者教程:http://vimeo.com/8311407

rebar官方文档:https://github.com/basho/rebar/wiki

rebar的工程配置文件

每个erlang工程会有一个rebar.config控制rebar的使用,当然rebar.config不是必须的,没有的话一切都按rebar缺省的来。rebar安装路径下有一个rebar.config.sample的文件,研究这个文件可以发现许多rebar的使用诀窍。

使用rebar时加上-v参数可以详细的打印出rebar构建过程时的相关命令和参数,这有助于我们查看rebar.config文件的配置是否正确。

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 list-templates 子命令可以查看rebar缺省提供的工程模板(当然也可以创建自己的模板)

模板是针对某种有着固定模式或结构的代码的,例如OTP的3个著名模式都有着各自的程序骨架,每次写一个srv或者fsm的模块,我们都得重复写许多固定的骨架代码,rebar通过模板帮我们省下了这些重复工作,我们只管往里面填应用的逻辑代码就行了。

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

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

 1rebar create template=simpleapp 
 2rebar create-app appid=anmial 
 3
 4rebar create template=simplefsm 
 5
 6rebar create template=simplesrv
 7
 8rebar compile 
 9rebar compile -v  
10

rebar.config

erl_opts

概述

使用rebar构建Erlang project的时候,通过设置rebar.config可以为rebar配置各种选项。

其中比较常用的有 erl_opts 这个选项。

1{erl_opts, [smp, debug_info, {d, 'APP', myproject}, {d, debug}]}.

实际上它是设置Erlang Compiler的参数。(详细说明见 http://www.erlang.org/doc/man/compile.html

平时我们可以在每个 .erl 文件的头部写上这种语句

1-compile({no_auto_import,[error/1]}).

来告诉编译器编译本文件时用到的编译选项。

如果把这些参数放在rebar.config里面设置的话,就可以对所有文件使用同一套编译参数了。

比如在rebar.config里面:

1{erl_opts, [smp, debug_info, nowarn_unused_function]}.

这里设置了nowarn_unused_function,即module中有未被使用的function时不触发警告。

效果等同于在每个module文件中加入这句

1-compile(nowarn_unused_function).

{d, macro, value}

有如下情景,使用rebar.config来配置全局编译参数时会比较方便:

在开发和调试阶段,可能有需要在console打印一些调试信息,通常会用到io:format. 但是发布的程序,在正式环境下是不需要打印这些东西的。

那么我们可以这样做。

在rebar.config设置erl_opts, 定义一个Macro, {d, debug}, 表示调试模式。

1{erl_opts, [smp, no_debug_info, {d, debug}]}.

然后在一个全局的hrl文件中定义输出调试信息的Macro

1-ifdef(debug).
2-define(TRACE(Str), io:format(Str)).
3-define(TRACE(Str, Args), io:format(Str, Args)).
4-else.
5-define(TRACE(Str), void).
6-define(TRACE(Str, Args), void).
7-endif.

这样,我们在需要打印调试信息的地方用

TRACE(“something to show”) 而不是直接用 io:format.

好处是, 当发布正式版本时, 只须要把rebar.config里面的{d, debug}去掉而不用改动代码,就可以不打印调试信息了。

{i,Dir}

{i,Dir}-在包含文件时将Dir添加到要搜索的目录列表中。当遇到-include或-include_lib指令时,编译器会在以下目录中搜索头文件:

  • “.”,文件服务器的当前工作目录
  • 编译文件的基本名称
  • 使用选项i指定的目录;首先搜索最后指定的目录

deps

这里面放的是依赖库,然后应用程序就可以直接调用对应模块的函数了。

port_envs

可以在rebar.config中通过为port_envs设置环境变量CFLAGS和LDFLAGS指定编译或链接的参数。

在port_envs哪些变量可以定制,似乎没有什么在线文档,所以直接看rebar的源代码程序:rebar_port_compiler.erl。开头的注释中就说明了可以定制哪些参数,有编译的也有链接的。

举个例子,我最近写的一个nif模块c代码用到了c99的一些特性,还使用到了一个第三方共享库gdal。linux下nif动态库的编译并链接的命令是这样的:

1gcc -std=c99 -fPIC -shared -o gdal_nifs.so gdal_nifs.c -I$ERL_HOME/usr/include -lgdal 

mac下的的编译链接命令是这样:

1gcc -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定制文件就是

1{port_envs, [ 
2   {"CFLAGS", "$CFLAGS -std=c99"}, 
3   {"LDFLAGS", "$LDFLAGS -lgdal"} 
4   ]}. 

以后就可以通过rebar compile跨各种平台编译了。

port_specs

要编译的文件名或通配符列表。也可能包含元组,由应用于系统的正则表达式组成,架构作为过滤器

rebar.config.sample

https://github.com/rebar/rebar/blame/b6d309417c502ca243f810e5313bea36951ef038/rebar.config.sample