3 # Thomas Nagy, 2006 (ita)
8 import TaskGen
, Utils
, Task
, Build
10 from TaskGen
import taskgen
, feature
, before
, after
, extension
18 open_re
= re
.compile('^\s*open\s+([a-zA-Z]+)(;;){0,1}$', re
.M
)
19 foo
= re
.compile(r
"""(\(\*)|(\*\))|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^()*"'\\]*)""", re
.M
)
20 def filter_comments(txt
):
23 if m
.group(1): meh
[0] += 1
24 elif m
.group(2): meh
[0] -= 1
25 elif not meh
[0]: return m
.group(0)
27 return foo
.sub(repl
, txt
)
31 code
= filter_comments(node
.read(self
.env
))
35 import_iterator
= open_re
.finditer(code
)
37 for import_match
in import_iterator
:
38 names
.append(import_match
.group(1))
43 for x
in self
.incpaths
:
44 nd
= x
.find_resource(name
.lower()+'.ml')
45 if not nd
: nd
= x
.find_resource(name
+'.ml')
52 return (found_lst
, raw_lst
)
54 native_lst
=['native', 'all', 'c_object']
55 bytecode_lst
=['bytecode', 'all']
56 class ocaml_taskgen(TaskGen
.task_gen
):
57 def __init__(self
, *k
, **kw
):
58 TaskGen
.task_gen
.__init
__(self
, *k
, **kw
)
65 bld_incpaths_lst
= [],
81 def init_envs_ml(self
):
83 self
.islibrary
= getattr(self
, 'islibrary', False)
85 global native_lst
, bytecode_lst
86 self
.native_env
= None
87 if self
.type in native_lst
:
88 self
.native_env
= self
.env
.copy()
89 if self
.islibrary
: self
.native_env
['OCALINKFLAGS'] = '-a'
91 self
.bytecode_env
= None
92 if self
.type in bytecode_lst
:
93 self
.bytecode_env
= self
.env
.copy()
94 if self
.islibrary
: self
.bytecode_env
['OCALINKFLAGS'] = '-a'
96 if self
.type == 'c_object':
97 self
.native_env
.append_unique('OCALINKFLAGS_OPT', '-output-obj')
100 @before('apply_vars_ml')
101 @after('init_envs_ml')
102 def apply_incpaths_ml(self
):
103 inc_lst
= self
.includes
.split()
104 lst
= self
.incpaths_lst
106 node
= self
.path
.find_dir(dir)
108 error("node not found: " + str(dir))
110 self
.bld
.rescan(node
)
111 if not node
in lst
: lst
.append(node
)
112 self
.bld_incpaths_lst
.append(node
)
113 # now the nodes are added to self.incpaths_lst
116 @before('apply_core')
117 def apply_vars_ml(self
):
118 for i
in self
.incpaths_lst
:
119 if self
.bytecode_env
:
120 app
= self
.bytecode_env
.append_value
121 app('OCAMLPATH', '-I')
122 app('OCAMLPATH', i
.srcpath(self
.env
))
123 app('OCAMLPATH', '-I')
124 app('OCAMLPATH', i
.bldpath(self
.env
))
127 app
= self
.native_env
.append_value
128 app('OCAMLPATH', '-I')
129 app('OCAMLPATH', i
.bldpath(self
.env
))
130 app('OCAMLPATH', '-I')
131 app('OCAMLPATH', i
.srcpath(self
.env
))
133 varnames
= ['INCLUDES', 'OCAMLFLAGS', 'OCALINKFLAGS', 'OCALINKFLAGS_OPT']
134 for name
in self
.uselib
.split():
135 for vname
in varnames
:
136 cnt
= self
.env
[vname
+'_'+name
]
138 if self
.bytecode_env
: self
.bytecode_env
.append_value(vname
, cnt
)
139 if self
.native_env
: self
.native_env
.append_value(vname
, cnt
)
143 def apply_link_ml(self
):
145 if self
.bytecode_env
:
146 ext
= self
.islibrary
and '.cma' or '.run'
148 linktask
= self
.create_task('ocalink')
149 linktask
.bytecode
= 1
150 linktask
.set_outputs(self
.path
.find_or_declare(self
.target
+ ext
))
152 linktask
.env
= self
.bytecode_env
153 self
.linktasks
.append(linktask
)
156 if self
.type == 'c_object': ext
= '.o'
157 elif self
.islibrary
: ext
= '.cmxa'
160 linktask
= self
.create_task('ocalinkx')
161 linktask
.set_outputs(self
.path
.find_or_declare(self
.target
+ ext
))
163 linktask
.env
= self
.native_env
164 self
.linktasks
.append(linktask
)
166 # we produce a .o file to be used by gcc
167 self
.compiled_tasks
.append(linktask
)
170 def mll_hook(self
, node
):
171 mll_task
= self
.create_task('ocamllex', node
, node
.change_ext('.ml'), env
=self
.native_env
)
172 self
.mlltasks
.append(mll_task
)
174 self
.allnodes
.append(mll_task
.outputs
[0])
177 def mly_hook(self
, node
):
178 mly_task
= self
.create_task('ocamlyacc', node
, [node
.change_ext('.ml'), node
.change_ext('.mli')], env
=self
.native_env
)
179 self
.mlytasks
.append(mly_task
)
180 self
.allnodes
.append(mly_task
.outputs
[0])
182 task
= self
.create_task('ocamlcmi', mly_task
.outputs
[1], mly_task
.outputs
[1].change_ext('.cmi'), env
=self
.native_env
)
185 def mli_hook(self
, node
):
186 task
= self
.create_task('ocamlcmi', node
, node
.change_ext('.cmi'), env
=self
.native_env
)
187 self
.mlitasks
.append(task
)
190 def mlc_hook(self
, node
):
191 task
= self
.create_task('ocamlcc', node
, node
.change_ext('.o'), env
=self
.native_env
)
192 self
.compiled_tasks
.append(task
)
195 def ml_hook(self
, node
):
197 task
= self
.create_task('ocamlx', node
, node
.change_ext('.cmx'), env
=self
.native_env
)
199 task
.incpaths
= self
.bld_incpaths_lst
200 self
.native_tasks
.append(task
)
202 if self
.bytecode_env
:
203 task
= self
.create_task('ocaml', node
, node
.change_ext('.cmo'), env
=self
.bytecode_env
)
206 task
.incpaths
= self
.bld_incpaths_lst
207 self
.bytecode_tasks
.append(task
)
209 def compile_may_start(self
):
210 if not getattr(self
, 'flag_deps', ''):
213 # the evil part is that we can only compute the dependencies after the
214 # source files can be read (this means actually producing the source files)
215 if getattr(self
, 'bytecode', ''): alltasks
= self
.obj
.bytecode_tasks
216 else: alltasks
= self
.obj
.native_tasks
218 self
.signature() # ensure that files are scanned - unfortunately
219 tree
= self
.generator
.bld
221 for node
in self
.inputs
:
222 lst
= tree
.node_deps
[self
.unique_id()]
225 if t
== self
: continue
226 if depnode
in t
.inputs
:
227 self
.set_run_after(t
)
229 # TODO necessary to get the signature right - for now
230 delattr(self
, 'cache_sig')
233 return Task
.Task
.runnable_status(self
)
235 b
= Task
.simple_task_type
236 cls
= b('ocamlx', '${OCAMLOPT} ${OCAMLPATH} ${OCAMLFLAGS} ${INCLUDES} -c -o ${TGT} ${SRC}', color
='GREEN', shell
=False)
237 cls
.runnable_status
= compile_may_start
240 b
= Task
.simple_task_type
241 cls
= b('ocaml', '${OCAMLC} ${OCAMLPATH} ${OCAMLFLAGS} ${INCLUDES} -c -o ${TGT} ${SRC}', color
='GREEN', shell
=False)
242 cls
.runnable_status
= compile_may_start
246 b('ocamlcmi', '${OCAMLC} ${OCAMLPATH} ${INCLUDES} -o ${TGT} -c ${SRC}', color
='BLUE', before
="ocaml ocamlcc ocamlx")
247 b('ocamlcc', 'cd ${TGT[0].bld_dir(env)} && ${OCAMLOPT} ${OCAMLFLAGS} ${OCAMLPATH} ${INCLUDES} -c ${SRC[0].abspath(env)}', color
='GREEN')
249 b('ocamllex', '${OCAMLLEX} ${SRC} -o ${TGT}', color
='BLUE', before
="ocamlcmi ocaml ocamlcc")
250 b('ocamlyacc', '${OCAMLYACC} -b ${TGT[0].bld_base(env)} ${SRC}', color
='BLUE', before
="ocamlcmi ocaml ocamlcc")
253 def link_may_start(self
):
254 if not getattr(self
, 'order', ''):
256 # now reorder the inputs given the task dependencies
257 if getattr(self
, 'bytecode', 0): alltasks
= self
.obj
.bytecode_tasks
258 else: alltasks
= self
.obj
.native_tasks
260 # this part is difficult, we do not have a total order on the tasks
261 # if the dependencies are wrong, this may not stop
263 pendant
= []+alltasks
265 task
= pendant
.pop(0)
266 if task
in seen
: continue
267 for x
in task
.run_after
:
273 self
.inputs
= [x
.outputs
[0] for x
in seen
]
275 return Task
.Task
.runnable_status(self
)
277 act
= b('ocalink', '${OCAMLC} -o ${TGT} ${INCLUDES} ${OCALINKFLAGS} ${SRC}', color
='YELLOW', after
="ocaml ocamlcc")
278 act
.runnable_status
= link_may_start
279 act
= b('ocalinkx', '${OCAMLOPT} -o ${TGT} ${INCLUDES} ${OCALINKFLAGS_OPT} ${SRC}', color
='YELLOW', after
="ocamlx ocamlcc")
280 act
.runnable_status
= link_may_start
283 opt
= conf
.find_program('ocamlopt', var
='OCAMLOPT')
284 occ
= conf
.find_program('ocamlc', var
='OCAMLC')
285 if (not opt
) or (not occ
):
286 conf
.fatal('The objective caml compiler was not found:\ninstall it or make it available in your PATH')
291 v
['OCAMLLEX'] = conf
.find_program('ocamllex', var
='OCAMLLEX')
292 v
['OCAMLYACC'] = conf
.find_program('ocamlyacc', var
='OCAMLYACC')
294 v
['OCAMLLIB'] = Utils
.cmd_output(conf
.env
['OCAMLC']+' -where').strip()+os
.sep
295 v
['LIBPATH_OCAML'] = Utils
.cmd_output(conf
.env
['OCAMLC']+' -where').strip()+os
.sep
296 v
['CPPPATH_OCAML'] = Utils
.cmd_output(conf
.env
['OCAMLC']+' -where').strip()+os
.sep
297 v
['LIB_OCAML'] = 'camlrun'