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