View source with raw comments or as raw
    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-2020, University of Amsterdam
    7                              VU University Amsterdam
    8                              CWI, Amsterdam
    9    All rights reserved.
   10
   11    Redistribution and use in source and binary forms, with or without
   12    modification, are permitted provided that the following conditions
   13    are met:
   14
   15    1. Redistributions of source code must retain the above copyright
   16       notice, this list of conditions and the following disclaimer.
   17
   18    2. Redistributions in binary form must reproduce the above copyright
   19       notice, this list of conditions and the following disclaimer in
   20       the documentation and/or other materials provided with the
   21       distribution.
   22
   23    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   24    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   25    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   26    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   27    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   28    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   29    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   30    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   31    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   33    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   34    POSSIBILITY OF SUCH DAMAGE.
   35*/
   36
   37:- module('$autoload',
   38          [ '$find_library'/5,
   39            '$in_library'/3,
   40            '$define_predicate'/1,
   41            '$update_library_index'/0,
   42            '$autoload'/1,
   43
   44            make_library_index/1,
   45            make_library_index/2,
   46            reload_library_index/0,
   47            autoload_path/1,
   48
   49            autoload/1,                         % +File
   50            autoload/2,                         % +File, +Imports
   51
   52            require/1				% +Predicates
   53          ]).   54
   55:- meta_predicate
   56    '$autoload'(:),
   57    autoload(:),
   58    autoload(:, +),
   59    require(:).   60
   61:- dynamic
   62    library_index/3,                % Head x Module x Path
   63    autoload_directories/1,         % List
   64    index_checked_at/1.             % Time
   65:- volatile
   66    library_index/3,
   67    autoload_directories/1,
   68    index_checked_at/1.   69
   70user:file_search_path(autoload, swi(library)).
   71user:file_search_path(autoload, pce(prolog/lib)).
   72user:file_search_path(autoload, app_config(lib)).
 $find_library(+Module, +Name, +Arity, -LoadModule, -Library) is semidet
Locate a predicate in the library. Name and arity are the name and arity of the predicate searched for. `Module' is the preferred target module. The return values are the full path name (excluding extension) of the library and module declared in that file.
   83'$find_library'(Module, Name, Arity, LoadModule, Library) :-
   84    load_library_index(Name, Arity),
   85    functor(Head, Name, Arity),
   86    (   library_index(Head, Module, Library),
   87        LoadModule = Module
   88    ;   library_index(Head, LoadModule, Library)
   89    ),
   90    !.
 $in_library(+Name, +Arity, -Path) is semidet
$in_library(-Name, -Arity, -Path) is nondet
Is true if Name/Arity is in the autoload libraries.
   97'$in_library'(Name, Arity, Path) :-
   98    atom(Name), integer(Arity),
   99    !,
  100    load_library_index(Name, Arity),
  101    functor(Head, Name, Arity),
  102    library_index(Head, _, Path).
  103'$in_library'(Name, Arity, Path) :-
  104    load_library_index(Name, Arity),
  105    library_index(Head, _, Path),
  106    functor(Head, Name, Arity).
 $define_predicate(:Head)
Make sure PredInd can be called. First test if the predicate is defined. If not, invoke the autoloader.
  113:- meta_predicate
  114    '$define_predicate'(:).  115
  116'$define_predicate'(Head) :-
  117    '$defined_predicate'(Head),
  118    !.
  119'$define_predicate'(Term) :-
  120    Term = Module:Head,
  121    (   compound(Head)
  122    ->  compound_name_arity(Head, Name, Arity)
  123    ;   Name = Head, Arity = 0
  124    ),
  125    '$undefined_procedure'(Module, Name, Arity, retry).
  126
  127
  128                /********************************
  129                *          UPDATE INDEX         *
  130                ********************************/
  131
  132:- thread_local
  133    silent/0.
 $update_library_index
Called from make/0 to update the index of the library for each library directory that has a writable index. Note that in the Windows version access_file/2 is mostly bogus. We assert silent/0 to suppress error messages.
  142'$update_library_index' :-
  143    setof(Dir, writable_indexed_directory(Dir), Dirs),
  144    !,
  145    setup_call_cleanup(
  146        asserta(silent, Ref),
  147        guarded_make_library_index(Dirs),
  148        erase(Ref)),
  149    (   flag('$modified_index', true, false)
  150    ->  reload_library_index
  151    ;   true
  152    ).
  153'$update_library_index'.
  154
  155guarded_make_library_index([]).
  156guarded_make_library_index([Dir|Dirs]) :-
  157    (   catch(make_library_index(Dir), E,
  158              print_message(error, E))
  159    ->  true
  160    ;   print_message(warning, goal_failed(make_library_index(Dir)))
  161    ),
  162    guarded_make_library_index(Dirs).
 writable_indexed_directory(-Dir) is nondet
True when Dir is an indexed library directory with a writable index, i.e., an index that can be updated.
  169writable_indexed_directory(Dir) :-
  170    index_file_name(IndexFile, autoload('INDEX'), [access([read,write])]),
  171    file_directory_name(IndexFile, Dir).
  172writable_indexed_directory(Dir) :-
  173    absolute_file_name(library('MKINDEX'),
  174                       [ file_type(prolog),
  175                         access(read),
  176                         solutions(all),
  177                         file_errors(fail)
  178                       ], MkIndexFile),
  179    file_directory_name(MkIndexFile, Dir),
  180    plfile_in_dir(Dir, 'INDEX', _, IndexFile),
  181    access_file(IndexFile, write).
  182
  183
  184                /********************************
  185                *           LOAD INDEX          *
  186                ********************************/
 reload_library_index
Reload the index on the next call
  192reload_library_index :-
  193    context_module(M),
  194    reload_library_index(M).
  195
  196reload_library_index(M) :-
  197    with_mutex('$autoload', clear_library_index(M)).
  198
  199clear_library_index(M) :-
  200    retractall(M:library_index(_, _, _)),
  201    retractall(M:autoload_directories(_)),
  202    retractall(M:index_checked_at(_)).
 load_library_index(?Name, ?Arity) is det
 load_library_index(?Name, ?Arity, :IndexSpec) is det
Try to find Name/Arity in the library. If the predicate is there, we are happy. If not, we check whether the set of loaded libraries has changed and if so we reload the index.
  212:- meta_predicate load_library_index(?, ?, :).  213:- public load_library_index/3.  214
  215load_library_index(Name, Arity) :-
  216    load_library_index(Name, Arity, autoload('INDEX')).
  217
  218load_library_index(Name, Arity, M:_Spec) :-
  219    atom(Name), integer(Arity),
  220    functor(Head, Name, Arity),
  221    M:library_index(Head, _, _),
  222    !.
  223load_library_index(_, _, Spec) :-
  224    notrace(with_mutex('$autoload', load_library_index_p(Spec))).
  225
  226load_library_index_p(M:_) :-
  227    M:index_checked_at(Time),
  228    get_time(Now),
  229    Now-Time < 60,
  230    !.
  231load_library_index_p(M:Spec) :-
  232    findall(Index, index_file_name(Index, Spec, [access(read)]), List0),
  233    '$list_to_set'(List0, List),
  234    retractall(M:index_checked_at(_)),
  235    get_time(Now),
  236    assert(M:index_checked_at(Now)),
  237    (   M:autoload_directories(List)
  238    ->  true
  239    ;   retractall(M:library_index(_, _, _)),
  240        retractall(M:autoload_directories(_)),
  241        read_index(List, M),
  242        assert(M:autoload_directories(List))
  243    ).
 index_file_name(-IndexFile, +Spec, +Options) is nondet
True if IndexFile is an autoload index file. Options is passed to absolute_file_name/3. This predicate searches the path autoload.
See also
- file_search_path/2.
  253index_file_name(IndexFile, FileSpec, Options) :-
  254    absolute_file_name(FileSpec,
  255                       IndexFile,
  256                       [ file_type(prolog),
  257                         solutions(all),
  258                         file_errors(fail)
  259                       | Options
  260                       ]).
  261
  262read_index([], _) :- !.
  263read_index([H|T], M) :-
  264    !,
  265    read_index(H, M),
  266    read_index(T, M).
  267read_index(Index, M) :-
  268    print_message(silent, autoload(read_index(Dir))),
  269    file_directory_name(Index, Dir),
  270    setup_call_cleanup(
  271        '$push_input_context'(autoload_index),
  272        setup_call_cleanup(
  273            open(Index, read, In),
  274            read_index_from_stream(Dir, In, M),
  275            close(In)),
  276        '$pop_input_context').
  277
  278read_index_from_stream(Dir, In, M) :-
  279    repeat,
  280        read(In, Term),
  281        assert_index(Term, Dir, M),
  282    !.
  283
  284assert_index(end_of_file, _, _) :- !.
  285assert_index(index(Name, Arity, Module, File), Dir, M) :-
  286    !,
  287    functor(Head, Name, Arity),
  288    atomic_list_concat([Dir, '/', File], Path),
  289    assertz(M:library_index(Head, Module, Path)),
  290    fail.
  291assert_index(Term, Dir, _) :-
  292    print_message(error, illegal_autoload_index(Dir, Term)),
  293    fail.
  294
  295
  296                /********************************
  297                *       CREATE INDEX.pl         *
  298                ********************************/
 make_library_index(+Dir) is det
Create an index for autoloading from the directory Dir. The index file is called 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.
See also
- make_library_index/2
  311make_library_index(Dir0) :-
  312    forall(absolute_file_name(Dir0, Dir,
  313                              [ expand(true),
  314                                file_type(directory),
  315                                file_errors(fail),
  316                                solutions(all)
  317                              ]),
  318           make_library_index2(Dir)).
  319
  320make_library_index2(Dir) :-
  321    plfile_in_dir(Dir, 'MKINDEX', _MkIndex, AbsMkIndex),
  322    access_file(AbsMkIndex, read),
  323    !,
  324    load_files(user:AbsMkIndex, [silent(true)]).
  325make_library_index2(Dir) :-
  326    findall(Pattern, source_file_pattern(Pattern), PatternList),
  327    make_library_index2(Dir, PatternList).
 make_library_index(+Dir, +Patterns:list(atom)) is det
Create an autoload index 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']).
See also
- make_library_index/1.
  342make_library_index(Dir0, Patterns) :-
  343    forall(absolute_file_name(Dir0, Dir,
  344                              [ expand(true),
  345                                file_type(directory),
  346                                file_errors(fail),
  347                                solutions(all)
  348                              ]),
  349           make_library_index2(Dir, Patterns)).
  350
  351make_library_index2(Dir, Patterns) :-
  352    plfile_in_dir(Dir, 'INDEX', _Index, AbsIndex),
  353    ensure_slash(Dir, DirS),
  354    pattern_files(Patterns, DirS, Files),
  355    (   library_index_out_of_date(Dir, AbsIndex, Files)
  356    ->  do_make_library_index(AbsIndex, DirS, Files),
  357        flag('$modified_index', _, true)
  358    ;   true
  359    ).
  360
  361ensure_slash(Dir, DirS) :-
  362    (   sub_atom(Dir, _, _, 0, /)
  363    ->  DirS = Dir
  364    ;   atom_concat(Dir, /, DirS)
  365    ).
  366
  367source_file_pattern(Pattern) :-
  368    user:prolog_file_type(PlExt, prolog),
  369    PlExt \== qlf,
  370    atom_concat('*.', PlExt, Pattern).
  371
  372plfile_in_dir(Dir, Base, PlBase, File) :-
  373    file_name_extension(Base, pl, PlBase),
  374    atomic_list_concat([Dir, '/', PlBase], File).
  375
  376pattern_files([], _, []).
  377pattern_files([H|T], DirS, Files) :-
  378    atom_concat(DirS, H, P0),
  379    expand_file_name(P0, Files0),
  380    '$append'(Files0, Rest, Files),
  381    pattern_files(T, DirS, Rest).
  382
  383library_index_out_of_date(_Dir, Index, _Files) :-
  384    \+ exists_file(Index),
  385    !.
  386library_index_out_of_date(Dir, Index, Files) :-
  387    time_file(Index, IndexTime),
  388    (   time_file(Dir, DotTime),
  389        DotTime > IndexTime
  390    ;   '$member'(File, Files),
  391        time_file(File, FileTime),
  392        FileTime > IndexTime
  393    ),
  394    !.
  395
  396
  397do_make_library_index(Index, Dir, Files) :-
  398    ensure_slash(Dir, DirS),
  399    '$stage_file'(Index, StagedIndex),
  400    setup_call_catcher_cleanup(
  401        open(StagedIndex, write, Out),
  402        ( print_message(informational, make(library_index(Dir))),
  403          index_header(Out),
  404          index_files(Files, DirS, Out)
  405        ),
  406        Catcher,
  407        install_index(Out, Catcher, StagedIndex, Index)).
  408
  409install_index(Out, Catcher, StagedIndex, Index) :-
  410    catch(close(Out), Error, true),
  411    (   silent
  412    ->  OnError = silent
  413    ;   OnError = error
  414    ),
  415    (   var(Error)
  416    ->  TheCatcher = Catcher
  417    ;   TheCatcher = exception(Error)
  418    ),
  419    '$install_staged_file'(TheCatcher, StagedIndex, Index, OnError).
 index_files(+Files, +Directory, +Out:stream) is det
Write index for Files in Directory to the stream Out.
  425index_files([], _, _).
  426index_files([File|Files], DirS, Fd) :-
  427    catch(setup_call_cleanup(
  428              open(File, read, In),
  429              read(In, Term),
  430              close(In)),
  431          E, print_message(warning, E)),
  432    (   Term = (:- module(Module, Public)),
  433        is_list(Public)
  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
  454index_header(Fd):-
  455    format(Fd, '/*  Creator: make/0~n~n', []),
  456    format(Fd, '    Purpose: Provide index for autoload~n', []),
  457    format(Fd, '*/~n~n', []).
  458
  459
  460                 /*******************************
  461                 *            EXTENDING         *
  462                 *******************************/
 autoload_path(+Path) is det
Add Path to the libraries that are used by the autoloader. This extends the search path 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.

  479autoload_path(Alias) :-
  480    (   user:file_search_path(autoload, Alias)
  481    ->  true
  482    ;   assertz(user:file_search_path(autoload, Alias)),
  483        reload_library_index
  484    ).
  485
  486system:term_expansion((:- autoload_path(Alias)),
  487                      [ user:file_search_path(autoload, Alias),
  488                        (:- reload_library_index)
  489                      ]).
  490
  491
  492		 /*******************************
  493		 *      RUNTIME AUTOLOADER	*
  494		 *******************************/
Provide PI by autoloading. This checks:
  504'$autoload'(PI) :-
  505    source_location(File, _Line),
  506    !,
  507    setup_call_cleanup(
  508        '$start_aux'(File, Context),
  509        '$autoload2'(PI),
  510        '$end_aux'(File, Context)).
  511'$autoload'(PI) :-
  512    '$autoload2'(PI).
  513
  514'$autoload2'(PI) :-
  515    autoload_from(PI, LoadModule, FullFile),
  516    do_autoload(FullFile, PI, LoadModule).
 autoload_from(+PI, -LoadModule, -File) is semidet
True when PI can be defined by loading File which is defined the module LoadModule.
  523autoload_from(Module:PI, LoadModule, FullFile) :-
  524    autoload_in(Module, explicit),
  525    current_autoload(Module:File, Ctx, import(Imports)),
  526    memberchk(PI, Imports),
  527    library_info(File, Ctx, FullFile, LoadModule, Exports),
  528    (   pi_in_exports(PI, Exports)
  529    ->  !
  530    ;   autoload_error(Ctx, not_exported(PI, File, FullFile, Exports)),
  531        fail
  532    ).
  533autoload_from(Module:Name/Arity, LoadModule, FullFile) :-
  534    autoload_in(Module, explicit),
  535    PI = Name/Arity,
  536    current_autoload(Module:File, Ctx, all),
  537    library_info(File, Ctx, FullFile, LoadModule, Exports),
  538    pi_in_exports(PI, Exports).
  539autoload_from(Module:Name/Arity, LoadModule, Library) :-
  540    autoload_in(Module, general),
  541    '$find_library'(Module, Name, Arity, LoadModule, Library).
  542
  543:- public autoload_in/2.                        % used in syspred
  544
  545autoload_in(Module, How) :-
  546    current_prolog_flag(autoload, AutoLoad),
  547    autoload_in(AutoLoad, How, Module),
  548    !.
 autoload_in(+AutoloadFlag, +AutoloadMode, +TargetModule) is semidet
  552autoload_in(true,             _,        _).
  553autoload_in(explicit,         explicit, _).
  554autoload_in(explicit_or_user, explicit, _).
  555autoload_in(user,             explicit, user).
  556autoload_in(explicit_or_user, explicit, _).
  557autoload_in(user,             _,        user).
  558autoload_in(explicit_or_user, general,  user).
 do_autoload(+File, :PI, +LoadModule) is det
Load File, importing PI into the qualified module. File is known to define LoadModule. There are three cases:
  574do_autoload(Library, Module:Name/Arity, LoadModule) :-
  575    functor(Head, Name, Arity),
  576    '$update_autoload_level'([autoload(true)], Old),
  577    verbose_autoload(Module:Name/Arity, Library),
  578    '$compilation_mode'(OldComp, database),
  579    (   Module == LoadModule
  580    ->  ensure_loaded(Module:Library)
  581    ;   (   '$c_current_predicate'(_, LoadModule:Head),
  582            '$get_predicate_attribute'(LoadModule:Head, defined, 1),
  583            \+ '$loading'(Library)
  584        ->  Module:import(LoadModule:Name/Arity)
  585        ;   use_module(Module:Library, [Name/Arity])
  586        )
  587    ),
  588    '$set_compilation_mode'(OldComp),
  589    '$set_autoload_level'(Old),
  590    '$c_current_predicate'(_, Module:Head).
  591
  592verbose_autoload(PI, Library) :-
  593    current_prolog_flag(verbose_autoload, true),
  594    !,
  595    set_prolog_flag(verbose_autoload, false),
  596    print_message(informational, autoload(PI, Library)),
  597    set_prolog_flag(verbose_autoload, true).
  598verbose_autoload(PI, Library) :-
  599    print_message(silent, autoload(PI, Library)).
 autoloadable(:Head, -File) is nondet
True when Head can be autoloaded from File. This implements the predicate_property/2 property autoload(File). The module muse be instantiated.
  608:- public                               % used from predicate_property/2
  609    autoloadable/2.  610
  611autoloadable(M:Head, FullFile) :-
  612    atom(M),
  613    current_module(M),
  614    autoload_in(M, explicit),
  615    (   callable(Head)
  616    ->  goal_name_arity(Head, Name, Arity),
  617        autoload_from(M:Name/Arity, _, FullFile)
  618    ;   findall((M:H)-F, autoloadable_2(M:H, F), Pairs),
  619        (   '$member'(M:Head-FullFile, Pairs)
  620        ;   current_autoload(M:File, Ctx, all),
  621            library_info(File, Ctx, FullFile, _, Exports),
  622            '$member'(PI, Exports),
  623            '$pi_head'(PI, Head),
  624            \+ memberchk(M:Head-_, Pairs)
  625        )
  626    ).
  627autoloadable(M:Head, FullFile) :-
  628    (   var(M)
  629    ->  autoload_in(any, general)
  630    ;   autoload_in(M, general)
  631    ),
  632    (   callable(Head)
  633    ->  goal_name_arity(Head, Name, Arity),
  634        (   '$find_library'(_, Name, Arity, _, FullFile)
  635        ->  true
  636        )
  637    ;   '$in_library'(Name, Arity, autoload),
  638        functor(Head, Name, Arity)
  639    ).
  640
  641
  642autoloadable_2(M:Head, FullFile) :-
  643    current_autoload(M:File, Ctx, import(Imports)),
  644    library_info(File, Ctx, FullFile, _LoadModule, _Exports),
  645    '$member'(PI, Imports),
  646    '$pi_head'(PI, Head).
  647
  648goal_name_arity(Head, Name, Arity) :-
  649    compound(Head),
  650    !,
  651    compound_name_arity(Head, Name, Arity).
  652goal_name_arity(Head, Head, 0).
 library_info(+Spec, +AutoloadContext, -FullFile, -Module, -Exports)
Find information about a library.
  658library_info(Spec, _, FullFile, Module, Exports) :-
  659    '$resolved_source_path'(Spec, FullFile, []),
  660    !,
  661    (   \+ '$loading_file'(FullFile, _Queue, _LoadThread)
  662    ->  '$current_module'(Module, FullFile),
  663        '$module_property'(Module, exports(Exports))
  664    ;   library_info_from_file(FullFile, Module, Exports)
  665    ).
  666library_info(Spec, Context, FullFile, Module, Exports) :-
  667    (   Context = (Path:_Line)
  668    ->  Extra = [relative_to(Path)]
  669    ;   Extra = []
  670    ),
  671    (   absolute_file_name(Spec, FullFile,
  672                           [ file_type(prolog),
  673                             access(read),
  674                             file_errors(fail)
  675                           | Extra
  676                           ])
  677    ->  '$register_resolved_source_path'(Spec, FullFile),
  678        library_info_from_file(FullFile, Module, Exports)
  679    ;   autoload_error(Context, no_file(Spec)),
  680        fail
  681    ).
  682
  683
  684library_info_from_file(FullFile, Module, Exports) :-
  685    setup_call_cleanup(
  686        '$open_source'(FullFile, In, State, [], []),
  687        '$term_in_file'(In, _Read, _RLayout, Term, _TLayout, _Stream,
  688                        [FullFile], []),
  689        '$close_source'(State, true)),
  690    (   Term = (:- module(Module, Exports))
  691    ->  !
  692    ;   nonvar(Term),
  693        skip_header(Term)
  694    ->  fail
  695    ;   throw(error(domain_error(module_file, FullFile), _))
  696    ).
  697
  698skip_header(begin_of_file).
  699
  700
  701:- dynamic printed/3.  702:- volatile printed/3.  703
  704autoload_error(Context, Error) :-
  705    suppress(Context, Error),
  706    !.
  707autoload_error(Context, Error) :-
  708    get_time(Now),
  709    assertz(printed(Context, Error, Now)),
  710    print_message(warning, error(autoload(Error), autoload(Context))).
  711
  712suppress(Context, Error) :-
  713    printed(Context, Error, Printed),
  714    get_time(Now),
  715    (   Now - Printed < 1
  716    ->  true
  717    ;   retractall(printed(Context, Error, _)),
  718        fail
  719    ).
  720
  721
  722		 /*******************************
  723		 *            CALLBACK		*
  724		 *******************************/
  725
  726:- public
  727    set_autoload/1.
 set_autoload(+Value) is det
Hook called from set_prolog_flag/2 when autoloading is switched. If the desired value is false we should materialize all registered requests for autoloading. We must do so before disabling autoloading as loading the files may require autoloading.
  736set_autoload(FlagValue) :-
  737    current_prolog_flag(autoload, FlagValue),
  738    !.
  739set_autoload(FlagValue) :-
  740    \+ autoload_in(FlagValue, explicit, any),
  741    !,
  742    setup_call_cleanup(
  743        nb_setval('$autoload_disabling', true),
  744        materialize_autoload(Count),
  745        nb_delete('$autoload_disabling')),
  746    print_message(informational, autoload(disabled(Count))).
  747set_autoload(_).
  748
  749materialize_autoload(Count) :-
  750    State = state(0),
  751    forall(current_predicate(M:'$autoload'/3),
  752           materialize_autoload(M, State)),
  753    arg(1, State, Count).
  754
  755materialize_autoload(M, State) :-
  756    (   current_autoload(M:File, Context, Import),
  757        library_info(File, Context, FullFile, _LoadModule, _Exports),
  758        arg(1, State, N0),
  759        N is N0+1,
  760        nb_setarg(1, State, N),
  761        (   Import == all
  762        ->  verbose_autoload(M:all, FullFile),
  763            use_module(M:FullFile)
  764        ;   Import = import(Preds)
  765        ->  verbose_autoload(M:Preds, FullFile),
  766            use_module(M:FullFile, Preds)
  767        ),
  768        fail
  769    ;   true
  770    ),
  771    abolish(M:'$autoload'/3).
  772
  773
  774		 /*******************************
  775		 *          AUTOLOAD/2		*
  776		 *******************************/
  777
  778autoload(M:File) :-
  779    (   \+ autoload_in(M, explicit)
  780    ;   nb_current('$autoload_disabling', true)
  781    ),
  782    !,
  783    use_module(M:File).
  784autoload(M:File) :-
  785    '$must_be'(filespec, File),
  786    source_context(Context),
  787    retractall(M:'$autoload'(File, _, _)),
  788    assert_autoload(M:'$autoload'(File, Context, all)).
  789
  790autoload(M:File, Imports) :-
  791    (   \+ autoload_in(M, explicit)
  792    ;   nb_current('$autoload_disabling', true)
  793    ),
  794    !,
  795    use_module(M:File, Imports).
  796autoload(M:File, Imports0) :-
  797    '$must_be'(filespec, File),
  798    valid_imports(Imports0, Imports),
  799    source_context(Context),
  800    register_autoloads(Imports, M, File, Context),
  801    (   current_autoload(M:File, _, import(Imports))
  802    ->  true
  803    ;   assert_autoload(M:'$autoload'(File, Context, import(Imports)))
  804    ).
  805
  806source_context(Path:Line) :-
  807    source_location(Path, Line),
  808    !.
  809source_context(-).
  810
  811assert_autoload(Clause) :-
  812    '$initialization_context'(Source, Ctx),
  813    '$store_admin_clause2'(Clause, _Layout, Source, Ctx).
  814
  815valid_imports(Imports0, Imports) :-
  816    '$must_be'(list, Imports0),
  817    valid_import_list(Imports0, Imports).
  818
  819valid_import_list([], []).
  820valid_import_list([H0|T0], [H|T]) :-
  821    '$pi_head'(H0, Head),
  822    '$pi_head'(H, Head),
  823    valid_import_list(T0, T).
 register_autoloads(+ListOfPI, +Module, +File, +Context)
Put an autoload flag on all predicates declared using autoload/2 to prevent duplicates or the user defining the same predicate.
  830register_autoloads([], _, _, _).
  831register_autoloads([PI|T], Module, File, Context) :-
  832    PI = Name/Arity,
  833    functor(Head, Name, Arity),
  834    (   '$get_predicate_attribute'(Module:Head, autoload, 1)
  835    ->  (   current_autoload(Module:_File0, _Ctx0, import(Imports)),
  836            memberchk(PI, Imports)
  837        ->  '$permission_error'(redefine, imported_procedure, PI),
  838            fail
  839        ;   Done = true
  840        )
  841    ;   '$c_current_predicate'(_, Module:Head), % no auto-import
  842        '$get_predicate_attribute'(Module:Head, imported, From)
  843    ->  (   (   '$resolved_source_path'(File, FullFile)
  844            ->  true
  845            ;   '$resolve_source_path'(File, FullFile, [])
  846            ),
  847            module_property(From, file(FullFile))
  848        ->  Done = true
  849        ;   print_message(warning,
  850                          autoload(already_defined(Module:PI, From))),
  851            Done = true
  852        )
  853    ;   true
  854    ),
  855    (   Done == true
  856    ->  true
  857    ;   '$set_predicate_attribute'(Module:Head, autoload, 1)
  858    ),
  859    register_autoloads(T, Module, File, Context).
  860
  861pi_in_exports(PI, Exports) :-
  862    '$member'(E, Exports),
  863    canonical_pi(E, PI),
  864    !.
  865
  866current_autoload(M:File, Context, Term) :-
  867    '$get_predicate_attribute'(M:'$autoload'(_,_,_), defined, 1),
  868    M:'$autoload'(File, Context, Term).
  869
  870                 /*******************************
  871                 *             REQUIRE          *
  872                 *******************************/
 require(:ListOfPredIndicators) is det
Register the predicates in ListOfPredIndicators for autoloading using autoload/2 if they are not system predicates.
  879require(M:Spec) :-
  880    (   is_list(Spec)
  881    ->  List = Spec
  882    ;   phrase(comma_list(Spec), List)
  883    ), !,
  884    require(List, M, FromLib),
  885    keysort(FromLib, Sorted),
  886    by_file(Sorted, Autoload),
  887    forall('$member'(File-Import, Autoload),
  888           autoload(M:File, Import)).
  889require(_:Spec) :-
  890    '$type_error'(list, Spec).
  891
  892require([],_, []).
  893require([H|T], M, Needed) :-
  894   '$pi_head'(H, Head),
  895   (   '$get_predicate_attribute'(system:Head, defined, 1)
  896   ->  require(T, M, Needed)
  897   ;   '$pi_head'(Module:Name/Arity, M:Head),
  898       (   '$find_library'(Module, Name, Arity, _LoadModule, Library)
  899       ->  Needed = [Library-H|More],
  900           require(T, M, More)
  901       ;   print_message(error, error(existence_error(procedure, Name/Arity), _)),
  902           require(T, M, Needed)
  903       )
  904   ).
  905
  906by_file([], []).
  907by_file([File-PI|T0], [Spec-[PI|PIs]|T]) :-
  908    on_path(File, Spec),
  909    same_file(T0, File, PIs, T1),
  910    by_file(T1, T).
  911
  912on_path(Library, library(Base)) :-
  913    file_base_name(Library, Base),
  914    findall(Path, plain_source(library(Base), Path), [Library]),
  915    !.
  916on_path(Library, Library).
  917
  918plain_source(Spec, Path) :-
  919    absolute_file_name(Spec, PathExt,
  920                       [ file_type(prolog),
  921                         access(read),
  922                         file_errors(fail),
  923                         solutions(all)
  924                       ]),
  925    file_name_extension(Path, _, PathExt).
  926
  927same_file([File-PI|T0], File, [PI|PIs], T) :-
  928    !,
  929    same_file(T0, File, PIs, T).
  930same_file(List, _, [], List).
  931
  932comma_list(Var) -->
  933    { var(Var),
  934      !,
  935      '$instantiation_error'(Var)
  936    }.
  937comma_list((A,B)) -->
  938    !,
  939    comma_list(A),
  940    comma_list(B).
  941comma_list(A) -->
  942    [A]