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
459exports(File, Module, Exports) :-
460 ( current_prolog_flag(xref, Old)
461 -> true
462 ; Old = false
463 ),
464 setup_call_cleanup(
465 set_prolog_flag(xref, true),
466 snapshot(exports_(File, Module, Exports)),
467 set_prolog_flag(xref, Old)).
468
469exports_(File, Module, Exports) :-
470 State = state(true, _, []),
471 ( '$source_term'(File,
472 _Read,_RLayout,
473 Term,_TermLayout,
474 _Stream,
475 [ syntax_errors(quiet)
476 ]),
477 ( Term = (:- module(M,Public)),
478 is_list(Public),
479 arg(1, State, true)
480 -> nb_setarg(1, State, false),
481 nb_setarg(2, State, M),
482 nb_setarg(3, State, Public),
483 fail
484 ; nb_setarg(1, State, false),
485 fail
486 ; Term = (:- export(PI)),
487 ground(PI)
488 -> arg(3, State, E0),
489 '$append'(E0, [PI], E1),
490 nb_setarg(3, State, E1),
491 fail
492 ; Term = (:- use_foreign_library(Lib)),
493 nonvar(Lib),
494 arg(2, State, M),
495 atom(M)
496 -> catch('$syspreds':use_foreign_library_noi(M:Lib), error(_,_), true),
497 fail
498 ; Term = (:- Directive),
499 nonvar(Directive)
500 -> fail
501 ; !
502 )
503 ; true
504 ),
505 arg(2, State, Module),
506 arg(3, State, Exports).
507
508
509 512
527
528autoload_path(Alias) :-
529 ( user:file_search_path(autoload, Alias)
530 -> true
531 ; assertz(user:file_search_path(autoload, Alias)),
532 reload_library_index
533 ).
534
535system:term_expansion((:- autoload_path(Alias)),
536 [ user:file_search_path(autoload, Alias),
537 (:- reload_library_index)
538 ]).
539
540
541 544
552
553'$autoload'(PI) :-
554 source_location(File, _Line),
555 !,
556 setup_call_cleanup(
557 '$start_aux'(File, Context),
558 '$autoload2'(PI),
559 '$end_aux'(File, Context)).
560'$autoload'(PI) :-
561 '$autoload2'(PI).
562
563'$autoload2'(PI) :-
564 setup_call_cleanup(
565 leave_sandbox(Old),
566 '$autoload3'(PI),
567 restore_sandbox(Old)).
568
569leave_sandbox(Sandboxed) :-
570 current_prolog_flag(sandboxed_load, Sandboxed),
571 set_prolog_flag(sandboxed_load, false).
572restore_sandbox(Sandboxed) :-
573 set_prolog_flag(sandboxed_load, Sandboxed).
574
575'$autoload3'(PI) :-
576 autoload_from(PI, LoadModule, FullFile),
577 do_autoload(FullFile, PI, LoadModule).
578
583
584autoload_from(Module:PI, LoadModule, FullFile) :-
585 autoload_in(Module, explicit),
586 current_autoload(Module:File, Ctx, import(Imports)),
587 memberchk(PI, Imports),
588 library_info(File, Ctx, FullFile, LoadModule, Exports),
589 ( pi_in_exports(PI, Exports)
590 -> !
591 ; autoload_error(Ctx, not_exported(PI, File, FullFile, Exports)),
592 fail
593 ).
594autoload_from(Module:Name/Arity, LoadModule, FullFile) :-
595 autoload_in(Module, explicit),
596 PI = Name/Arity,
597 current_autoload(Module:File, Ctx, all),
598 library_info(File, Ctx, FullFile, LoadModule, Exports),
599 pi_in_exports(PI, Exports).
600autoload_from(Module:Name/Arity, LoadModule, Library) :-
601 autoload_in(Module, general),
602 '$find_library'(Module, Name, Arity, LoadModule, Library).
603
604:- public autoload_in/2. 605
606autoload_in(Module, How) :-
607 current_prolog_flag(autoload, AutoLoad),
608 autoload_in(AutoLoad, How, Module),
609 !.
610
612
613autoload_in(true, _, _).
614autoload_in(explicit, explicit, _).
615autoload_in(user, _, user).
616autoload_in(user_or_explicit, explicit, _).
617autoload_in(user_or_explicit, _, user).
618
619
632
633do_autoload(Library, Module:Name/Arity, LoadModule) :-
634 functor(Head, Name, Arity),
635 '$update_autoload_level'([autoload(true)], Old),
636 verbose_autoload(Module:Name/Arity, Library),
637 '$compilation_mode'(OldComp, database),
638 ( Module == LoadModule
639 -> ensure_loaded(Module:Library)
640 ; ( '$c_current_predicate'(_, LoadModule:Head),
641 '$get_predicate_attribute'(LoadModule:Head, defined, 1),
642 \+ '$loading'(Library)
643 -> Module:import(LoadModule:Name/Arity)
644 ; use_module(Module:Library, [Name/Arity])
645 ),
646 warn_autoload(Module, LoadModule:Name/Arity)
647 ),
648 '$set_compilation_mode'(OldComp),
649 '$set_autoload_level'(Old),
650 '$c_current_predicate'(_, Module:Head).
651
652verbose_autoload(PI, Library) :-
653 current_prolog_flag(verbose_autoload, true),
654 !,
655 set_prolog_flag(verbose_autoload, false),
656 print_message(informational, autoload(PI, Library)),
657 set_prolog_flag(verbose_autoload, true).
658verbose_autoload(PI, Library) :-
659 print_message(silent, autoload(PI, Library)).
660
661
667
668:- public 669 autoloadable/2. 670
671autoloadable(M:Head, FullFile) :-
672 atom(M),
673 current_module(M),
674 autoload_in(M, explicit),
675 ( callable(Head)
676 -> goal_name_arity(Head, Name, Arity),
677 autoload_from(M:Name/Arity, _, FullFile)
678 ; findall((M:H)-F, autoloadable_2(M:H, F), Pairs),
679 ( '$member'(M:Head-FullFile, Pairs)
680 ; current_autoload(M:File, Ctx, all),
681 library_info(File, Ctx, FullFile, _, Exports),
682 '$member'(PI, Exports),
683 '$pi_head'(PI, Head),
684 \+ memberchk(M:Head-_, Pairs)
685 )
686 ).
687autoloadable(M:Head, FullFile) :-
688 ( var(M)
689 -> autoload_in(any, general)
690 ; autoload_in(M, general)
691 ),
692 ( callable(Head)
693 -> goal_name_arity(Head, Name, Arity),
694 ( '$find_library'(_, Name, Arity, _, FullFile)
695 -> true
696 )
697 ; '$in_library'(Name, Arity, autoload),
698 functor(Head, Name, Arity)
699 ).
700
701
702autoloadable_2(M:Head, FullFile) :-
703 current_autoload(M:File, Ctx, import(Imports)),
704 library_info(File, Ctx, FullFile, _LoadModule, _Exports),
705 '$member'(PI, Imports),
706 '$pi_head'(PI, Head).
707
708goal_name_arity(Head, Name, Arity) :-
709 compound(Head),
710 !,
711 compound_name_arity(Head, Name, Arity).
712goal_name_arity(Head, Head, 0).
713
717
718library_info(Spec, _, FullFile, Module, Exports) :-
719 '$resolved_source_path'(Spec, FullFile, []),
720 !,
721 ( \+ '$loading_file'(FullFile, _Queue, _LoadThread)
722 -> '$current_module'(Module, FullFile),
723 '$module_property'(Module, exports(Exports))
724 ; library_info_from_file(FullFile, Module, Exports)
725 ).
726library_info(Spec, Context, FullFile, Module, Exports) :-
727 ( Context = (Path:_Line)
728 -> Extra = [relative_to(Path)]
729 ; Extra = []
730 ),
731 ( absolute_file_name(Spec, FullFile,
732 [ file_type(prolog),
733 access(read),
734 file_errors(fail)
735 | Extra
736 ])
737 -> '$register_resolved_source_path'(Spec, FullFile),
738 library_info_from_file(FullFile, Module, Exports)
739 ; autoload_error(Context, no_file(Spec)),
740 fail
741 ).
742
743library_info_from_file(FullFile, Module, Exports) :-
744 setup_call_cleanup(
745 '$set_source_module'(OldModule, system),
746 setup_call_cleanup(
747 '$open_source'(FullFile, In, State, [], []),
748 '$term_in_file'(In, _Read, _RLayout, Term, _TLayout, _Stream,
749 [FullFile], []),
750 '$close_source'(State, true)),
751 '$set_source_module'(OldModule)),
752 ( Term = (:- module(Module, Exports))
753 -> !
754 ; nonvar(Term),
755 skip_header(Term)
756 -> fail
757 ; '$domain_error'(module_header, Term)
758 ).
759
(begin_of_file).
761
762
763:- dynamic printed/3. 764:- volatile printed/3. 765
766autoload_error(Context, Error) :-
767 suppress(Context, Error),
768 !.
769autoload_error(Context, Error) :-
770 get_time(Now),
771 assertz(printed(Context, Error, Now)),
772 print_message(warning, error(autoload(Error), autoload(Context))).
773
774suppress(Context, Error) :-
775 printed(Context, Error, Printed),
776 get_time(Now),
777 ( Now - Printed < 1
778 -> true
779 ; retractall(printed(Context, Error, _)),
780 fail
781 ).
782
783
784 787
788:- public
789 set_autoload/1. 790
797
798set_autoload(FlagValue) :-
799 current_prolog_flag(autoload, FlagValue),
800 !.
801set_autoload(FlagValue) :-
802 \+ autoload_in(FlagValue, explicit, any),
803 !,
804 setup_call_cleanup(
805 nb_setval('$autoload_disabling', true),
806 materialize_autoload(Count),
807 nb_delete('$autoload_disabling')),
808 print_message(informational, autoload(disabled(Count))).
809set_autoload(_).
810
811materialize_autoload(Count) :-
812 State = state(0),
813 forall(current_predicate(M:'$autoload'/3),
814 materialize_autoload(M, State)),
815 arg(1, State, Count).
816
817materialize_autoload(M, State) :-
818 ( current_autoload(M:File, Context, Import),
819 library_info(File, Context, FullFile, _LoadModule, _Exports),
820 arg(1, State, N0),
821 N is N0+1,
822 nb_setarg(1, State, N),
823 ( Import == all
824 -> verbose_autoload(M:all, FullFile),
825 use_module(M:FullFile)
826 ; Import = import(Preds)
827 -> verbose_autoload(M:Preds, FullFile),
828 use_module(M:FullFile, Preds)
829 ),
830 fail
831 ; true
832 ),
833 abolish(M:'$autoload'/3).
834
835
836 839
840autoload(M:File) :-
841 ( \+ autoload_in(M, explicit)
842 ; nb_current('$autoload_disabling', true)
843 ),
844 !,
845 use_module(M:File).
846autoload(M:File) :-
847 '$must_be'(filespec, File),
848 source_context(Context),
849 ( current_autoload(M:File, _, import(all))
850 -> true
851 ; assert_autoload(M:'$autoload'(File, Context, all))
852 ).
853
854autoload(M:File, Imports) :-
855 ( \+ autoload_in(M, explicit)
856 ; nb_current('$autoload_disabling', true)
857 ),
858 !,
859 use_module(M:File, Imports).
860autoload(M:File, Imports0) :-
861 '$must_be'(filespec, File),
862 valid_imports(Imports0, Imports),
863 source_context(Context),
864 register_autoloads(Imports, M, File, Context),
865 ( current_autoload(M:File, _, import(Imports))
866 -> true
867 ; assert_autoload(M:'$autoload'(File, Context, import(Imports)))
868 ).
869
870source_context(Path:Line) :-
871 source_location(Path, Line),
872 !.
873source_context(-).
874
875assert_autoload(Clause) :-
876 '$initialization_context'(Source, Ctx),
877 '$store_admin_clause2'(Clause, _Layout, Source, Ctx).
878
879valid_imports(Imports0, Imports) :-
880 '$must_be'(list, Imports0),
881 valid_import_list(Imports0, Imports).
882
883valid_import_list([], []).
884valid_import_list([H0|T0], [H|T]) :-
885 '$pi_head'(H0, Head),
886 '$pi_head'(H, Head),
887 valid_import_list(T0, T).
888
893
894register_autoloads([], _, _, _).
895register_autoloads([PI|T], Module, File, Context) :-
896 PI = Name/Arity,
897 functor(Head, Name, Arity),
898 ( '$get_predicate_attribute'(Module:Head, autoload, 1)
899 -> ( current_autoload(Module:_File0, _Ctx0, import(Imports)),
900 memberchk(PI, Imports)
901 -> '$permission_error'(redefine, imported_procedure, PI),
902 fail
903 ; Done = true
904 )
905 ; '$c_current_predicate'(_, Module:Head), 906 '$get_predicate_attribute'(Module:Head, imported, From)
907 -> ( ( '$resolved_source_path'(File, FullFile)
908 -> true
909 ; '$resolve_source_path'(File, FullFile, [])
910 ),
911 module_property(From, file(FullFile))
912 -> Done = true
913 ; print_message(warning,
914 autoload(already_defined(Module:PI, From))),
915 Done = true
916 )
917 ; true
918 ),
919 ( Done == true
920 -> true
921 ; '$set_predicate_attribute'(Module:Head, autoload, 1)
922 ),
923 register_autoloads(T, Module, File, Context).
924
925pi_in_exports(PI, Exports) :-
926 '$member'(E, Exports),
927 canonical_pi(E, PI),
928 !.
929
930current_autoload(M:File, Context, Term) :-
931 '$get_predicate_attribute'(M:'$autoload'(_,_,_), defined, 1),
932 M:'$autoload'(File, Context, Term).
933
934 937
938warn_autoload(TargetModule, PI) :-
939 current_prolog_flag(warn_autoload, true),
940 \+ current_prolog_flag(xref, true),
941 \+ nb_current('$autoload_warning', true),
942 '$pi_head'(PI, Head),
943 source_file(Head, File),
944 expansion_hook(P),
945 source_file(P, File),
946 !,
947 setup_call_cleanup(
948 b_setval('$autoload_warning', true),
949 print_message(warning,
950 deprecated(autoload(TargetModule, File, PI, expansion))),
951 nb_delete('$autoload_warning')).
952warn_autoload(_, _).
953
954expansion_hook(user:goal_expansion(_,_)).
955expansion_hook(user:goal_expansion(_,_,_,_)).
956expansion_hook(system:goal_expansion(_,_)).
957expansion_hook(system:goal_expansion(_,_,_,_)).
958
959
960 963
968
969require(M:Spec) :-
970 ( is_list(Spec)
971 -> List = Spec
972 ; phrase(comma_list(Spec), List)
973 ), !,
974 require(List, M, FromLib),
975 keysort(FromLib, Sorted),
976 by_file(Sorted, Autoload),
977 forall('$member'(File-Import, Autoload),
978 autoload(M:File, Import)).
979require(_:Spec) :-
980 '$type_error'(list, Spec).
981
982require([],_, []).
983require([H|T], M, Needed) :-
984 '$pi_head'(H, Head),
985 ( '$get_predicate_attribute'(system:Head, defined, 1)
986 -> require(T, M, Needed)
987 ; '$pi_head'(Module:Name/Arity, M:Head),
988 ( '$find_library'(Module, Name, Arity, LoadModule, Library)
989 -> ( current_predicate(LoadModule:Name/Arity)
990 -> Module:import(LoadModule:Name/Arity),
991 require(T, M, Needed)
992 ; Needed = [Library-H|More],
993 require(T, M, More)
994 )
995 ; print_message(error, error(existence_error(procedure, Name/Arity), _)),
996 require(T, M, Needed)
997 )
998 ).
999
1000by_file([], []).
1001by_file([File-PI|T0], [Spec-[PI|PIs]|T]) :-
1002 on_path(File, Spec),
1003 same_file(T0, File, PIs, T1),
1004 by_file(T1, T).
1005
1006on_path(Library, library(Base)) :-
1007 file_base_name(Library, Base),
1008 findall(Path, plain_source(library(Base), Path), [Library]),
1009 !.
1010on_path(Library, Library).
1011
1012plain_source(Spec, Path) :-
1013 absolute_file_name(Spec, PathExt,
1014 [ file_type(prolog),
1015 access(read),
1016 file_errors(fail),
1017 solutions(all)
1018 ]),
1019 file_name_extension(Path, _, PathExt).
1020
1021same_file([File-PI|T0], File, [PI|PIs], T) :-
1022 !,
1023 same_file(T0, File, PIs, T).
1024same_file(List, _, [], List).
1025
1026comma_list(Var) -->
1027 { var(Var),
1028 !,
1029 '$instantiation_error'(Var)
1030 }.
1031comma_list((A,B)) -->
1032 !,
1033 comma_list(A),
1034 comma_list(B).
1035comma_list(A) -->
1036 [A]