erlang.py (3515B)
1 #!/usr/bin/env python 2 # encoding: utf-8 3 # Thomas Nagy, 2010 (ita) 4 # Przemyslaw Rzepecki, 2016 5 6 """ 7 Erlang support 8 """ 9 10 import re 11 from waflib import Task, TaskGen 12 from waflib.TaskGen import feature, after_method, before_method 13 # to load the method "to_incnodes" below 14 from waflib.Tools import ccroot 15 16 # Those flags are required by the Erlang VM to execute/evaluate code in 17 # non-interactive mode. It is used in this tool to create Erlang modules 18 # documentation and run unit tests. The user can pass additional arguments to the 19 # 'erl' command with ERL_FLAGS environment variable. 20 EXEC_NON_INTERACTIVE = ['-noshell', '-noinput', '-eval'] 21 22 def configure(conf): 23 conf.find_program('erlc', var='ERLC') 24 conf.find_program('erl', var='ERL') 25 conf.add_os_flags('ERLC_FLAGS') 26 conf.add_os_flags('ERL_FLAGS') 27 conf.env.ERLC_DEF_PATTERN = '-D%s' 28 conf.env.ERLC_INC_PATTERN = '-I%s' 29 30 @TaskGen.extension('.erl') 31 def process_erl_node(self, node): 32 tsk = self.create_task('erl', node, node.change_ext('.beam')) 33 tsk.erlc_incnodes = [tsk.outputs[0].parent] + self.to_incnodes(self.includes) 34 tsk.env.append_value('ERLC_INCPATHS', [x.abspath() for x in tsk.erlc_incnodes]) 35 tsk.env.append_value('ERLC_DEFINES', self.to_list(getattr(self, 'defines', []))) 36 tsk.env.append_value('ERLC_FLAGS', self.to_list(getattr(self, 'flags', []))) 37 tsk.cwd = tsk.outputs[0].parent 38 39 class erl(Task.Task): 40 color = 'GREEN' 41 run_str = '${ERLC} ${ERL_FLAGS} ${ERLC_INC_PATTERN:ERLC_INCPATHS} ${ERLC_DEF_PATTERN:ERLC_DEFINES} ${SRC}' 42 43 def scan(task): 44 node = task.inputs[0] 45 46 deps = [] 47 scanned = set([]) 48 nodes_to_scan = [node] 49 50 for n in nodes_to_scan: 51 if n.abspath() in scanned: 52 continue 53 54 for i in re.findall(r'-include\("(.*)"\)\.', n.read()): 55 for d in task.erlc_incnodes: 56 r = d.find_node(i) 57 if r: 58 deps.append(r) 59 nodes_to_scan.append(r) 60 break 61 scanned.add(n.abspath()) 62 63 return (deps, []) 64 65 @TaskGen.extension('.beam') 66 def process(self, node): 67 pass 68 69 70 class erl_test(Task.Task): 71 color = 'BLUE' 72 run_str = '${ERL} ${ERL_FLAGS} ${ERL_TEST_FLAGS}' 73 74 @feature('eunit') 75 @after_method('process_source') 76 def add_erl_test_run(self): 77 test_modules = [t.outputs[0] for t in self.tasks] 78 test_task = self.create_task('erl_test') 79 test_task.set_inputs(self.source + test_modules) 80 test_task.cwd = test_modules[0].parent 81 82 test_task.env.append_value('ERL_FLAGS', self.to_list(getattr(self, 'flags', []))) 83 84 test_list = ", ".join([m.change_ext("").path_from(test_task.cwd)+":test()" for m in test_modules]) 85 test_flag = 'halt(case lists:all(fun(Elem) -> Elem == ok end, [%s]) of true -> 0; false -> 1 end).' % test_list 86 test_task.env.append_value('ERL_TEST_FLAGS', EXEC_NON_INTERACTIVE) 87 test_task.env.append_value('ERL_TEST_FLAGS', test_flag) 88 89 90 class edoc(Task.Task): 91 color = 'BLUE' 92 run_str = "${ERL} ${ERL_FLAGS} ${ERL_DOC_FLAGS}" 93 def keyword(self): 94 return 'Generating edoc' 95 96 @feature('edoc') 97 @before_method('process_source') 98 def add_edoc_task(self): 99 # do not process source, it would create double erl->beam task 100 self.meths.remove('process_source') 101 e = self.path.find_resource(self.source) 102 t = e.change_ext('.html') 103 png = t.parent.make_node('erlang.png') 104 css = t.parent.make_node('stylesheet.css') 105 tsk = self.create_task('edoc', e, [t, png, css]) 106 tsk.cwd = tsk.outputs[0].parent 107 tsk.env.append_value('ERL_DOC_FLAGS', EXEC_NON_INTERACTIVE) 108 tsk.env.append_value('ERL_DOC_FLAGS', 'edoc:files(["%s"]), halt(0).' % tsk.inputs[0].abspath()) 109 # TODO the above can break if a file path contains '"' 110