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