2
3:- use_module(library(biomake/biomake)). 4:- use_module(library(biomake/utils)). 5:- use_module(library(biomake/embed)). 6
10
12:- nodebug(verbose). 13:- nodebug(build). 14:- nodebug(md5). 15
16
17main :-
18 current_prolog_flag(argv, Arguments),
19 (append(_SytemArgs, [--|Args], Arguments) ; =(Arguments,Args)),
20 !,
21 parse_args(Args,TmpOpts),
22 get_cmd_args(TmpOpts,Opts),
23 add_assignments(Opts),
24 bind_special_variables(Opts),
25 eval_makefile_syntax_args(Opts2,Opts),
26 eval_makespec_syntax_args(Opts3,Opts2),
27 consult_makefile(Opts4,Opts3),
28 AllOpts = Opts4,
29 forall(member(goal(G),AllOpts),
30 G),
31 forall(member(flush_queue(T),AllOpts),
32 flush_queue_recursive(T,AllOpts)),
33 (build_toplevel(AllOpts)
34 -> halt_success
35 ; halt_error).
36
37build_toplevel(Opts) :-
38 member(toplevel(_),Opts),
39 !,
40 start_queue(Opts),
41 forall(member(toplevel(T),Opts),
42 build(T,Opts)),
43 finish_queue(Opts).
44
45build_toplevel(Opts) :-
46 nonbuild_task_specified(Opts),
47 !.
48
49build_toplevel(Opts) :-
50 start_queue(Opts),
51 build_default(Opts),
52 finish_queue(Opts).
53
54nonbuild_task_specified(Opts) :- member(translate_gnu_makefile(_),Opts).
55nonbuild_task_specified(Opts) :- member(goal(_),Opts).
56nonbuild_task_specified(Opts) :- member(flush_queue(_),Opts).
57
58add_assignments(Opts) :-
59 forall(member(assignment(Var,Val),Opts),
60 add_cmdline_assignment((Var = Val))).
61
62eval_makefile_syntax_args(OptsOut,OptsIn) :-
63 bagof(Eval,member(eval_makefile_syntax(Eval),OptsIn),Evals),
64 !,
65 ensure_loaded(library(biomake/gnumake_parser)),
66 eval_makefile_syntax_args(Evals,OptsOut,OptsIn).
67eval_makefile_syntax_args(Opts,Opts).
68eval_makefile_syntax_args([Eval|Evals],OptsOut,OptsIn) :-
69 eval_gnu_makefile(Eval,_,Opts,OptsIn),
70 eval_makefile_syntax_args(Evals,OptsOut,Opts).
71eval_makefile_syntax_args([],Opts,Opts).
72
73eval_makespec_syntax_args(OptsOut,OptsIn) :-
74 bagof(Eval,member(eval_makespec_syntax(Eval),OptsIn),Evals),
75 !,
76 eval_makespec_syntax_args(Evals,OptsOut,OptsIn).
77eval_makespec_syntax_args(Opts,Opts).
78eval_makespec_syntax_args([Eval|Evals],OptsOut,OptsIn) :-
79 eval_atom_as_makeprog_term(Eval,Opts,OptsIn),
80 eval_makespec_syntax_args(Evals,OptsOut,Opts).
81eval_makespec_syntax_args([],Opts,Opts).
82
83consult_makefile(AllOpts,Opts) :-
84 DefaultMakeprogs = ['Makeprog','makeprog','Makespec.pro','makespec.pro'],
85 DefaultGnuMakefiles = ['Makefile','makefile'],
86 (member(makeprog(BF),Opts)
87 -> consult_makeprog(BF,AllOpts,Opts);
88 (member(gnu_makefile(F),Opts)
89 -> consult_gnu_makefile(F,AllOpts,Opts);
90 (find_file(DefaultMakeprog,DefaultMakeprogs)
91 -> consult_makeprog(DefaultMakeprog,AllOpts,Opts);
92 (find_file(DefaultGnuMakefile,DefaultGnuMakefiles)
93 -> consult_gnu_makefile(DefaultGnuMakefile,AllOpts,Opts)
94 ; (format("No Makefile found~n"),
95 halt_error))))).
96
97find_file(File,List) :-
98 member(File,List),
99 exists_file(File),
100 !.
101
105
106parse_args([],[]).
107parse_args([Alias|Rest],Opt) :-
108 arg_alias(Arg,Alias),
109 !,
110 parse_args([Arg|Rest],Opt).
111parse_args([ArgEqualsVal|Rest],Opts) :-
112 string_chars(ArgEqualsVal,C),
113 phrase(arg_equals_val(Arg,Val),C),
114 !,
115 parse_args([Arg,Val|Rest],Opts).
116parse_args([MultiArgs|Args],Opts) :-
117 string_codes(MultiArgs,C),
118 phrase(multi_args(MultiOpts),C),
119 !,
120 append(MultiOpts,RestOpts,Opts),
121 parse_args(Args,RestOpts).
122parse_args(Args,Opts) :-
123 parse_arg(Args,RestArgs,Opt),
124 !,
125 (Opt = [_|_] -> ArgOpts = Opt; ArgOpts = [Opt]),
126 append(ArgOpts,RestOpts,Opts),
127 parse_args(RestArgs,RestOpts).
128parse_args([A|Args],[toplevel(A)|Opts]) :-
129 parse_args(Args,Opts).
130
131arg_equals_val(Arg,Val) --> arg_chars(Arg), ['='], !, val_chars(Val).
132arg_chars(A) --> ['-','-'], char_list(Ac,"="), {atom_chars(A,['-','-'|Ac])}.
133val_chars(V) --> atom_from_chars(V,"").
134
135get_cmd_args(FlatOpts,Opts) :-
136 (bagof(Arg,arg_from_opts(Arg,FlatOpts),LumpyCore);
137 LumpyCore=[]),
138 flatten(LumpyCore,Core),
139 concat_string_list_spaced(Core,CoreStr),
140 biomake_prog(Cmd),
141 absolute_file_name(Cmd,CmdPath),
142 working_directory(CWD,CWD),
143 default_qsub_biomake_args(DQ),
144 CmdOpts = [biomake_prog(CmdPath),
145 biomake_args(CoreStr),
146 biomake_cwd(CWD),
147 qsub_biomake_args(DQ)],
148 append(FlatOpts,CmdOpts,Opts).
149
150arg_from_opts(Arg,Opts) :-
151 member(Opt,Opts),
152 recover_arg(Arg,Opt).
153
154multi_args(Opts) --> "-", multi_arg(Opts).
155multi_arg([Opt|Rest]) --> [C], {char_code('-',H),C\=H,atom_codes(Arg,[H,C])}, !, {parse_arg([Arg],[],Opt)}, !, multi_arg(Rest).
156multi_arg([]) --> !.
157
158:- discontiguous parse_arg/3. 159:- discontiguous recover_arg/2. 160:- discontiguous simple_arg/2. 161:- discontiguous arg_alias/2. 162:- discontiguous arg_info/3. 163
164parse_arg([Arg|L],L,Opt) :- simple_arg(Arg,Opt).
165recover_arg(Arg,Opt) :- simple_arg(Arg,Opt).
166
170
171parse_arg(['-h'|L],L,null) :- show_help, !.
172arg_alias('-h','--help').
173arg_info('-h','','Show help').
174
175show_help :-
176 writeln('biomake [OPTION...] target1 target2...'),
177 nl,
178 writeln('Options:'),
179 forall(arg_info(X,Args,Info),
180 ((bagof(Alias,arg_alias(X,Alias),AliasList); AliasList = []),
181 atomic_list_concat([X|AliasList],",",AliasStr),
182 format("~w ~w~n ~w~n",[AliasStr,Args,Info]))),
183 nl,
184 writeln('For more info see http://github.com/evoldoers/biomake'),
185 nl,
186 halt_success.
187
188parse_arg(['-v'|L],L,null) :- show_version, !.
189arg_alias('-v','--version').
190arg_info('-v','','Show version').
191
192show_version :-
193 writeln('Biomake v0.1.5'),
194 writeln('Copyright (C) 2016 Evolutionary Software Foundation, Inc.'),
195 writeln('Authors: Chris Mungall, Ian Holmes.'),
196 writeln('This is free software; see the source for copying conditions.'),
197 writeln('There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A'),
198 writeln('PARTICULAR PURPOSE.'),
199 halt_success.
200
201simple_arg('-n',dry_run(true)).
202arg_alias('-n','--dry-run').
203arg_alias('-n','--recon').
204arg_alias('-n','--just-print').
205arg_info('-n','','Print the commands that would be executed, but do not execute them').
206
207simple_arg('-B',always_make(true)).
208arg_alias('-B','--always-make').
209arg_info('-B','','Always build fresh target even if dependency is up to date').
210
211parse_arg(['-f',F|L],L,gnu_makefile(F)).
212arg_alias('-f','--file').
213arg_alias('-f','--makefile').
214recover_arg(['-f',Fabs],gnu_makefile(F)) :- absolute_file_name(F,Fabs).
215arg_info('-f','GNUMAKEFILE','Use a GNU Makefile as the build specification [default: Makefile]').
216
217parse_arg(['-p',F|L],L,makeprog(F)).
218arg_alias('-p','--prog').
219arg_alias('-p','--makeprog').
220recover_arg(['-p',Fabs],makeprog(F)) :- absolute_file_name(F,Fabs).
221arg_info('-p','MAKEPROG','Use MAKEPROG as the (Prolog) build specification [default: Makeprog]').
222
223parse_arg(['-m',Text|L],L,eval_makefile_syntax(Text)).
224recover_arg(['-m',Text],eval_makefile_syntax(Text)).
225arg_alias('-m','--eval').
226arg_alias('-m','--makefile-syntax').
227arg_info('-m','STRING','Evaluate STRING as GNU Makefile syntax').
228
229parse_arg(['-P',Text|L],L,eval_makespec_syntax(Text)).
230recover_arg(['-P',Text],eval_makespec_syntax(Text)).
231arg_alias('-P','--eval-prolog').
232arg_alias('-P','--makeprog-syntax').
233arg_info('-P','STRING','Evaluate STRING as Prolog Makeprog syntax').
234
235parse_arg(['-I',D|L],L,include_dir(D)).
236arg_alias('-I','--include-dir').
237recover_arg(['-I',Dabs],include_dir(D)) :- absolute_file_name(D,Dabs).
238arg_info('-I','DIR','Specify search directory for included Makefiles').
239
240parse_arg(['--target',T|L],L,toplevel(T)).
241arg_info('--target','TARGET','Force biomake to recognize a target even if it looks like an option').
242
243parse_arg(['-T',F|L],L,translate_gnu_makefile(F)).
244arg_alias('-T','--translate').
245arg_alias('-T','--save-prolog').
246arg_info('-T','FILE','Translate GNU Makefile to Prolog Makeprog syntax').
247
248parse_arg(['-W',F|L],L,what_if(Fs)) :- atom_string(F,Fs).
249arg_alias('-W','--what-if').
250arg_alias('-W','--new-file').
251arg_alias('-W','--assume-new').
252recover_arg(['-W',F],what_if(F)).
253arg_info('-W','TARGET','Pretend that TARGET has been modified').
254
255parse_arg(['-o',F|L],L,old_file(Fs)) :- atom_string(F,Fs).
256arg_alias('-o','--old-file').
257arg_alias('-o','--assume-old').
258recover_arg(['-o',F],old_file(F)).
259arg_info('-o','TARGET','Do not remake TARGET, or remake anything on account of it').
260
261simple_arg('-k',keep_going_on_error(true)).
262arg_alias('-k','--keep-going').
263arg_info('-k','','Keep going after error').
264
265simple_arg('-S',keep_going_on_error(false)).
266arg_alias('-S','--no-keep-going').
267arg_alias('-S','--stop').
268arg_info('-S','','Stop after error').
269
270simple_arg('-t',touch_only(true)).
271arg_alias('-t','--touch').
272arg_info('-t','','Touch files (& update MD5 hashes, if appropriate) instead of running recipes').
273
274parse_arg(['-N'|L],L,no_deps(true)).
275arg_alias('-N','--no-dependencies').
276arg_info('-N','','Do not test or rebuild dependencies').
277
278parse_arg(['-D',Var,Val|L],L,assignment(Var,Val)).
279arg_alias('-D','--define').
280parse_arg([VarEqualsVal|L],L,assignment(Var,Val)) :-
281 string_codes(VarEqualsVal,C),
282 phrase(makefile_assign(Var,Val),C).
283recover_arg(VarEqualsVal,assignment(Var,Val)) :-
284 format(string(VarEqualsVal),"--define ~w ~q",[Var,Val]).
285arg_info('-D','Var Val','Assign Makefile variables from command line').
286arg_info('Var=Val','','Alternative syntax for \'-D Var Val\'').
287
288makefile_assign(Var,Val) --> makefile_var(Var), "=", makefile_val(Val).
289makefile_var(A) --> makefile_var_atom_from_codes(A).
290makefile_val(S) --> "\"", string_from_codes(S,"\""), "\"".
291makefile_val(S) --> string_from_codes(S," ").
292
296
297parse_arg(['-l',F|L],L,
298 goal( (collect_stored_targets(F,[]),
299 show_stored_targets
300 ) )) :-
301 ensure_loaded(library(biomake/scan)),
302 !.
303arg_info('-l','DIRECTORY','Iterates through directory writing metadata on each file found').
304
305simple_arg('-s',silent(true)).
306arg_alias('-s','--quiet').
307arg_alias('-s','--silent').
308arg_info('-s','','Silent operation; do not print recipes as they are executed').
309
310simple_arg('--one-shell',oneshell(true)).
311arg_info('--one-shell','','Run recipes in single shell (loosely equivalent to GNU Make\'s .ONESHELL)').
312
316
317parse_arg(['-H'|L],L,md5(true)) :- ensure_loaded(library(biomake/md5hash)), !.
318arg_alias('-H','--md5-hash').
319arg_alias('-H','--md5-checksum').
320recover_arg(['-H'],md5(true)).
321arg_info('-H','','Use MD5 hashes instead of timestamps').
322
323simple_arg('-C',no_md5_cache(true)).
324arg_alias('-C','--no-md5-cache').
325arg_info('-C','','Recompute MD5 checksums whenever biomake is restarted').
326
327simple_arg('-M',ignore_md5_timestamp(true)).
328arg_alias('-M','--no-md5-timestamp').
329arg_info('-M','','Do not recompute MD5 checksums when timestamps appear stale').
330
334
335parse_arg(['-Q',Qs|L],L,queue(Q)) :-
336 ensure_loaded(library(biomake/queue)),
337 atom_string(Q,Qs),
338 queue_engine(Q),
339 !.
340parse_arg(['-Q',Qs|L],L,null) :- format("Warning: unknown queue '~w'~n",Qs), !.
341arg_alias('-Q','--queue-engine').
342arg_info('-Q','ENGINE','Queue recipes using ENGINE (supported: poolq,sge,pbs,slurm,test)').
343
344parse_arg(['-j',Jobs|L],L,poolq_threads(NJobs)) :- atom_number(Jobs,NJobs).
345arg_alias('-j','--jobs').
346arg_info('-j','JOBS','Number of job threads (poolq engine)').
347
348parse_arg(['--qsub-exec',X|L],L,qsub_exec(X)).
349arg_alias('--qsub-exec','--sbatch-exec').
350arg_info('--qsub-exec','PATH','Path to qsub (sge,pbs) or sbatch (slurm)').
351
352parse_arg(['--qdel-exec',X|L],L,qsub_exec(X)).
353arg_alias('--qdel-exec','--scancel-exec').
354arg_info('--qdel-exec','PATH','Path to qdel (sge,pbs) or scancel (slurm)').
355
356parse_arg(['--queue-args',X|L],L,queue_args(X)).
357arg_info('--queue-args','\'ARGS\'','Queue-specifying arguments for qsub/qdel (sge,pbs) or sbatch/scancel (slurm)').
358
359parse_arg(['--qsub-args',X|L],L,qsub_args(X)).
360arg_alias('--qsub-args','--sbatch-args').
361arg_info('--qsub-args','\'ARGS\'','Additional arguments for qsub (sge,pbs) or sbatch (slurm)').
362
363parse_arg(['--qsub-use-biomake'|L],L,qsub_use_biomake(true)).
364arg_alias('--qsub-use-biomake','--sbatch-use-biomake').
365arg_info('--qsub-use-biomake','','Force qsub/sbatch to always call biomake recursively').
366
367parse_arg(['--qsub-biomake-args',X|L],L,qsub_args(X)).
368parse_arg(['--qsub-biomake-args',X|L],L,qsub_args(X)).
369arg_alias('--qsub-biomake-args','--sbatch-biomake-args').
370default_qsub_biomake_args('-N').
371arg_info('--qsub-biomake-args','\'ARGS\'',S) :-
372 default_qsub_biomake_args(Default),
373 format(atom(S),'Arguments passed recursively to biomake by qsub/sbatch (default: ~q)',[Default]).
374
375parse_arg(['--qsub-header',X|L],L,qsub_header(X)).
376arg_alias('--qsub-header','--sbatch-header').
377arg_info('--qsub-header','\'HEADER\'','Header for qsub (sge,pbs) or sbatch (slurm)').
378
379parse_arg(['--qsub-header-file',X|L],L,qsub_header_file(X)).
380arg_alias('--qsub-header-file','--sbatch-header-file').
381arg_info('--qsub-header-file','\'FILENAME\'','Header file for qsub (sge,pbs) or sbatch (slurm)').
382
383parse_arg(['--qdel-args',X|L],L,qdel_args(X)).
384arg_alias('--qdel-args','--scancel-args').
385arg_info('--qdel-args','\'ARGS\'','Additional arguments for qdel (sge,pbs) or scancel (slurm)').
386
387parse_arg(['--flush',X|L],L,flush_queue(X)).
388arg_alias('--flush','--qsub-flush').
389arg_info('--flush','<target or directory>','Erase all jobs for given target/dir').
390
394
395parse_arg(['-d'|L],L,null) :- debug(verbose), debug(build), set_prolog_flag(verbose,normal).
396arg_info('-d','','[developers] Print debugging messages. Equivalent to \'--debug verbose\'').
397
398parse_arg(['--debug',D|L],L,null) :- debug(D), set_prolog_flag(verbose,normal).
399arg_info('--debug','MSG','[developers] Richer debugging messages. MSG can be verbose, bindrule, build, pattern, makefile, makeprog, md5...').
400
401parse_arg(['--trace',Pred|L],L,null) :- trace(Pred), !.
402arg_info('--trace','PREDICATE','[developers] Print debugging trace for given predicate').
403
404parse_arg(['--no-backtrace'|L],L,null) :- disable_backtrace, !.
405arg_info('--no-backtrace','','[developers] Do not print a backtrace on error')