rebar是一個開源的erlang應用自動構建工具。
basho的
tuncer開發。它其實是一個erlang腳本(escript)的工具,所以在不一樣平臺間遷移起來比較方便。
1.安裝
能夠去github下載源代碼編譯
- git clone git://github.com/basho/rebar.git
構建rebar工具
把編譯好的rebar放到系統目錄中完成安裝:
- sudo mv rebar /usr/local/bin
查看rebar的版本檢查一下安裝:
rebar version: 2 date: 20110827_060830 vcs: git 8376693
不過經過源代碼獲得的是不穩定的版本,使用時會出現些小問題。
也有現成的穩定rebar下載:
- 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)添加一行:
- 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的使用訣竅。例如這句
- {pre_hooks, [{clean, "./prepare_package_files.sh"},
- {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:
- $ rebar create template=simpleapp
也能夠建立一個fsm的模塊:
- $ rebar create template=simplefsm
再來一個server模塊:
- $ rebar create template=simplesrv
而後在src查看這些自動生成的代碼就能理解所謂的rebar 自動生成模板是怎麼回事了。
每類模板都有它們本身的生成控制變量,沒有這些變量,一切都是默認的。例如上面的實驗裏,都沒有指定模塊的控制變量,因此生成的模塊都是叫myxxx之類的缺省名字。
在rebar源代碼目錄的priv/templates目錄下有全部缺省模板的源程序,查閱這些模板的源碼能夠幫助咱們理解rebar的這些模板建立命令的變量是如何工做的:
A) simplefsm.template模板
- {variables, [{fsmid, "myfsm"}]}.
- {template, "simplefsm.erl", "src/{{fsmid}}.erl"}.
這說明fsm模板提供了一個fsmid的變量控制着fsm模塊的生成,自定義一個:
- rebar create template=simplefsm fsmid=cat
就在src下建立了一個fsm的cat模塊
B) simplemod.tempalte模板
- {variables, [{modid, "mymod"}]}.
- {template, "simplemod.erl", "src/{{modid}}.erl"}.
- {template, "simplemod_tests.erl", "test/{{modid}}_tests.erl"}.
能夠經過這個模板建立一個普通的erlang模塊,同時它會自動生成該模塊的單元測試代碼:
該模板提供的控制變量是modid
下面建立一個叫fish的erlang模塊:
- rebar create template=simplemod modid=fish
C)basicnif.template模板
- {variables, [{module, "mymodule"}]}.
- {template, "basicnif.erl", "src/{{module}}.erl"}.
- {template, "basicnif.c", "c_src/{{module}}.c"}.
這個模板是用來生成nif模塊的,它提供了一個叫module的控制變量
試着生成一個叫dragon的nif模塊看看:
- rebar create template=basicnif module=dragon
nif的c代碼和erl代碼分別放在c_src和src目錄下了。
D) simpleapp.template模板
- {variables, [{appid, "myapp"}]}.
- {template, "simpleapp.app.src", "src/{{appid}}.app.src"}.
- {template, "simpleapp_app.erl", "src/{{appid}}_app.erl"}.
- {template, "simpleapp_sup.erl", "src/{{appid}}_sup.erl"}.
這說明simpleapp模板提供了一個叫appid的變量,
下面自定義一個叫anmial的應用:
- rebar create template=simpleapp appid=anmial
而後發現src下多了3個和dog application相關的erl源代碼
實際上,rebar提供了一個直接建立application的子命令create-app:
- rebar create-app appid=anmial
效果同樣。不過命令更短,幫助也詳細(至少告訴咱們模板變量名是 appid)
下面是以上例子建立了的文件:
.
./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自動編譯一下:
能夠發現源代碼分別編譯到ebin和priv兩個目錄下了,erlang是跨平臺的,這沒什麼好說的。神奇的是nif(包括port driver)的動態共享庫(so文件)也自動編譯好了,並且對linux,mac 等自動跨平臺支持。全部這些編譯都由rebar compile一個命令搞定了。
咱們能夠經過加個-v參數詳細查看編譯過程當中rebar都作了什麼:
控制檯上會詳細打印出編譯過程當中用到的命令和參數,還有相關的環境變量。
如前所述,這些命令參數咱們能夠經過rebar.config進行指定。例如生成nif動態共享庫的連接參數,若是動態共享庫還須要連接第三方庫,那麼須要爲連接器指定相關連接參數
比較坑爹的是,若是上面的例子中沒有建立applicaton,compile默認是沒法編譯fsm,server或nif等模塊的。整個工程必須有一個application
- 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動態庫的編譯並連接的命令是這樣的:
- gcc -std=c99 -fPIC -shared -o gdal_nifs.so gdal_nifs.c -I$ERL_HOME/usr/include -lgdal
mac下的的編譯連接命令是這樣:
- 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定製文件就是
- {port_specs, [{"priv/xxxx.so", ["c_src/*.c"}]}.
- {port_env, [
- {"CFLAGS", "$CFLAGS -std=c99"},
- {"LDFLAGS", "$LDFLAGS -lgdal"}
- ]}.
之後就能夠經過rebar compile跨各類平臺編譯了。
清理編譯好的文件:
剛纔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數量。
不過因爲這種並行處理能力,有時候發現會出現靈異現象,好比有次我想同時清理而後編譯:
- rebar clean; rebar compile
發現新的改寫代碼沒有起做用,改爲
- rebar clean
- 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中找到這幾行代碼:
- %% so_specs - useful for building multiple *.so files
- %% from one or more object files
- {so_specs, [{"priv/so_name.so", ["c_src/object_file_name.o"]}]}.