1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 1985-2025, University of Amsterdam 7 VU University Amsterdam 8 CWI, Amsterdam 9 SWI-Prolog Solutions b.v. 10 All rights reserved. 11 12 Redistribution and use in source and binary forms, with or without 13 modification, are permitted provided that the following conditions 14 are met: 15 16 1. Redistributions of source code must retain the above copyright 17 notice, this list of conditions and the following disclaimer. 18 19 2. Redistributions in binary form must reproduce the above copyright 20 notice, this list of conditions and the following disclaimer in 21 the documentation and/or other materials provided with the 22 distribution. 23 24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 34 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 POSSIBILITY OF SUCH DAMAGE. 36*/ 37 38:- module('$autoload', 39 [ '$find_library'/5, 40 '$in_library'/3, 41 '$define_predicate'/1, 42 '$update_library_index'/1, % +Options 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, % +File 51 autoload/2, % +File, +Imports 52 53 require/1 % +Predicates 54 ]). 55 56:- meta_predicate 57 '$autoload'( ), 58 autoload( ), 59 autoload( , ), 60 require( ). 61 62:- dynamic 63 library_index/3, % Head x Module x Path 64 autoload_directories/1, % List 65 index_checked_at/1. % Time 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, []).
87'$find_library'(_Module, :, 2, _LoadModule, _Library) :- 88 !, fail. 89'$find_library'(Module, Name, Arity, LoadModule, Library) :- 90 load_library_index(Name, Arity), 91 functor(Head, Name, Arity), 92 ( library_index(Head, Module, Library), 93 LoadModule = Module 94 ; library_index(Head, LoadModule, Library) 95 ), 96 !.
103'$in_library'(Name, Arity, Path) :- 104 atom(Name), integer(Arity), 105 !, 106 Name/Arity \= (:)/2, 107 load_library_index(Name, Arity), 108 functor(Head, Name, Arity), 109 library_index(Head, _, Path). 110'$in_library'(Name, Arity, Path) :- 111 load_library_index(Name, Arity), 112 library_index(Head, _, Path), 113 Head \= _:_, 114 functor(Head, Name, Arity).
121:- meta_predicate 122 '$define_predicate'( ). 123 124'$define_predicate'(Head) :- 125 '$defined_predicate'(Head), 126 !. 127'$define_predicate'(Term) :- 128 Term = Module:Head, 129 ( compound(Head) 130 -> compound_name_arity(Head, Name, Arity) 131 ; Name = Head, Arity = 0 132 ), 133 '$undefined_procedure'(Module, Name, Arity, retry). 134 135 136 /******************************** 137 * UPDATE INDEX * 138 ********************************/ 139 140:- thread_local 141 silent/0.
false
.true
.155'$update_library_index'(Options) :- 156 setof(Dir, writable_indexed_directory(Dir, Options), Dirs), 157 !, 158 setup_call_cleanup( 159 asserta(silent, Ref), 160 guarded_make_library_index(Dirs), 161 erase(Ref)), 162 ( flag('$modified_index', true, false) 163 -> reload_library_index 164 ; true 165 ). 166'$update_library_index'(_). 167 168guarded_make_library_index([]). 169guarded_make_library_index([Dir|Dirs]) :- 170 ( catch(make_library_index(Dir), E, 171 print_message(error, E)) 172 -> true 173 ; print_message(warning, goal_failed(make_library_index(Dir))) 174 ), 175 guarded_make_library_index(Dirs).
182writable_indexed_directory(Dir, Options) :- 183 current_prolog_flag(home, Home), 184 writable_indexed_directory(Dir), 185 ( sub_atom(Dir, 0, _, _, Home) 186 -> '$option'(system(true), Options, false) 187 ; '$option'(user(true), Options, true) 188 ). 189 190writable_indexed_directory(Dir) :- 191 index_file_name(IndexFile, autoload('INDEX'), [access([read,write])]), 192 file_directory_name(IndexFile, Dir). 193writable_indexed_directory(Dir) :- 194 absolute_file_name(library('MKINDEX'), 195 [ file_type(prolog), 196 access(read), 197 solutions(all), 198 file_errors(fail) 199 ], MkIndexFile), 200 file_directory_name(MkIndexFile, Dir), 201 plfile_in_dir(Dir, 'INDEX', _, IndexFile), 202 access_file(IndexFile, write). 203 204 205 /******************************** 206 * LOAD INDEX * 207 ********************************/
213reload_library_index :- 214 context_module(M), 215 reload_library_index(M). 216 217reload_library_index(M) :- 218 with_mutex('$autoload', clear_library_index(M)). 219 220clear_library_index(M) :- 221 retractall(M:library_index(_, _, _)), 222 retractall(M:autoload_directories(_)), 223 retractall(M:index_checked_at(_)).
233:- meta_predicate load_library_index( , , ). 234:- public load_library_index/3. 235 236load_library_index(Name, Arity) :- 237 load_library_index(Name, Arity, autoload('INDEX')). 238 239load_library_index(Name, Arity, M:_Spec) :- 240 atom(Name), integer(Arity), 241 functor(Head, Name, Arity), 242 M:library_index(Head, _, _), 243 !. 244load_library_index(_, _, Spec) :- 245 notrace(with_mutex('$autoload', load_library_index_p(Spec))). 246 247load_library_index_p(M:_) :- 248 M:index_checked_at(Time), 249 get_time(Now), 250 Now-Time < 60, 251 !. 252load_library_index_p(M:Spec) :- 253 findall(Index, index_file_name(Index, Spec, [access(read)]), List0), 254 '$list_to_set'(List0, List), 255 retractall(M:index_checked_at(_)), 256 get_time(Now), 257 assert(M:index_checked_at(Now)), 258 ( M:autoload_directories(List) 259 -> true 260 ; retractall(M:library_index(_, _, _)), 261 retractall(M:autoload_directories(_)), 262 read_index(List, M), 263 assert(M:autoload_directories(List)) 264 ).
autoload
.
274index_file_name(IndexFile, FileSpec, Options) :- 275 absolute_file_name(FileSpec, 276 IndexFile, 277 [ file_type(prolog), 278 solutions(all), 279 file_errors(fail) 280 | Options 281 ]). 282 283read_index([], _) :- !. 284read_index([H|T], M) :- 285 !, 286 read_index(H, M), 287 read_index(T, M). 288read_index(Index, M) :- 289 print_message(silent, autoload(read_index(Dir))), 290 file_directory_name(Index, Dir), 291 setup_call_cleanup( 292 '$push_input_context'(autoload_index), 293 setup_call_cleanup( 294 open(Index, read, In), 295 read_index_from_stream(Dir, In, M), 296 close(In)), 297 '$pop_input_context'). 298 299read_index_from_stream(Dir, In, M) :- 300 repeat, 301 read(In, Term), 302 assert_index(Term, Dir, M), 303 !. 304 305assert_index(end_of_file, _, _) :- !. 306assert_index(index(Term, Module, File), Dir, M) :- 307 !, 308 atomic_list_concat([Dir, '/', File], Path), 309 assertz(M:library_index(Term, Module, Path)), 310 fail. 311assert_index(index(Name, Arity, Module, File), Dir, M) :- 312 !, % Read old index format 313 functor(Head, Name, Arity), 314 head_meta_any(Head), 315 assert_index(index(Head, Module, File), Dir, M). 316assert_index(Term, Dir, _) :- 317 print_message(error, illegal_autoload_index(Dir, Term)), 318 fail. 319 320 321 /******************************** 322 * CREATE INDEX.pl * 323 ********************************/
INDEX.pl
. In Dir contains a file
MKINDEX.pl
, this file is loaded and we assume that the index is
created by directives that appearin this file. Otherwise, all
source files are scanned for their module-header and all
exported predicates are added to the autoload index.
336make_library_index(Dir0) :- 337 forall(absolute_file_name(Dir0, Dir, 338 [ expand(true), 339 file_type(directory), 340 file_errors(fail), 341 solutions(all) 342 ]), 343 make_library_index2(Dir)). 344 345make_library_index2(Dir) :- 346 plfile_in_dir(Dir, 'MKINDEX', _MkIndex, AbsMkIndex), 347 access_file(AbsMkIndex, read), 348 !, 349 load_files(user:AbsMkIndex, [silent(true)]). 350make_library_index2(Dir) :- 351 findall(Pattern, source_file_pattern(Pattern), PatternList), 352 make_library_index2(Dir, PatternList).
INDEX.pl
for Dir by scanning all files
that match any of the file-patterns in Patterns. Typically, this
appears as a directive in MKINDEX.pl
. For example:
:- prolog_load_context(directory, Dir), make_library_index(Dir, ['*.pl']).
367make_library_index(Dir0, Patterns) :- 368 forall(absolute_file_name(Dir0, Dir, 369 [ expand(true), 370 file_type(directory), 371 file_errors(fail), 372 solutions(all) 373 ]), 374 make_library_index2(Dir, Patterns)). 375 376make_library_index2(Dir, Patterns) :- 377 plfile_in_dir(Dir, 'INDEX', _Index, AbsIndex), 378 ensure_slash(Dir, DirS), 379 pattern_files(Patterns, DirS, Files), 380 ( library_index_out_of_date(Dir, AbsIndex, Files) 381 -> do_make_library_index(AbsIndex, DirS, Files), 382 set_flag('$modified_index', true) 383 ; true 384 ). 385 386ensure_slash(Dir, DirS) :- 387 ( sub_atom(Dir, _, _, 0, /) 388 -> DirS = Dir 389 ; atom_concat(Dir, /, DirS) 390 ). 391 392source_file_pattern(Pattern) :- 393 user:prolog_file_type(PlExt, prolog), 394 PlExt \== qlf, 395 atom_concat('*.', PlExt, Pattern). 396 397plfile_in_dir(Dir, Base, PlBase, File) :- 398 file_name_extension(Base, pl, PlBase), 399 atomic_list_concat([Dir, '/', PlBase], File). 400 401pattern_files([], _, []). 402pattern_files([H|T], DirS, Files) :- 403 atom_concat(DirS, H, P0), 404 expand_file_name(P0, Files0), 405 '$append'(Files0, Rest, Files), 406 pattern_files(T, DirS, Rest). 407 408library_index_out_of_date(_Dir, Index, _Files) :- 409 \+ exists_file(Index), 410 !. 411library_index_out_of_date(Dir, Index, Files) :- 412 time_file(Index, IndexTime), 413 ( time_file(Dir, DotTime), 414 DotTime - IndexTime > 0.001 % compensate for jitter 415 ; '$member'(File, Files), % and rounding 416 time_file(File, FileTime), 417 FileTime - IndexTime > 0.001 418 ), 419 !. 420 421 422do_make_library_index(Index, Dir, Files) :- 423 ensure_slash(Dir, DirS), 424 '$stage_file'(Index, StagedIndex), 425 setup_call_catcher_cleanup( 426 open(StagedIndex, write, Out), 427 ( print_message(informational, make(library_index(Dir))), 428 index_header(Out), 429 index_files(Files, DirS, Out) 430 ), 431 Catcher, 432 install_index(Out, Catcher, StagedIndex, Index)). 433 434install_index(Out, Catcher, StagedIndex, Index) :- 435 catch(close(Out), Error, true), 436 ( silent 437 -> OnError = silent 438 ; OnError = error 439 ), 440 ( var(Error) 441 -> TheCatcher = Catcher 442 ; TheCatcher = exception(Error) 443 ), 444 '$install_staged_file'(TheCatcher, StagedIndex, Index, OnError).
450index_files([], _, _). 451index_files([File|Files], DirS, Fd) :- 452 ( catch(exports(File, Module, Exports, Meta, Public), E, 453 print_message(warning, E)), 454 nonvar(Module) 455 -> atom_concat(DirS, Local, File), 456 file_name_extension(Base, _, Local), 457 forall(index_term(Exports, Meta, Public, Term), 458 format(Fd, 'index(~k, ~k, ~k).~n', 459 [Term, Module, Base])) 460 ; true 461 ), 462 index_files(Files, DirS, Fd). 463 464index_term(Exports, Meta, _Public, Term) :- 465 '$member'(Export, Exports), 466 ground(Export), 467 export_term(Export, Meta, Term). 468index_term(_Exports, _Meta, Publics, (public):Head) :- 469 '$member'(Public, Publics), 470 '$pi_head'(Public, Head). 471 472export_term(Op, _Meta, Term) :- 473 Op = op(_Pri,_Type,_Name), 474 !, 475 Term = op:Op. 476export_term(PI, Meta, Head) :- 477 '$pi_head'(PI, Head), 478 ( '$member'(Head, Meta) 479 -> true 480 ; head_meta_any(Head) 481 ). 482 483head_meta_any(Head) :- 484 ( atom(Head) 485 -> true 486 ; compound_name_arguments(Head, _, Args), 487 meta_any(Args) 488 ). 489 490meta_any([]). 491meta_any([?|T]) :- 492 meta_any(T). 493 494index_header(Fd):- 495 format(Fd, '/* Creator: make/0~n~n', []), 496 format(Fd, ' Purpose: Provide index for autoload~n', []), 497 format(Fd, '*/~n~n', []).
507:- public exports/3. % using by library(prolog_deps). 508exports(File, Module, Exports) :- 509 exports(File, Module, Exports, _Meta, _Public). 510 511exports(File, Module, Exports, Meta, Public) :- 512 ( current_prolog_flag(xref, Old) 513 -> true 514 ; Old = false 515 ), 516 setup_call_cleanup( 517 set_prolog_flag(xref, true), 518 snapshot(exports_(File, Module, Exports, Meta, Public)), 519 set_prolog_flag(xref, Old)). 520 521exports_(File, Module, Exports, Meta, Public) :- 522 State = state(true, _, [], [], []), 523 ( '$source_term'(File, 524 _Read,_RLayout, 525 Term,_TermLayout, 526 _Stream, 527 [ syntax_errors(quiet) 528 ]), 529 ( Term = (:- module(M,ModuleExports)), 530 is_list(ModuleExports), 531 arg(1, State, true) 532 -> nb_setarg(1, State, false), 533 nb_setarg(2, State, M), 534 nb_setarg(3, State, ModuleExports), 535 fail 536 ; nb_setarg(1, State, false), 537 fail 538 ; Term = (:- export(Export)) 539 -> phrase(export_pi(Export), PIs), 540 arg(3, State, E0), 541 '$append'(E0, PIs, E1), 542 nb_setarg(3, State, E1), 543 fail 544 ; Term = (:- public(Public)) 545 -> phrase(export_pi(Public), PIs), 546 arg(5, State, E0), 547 '$append'(E0, PIs, E1), 548 nb_setarg(5, State, E1), 549 fail 550 ; Term = (:- meta_predicate(Heads)), 551 phrase(meta(Heads), M1), 552 arg(4, State, M0), 553 '$append'(M0, M1, M2), 554 nb_setarg(4, State, M2) 555 ; Term = (:- use_foreign_library(Lib)), 556 nonvar(Lib), 557 arg(2, State, M), 558 atom(M) 559 -> catch('$syspreds':use_foreign_library_noi(M:Lib), error(_,_), true), 560 fail 561 ; Term = (:- Directive), 562 nonvar(Directive) 563 -> fail 564 ; Term == [] % Expansion for conditionals 565 -> fail 566 ; ! 567 ) 568 ; true 569 ), 570 arg(2, State, Module), 571 arg(3, State, Exports), 572 arg(4, State, Meta), 573 arg(5, State, Public). 574 575export_pi(Var) --> 576 { var(Var) }, 577 !. 578export_pi((A,B)) --> 579 !, 580 export_pi(A), 581 export_pi(B). 582export_pi(PI) --> 583 { ground(PI) }, 584 [PI]. 585 586meta(Var) --> 587 { var(Var) }, 588 !. 589meta((A,B)) --> 590 !, 591 meta(A), 592 meta(B). 593meta(Head) --> 594 { callable(Head) }, 595 [Head]. 596 597 598 /******************************* 599 * EXTENDING * 600 *******************************/
autoload
and reloads the library
index. For example:
:- autoload_path(library(http)).
If this call appears as a directive, it is term-expanded into a clause for file_search_path/2 and a directive calling reload_library_index/0. This keeps source information and allows for removing this directive.
617autoload_path(Alias) :- 618 ( user:file_search_path(autoload, Alias) 619 -> true 620 ; assertz(user:file_search_path(autoload, Alias)), 621 reload_library_index 622 ). 623 624systemterm_expansion((:- autoload_path(Alias)), 625 [ user:file_search_path(autoload, Alias), 626 (:- reload_library_index) 627 ]). 628 629 630 /******************************* 631 * RUNTIME AUTOLOADER * 632 *******************************/
current_prolog_flag(autoload, true)
holds.642'$autoload'(PI) :- 643 source_location(File, _Line), 644 !, 645 setup_call_cleanup( 646 '$start_aux'(File, Context), 647 '$autoload2'(PI), 648 '$end_aux'(File, Context)). 649'$autoload'(PI) :- 650 '$autoload2'(PI). 651 652'$autoload2'(PI) :- 653 setup_call_cleanup( 654 leave_sandbox(Old), 655 '$autoload3'(PI), 656 restore_sandbox(Old)). 657 658leave_sandbox(Sandboxed) :- 659 current_prolog_flag(sandboxed_load, Sandboxed), 660 set_prolog_flag(sandboxed_load, false). 661restore_sandbox(Sandboxed) :- 662 set_prolog_flag(sandboxed_load, Sandboxed). 663 664'$autoload3'(PI) :- 665 autoload_from(PI, LoadModule, FullFile), 666 do_autoload(FullFile, PI, LoadModule).
673autoload_from(Module:PI, LoadModule, FullFile) :- 674 autoload_in(Module, explicit), 675 current_autoload(Module:File, Ctx, import(Imports)), 676 memberchk(PI, Imports), 677 library_info(File, Ctx, FullFile, LoadModule, Exports), 678 ( pi_in_exports(PI, Exports) 679 -> ! 680 ; autoload_error(Ctx, not_exported(PI, File, FullFile, Exports)), 681 fail 682 ). 683autoload_from(Module:Name/Arity, LoadModule, FullFile) :- 684 autoload_in(Module, explicit), 685 PI = Name/Arity, 686 current_autoload(Module:File, Ctx, all), 687 library_info(File, Ctx, FullFile, LoadModule, Exports), 688 pi_in_exports(PI, Exports). 689autoload_from(Module:Name/Arity, LoadModule, Library) :- 690 autoload_in(Module, general), 691 '$find_library'(Module, Name, Arity, LoadModule, Library). 692 693:- public autoload_in/2. % used in syspred 694 695autoload_in(Module, How) :- 696 current_prolog_flag(autoload, AutoLoad), 697 autoload_in(AutoLoad, How, Module), 698 !.
702autoload_in(true, _, _). 703autoload_in(explicit, explicit, _). 704autoload_in(user, _, user). 705autoload_in(user_or_explicit, explicit, _). 706autoload_in(user_or_explicit, _, user).
user
. '$c_current_predicate'/2
verifies the predicate really exists, but doesn't validate
that it is defined.725do_autoload(Library, Module:Name/Arity, LoadModule) :- 726 functor(Head, Name, Arity), 727 '$update_autoload_level'([autoload(true)], Old), 728 verbose_autoload(Module:Name/Arity, Library), 729 loadable_file(Library, File), 730 '$compilation_mode'(OldComp, database), 731 ( Module == LoadModule 732 -> ensure_loaded(Module:File) 733 ; ( '$c_current_predicate'(_, LoadModule:Head), 734 '$get_predicate_attribute'(LoadModule:Head, defined, 1), 735 \+ '$loading'(Library) 736 -> Module:import(LoadModule:Name/Arity) 737 ; use_module(Module:File, [Name/Arity]) 738 ), 739 warn_autoload(Module, LoadModule:Name/Arity) 740 ), 741 '$set_compilation_mode'(OldComp), 742 '$set_autoload_level'(Old), 743 '$c_current_predicate'(_, Module:Head). 744 745loadable_file(PlFile, File) :- 746 exists_file(PlFile), !, 747 File = PlFile. 748loadable_file(PlFile, Base) :- 749 file_name_extension(Base, pl, PlFile), 750 !. 751loadable_file(File, File). 752 753verbose_autoload(PI, Library) :- 754 current_prolog_flag(verbose_autoload, true), 755 !, 756 set_prolog_flag(verbose_autoload, false), 757 print_message(informational, autoload(PI, Library)), 758 set_prolog_flag(verbose_autoload, true). 759verbose_autoload(PI, Library) :- 760 print_message(silent, autoload(PI, Library)).
autoload(File)
. The module must be
instantiated.769:- public % used from predicate_property/2 770 autoloadable/2. 771 772autoloadable(M:Head, FullFile) :- 773 atom(M), 774 current_module(M), 775 autoload_in(M, explicit), 776 ( callable(Head) 777 -> goal_name_arity(Head, Name, Arity), 778 autoload_from(M:Name/Arity, _, FullFile) 779 ; findall((M:H)-F, autoloadable_2(M:H, F), Pairs), 780 ( '$member'(M:Head-FullFile, Pairs) 781 ; current_autoload(M:File, Ctx, all), 782 library_info(File, Ctx, FullFile, _, Exports), 783 '$member'(PI, Exports), 784 '$pi_head'(PI, Head), 785 \+ memberchk(M:Head-_, Pairs) 786 ) 787 ). 788autoloadable(M:Head, FullFile) :- 789 ( var(M) 790 -> autoload_in(any, general) 791 ; autoload_in(M, general) 792 ), 793 ( callable(Head) 794 -> goal_name_arity(Head, Name, Arity), 795 ( '$find_library'(_, Name, Arity, _, FullFile) 796 -> true 797 ) 798 ; '$in_library'(Name, Arity, autoload), 799 functor(Head, Name, Arity) 800 ). 801 802 803autoloadable_2(M:Head, FullFile) :- 804 current_autoload(M:File, Ctx, import(Imports)), 805 library_info(File, Ctx, FullFile, _LoadModule, _Exports), 806 '$member'(PI, Imports), 807 '$pi_head'(PI, Head). 808 809goal_name_arity(Head, Name, Arity) :- 810 compound(Head), 811 !, 812 compound_name_arity(Head, Name, Arity). 813goal_name_arity(Head, Head, 0).
826library_info(Spec, _, FullFile, Module, Exports) :- 827 '$resolved_source_path'(Spec, FullFile, []), 828 !, 829 ( \+ '$loading_file'(FullFile, _Queue, _LoadThread) 830 -> '$current_module'(Module, FullFile), 831 '$module_property'(Module, exports(Exports)) 832 ; library_info_from_file(FullFile, _, Module, Exports) 833 ). 834library_info(Spec, Context, FullFile, Module, Exports) :- 835 ( Context = (Path:_Line) 836 -> Extra = [relative_to(Path)] 837 ; Extra = [] 838 ), 839 ( absolute_file_name(Spec, AbsFile, 840 [ file_type(prolog), 841 access(read), 842 file_errors(fail) 843 | Extra 844 ]) 845 -> library_info_from_file(AbsFile, FullFile, Module, Exports), 846 '$register_resolved_source_path'(Spec, FullFile) 847 ; absolute_file_name(Spec, FullFile, 848 [ file_type(prolog), 849 solutions(all), 850 file_errors(fail) 851 | Extra 852 ]), 853 source_file(FullFile), 854 '$current_module'(Module, FullFile) 855 -> '$module_property'(Module, exports(Exports)) 856 ; autoload_error(Context, no_file(Spec)), 857 fail 858 ). 859 860library_info_from_file(QlfFile, PlFile, Module, Exports) :- 861 file_name_extension(_, qlf, QlfFile), 862 !, 863 '$qlf_module'(QlfFile, Info), 864 _{module:Module, exports:Exports, file:PlFile} :< Info. 865library_info_from_file(PlFile, PlFile, Module, Exports) :- 866 setup_call_cleanup( 867 '$set_source_module'(OldModule, system), 868 setup_call_cleanup( 869 '$open_source'(PlFile, In, State, [], []), 870 '$term_in_file'(In, _Read, _RLayout, Term, _TLayout, _Stream, 871 [PlFile], []), 872 '$close_source'(State, true)), 873 '$set_source_module'(OldModule)), 874 ( Term = (:- module(Module, Exports)) 875 -> ! 876 ; nonvar(Term), 877 skip_header(Term) 878 -> fail 879 ; '$domain_error'(module_header, Term) 880 ). 881 882skip_header(begin_of_file). 883 884 885:- dynamic printed/3. 886:- volatile printed/3. 887 888autoload_error(Context, Error) :- 889 suppress(Context, Error), 890 !. 891autoload_error(Context, Error) :- 892 get_time(Now), 893 assertz(printed(Context, Error, Now)), 894 print_message(warning, error(autoload(Error), autoload(Context))). 895 896suppress(Context, Error) :- 897 printed(Context, Error, Printed), 898 get_time(Now), 899 ( Now - Printed < 1 900 -> true 901 ; retractall(printed(Context, Error, _)), 902 fail 903 ). 904 905 906 /******************************* 907 * CALLBACK * 908 *******************************/ 909 910:- public 911 set_autoload/1.
false
we should materialize all registered
requests for autoloading. We must do so before disabling autoloading
as loading the files may require autoloading.920set_autoload(FlagValue) :- 921 current_prolog_flag(autoload, FlagValue), 922 !. 923set_autoload(FlagValue) :- 924 \+ autoload_in(FlagValue, explicit, any), 925 !, 926 setup_call_cleanup( 927 nb_setval('$autoload_disabling', true), 928 materialize_autoload(Count), 929 nb_delete('$autoload_disabling')), 930 print_message(informational, autoload(disabled(Count))). 931set_autoload(_). 932 933materialize_autoload(Count) :- 934 State = state(0), 935 forall(current_predicate(M:'$autoload'/3), 936 materialize_autoload(M, State)), 937 arg(1, State, Count). 938 939materialize_autoload(M, State) :- 940 ( current_autoload(M:File, Context, Import), 941 library_info(File, Context, PlFile, _LoadModule, _Exports), 942 arg(1, State, N0), 943 N is N0+1, 944 nb_setarg(1, State, N), 945 loadable_file(PlFile, LoadFile), 946 ( Import == all 947 -> verbose_autoload(M:all, PlFile), 948 use_module(M:LoadFile) 949 ; Import = import(Preds) 950 -> verbose_autoload(M:Preds, PlFile), 951 use_module(M:LoadFile, Preds) 952 ), 953 fail 954 ; true 955 ), 956 abolish(M:'$autoload'/3). 957 958 959 /******************************* 960 * AUTOLOAD/2 * 961 *******************************/ 962 963autoload(M:File) :- 964 ( \+ autoload_in(M, explicit) 965 ; nb_current('$autoload_disabling', true) 966 ), 967 !, 968 use_module(M:File). 969autoload(M:File) :- 970 '$must_be'(filespec, File), 971 source_context(Context), 972 assert_autoload(M, File, Context, all). 973 974autoload(M:File, Imports) :- 975 ( \+ autoload_in(M, explicit) 976 ; nb_current('$autoload_disabling', true) 977 ), 978 !, 979 use_module(M:File, Imports). 980autoload(M:File, Imports0) :- 981 '$must_be'(filespec, File), 982 valid_imports(Imports0, Imports), 983 source_context(Context), 984 register_autoloads(Imports, M, File, Context), 985 assert_autoload(M, File, Context, import(Imports)). 986 987source_context(Path:Line) :- 988 source_location(Path, Line), 989 !. 990source_context(-).
1000assert_autoload(Module, File, _, Imports) :- 1001 current_autoload(Module:File, _, Imports), 1002 !. 1003assert_autoload(Module, File, Context, Imports) :- 1004 set_admin_properties(Module), 1005 Clause = Module:'$autoload'(File, Context, Imports), 1006 '$initialization_context'(Source, Ctx), 1007 '$store_admin_clause2'(Clause, _Layout, Source, Ctx). 1008 1009set_admin_properties(Module) :- 1010 predicate_property(Module:'$autoload'(_,_,_), discontiguous), 1011 !. 1012set_admin_properties(Module) :- 1013 discontiguous(Module:'$autoload'/3). 1014 1015valid_imports(Imports0, Imports) :- 1016 '$must_be'(list, Imports0), 1017 valid_import_list(Imports0, Imports). 1018 1019valid_import_list([], []). 1020valid_import_list([H0|T0], [H|T]) :- 1021 '$pi_head'(H0, Head), 1022 '$pi_head'(H, Head), 1023 valid_import_list(T0, T).
autoload
flag on all predicates declared using autoload/2
to prevent duplicates or the user defining the same predicate.
1032register_autoloads([], _, _, _). 1033register_autoloads([PI|T], Module, File, Context) :- 1034 PI = Name/Arity, 1035 functor(Head, Name, Arity), 1036 ( '$get_predicate_attribute'(Module:Head, autoload, 1) 1037 -> ( current_autoload(Module:_File0, _Ctx0, import(Imports)), 1038 memberchk(PI, Imports) 1039 -> '$permission_error'(redefine, imported_procedure, PI), 1040 fail 1041 ; Done = true 1042 ) 1043 ; '$c_current_predicate'(_, Module:Head), % no auto-import 1044 '$get_predicate_attribute'(Module:Head, imported, From) 1045 -> ( ( '$resolved_source_path'(File, FullFile) 1046 -> true 1047 ; '$resolve_source_path'(File, FullFile, []) 1048 ), 1049 module_property(From, file(FullFile)) 1050 -> Done = true 1051 ; print_message(warning, 1052 autoload(already_defined(Module:PI, From))), 1053 Done = true 1054 ) 1055 ; true 1056 ), 1057 ( Done == true 1058 -> true 1059 ; '$set_predicate_attribute'(Module:Head, autoload, 1) 1060 ), 1061 register_autoloads(T, Module, File, Context). 1062 1063pi_in_exports(PI, Exports) :- 1064 '$member'(E, Exports), 1065 canonical_pi(E, PI), 1066 !. 1067 1068canonical_pi(Var, _) :- 1069 var(Var), !, fail. 1070canonical_pi(Name/Arity, Name/Arity). 1071canonical_pi(Name//A0, Name/Arity) :- 1072 Arity is A0 + 2. 1073 1074current_autoload(M:File, Context, Term) :- 1075 '$get_predicate_attribute'(M:'$autoload'(_,_,_), defined, 1), 1076 M:'$autoload'(File, Context, Term). 1077 1078 /******************************* 1079 * CHECK * 1080 *******************************/
1086warn_autoload(TargetModule, PI) :- 1087 current_prolog_flag(warn_autoload, true), 1088 \+ current_prolog_flag(xref, true), 1089 \+ nb_current('$autoload_warning', true), 1090 \+ nowarn_autoload(TargetModule, PI), 1091 '$pi_head'(PI, Head), 1092 source_file(Head, File), 1093 '$source_defines_expansion'(File), 1094 setup_call_cleanup( 1095 b_setval('$autoload_warning', true), 1096 print_message(warning, 1097 deprecated(autoload(TargetModule, File, PI, expansion))), 1098 nb_delete('$autoload_warning')). 1099warn_autoload(_, _).
1114nowarn_autoload(TargetModule, LoadModule:PI) :- 1115 NoWarn = LoadModule:'$nowarn_autoload'(PI,TargetModule), 1116 '$c_current_predicate'(_, NoWarn), 1117 \+ '$get_predicate_attribute'(NoWarn, imported, _From), 1118 call(NoWarn). 1119 1120 1121 /******************************* 1122 * REQUIRE * 1123 *******************************/
1130require(M:Spec) :- 1131 ( is_list(Spec) 1132 -> List = Spec 1133 ; phrase(comma_list(Spec), List) 1134 ), !, 1135 require(List, M, FromLib), 1136 keysort(FromLib, Sorted), 1137 by_file(Sorted, Autoload), 1138 forall('$member'(File-Import, Autoload), 1139 autoload(M:File, Import)). 1140require(_:Spec) :- 1141 '$type_error'(list, Spec). 1142 1143require([],_, []). 1144require([H|T], M, Needed) :- 1145 '$pi_head'(H, Head), 1146 ( '$get_predicate_attribute'(system:Head, defined, 1) 1147 -> require(T, M, Needed) 1148 ; '$pi_head'(Module:Name/Arity, M:Head), 1149 ( '$find_library'(Module, Name, Arity, LoadModule, Library) 1150 -> ( current_predicate(LoadModule:Name/Arity) 1151 -> Module:import(LoadModule:Name/Arity), 1152 require(T, M, Needed) 1153 ; Needed = [Library-H|More], 1154 require(T, M, More) 1155 ) 1156 ; print_message(error, error(existence_error(procedure, Name/Arity), _)), 1157 require(T, M, Needed) 1158 ) 1159 ). 1160 1161by_file([], []). 1162by_file([File-PI|T0], [Spec-[PI|PIs]|T]) :- 1163 on_path(File, Spec), 1164 same_file(T0, File, PIs, T1), 1165 by_file(T1, T). 1166 1167on_path(Library, library(Base)) :- 1168 file_base_name(Library, Base), 1169 findall(Path, plain_source(library(Base), Path), [Library]), 1170 !. 1171on_path(Library, Library). 1172 1173plain_source(Spec, Path) :- 1174 absolute_file_name(Spec, PathExt, 1175 [ file_type(prolog), 1176 access(read), 1177 file_errors(fail), 1178 solutions(all) 1179 ]), 1180 file_name_extension(Path, _, PathExt). 1181 1182same_file([File-PI|T0], File, [PI|PIs], T) :- 1183 !, 1184 same_file(T0, File, PIs, T). 1185same_file(List, _, [], List). 1186 1187comma_list(Var) --> 1188 { var(Var), 1189 !, 1190 '$instantiation_error'(Var) 1191 }. 1192comma_list((A,B)) --> 1193 !, 1194 comma_list(A), 1195 comma_list(B). 1196comma_list(A) --> 1197 [A]