37
38:- module('$autoload',
39 [ '$find_library'/5,
40 '$in_library'/3,
41 '$define_predicate'/1,
42 '$update_library_index'/1, 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
150
151'$update_library_index'(Options) :-
152 setof(Dir, writable_indexed_directory(Dir, Options), Dirs),
153 !,
154 setup_call_cleanup(
155 asserta(silent, Ref),
156 guarded_make_library_index(Dirs),
157 erase(Ref)),
158 ( flag('$modified_index', true, false)
159 -> reload_library_index
160 ; true
161 ).
162'$update_library_index'(_).
163
164guarded_make_library_index([]).
165guarded_make_library_index([Dir|Dirs]) :-
166 ( catch(make_library_index(Dir), E,
167 print_message(error, E))
168 -> true
169 ; print_message(warning, goal_failed(make_library_index(Dir)))
170 ),
171 guarded_make_library_index(Dirs).
172
177
178writable_indexed_directory(Dir, Options) :-
179 current_prolog_flag(home, Home),
180 writable_indexed_directory(Dir),
181 ( sub_atom(Dir, 0, _, _, Home)
182 -> '$option'(system(true), Options, false)
183 ; '$option'(user(true), Options, true)
184 ).
185
186writable_indexed_directory(Dir) :-
187 index_file_name(IndexFile, autoload('INDEX'), [access([read,write])]),
188 file_directory_name(IndexFile, Dir).
189writable_indexed_directory(Dir) :-
190 absolute_file_name(library('MKINDEX'),
191 [ file_type(prolog),
192 access(read),
193 solutions(all),
194 file_errors(fail)
195 ], MkIndexFile),
196 file_directory_name(MkIndexFile, Dir),
197 plfile_in_dir(Dir, 'INDEX', _, IndexFile),
198 access_file(IndexFile, write).
199
200
201 204
208
209reload_library_index :-
210 context_module(M),
211 reload_library_index(M).
212
213reload_library_index(M) :-
214 with_mutex('$autoload', clear_library_index(M)).
215
216clear_library_index(M) :-
217 retractall(M:library_index(_, _, _)),
218 retractall(M:autoload_directories(_)),
219 retractall(M:index_checked_at(_)).
220
221
228
229:- meta_predicate load_library_index(?, ?, :). 230:- public load_library_index/3. 231
232load_library_index(Name, Arity) :-
233 load_library_index(Name, Arity, autoload('INDEX')).
234
235load_library_index(Name, Arity, M:_Spec) :-
236 atom(Name), integer(Arity),
237 functor(Head, Name, Arity),
238 M:library_index(Head, _, _),
239 !.
240load_library_index(_, _, Spec) :-
241 notrace(with_mutex('$autoload', load_library_index_p(Spec))).
242
243load_library_index_p(M:_) :-
244 M:index_checked_at(Time),
245 get_time(Now),
246 Now-Time < 60,
247 !.
248load_library_index_p(M:Spec) :-
249 findall(Index, index_file_name(Index, Spec, [access(read)]), List0),
250 '$list_to_set'(List0, List),
251 retractall(M:index_checked_at(_)),
252 get_time(Now),
253 assert(M:index_checked_at(Now)),
254 ( M:autoload_directories(List)
255 -> true
256 ; retractall(M:library_index(_, _, _)),
257 retractall(M:autoload_directories(_)),
258 read_index(List, M),
259 assert(M:autoload_directories(List))
260 ).
261
269
270index_file_name(IndexFile, FileSpec, Options) :-
271 absolute_file_name(FileSpec,
272 IndexFile,
273 [ file_type(prolog),
274 solutions(all),
275 file_errors(fail)
276 | Options
277 ]).
278
279read_index([], _) :- !.
280read_index([H|T], M) :-
281 !,
282 read_index(H, M),
283 read_index(T, M).
284read_index(Index, M) :-
285 print_message(silent, autoload(read_index(Dir))),
286 file_directory_name(Index, Dir),
287 setup_call_cleanup(
288 '$push_input_context'(autoload_index),
289 setup_call_cleanup(
290 open(Index, read, In),
291 read_index_from_stream(Dir, In, M),
292 close(In)),
293 '$pop_input_context').
294
295read_index_from_stream(Dir, In, M) :-
296 repeat,
297 read(In, Term),
298 assert_index(Term, Dir, M),
299 !.
300
301assert_index(end_of_file, _, _) :- !.
302assert_index(index(Name, Arity, Module, File), Dir, M) :-
303 !,
304 functor(Head, Name, Arity),
305 atomic_list_concat([Dir, '/', File], Path),
306 assertz(M:library_index(Head, Module, Path)),
307 fail.
308assert_index(Term, Dir, _) :-
309 print_message(error, illegal_autoload_index(Dir, Term)),
310 fail.
311
312
313 316
327
328make_library_index(Dir0) :-
329 forall(absolute_file_name(Dir0, Dir,
330 [ expand(true),
331 file_type(directory),
332 file_errors(fail),
333 solutions(all)
334 ]),
335 make_library_index2(Dir)).
336
337make_library_index2(Dir) :-
338 plfile_in_dir(Dir, 'MKINDEX', _MkIndex, AbsMkIndex),
339 access_file(AbsMkIndex, read),
340 !,
341 load_files(user:AbsMkIndex, [silent(true)]).
342make_library_index2(Dir) :-
343 findall(Pattern, source_file_pattern(Pattern), PatternList),
344 make_library_index2(Dir, PatternList).
345
358
359make_library_index(Dir0, Patterns) :-
360 forall(absolute_file_name(Dir0, Dir,
361 [ expand(true),
362 file_type(directory),
363 file_errors(fail),
364 solutions(all)
365 ]),
366 make_library_index2(Dir, Patterns)).
367
368make_library_index2(Dir, Patterns) :-
369 plfile_in_dir(Dir, 'INDEX', _Index, AbsIndex),
370 ensure_slash(Dir, DirS),
371 pattern_files(Patterns, DirS, Files),
372 ( library_index_out_of_date(Dir, AbsIndex, Files)
373 -> do_make_library_index(AbsIndex, DirS, Files),
374 set_flag('$modified_index', true)
375 ; true
376 ).
377
378ensure_slash(Dir, DirS) :-
379 ( sub_atom(Dir, _, _, 0, /)
380 -> DirS = Dir
381 ; atom_concat(Dir, /, DirS)
382 ).
383
384source_file_pattern(Pattern) :-
385 user:prolog_file_type(PlExt, prolog),
386 PlExt \== qlf,
387 atom_concat('*.', PlExt, Pattern).
388
389plfile_in_dir(Dir, Base, PlBase, File) :-
390 file_name_extension(Base, pl, PlBase),
391 atomic_list_concat([Dir, '/', PlBase], File).
392
393pattern_files([], _, []).
394pattern_files([H|T], DirS, Files) :-
395 atom_concat(DirS, H, P0),
396 expand_file_name(P0, Files0),
397 '$append'(Files0, Rest, Files),
398 pattern_files(T, DirS, Rest).
399
400library_index_out_of_date(_Dir, Index, _Files) :-
401 \+ exists_file(Index),
402 !.
403library_index_out_of_date(Dir, Index, Files) :-
404 time_file(Index, IndexTime),
405 ( time_file(Dir, DotTime),
406 DotTime - IndexTime > 0.001 407 ; '$member'(File, Files), 408 time_file(File, FileTime),
409 FileTime - IndexTime > 0.001
410 ),
411 !.
412
413
414do_make_library_index(Index, Dir, Files) :-
415 ensure_slash(Dir, DirS),
416 '$stage_file'(Index, StagedIndex),
417 setup_call_catcher_cleanup(
418 open(StagedIndex, write, Out),
419 ( print_message(informational, make(library_index(Dir))),
420 index_header(Out),
421 index_files(Files, DirS, Out)
422 ),
423 Catcher,
424 install_index(Out, Catcher, StagedIndex, Index)).
425
426install_index(Out, Catcher, StagedIndex, Index) :-
427 catch(close(Out), Error, true),
428 ( silent
429 -> OnError = silent
430 ; OnError = error
431 ),
432 ( var(Error)
433 -> TheCatcher = Catcher
434 ; TheCatcher = exception(Error)
435 ),
436 '$install_staged_file'(TheCatcher, StagedIndex, Index, OnError).
437
441
442index_files([], _, _).
443index_files([File|Files], DirS, Fd) :-
444 ( catch(exports(File, Module, Public), E,
445 print_message(warning, E)),
446 nonvar(Module)
447 -> atom_concat(DirS, Local, File),
448 file_name_extension(Base, _, Local),
449 forall(public_predicate(Public, Name/Arity),
450 format(Fd, 'index((~k), ~k, ~k, ~k).~n',
451 [Name, Arity, Module, Base]))
452 ; true
453 ),
454 index_files(Files, DirS, Fd).
455
456public_predicate(Public, PI) :-
457 '$member'(PI0, Public),
458 canonical_pi(PI0, PI).
459
460canonical_pi(Var, _) :-
461 var(Var), !, fail.
462canonical_pi(Name/Arity, Name/Arity).
463canonical_pi(Name//A0, Name/Arity) :-
464 Arity is A0 + 2.
465
466
(Fd):-
468 format(Fd, '/* Creator: make/0~n~n', []),
469 format(Fd, ' Purpose: Provide index for autoload~n', []),
470 format(Fd, '*/~n~n', []).
471
475
476:- public exports/3. 477exports(File, Module, Exports) :-
478 ( current_prolog_flag(xref, Old)
479 -> true
480 ; Old = false
481 ),
482 setup_call_cleanup(
483 set_prolog_flag(xref, true),
484 snapshot(exports_(File, Module, Exports)),
485 set_prolog_flag(xref, Old)).
486
487exports_(File, Module, Exports) :-
488 State = state(true, _, []),
489 ( '$source_term'(File,
490 _Read,_RLayout,
491 Term,_TermLayout,
492 _Stream,
493 [ syntax_errors(quiet)
494 ]),
495 ( Term = (:- module(M,Public)),
496 is_list(Public),
497 arg(1, State, true)
498 -> nb_setarg(1, State, false),
499 nb_setarg(2, State, M),
500 nb_setarg(3, State, Public),
501 fail
502 ; nb_setarg(1, State, false),
503 fail
504 ; Term = (:- export(Export))
505 -> phrase(export_pi(Export), PIs),
506 arg(3, State, E0),
507 '$append'(E0, PIs, E1),
508 nb_setarg(3, State, E1),
509 fail
510 ; Term = (:- use_foreign_library(Lib)),
511 nonvar(Lib),
512 arg(2, State, M),
513 atom(M)
514 -> catch('$syspreds':use_foreign_library_noi(M:Lib), error(_,_), true),
515 fail
516 ; Term = (:- Directive),
517 nonvar(Directive)
518 -> fail
519 ; Term == [] 520 -> fail
521 ; !
522 )
523 ; true
524 ),
525 arg(2, State, Module),
526 arg(3, State, Exports).
527
528export_pi(Var) -->
529 { var(Var) },
530 !.
531export_pi((A,B)) -->
532 !,
533 export_pi(A),
534 export_pi(B).
535export_pi(PI) -->
536 { ground(PI) },
537 [PI].
538
539
540 543
558
559autoload_path(Alias) :-
560 ( user:file_search_path(autoload, Alias)
561 -> true
562 ; assertz(user:file_search_path(autoload, Alias)),
563 reload_library_index
564 ).
565
566system:term_expansion((:- autoload_path(Alias)),
567 [ user:file_search_path(autoload, Alias),
568 (:- reload_library_index)
569 ]).
570
571
572 575
583
584'$autoload'(PI) :-
585 source_location(File, _Line),
586 !,
587 setup_call_cleanup(
588 '$start_aux'(File, Context),
589 '$autoload2'(PI),
590 '$end_aux'(File, Context)).
591'$autoload'(PI) :-
592 '$autoload2'(PI).
593
594'$autoload2'(PI) :-
595 setup_call_cleanup(
596 leave_sandbox(Old),
597 '$autoload3'(PI),
598 restore_sandbox(Old)).
599
600leave_sandbox(Sandboxed) :-
601 current_prolog_flag(sandboxed_load, Sandboxed),
602 set_prolog_flag(sandboxed_load, false).
603restore_sandbox(Sandboxed) :-
604 set_prolog_flag(sandboxed_load, Sandboxed).
605
606'$autoload3'(PI) :-
607 autoload_from(PI, LoadModule, FullFile),
608 do_autoload(FullFile, PI, LoadModule).
609
614
615autoload_from(Module:PI, LoadModule, FullFile) :-
616 autoload_in(Module, explicit),
617 current_autoload(Module:File, Ctx, import(Imports)),
618 memberchk(PI, Imports),
619 library_info(File, Ctx, FullFile, LoadModule, Exports),
620 ( pi_in_exports(PI, Exports)
621 -> !
622 ; autoload_error(Ctx, not_exported(PI, File, FullFile, Exports)),
623 fail
624 ).
625autoload_from(Module:Name/Arity, LoadModule, FullFile) :-
626 autoload_in(Module, explicit),
627 PI = Name/Arity,
628 current_autoload(Module:File, Ctx, all),
629 library_info(File, Ctx, FullFile, LoadModule, Exports),
630 pi_in_exports(PI, Exports).
631autoload_from(Module:Name/Arity, LoadModule, Library) :-
632 autoload_in(Module, general),
633 '$find_library'(Module, Name, Arity, LoadModule, Library).
634
635:- public autoload_in/2. 636
637autoload_in(Module, How) :-
638 current_prolog_flag(autoload, AutoLoad),
639 autoload_in(AutoLoad, How, Module),
640 !.
641
643
644autoload_in(true, _, _).
645autoload_in(explicit, explicit, _).
646autoload_in(user, _, user).
647autoload_in(user_or_explicit, explicit, _).
648autoload_in(user_or_explicit, _, user).
649
650
663
664do_autoload(Library, Module:Name/Arity, LoadModule) :-
665 functor(Head, Name, Arity),
666 '$update_autoload_level'([autoload(true)], Old),
667 verbose_autoload(Module:Name/Arity, Library),
668 '$compilation_mode'(OldComp, database),
669 ( Module == LoadModule
670 -> ensure_loaded(Module:Library)
671 ; ( '$c_current_predicate'(_, LoadModule:Head),
672 '$get_predicate_attribute'(LoadModule:Head, defined, 1),
673 \+ '$loading'(Library)
674 -> Module:import(LoadModule:Name/Arity)
675 ; use_module(Module:Library, [Name/Arity])
676 ),
677 warn_autoload(Module, LoadModule:Name/Arity)
678 ),
679 '$set_compilation_mode'(OldComp),
680 '$set_autoload_level'(Old),
681 '$c_current_predicate'(_, Module:Head).
682
683verbose_autoload(PI, Library) :-
684 current_prolog_flag(verbose_autoload, true),
685 !,
686 set_prolog_flag(verbose_autoload, false),
687 print_message(informational, autoload(PI, Library)),
688 set_prolog_flag(verbose_autoload, true).
689verbose_autoload(PI, Library) :-
690 print_message(silent, autoload(PI, Library)).
691
692
698
699:- public 700 autoloadable/2. 701
702autoloadable(M:Head, FullFile) :-
703 atom(M),
704 current_module(M),
705 autoload_in(M, explicit),
706 ( callable(Head)
707 -> goal_name_arity(Head, Name, Arity),
708 autoload_from(M:Name/Arity, _, FullFile)
709 ; findall((M:H)-F, autoloadable_2(M:H, F), Pairs),
710 ( '$member'(M:Head-FullFile, Pairs)
711 ; current_autoload(M:File, Ctx, all),
712 library_info(File, Ctx, FullFile, _, Exports),
713 '$member'(PI, Exports),
714 '$pi_head'(PI, Head),
715 \+ memberchk(M:Head-_, Pairs)
716 )
717 ).
718autoloadable(M:Head, FullFile) :-
719 ( var(M)
720 -> autoload_in(any, general)
721 ; autoload_in(M, general)
722 ),
723 ( callable(Head)
724 -> goal_name_arity(Head, Name, Arity),
725 ( '$find_library'(_, Name, Arity, _, FullFile)
726 -> true
727 )
728 ; '$in_library'(Name, Arity, autoload),
729 functor(Head, Name, Arity)
730 ).
731
732
733autoloadable_2(M:Head, FullFile) :-
734 current_autoload(M:File, Ctx, import(Imports)),
735 library_info(File, Ctx, FullFile, _LoadModule, _Exports),
736 '$member'(PI, Imports),
737 '$pi_head'(PI, Head).
738
739goal_name_arity(Head, Name, Arity) :-
740 compound(Head),
741 !,
742 compound_name_arity(Head, Name, Arity).
743goal_name_arity(Head, Head, 0).
744
748
749library_info(Spec, _, FullFile, Module, Exports) :-
750 '$resolved_source_path'(Spec, FullFile, []),
751 !,
752 ( \+ '$loading_file'(FullFile, _Queue, _LoadThread)
753 -> '$current_module'(Module, FullFile),
754 '$module_property'(Module, exports(Exports))
755 ; library_info_from_file(FullFile, Module, Exports)
756 ).
757library_info(Spec, Context, FullFile, Module, Exports) :-
758 ( Context = (Path:_Line)
759 -> Extra = [relative_to(Path)]
760 ; Extra = []
761 ),
762 ( absolute_file_name(Spec, FullFile,
763 [ file_type(prolog),
764 access(read),
765 file_errors(fail)
766 | Extra
767 ])
768 -> '$register_resolved_source_path'(Spec, FullFile),
769 library_info_from_file(FullFile, Module, Exports)
770 ; autoload_error(Context, no_file(Spec)),
771 fail
772 ).
773
774library_info_from_file(FullFile, Module, Exports) :-
775 setup_call_cleanup(
776 '$set_source_module'(OldModule, system),
777 setup_call_cleanup(
778 '$open_source'(FullFile, In, State, [], []),
779 '$term_in_file'(In, _Read, _RLayout, Term, _TLayout, _Stream,
780 [FullFile], []),
781 '$close_source'(State, true)),
782 '$set_source_module'(OldModule)),
783 ( Term = (:- module(Module, Exports))
784 -> !
785 ; nonvar(Term),
786 skip_header(Term)
787 -> fail
788 ; '$domain_error'(module_header, Term)
789 ).
790
(begin_of_file).
792
793
794:- dynamic printed/3. 795:- volatile printed/3. 796
797autoload_error(Context, Error) :-
798 suppress(Context, Error),
799 !.
800autoload_error(Context, Error) :-
801 get_time(Now),
802 assertz(printed(Context, Error, Now)),
803 print_message(warning, error(autoload(Error), autoload(Context))).
804
805suppress(Context, Error) :-
806 printed(Context, Error, Printed),
807 get_time(Now),
808 ( Now - Printed < 1
809 -> true
810 ; retractall(printed(Context, Error, _)),
811 fail
812 ).
813
814
815 818
819:- public
820 set_autoload/1. 821
828
829set_autoload(FlagValue) :-
830 current_prolog_flag(autoload, FlagValue),
831 !.
832set_autoload(FlagValue) :-
833 \+ autoload_in(FlagValue, explicit, any),
834 !,
835 setup_call_cleanup(
836 nb_setval('$autoload_disabling', true),
837 materialize_autoload(Count),
838 nb_delete('$autoload_disabling')),
839 print_message(informational, autoload(disabled(Count))).
840set_autoload(_).
841
842materialize_autoload(Count) :-
843 State = state(0),
844 forall(current_predicate(M:'$autoload'/3),
845 materialize_autoload(M, State)),
846 arg(1, State, Count).
847
848materialize_autoload(M, State) :-
849 ( current_autoload(M:File, Context, Import),
850 library_info(File, Context, FullFile, _LoadModule, _Exports),
851 arg(1, State, N0),
852 N is N0+1,
853 nb_setarg(1, State, N),
854 ( Import == all
855 -> verbose_autoload(M:all, FullFile),
856 use_module(M:FullFile)
857 ; Import = import(Preds)
858 -> verbose_autoload(M:Preds, FullFile),
859 use_module(M:FullFile, Preds)
860 ),
861 fail
862 ; true
863 ),
864 abolish(M:'$autoload'/3).
865
866
867 870
871autoload(M:File) :-
872 ( \+ autoload_in(M, explicit)
873 ; nb_current('$autoload_disabling', true)
874 ),
875 !,
876 use_module(M:File).
877autoload(M:File) :-
878 '$must_be'(filespec, File),
879 source_context(Context),
880 ( current_autoload(M:File, _, import(all))
881 -> true
882 ; assert_autoload(M:'$autoload'(File, Context, all))
883 ).
884
885autoload(M:File, Imports) :-
886 ( \+ autoload_in(M, explicit)
887 ; nb_current('$autoload_disabling', true)
888 ),
889 !,
890 use_module(M:File, Imports).
891autoload(M:File, Imports0) :-
892 '$must_be'(filespec, File),
893 valid_imports(Imports0, Imports),
894 source_context(Context),
895 register_autoloads(Imports, M, File, Context),
896 ( current_autoload(M:File, _, import(Imports))
897 -> true
898 ; assert_autoload(M:'$autoload'(File, Context, import(Imports)))
899 ).
900
901source_context(Path:Line) :-
902 source_location(Path, Line),
903 !.
904source_context(-).
905
906assert_autoload(Clause) :-
907 '$initialization_context'(Source, Ctx),
908 '$store_admin_clause2'(Clause, _Layout, Source, Ctx).
909
910valid_imports(Imports0, Imports) :-
911 '$must_be'(list, Imports0),
912 valid_import_list(Imports0, Imports).
913
914valid_import_list([], []).
915valid_import_list([H0|T0], [H|T]) :-
916 '$pi_head'(H0, Head),
917 '$pi_head'(H, Head),
918 valid_import_list(T0, T).
919
924
925register_autoloads([], _, _, _).
926register_autoloads([PI|T], Module, File, Context) :-
927 PI = Name/Arity,
928 functor(Head, Name, Arity),
929 ( '$get_predicate_attribute'(Module:Head, autoload, 1)
930 -> ( current_autoload(Module:_File0, _Ctx0, import(Imports)),
931 memberchk(PI, Imports)
932 -> '$permission_error'(redefine, imported_procedure, PI),
933 fail
934 ; Done = true
935 )
936 ; '$c_current_predicate'(_, Module:Head), 937 '$get_predicate_attribute'(Module:Head, imported, From)
938 -> ( ( '$resolved_source_path'(File, FullFile)
939 -> true
940 ; '$resolve_source_path'(File, FullFile, [])
941 ),
942 module_property(From, file(FullFile))
943 -> Done = true
944 ; print_message(warning,
945 autoload(already_defined(Module:PI, From))),
946 Done = true
947 )
948 ; true
949 ),
950 ( Done == true
951 -> true
952 ; '$set_predicate_attribute'(Module:Head, autoload, 1)
953 ),
954 register_autoloads(T, Module, File, Context).
955
956pi_in_exports(PI, Exports) :-
957 '$member'(E, Exports),
958 canonical_pi(E, PI),
959 !.
960
961current_autoload(M:File, Context, Term) :-
962 '$get_predicate_attribute'(M:'$autoload'(_,_,_), defined, 1),
963 M:'$autoload'(File, Context, Term).
964
965 968
969warn_autoload(TargetModule, PI) :-
970 current_prolog_flag(warn_autoload, true),
971 \+ current_prolog_flag(xref, true),
972 \+ nb_current('$autoload_warning', true),
973 '$pi_head'(PI, Head),
974 source_file(Head, File),
975 expansion_hook(P),
976 source_file(P, File),
977 !,
978 setup_call_cleanup(
979 b_setval('$autoload_warning', true),
980 print_message(warning,
981 deprecated(autoload(TargetModule, File, PI, expansion))),
982 nb_delete('$autoload_warning')).
983warn_autoload(_, _).
984
985expansion_hook(user:goal_expansion(_,_)).
986expansion_hook(user:goal_expansion(_,_,_,_)).
987expansion_hook(system:goal_expansion(_,_)).
988expansion_hook(system:goal_expansion(_,_,_,_)).
989
990
991 994
999
1000require(M:Spec) :-
1001 ( is_list(Spec)
1002 -> List = Spec
1003 ; phrase(comma_list(Spec), List)
1004 ), !,
1005 require(List, M, FromLib),
1006 keysort(FromLib, Sorted),
1007 by_file(Sorted, Autoload),
1008 forall('$member'(File-Import, Autoload),
1009 autoload(M:File, Import)).
1010require(_:Spec) :-
1011 '$type_error'(list, Spec).
1012
1013require([],_, []).
1014require([H|T], M, Needed) :-
1015 '$pi_head'(H, Head),
1016 ( '$get_predicate_attribute'(system:Head, defined, 1)
1017 -> require(T, M, Needed)
1018 ; '$pi_head'(Module:Name/Arity, M:Head),
1019 ( '$find_library'(Module, Name, Arity, LoadModule, Library)
1020 -> ( current_predicate(LoadModule:Name/Arity)
1021 -> Module:import(LoadModule:Name/Arity),
1022 require(T, M, Needed)
1023 ; Needed = [Library-H|More],
1024 require(T, M, More)
1025 )
1026 ; print_message(error, error(existence_error(procedure, Name/Arity), _)),
1027 require(T, M, Needed)
1028 )
1029 ).
1030
1031by_file([], []).
1032by_file([File-PI|T0], [Spec-[PI|PIs]|T]) :-
1033 on_path(File, Spec),
1034 same_file(T0, File, PIs, T1),
1035 by_file(T1, T).
1036
1037on_path(Library, library(Base)) :-
1038 file_base_name(Library, Base),
1039 findall(Path, plain_source(library(Base), Path), [Library]),
1040 !.
1041on_path(Library, Library).
1042
1043plain_source(Spec, Path) :-
1044 absolute_file_name(Spec, PathExt,
1045 [ file_type(prolog),
1046 access(read),
1047 file_errors(fail),
1048 solutions(all)
1049 ]),
1050 file_name_extension(Path, _, PathExt).
1051
1052same_file([File-PI|T0], File, [PI|PIs], T) :-
1053 !,
1054 same_file(T0, File, PIs, T).
1055same_file(List, _, [], List).
1056
1057comma_list(Var) -->
1058 { var(Var),
1059 !,
1060 '$instantiation_error'(Var)
1061 }.
1062comma_list((A,B)) -->
1063 !,
1064 comma_list(A),
1065 comma_list(B).
1066comma_list(A) -->
1067 [A]