Erlang makefile,运行时生成
我为我的erlang项目编写了一个makefile,它可以正常工作。但在项目运行时,如果我更改了一个文件并使用makefile创建它,新版本的代码将无法工作,我必须退出shell并再次启动它以运行新版本。如何解决呢 生成文件:Erlang makefile,运行时生成,makefile,erlang,Makefile,Erlang,我为我的erlang项目编写了一个makefile,它可以正常工作。但在项目运行时,如果我更改了一个文件并使用makefile创建它,新版本的代码将无法工作,我必须退出shell并再次启动它以运行新版本。如何解决呢 生成文件: # Makefile SRC_DIR = src BIN_DIR = ebin DB_DIR = db ERL = erl ERLC = erlc ERLC_FLAGS= SOURCES=$(wildcard ${SRC_DIR}/*.erl) HEADERS=$
# Makefile
SRC_DIR = src
BIN_DIR = ebin
DB_DIR = db
ERL = erl
ERLC = erlc
ERLC_FLAGS=
SOURCES=$(wildcard ${SRC_DIR}/*.erl)
HEADERS=$(wildcard ${SRC_DIR}/*.hrl)
OBJECTS=$(SOURCES:${SRC_DIR}/%.erl=${BIN_DIR}/%.beam)
all: $(OBJECTS)
ebin/%.beam : src/%.erl $(HEADERS) Makefile
${ERLC} $(ERLC_FLAGS) -o ${BIN_DIR}/ $<
drop_db:
rm -r ${DB_DIR}
clean:
-rm $(OBJECTS)
run:
${ERL} -pa ${BIN_DIR} -s god run
#生成文件
SRC_DIR=SRC
BIN_DIR=ebin
DB_DIR=DB
厄尔=厄尔
ERLC=ERLC
厄尔库旗=
SOURCES=$(通配符${SRC_DIR}/*.erl)
HEADERS=$(通配符${SRC_DIR}/*.hrl)
OBJECTS=$(源:${SRC_DIR}/%.erl=${BIN_DIR}/%.beam)
全部:$(对象)
ebin/%.beam:src/%.erl$(标题)生成文件
${ERLC}$(ERLC_标志)-o${BIN_DIR}/$<
drop_db:
rm-r${DB_DIR}
清洁:
-rm$(对象)
运行:
${ERL}-pa${BIN_DIR}-s god run
Erlang允许在运行时轻松修改应用程序代码,但这并不意味着它对用户是透明的
希望它不是透明的,否则该特性将无法使用,或者仅限于琐碎的用例。以下是我想到的证明代码更改必须由用户负责和控制的前3个原因:
- 从一个版本到另一个版本,可能需要调整数据(修改记录、修改结构、新数据…)。所以在转换时,新版本的代码必须更新状态数据;它甚至必须验证它是否能够做到这一点(它是否有从版本X到版本Y的转换代码)。OTP行为为此提供了特殊回调
- 应用程序修改可能涉及多个模块中的更改,并且一个模块可能由多个进程运行(例如,web客户端)。但是代码是在非常特定的时间(完全限定调用)在流程级别更新的,并且不能同时对所有流程进行更新。因此,您必须控制模块升级的顺序。功能
允许这样做code:load_file(模块)
- 一个节点中只能同时存在(:o)2个版本的模块。如果您运行一个模块,然后两次加载该模块进行2次修改,最旧的代码将“消失”,并且仍然使用此版本的任何进程都将死亡。您需要同步升级。功能
可帮助您实现这一点code:soft\u purge(模块)
- 新的beam文件(编译后的代码)必须位于Erlang VM的代码路径中(或者您必须在下一步中使用
)code:load\u abs(Filename)
- 您必须在VM中加载新代码。如果使用
将自动完成。如果通过其他方式编译,则必须使用例如c(my_模块)从shell编译代码。
在VM中显式加载新代码code:load\u file(my\u模块)
- 然后,您必须确保使用此模块的每个进程执行对导出函数的完全限定调用,即:
。如果使用OTP行为,则存在此回调,并在参数中为您提供旧版本的代码my\u模块:code\u更改(状态)
-module(one).
-compile([export_all]).
-define (VERSION,1).
start() ->
rserver,spawn(?MODULE,init,[]).
init() ->
loop(0).
loop(N) ->
receive
print ->
io:format("received ~p message(s) so far~n",[N+1]),
loop(N+1);
load ->
io:format("received ~p message(s) so far~n reload the code~n",[N+1]),
?MODULE:loop(N+1);
version ->
io:format("received ~p message(s) so far~n version is ~p~n",[N+1,?VERSION]),
loop(N+1);
M ->
io:format("received unexpected message ~p: ignored~n",[M]),
loop(N)
end.
我在shell中编译它,启动两个进程并使用它们:
1> c(one).
{ok,one}
2> P1 = one:start().
<0.40.0>
3> P2 = one:start().
<0.42.0>
4> P1 ! print.
received 1 message(s) so far
print
5> P1 ! print.
received 2 message(s) so far
print
6> P1 ! version.
received 3 message(s) so far
version is 1
version
7> P1 ! reset.
received unexpected message reset: ignored
reset
8> P2 ! print.
received 1 message(s) so far
print
9>
在VM外部编译并测试:
9> P1 ! version.
received 4 message(s) so far
version is 1
version
10> P1 ! load.
received 5 message(s) so far
reload the code
load
11> P1 ! version.
received 6 message(s) so far
version is 1
version
12> P1 ! reset.
received unexpected message reset: ignored
reset
13> P2 ! print.
received 2 message(s) so far
print
14>
因为我没有加载代码,所以没有更新:如果每次外部调用都有新版本,VM将不会浪费时间在代码路径中搜索
14> code:load_file(one).
{module,one}
15> P1 ! version.
received 7 message(s) so far
version is 1
version
16> P2 ! version.
received 3 message(s) so far
version is 1
version
17> P1 ! load.
received 8 message(s) so far
reload the code
load
18> P1 ! version.
received 9 message(s) so far
version is 2
version
19> P1 ! reset.
received 10 message(s) so far, reset message count
reset
20> P1 ! print.
received 1 message(s) so far
print
21> P2 ! version.
received 4 message(s) so far
version is 1
version
22> P2 ! print.
received 5 message(s) so far
print
23>
加载新代码后,我已经能够升级P1的版本,而P2仍然在版本1上
现在我做了一个新的修改,只需转到版本3并在shell中编译,以强制加载代码:
23> c(one).
{ok,one}
24> P1 ! version.
received 2 message(s) so far
version is 2
version
25> P1 ! load.
received 3 message(s) so far
reload the code
load
26> P1 ! version.
received 4 message(s) so far
version is 3
version
27> P2 ! print.
print
28>
我已经能够将流程P1从版本2升级到版本3。但是仍然使用版本1的进程P2已停止。运行
make run
不会运行新代码,或者您以前运行的shell不会神奇地看到新编译的代码?你正在加载新代码吗?您是否有在erlang代码中切换旧运行代码的代码?编译后如何加载新模块?我已经很久没有使用erlang了,不能肯定这一点,但我认为只需从shell中再次编译它就足够了。在外部编译之后,您可能只需要告诉shell加载它(使用m()
或类似的方法)。但我真的不知道。我想大多数优秀的erlang指南都会涵盖这一点
23> c(one).
{ok,one}
24> P1 ! version.
received 2 message(s) so far
version is 2
version
25> P1 ! load.
received 3 message(s) so far
reload the code
load
26> P1 ! version.
received 4 message(s) so far
version is 3
version
27> P2 ! print.
print
28>