36
37:- module('$autoload',
38 [ '$find_library'/5,
39 '$in_library'/3,
40 '$define_predicate'/1,
41 '$update_library_index'/0,
42 '$autoload'/1,
43
44 make_library_index/1,
45 make_library_index/2,
46 reload_library_index/0,
47 autoload_path/1,
48
49 autoload/1, 50 autoload/2, 51
52 require/1 53 ]). 54
55:- meta_predicate
56 '$autoload'(:),
57 autoload(:),
58 autoload(:, +),
59 require(:). 60
61:- dynamic
62 library_index/3, 63 autoload_directories/1, 64 index_checked_at/1. 65:- volatile
66 library_index/3,
67 autoload_directories/1,
68 index_checked_at/1. 69
70user:file_search_path(autoload, swi(library)).
71user:file_search_path(autoload, pce(prolog/lib)).
72user:file_search_path(autoload, app_config(lib)).
73
74
82
83'$find_library'(Module, Name, Arity, LoadModule, Library) :-
84 load_library_index(Name, Arity),
85 functor(Head, Name, Arity),
86 ( library_index(Head, Module, Library),
87 LoadModule = Module
88 ; library_index(Head, LoadModule, Library)
89 ),
90 !.
91
96
97'$in_library'(Name, Arity, Path) :-
98 atom(Name), integer(Arity),
99 !,
100 load_library_index(Name, Arity),
101 functor(Head, Name, Arity),
102 library_index(Head, _, Path).
103'$in_library'(Name, Arity, Path) :-
104 load_library_index(Name, Arity),
105 library_index(Head, _, Path),
106 functor(Head, Name, Arity).
107
112
113:- meta_predicate
114 '$define_predicate'(:). 115
116'$define_predicate'(Head) :-
117 '$defined_predicate'(Head),
118 !.
119'$define_predicate'(Term) :-
120 Term = Module:Head,
121 ( compound(Head)
122 -> compound_name_arity(Head, Name, Arity)
123 ; Name = Head, Arity = 0
124 ),
125 '$undefined_procedure'(Module, Name, Arity, retry).
126
127
128 131
132:- thread_local
133 silent/0. 134
141
142'$update_library_index' :-
143 setof(Dir, writable_indexed_directory(Dir), Dirs),
144 !,
145 setup_call_cleanup(
146 asserta(silent, Ref),
147 guarded_make_library_index(Dirs),
148 erase(Ref)),
149 ( flag('$modified_index', true, false)
150 -> reload_library_index
151 ; true
152 ).
153'$update_library_index'.
154
155guarded_make_library_index([]).
156guarded_make_library_index([Dir|Dirs]) :-
157 ( catch(make_library_index(Dir), E,
158 print_message(error, E))
159 -> true
160 ; print_message(warning, goal_failed(make_library_index(Dir)))
161 ),
162 guarded_make_library_index(Dirs).
163
168
169writable_indexed_directory(Dir) :-
170 index_file_name(IndexFile, autoload('INDEX'), [access([read,write])]),
171 file_directory_name(IndexFile, Dir).
172writable_indexed_directory(Dir) :-
173 absolute_file_name(library('MKINDEX'),
174 [ file_type(prolog),
175 access(read),
176 solutions(all),
177 file_errors(fail)
178 ], MkIndexFile),
179 file_directory_name(MkIndexFile, Dir),
180 plfile_in_dir(Dir, 'INDEX', _, IndexFile),
181 access_file(IndexFile, write).
182
183
184 187
191
192reload_library_index :-
193 context_module(M),
194 reload_library_index(M).
195
196reload_library_index(M) :-
197 with_mutex('$autoload', clear_library_index(M)).
198
199clear_library_index(M) :-
200 retractall(M:library_index(_, _, _)),
201 retractall(M:autoload_directories(_)),
202 retractall(M:index_checked_at(_)).
203
204
211
212:- meta_predicate load_library_index(?, ?, :). 213:- public load_library_index/3. 214
215load_library_index(Name, Arity) :-
216 load_library_index(Name, Arity, autoload('INDEX')).
217
218load_library_index(Name, Arity, M:_Spec) :-
219 atom(Name), integer(Arity),
220 functor(Head, Name, Arity),
221 M:library_index(Head, _, _),
222 !.
223load_library_index(_, _, Spec) :-
224 notrace(with_mutex('$autoload', load_library_index_p(Spec))).
225
226load_library_index_p(M:_) :-
227 M:index_checked_at(Time),
228 get_time(Now),
229 Now-Time < 60,
230 !.
231load_library_index_p(M:Spec) :-
232 findall(Index, index_file_name(Index, Spec, [access(read)]), List0),
233 '$list_to_set'(List0, List),
234 retractall(M:index_checked_at(_)),
235 get_time(Now),
236 assert(M:index_checked_at(Now)),
237 ( M:autoload_directories(List)
238 -> true
239 ; retractall(M:library_index(_, _, _)),
240 retractall(M:autoload_directories(_)),
241 read_index(List, M),
242 assert(M:autoload_directories(List))
243 ).
244
252
253index_file_name(IndexFile, FileSpec, Options) :-
254 absolute_file_name(FileSpec,
255 IndexFile,
256 [ file_type(prolog),
257 solutions(all),
258 file_errors(fail)
259 | Options
260 ]).
261
262read_index([], _) :- !.
263read_index([H|T], M) :-
264 !,
265 read_index(H, M),
266 read_index(T, M).
267read_index(Index, M) :-
268 print_message(silent, autoload(read_index(Dir))),
269 file_directory_name(Index, Dir),
270 setup_call_cleanup(
271 '$push_input_context'(autoload_index),
272 setup_call_cleanup(
273 open(Index, read, In),
274 read_index_from_stream(Dir, In, M),
275 close(In)),
276 '$pop_input_context').
277
278read_index_from_stream(Dir, In, M) :-
279 repeat,
280 read(In, Term),
281 assert_index(Term, Dir, M),
282 !.
283
284assert_index(end_of_file, _, _) :- !.
285assert_index(index(Name, Arity, Module, File), Dir, M) :-
286 !,
287 functor(Head, Name, Arity),
288 atomic_list_concat([Dir, '/', File], Path),
289 assertz(M:library_index(Head, Module, Path)),
290 fail.
291assert_index(Term, Dir, _) :-
292 print_message(error, illegal_autoload_index(Dir, Term)),
293 fail.
294
295
296 299
310
311make_library_index(Dir0) :-
312 forall(absolute_file_name(Dir0, Dir,
313 [ expand(true),
314 file_type(directory),
315 file_errors(fail),
316 solutions(all)
317 ]),
318 make_library_index2(Dir)).
319
320make_library_index2(Dir) :-
321 plfile_in_dir(Dir, 'MKINDEX', _MkIndex, AbsMkIndex),
322 access_file(AbsMkIndex, read),
323 !,
324 load_files(user:AbsMkIndex, [silent(true)]).
325make_library_index2(Dir) :-
326 findall(Pattern, source_file_pattern(Pattern), PatternList),
327 make_library_index2(Dir, PatternList).
328
341
342make_library_index(Dir0, Patterns) :-
343 forall(absolute_file_name(Dir0, Dir,
344 [ expand(true),
345 file_type(directory),
346 file_errors(fail),
347 solutions(all)
348 ]),
349 make_library_index2(Dir, Patterns)).
350
351make_library_index2(Dir, Patterns) :-
352 plfile_in_dir(Dir, 'INDEX', _Index, AbsIndex),
353 ensure_slash(Dir, DirS),
354 pattern_files(Patterns, DirS, Files),
355 ( library_index_out_of_date(Dir, AbsIndex, Files)
356 -> do_make_library_index(AbsIndex, DirS, Files),
357 flag('$modified_index', _, true)
358 ; true
359 ).
360
361ensure_slash(Dir, DirS) :-
362 ( sub_atom(Dir, _, _, 0, /)
363 -> DirS = Dir
364 ; atom_concat(Dir, /, DirS)
365 ).
366
367source_file_pattern(Pattern) :-
368 user:prolog_file_type(PlExt, prolog),
369 PlExt \== qlf,
370 atom_concat('*.', PlExt, Pattern).
371
372plfile_in_dir(Dir, Base, PlBase, File) :-
373 file_name_extension(Base, pl, PlBase),
374 atomic_list_concat([Dir, '/', PlBase], File).
375
376pattern_files([], _, []).
377pattern_files([H|T], DirS, Files) :-
378 atom_concat(DirS, H, P0),
379 expand_file_name(P0, Files0),
380 '$append'(Files0, Rest, Files),
381 pattern_files(T, DirS, Rest).
382
383library_index_out_of_date(_Dir, Index, _Files) :-
384 \+ exists_file(Index),
385 !.
386library_index_out_of_date(Dir, Index, Files) :-
387 time_file(Index, IndexTime),
388 ( time_file(Dir, DotTime),
389 DotTime > IndexTime
390 ; '$member'(File, Files),
391 time_file(File, FileTime),
392 FileTime > IndexTime
393 ),
394 !.
395
396
397do_make_library_index(Index, Dir, Files) :-
398 ensure_slash(Dir, DirS),
399 '$stage_file'(Index, StagedIndex),
400 setup_call_catcher_cleanup(
401 open(StagedIndex, write, Out),
402 ( print_message(informational, make(library_index(Dir))),
403 index_header(Out),
404 index_files(Files, DirS, Out)
405 ),
406 Catcher,
407 install_index(Out, Catcher, StagedIndex, Index)).
408
409install_index(Out, Catcher, StagedIndex, Index) :-
410 catch(close(Out), Error, true),
411 ( silent
412 -> OnError = silent
413 ; OnError = error
414 ),
415 ( var(Error)
416 -> TheCatcher = Catcher
417 ; TheCatcher = exception(Error)
418 ),
419 '$install_staged_file'(TheCatcher, StagedIndex, Index, OnError).
420
424
425index_files([], _, _).
426index_files([File|Files], DirS, Fd) :-
427 ( catch(exports(File, Module, Public), E,
428 print_message(warning, E)),
429 nonvar(Module)
430 -> atom_concat(DirS, Local, File),
431 file_name_extension(Base, _, Local),
432 forall(public_predicate(Public, Name/Arity),
433 format(Fd, 'index((~k), ~k, ~k, ~k).~n',
434 [Name, Arity, Module, Base]))
435 ; true
436 ),
437 index_files(Files, DirS, Fd).
438
439public_predicate(Public, PI) :-
440 '$member'(PI0, Public),
441 canonical_pi(PI0, PI).
442
443canonical_pi(Var, _) :-
444 var(Var), !, fail.
445canonical_pi(Name/Arity, Name/Arity).
446canonical_pi(Name//A0, Name/Arity) :-
447 Arity is A0 + 2.
448
449
(Fd):-
451 format(Fd, '/* Creator: make/0~n~n', []),
452 format(Fd, ' Purpose: Provide index for autoload~n', []),
453 format(Fd, '*/~n~n', []).
454
455exports(File, Module, Exports) :-
456 ( current_prolog_flag(xref, Old)
457 -> true
458 ; Old = false
459 ),
460 setup_call_cleanup(
461 set_prolog_flag(xref, true),
462 exports_(File, Module, Exports),
463 set_prolog_flag(xref, Old)).
464
465exports_(File, Module, Exports) :-
466 State = state(true, _, []),
467 ( '$source_term'(File, _,_,Term0,_,_,[syntax_errors(quiet)]),
468 ( is_list(Term0)
469 -> '$member'(Term, Term0)
470 ; Term = Term0
471 ),
472 ( Term = (:- module(M,Public)),
473 is_list(Public),
474 arg(1, State, true)
475 -> nb_setarg(1, State, false),
476 nb_setarg(2, State, M),
477 nb_setarg(3, State, Public),
478 fail
479 ; nb_setarg(1, State, false),
480 fail
481 ; Term = (:- export(PI)),
482 ground(PI)
483 -> arg(3, State, E0),
484 '$append'(E0, [PI], E1),
485 nb_setarg(3, State, E1),
486 fail
487 ; Term = (:- use_foreign_library(Lib)),
488 nonvar(Lib),
489 arg(2, State, M),
490 atom(M)
491 -> catch('$syspreds':use_foreign_library_noi(M:Lib), error(_,_), true),
492 fail
493 ; Term = (:- Directive),
494 nonvar(Directive)
495 -> fail
496 ; !
497 )
498 ; true
499 ),
500 arg(2, State, Module),
501 arg(3, State, Exports).
502
503
504 507
522
523autoload_path(Alias) :-
524 ( user:file_search_path(autoload, Alias)
525 -> true
526 ; assertz(user:file_search_path(autoload, Alias)),
527 reload_library_index
528 ).
529
530system:term_expansion((:- autoload_path(Alias)),
531 [ user:file_search_path(autoload, Alias),
532 (:- reload_library_index)
533 ]).
534
535
536 539
547
548'$autoload'(PI) :-
549 source_location(File, _Line),
550 !,
551 setup_call_cleanup(
552 '$start_aux'(File, Context),
553 '$autoload2'(PI),
554 '$end_aux'(File, Context)).
555'$autoload'(PI) :-
556 '$autoload2'(PI).
557
558'$autoload2'(PI) :-
559 setup_call_cleanup(
560 leave_sandbox(Old),
561 '$autoload3'(PI),
562 restore_sandbox(Old)).
563
564leave_sandbox(Sandboxed) :-
565 current_prolog_flag(sandboxed_load, Sandboxed),
566 set_prolog_flag(sandboxed_load, false).
567restore_sandbox(Sandboxed) :-
568 set_prolog_flag(sandboxed_load, Sandboxed).
569
570'$autoload3'(PI) :-
571 autoload_from(PI, LoadModule, FullFile),
572 do_autoload(FullFile, PI, LoadModule).
573
578
579autoload_from(Module:PI, LoadModule, FullFile) :-
580 autoload_in(Module, explicit),
581 current_autoload(Module:File, Ctx, import(Imports)),
582 memberchk(PI, Imports),
583 library_info(File, Ctx, FullFile, LoadModule, Exports),
584 ( pi_in_exports(PI, Exports)
585 -> !
586 ; autoload_error(Ctx, not_exported(PI, File, FullFile, Exports)),
587 fail
588 ).
589autoload_from(Module:Name/Arity, LoadModule, FullFile) :-
590 autoload_in(Module, explicit),
591 PI = Name/Arity,
592 current_autoload(Module:File, Ctx, all),
593 library_info(File, Ctx, FullFile, LoadModule, Exports),
594 pi_in_exports(PI, Exports).
595autoload_from(Module:Name/Arity, LoadModule, Library) :-
596 autoload_in(Module, general),
597 '$find_library'(Module, Name, Arity, LoadModule, Library).
598
599:- public autoload_in/2. 600
601autoload_in(Module, How) :-
602 current_prolog_flag(autoload, AutoLoad),
603 autoload_in(AutoLoad, How, Module),
604 !.
605
607
608autoload_in(true, _, _).
609autoload_in(explicit, explicit, _).
610autoload_in(user, _, user).
611autoload_in(user_or_explicit, explicit, _).
612autoload_in(user_or_explicit, _, user).
613
614
627
628do_autoload(Library, Module:Name/Arity, LoadModule) :-
629 functor(Head, Name, Arity),
630 '$update_autoload_level'([autoload(true)], Old),
631 verbose_autoload(Module:Name/Arity, Library),
632 '$compilation_mode'(OldComp, database),
633 ( Module == LoadModule
634 -> ensure_loaded(Module:Library)
635 ; ( '$c_current_predicate'(_, LoadModule:Head),
636 '$get_predicate_attribute'(LoadModule:Head, defined, 1),
637 \+ '$loading'(Library)
638 -> Module:import(LoadModule:Name/Arity)
639 ; use_module(Module:Library, [Name/Arity])
640 )
641 ),
642 '$set_compilation_mode'(OldComp),
643 '$set_autoload_level'(Old),
644 '$c_current_predicate'(_, Module:Head).
645
646verbose_autoload(PI, Library) :-
647 current_prolog_flag(verbose_autoload, true),
648 !,
649 set_prolog_flag(verbose_autoload, false),
650 print_message(informational, autoload(PI, Library)),
651 set_prolog_flag(verbose_autoload, true).
652verbose_autoload(PI, Library) :-
653 print_message(silent, autoload(PI, Library)).
654
655
661
662:- public 663 autoloadable/2. 664
665autoloadable(M:Head, FullFile) :-
666 atom(M),
667 current_module(M),
668 autoload_in(M, explicit),
669 ( callable(Head)
670 -> goal_name_arity(Head, Name, Arity),
671 autoload_from(M:Name/Arity, _, FullFile)
672 ; findall((M:H)-F, autoloadable_2(M:H, F), Pairs),
673 ( '$member'(M:Head-FullFile, Pairs)
674 ; current_autoload(M:File, Ctx, all),
675 library_info(File, Ctx, FullFile, _, Exports),
676 '$member'(PI, Exports),
677 '$pi_head'(PI, Head),
678 \+ memberchk(M:Head-_, Pairs)
679 )
680 ).
681autoloadable(M:Head, FullFile) :-
682 ( var(M)
683 -> autoload_in(any, general)
684 ; autoload_in(M, general)
685 ),
686 ( callable(Head)
687 -> goal_name_arity(Head, Name, Arity),
688 ( '$find_library'(_, Name, Arity, _, FullFile)
689 -> true
690 )
691 ; '$in_library'(Name, Arity, autoload),
692 functor(Head, Name, Arity)
693 ).
694
695
696autoloadable_2(M:Head, FullFile) :-
697 current_autoload(M:File, Ctx, import(Imports)),
698 library_info(File, Ctx, FullFile, _LoadModule, _Exports),
699 '$member'(PI, Imports),
700 '$pi_head'(PI, Head).
701
702goal_name_arity(Head, Name, Arity) :-
703 compound(Head),
704 !,
705 compound_name_arity(Head, Name, Arity).
706goal_name_arity(Head, Head, 0).
707
711
712library_info(Spec, _, FullFile, Module, Exports) :-
713 '$resolved_source_path'(Spec, FullFile, []),
714 !,
715 ( \+ '$loading_file'(FullFile, _Queue, _LoadThread)
716 -> '$current_module'(Module, FullFile),
717 '$module_property'(Module, exports(Exports))
718 ; library_info_from_file(FullFile, Module, Exports)
719 ).
720library_info(Spec, Context, FullFile, Module, Exports) :-
721 ( Context = (Path:_Line)
722 -> Extra = [relative_to(Path)]
723 ; Extra = []
724 ),
725 ( absolute_file_name(Spec, FullFile,
726 [ file_type(prolog),
727 access(read),
728 file_errors(fail)
729 | Extra
730 ])
731 -> '$register_resolved_source_path'(Spec, FullFile),
732 library_info_from_file(FullFile, Module, Exports)
733 ; autoload_error(Context, no_file(Spec)),
734 fail
735 ).
736
737library_info_from_file(FullFile, Module, Exports) :-
738 setup_call_cleanup(
739 '$set_source_module'(OldModule, system),
740 setup_call_cleanup(
741 '$open_source'(FullFile, In, State, [], []),
742 '$term_in_file'(In, _Read, _RLayout, Term, _TLayout, _Stream,
743 [FullFile], []),
744 '$close_source'(State, true)),
745 '$set_source_module'(OldModule)),
746 ( Term = (:- module(Module, Exports))
747 -> !
748 ; nonvar(Term),
749 skip_header(Term)
750 -> fail
751 ; '$domain_error'(module_header, Term)
752 ).
753
(begin_of_file).
755
756
757:- dynamic printed/3. 758:- volatile printed/3. 759
760autoload_error(Context, Error) :-
761 suppress(Context, Error),
762 !.
763autoload_error(Context, Error) :-
764 get_time(Now),
765 assertz(printed(Context, Error, Now)),
766 print_message(warning, error(autoload(Error), autoload(Context))).
767
768suppress(Context, Error) :-
769 printed(Context, Error, Printed),
770 get_time(Now),
771 ( Now - Printed < 1
772 -> true
773 ; retractall(printed(Context, Error, _)),
774 fail
775 ).
776
777
778 781
782:- public
783 set_autoload/1. 784
791
792set_autoload(FlagValue) :-
793 current_prolog_flag(autoload, FlagValue),
794 !.
795set_autoload(FlagValue) :-
796 \+ autoload_in(FlagValue, explicit, any),
797 !,
798 setup_call_cleanup(
799 nb_setval('$autoload_disabling', true),
800 materialize_autoload(Count),
801 nb_delete('$autoload_disabling')),
802 print_message(informational, autoload(disabled(Count))).
803set_autoload(_).
804
805materialize_autoload(Count) :-
806 State = state(0),
807 forall(current_predicate(M:'$autoload'/3),
808 materialize_autoload(M, State)),
809 arg(1, State, Count).
810
811materialize_autoload(M, State) :-
812 ( current_autoload(M:File, Context, Import),
813 library_info(File, Context, FullFile, _LoadModule, _Exports),
814 arg(1, State, N0),
815 N is N0+1,
816 nb_setarg(1, State, N),
817 ( Import == all
818 -> verbose_autoload(M:all, FullFile),
819 use_module(M:FullFile)
820 ; Import = import(Preds)
821 -> verbose_autoload(M:Preds, FullFile),
822 use_module(M:FullFile, Preds)
823 ),
824 fail
825 ; true
826 ),
827 abolish(M:'$autoload'/3).
828
829
830 833
834autoload(M:File) :-
835 ( \+ autoload_in(M, explicit)
836 ; nb_current('$autoload_disabling', true)
837 ),
838 !,
839 use_module(M:File).
840autoload(M:File) :-
841 '$must_be'(filespec, File),
842 source_context(Context),
843 ( current_autoload(M:File, _, import(all))
844 -> true
845 ; assert_autoload(M:'$autoload'(File, Context, all))
846 ).
847
848autoload(M:File, Imports) :-
849 ( \+ autoload_in(M, explicit)
850 ; nb_current('$autoload_disabling', true)
851 ),
852 !,
853 use_module(M:File, Imports).
854autoload(M:File, Imports0) :-
855 '$must_be'(filespec, File),
856 valid_imports(Imports0, Imports),
857 source_context(Context),
858 register_autoloads(Imports, M, File, Context),
859 ( current_autoload(M:File, _, import(Imports))
860 -> true
861 ; assert_autoload(M:'$autoload'(File, Context, import(Imports)))
862 ).
863
864source_context(Path:Line) :-
865 source_location(Path, Line),
866 !.
867source_context(-).
868
869assert_autoload(Clause) :-
870 '$initialization_context'(Source, Ctx),
871 '$store_admin_clause2'(Clause, _Layout, Source, Ctx).
872
873valid_imports(Imports0, Imports) :-
874 '$must_be'(list, Imports0),
875 valid_import_list(Imports0, Imports).
876
877valid_import_list([], []).
878valid_import_list([H0|T0], [H|T]) :-
879 '$pi_head'(H0, Head),
880 '$pi_head'(H, Head),
881 valid_import_list(T0, T).
882
887
888register_autoloads([], _, _, _).
889register_autoloads([PI|T], Module, File, Context) :-
890 PI = Name/Arity,
891 functor(Head, Name, Arity),
892 ( '$get_predicate_attribute'(Module:Head, autoload, 1)
893 -> ( current_autoload(Module:_File0, _Ctx0, import(Imports)),
894 memberchk(PI, Imports)
895 -> '$permission_error'(redefine, imported_procedure, PI),
896 fail
897 ; Done = true
898 )
899 ; '$c_current_predicate'(_, Module:Head), 900 '$get_predicate_attribute'(Module:Head, imported, From)
901 -> ( ( '$resolved_source_path'(File, FullFile)
902 -> true
903 ; '$resolve_source_path'(File, FullFile, [])
904 ),
905 module_property(From, file(FullFile))
906 -> Done = true
907 ; print_message(warning,
908 autoload(already_defined(Module:PI, From))),
909 Done = true
910 )
911 ; true
912 ),
913 ( Done == true
914 -> true
915 ; '$set_predicate_attribute'(Module:Head, autoload, 1)
916 ),
917 register_autoloads(T, Module, File, Context).
918
919pi_in_exports(PI, Exports) :-
920 '$member'(E, Exports),
921 canonical_pi(E, PI),
922 !.
923
924current_autoload(M:File, Context, Term) :-
925 '$get_predicate_attribute'(M:'$autoload'(_,_,_), defined, 1),
926 M:'$autoload'(File, Context, Term).
927
928 931
936
937require(M:Spec) :-
938 ( is_list(Spec)
939 -> List = Spec
940 ; phrase(comma_list(Spec), List)
941 ), !,
942 require(List, M, FromLib),
943 keysort(FromLib, Sorted),
944 by_file(Sorted, Autoload),
945 forall('$member'(File-Import, Autoload),
946 autoload(M:File, Import)).
947require(_:Spec) :-
948 '$type_error'(list, Spec).
949
950require([],_, []).
951require([H|T], M, Needed) :-
952 '$pi_head'(H, Head),
953 ( '$get_predicate_attribute'(system:Head, defined, 1)
954 -> require(T, M, Needed)
955 ; '$pi_head'(Module:Name/Arity, M:Head),
956 ( '$find_library'(Module, Name, Arity, LoadModule, Library)
957 -> ( current_predicate(LoadModule:Name/Arity)
958 -> Module:import(LoadModule:Name/Arity),
959 require(T, M, Needed)
960 ; Needed = [Library-H|More],
961 require(T, M, More)
962 )
963 ; print_message(error, error(existence_error(procedure, Name/Arity), _)),
964 require(T, M, Needed)
965 )
966 ).
967
968by_file([], []).
969by_file([File-PI|T0], [Spec-[PI|PIs]|T]) :-
970 on_path(File, Spec),
971 same_file(T0, File, PIs, T1),
972 by_file(T1, T).
973
974on_path(Library, library(Base)) :-
975 file_base_name(Library, Base),
976 findall(Path, plain_source(library(Base), Path), [Library]),
977 !.
978on_path(Library, Library).
979
980plain_source(Spec, Path) :-
981 absolute_file_name(Spec, PathExt,
982 [ file_type(prolog),
983 access(read),
984 file_errors(fail),
985 solutions(all)
986 ]),
987 file_name_extension(Path, _, PathExt).
988
989same_file([File-PI|T0], File, [PI|PIs], T) :-
990 !,
991 same_file(T0, File, PIs, T).
992same_file(List, _, [], List).
993
994comma_list(Var) -->
995 { var(Var),
996 !,
997 '$instantiation_error'(Var)
998 }.
999comma_list((A,B)) -->
1000 !,
1001 comma_list(A),
1002 comma_list(B).
1003comma_list(A) -->
1004 [A]