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-2023, 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'/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,                         % +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, []).
 $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.
   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    !.
 $in_library(+Name, +Arity, -Path) is semidet
$in_library(-Name, -Arity, -Path) is nondet
Is true if Name/Arity is in the autoload libraries.
  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).
 $define_predicate(:Head)
Make sure PredInd can be called. First test if the predicate is defined. If not, invoke the autoloader.
  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                /********************************
  133                *          UPDATE INDEX         *
  134                ********************************/
  135
  136:- thread_local
  137    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.
  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).
 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.
  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                /********************************
  189                *           LOAD INDEX          *
  190                ********************************/
 reload_library_index
Reload the index on the next call
  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(_)).
 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.
  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    ).
 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.
  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                /********************************
  301                *       CREATE INDEX.pl         *
  302                ********************************/
 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
  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).
 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.
  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             % compensate for jitter
  394    ;   '$member'(File, Files),                 % and rounding
  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).
 index_files(+Files, +Directory, +Out:stream) is det
Write index for Files in Directory to the stream Out.
  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
  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', []).
 exports(+File, -Module, -Exports) is det
Get the exports from a library as a list of PIs.
  463:- public exports/3.                            % using by library(prolog_deps).
  464exports(File, Module, Exports) :-
  465    (   current_prolog_flag(xref, Old)
  466    ->  true
  467    ;   Old = false
  468    ),
  469    setup_call_cleanup(
  470        set_prolog_flag(xref, true),
  471        snapshot(exports_(File, Module, Exports)),
  472        set_prolog_flag(xref, Old)).
  473
  474exports_(File, Module, Exports) :-
  475    State = state(true, _, []),
  476    (   '$source_term'(File,
  477                       _Read,_RLayout,
  478                       Term,_TermLayout,
  479                       _Stream,
  480                       [ syntax_errors(quiet)
  481                       ]),
  482        (   Term = (:- module(M,Public)),
  483            is_list(Public),
  484            arg(1, State, true)
  485        ->  nb_setarg(1, State, false),
  486            nb_setarg(2, State, M),
  487            nb_setarg(3, State, Public),
  488            fail
  489        ;   nb_setarg(1, State, false),
  490            fail
  491        ;   Term = (:- export(PI)),
  492            ground(PI)
  493        ->  arg(3, State, E0),
  494            '$append'(E0, [PI], E1),
  495            nb_setarg(3, State, E1),
  496            fail
  497        ;   Term = (:- use_foreign_library(Lib)),
  498            nonvar(Lib),
  499            arg(2, State, M),
  500            atom(M)
  501        ->  catch('$syspreds':use_foreign_library_noi(M:Lib), error(_,_), true),
  502            fail
  503        ;   Term = (:- Directive),
  504            nonvar(Directive)
  505        ->  fail
  506        ;   !
  507        )
  508    ;   true
  509    ),
  510    arg(2, State, Module),
  511    arg(3, State, Exports).
  512
  513
  514                 /*******************************
  515                 *            EXTENDING         *
  516                 *******************************/
 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.

  533autoload_path(Alias) :-
  534    (   user:file_search_path(autoload, Alias)
  535    ->  true
  536    ;   assertz(user:file_search_path(autoload, Alias)),
  537        reload_library_index
  538    ).
  539
  540system:term_expansion((:- autoload_path(Alias)),
  541                      [ user:file_search_path(autoload, Alias),
  542                        (:- reload_library_index)
  543                      ]).
  544
  545
  546		 /*******************************
  547		 *      RUNTIME AUTOLOADER	*
  548		 *******************************/
Provide PI by autoloading. This checks:
  558'$autoload'(PI) :-
  559    source_location(File, _Line),
  560    !,
  561    setup_call_cleanup(
  562        '$start_aux'(File, Context),
  563        '$autoload2'(PI),
  564        '$end_aux'(File, Context)).
  565'$autoload'(PI) :-
  566    '$autoload2'(PI).
  567
  568'$autoload2'(PI) :-
  569    setup_call_cleanup(
  570        leave_sandbox(Old),
  571        '$autoload3'(PI),
  572        restore_sandbox(Old)).
  573
  574leave_sandbox(Sandboxed) :-
  575    current_prolog_flag(sandboxed_load, Sandboxed),
  576    set_prolog_flag(sandboxed_load, false).
  577restore_sandbox(Sandboxed) :-
  578    set_prolog_flag(sandboxed_load, Sandboxed).
  579
  580'$autoload3'(PI) :-
  581    autoload_from(PI, LoadModule, FullFile),
  582    do_autoload(FullFile, PI, LoadModule).
 autoload_from(+PI, -LoadModule, -File) is semidet
True when PI can be defined by loading File which is defined the module LoadModule.
  589autoload_from(Module:PI, LoadModule, FullFile) :-
  590    autoload_in(Module, explicit),
  591    current_autoload(Module:File, Ctx, import(Imports)),
  592    memberchk(PI, Imports),
  593    library_info(File, Ctx, FullFile, LoadModule, Exports),
  594    (   pi_in_exports(PI, Exports)
  595    ->  !
  596    ;   autoload_error(Ctx, not_exported(PI, File, FullFile, Exports)),
  597        fail
  598    ).
  599autoload_from(Module:Name/Arity, LoadModule, FullFile) :-
  600    autoload_in(Module, explicit),
  601    PI = Name/Arity,
  602    current_autoload(Module:File, Ctx, all),
  603    library_info(File, Ctx, FullFile, LoadModule, Exports),
  604    pi_in_exports(PI, Exports).
  605autoload_from(Module:Name/Arity, LoadModule, Library) :-
  606    autoload_in(Module, general),
  607    '$find_library'(Module, Name, Arity, LoadModule, Library).
  608
  609:- public autoload_in/2.                        % used in syspred
  610
  611autoload_in(Module, How) :-
  612    current_prolog_flag(autoload, AutoLoad),
  613    autoload_in(AutoLoad, How, Module),
  614    !.
 autoload_in(+AutoloadFlag, +AutoloadMode, +TargetModule) is semidet
  618autoload_in(true,             _,        _).
  619autoload_in(explicit,         explicit, _).
  620autoload_in(user,             _,        user).
  621autoload_in(user_or_explicit, explicit, _).
  622autoload_in(user_or_explicit, _,        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:
  638do_autoload(Library, Module:Name/Arity, LoadModule) :-
  639    functor(Head, Name, Arity),
  640    '$update_autoload_level'([autoload(true)], Old),
  641    verbose_autoload(Module:Name/Arity, Library),
  642    '$compilation_mode'(OldComp, database),
  643    (   Module == LoadModule
  644    ->  ensure_loaded(Module:Library)
  645    ;   (   '$c_current_predicate'(_, LoadModule:Head),
  646            '$get_predicate_attribute'(LoadModule:Head, defined, 1),
  647            \+ '$loading'(Library)
  648        ->  Module:import(LoadModule:Name/Arity)
  649        ;   use_module(Module:Library, [Name/Arity])
  650        ),
  651        warn_autoload(Module, LoadModule:Name/Arity)
  652    ),
  653    '$set_compilation_mode'(OldComp),
  654    '$set_autoload_level'(Old),
  655    '$c_current_predicate'(_, Module:Head).
  656
  657verbose_autoload(PI, Library) :-
  658    current_prolog_flag(verbose_autoload, true),
  659    !,
  660    set_prolog_flag(verbose_autoload, false),
  661    print_message(informational, autoload(PI, Library)),
  662    set_prolog_flag(verbose_autoload, true).
  663verbose_autoload(PI, Library) :-
  664    print_message(silent, autoload(PI, Library)).
 autoloadable(:Head, -File) is nondet
True when Head can be autoloaded from File. This implements the predicate_property/2 property autoload(File). The module must be instantiated.
  673:- public                               % used from predicate_property/2
  674    autoloadable/2.  675
  676autoloadable(M:Head, FullFile) :-
  677    atom(M),
  678    current_module(M),
  679    autoload_in(M, explicit),
  680    (   callable(Head)
  681    ->  goal_name_arity(Head, Name, Arity),
  682        autoload_from(M:Name/Arity, _, FullFile)
  683    ;   findall((M:H)-F, autoloadable_2(M:H, F), Pairs),
  684        (   '$member'(M:Head-FullFile, Pairs)
  685        ;   current_autoload(M:File, Ctx, all),
  686            library_info(File, Ctx, FullFile, _, Exports),
  687            '$member'(PI, Exports),
  688            '$pi_head'(PI, Head),
  689            \+ memberchk(M:Head-_, Pairs)
  690        )
  691    ).
  692autoloadable(M:Head, FullFile) :-
  693    (   var(M)
  694    ->  autoload_in(any, general)
  695    ;   autoload_in(M, general)
  696    ),
  697    (   callable(Head)
  698    ->  goal_name_arity(Head, Name, Arity),
  699        (   '$find_library'(_, Name, Arity, _, FullFile)
  700        ->  true
  701        )
  702    ;   '$in_library'(Name, Arity, autoload),
  703        functor(Head, Name, Arity)
  704    ).
  705
  706
  707autoloadable_2(M:Head, FullFile) :-
  708    current_autoload(M:File, Ctx, import(Imports)),
  709    library_info(File, Ctx, FullFile, _LoadModule, _Exports),
  710    '$member'(PI, Imports),
  711    '$pi_head'(PI, Head).
  712
  713goal_name_arity(Head, Name, Arity) :-
  714    compound(Head),
  715    !,
  716    compound_name_arity(Head, Name, Arity).
  717goal_name_arity(Head, Head, 0).
 library_info(+Spec, +AutoloadContext, -FullFile, -Module, -Exports)
Find information about a library.
  723library_info(Spec, _, FullFile, Module, Exports) :-
  724    '$resolved_source_path'(Spec, FullFile, []),
  725    !,
  726    (   \+ '$loading_file'(FullFile, _Queue, _LoadThread)
  727    ->  '$current_module'(Module, FullFile),
  728        '$module_property'(Module, exports(Exports))
  729    ;   library_info_from_file(FullFile, Module, Exports)
  730    ).
  731library_info(Spec, Context, FullFile, Module, Exports) :-
  732    (   Context = (Path:_Line)
  733    ->  Extra = [relative_to(Path)]
  734    ;   Extra = []
  735    ),
  736    (   absolute_file_name(Spec, FullFile,
  737                           [ file_type(prolog),
  738                             access(read),
  739                             file_errors(fail)
  740                           | Extra
  741                           ])
  742    ->  '$register_resolved_source_path'(Spec, FullFile),
  743        library_info_from_file(FullFile, Module, Exports)
  744    ;   autoload_error(Context, no_file(Spec)),
  745        fail
  746    ).
  747
  748library_info_from_file(FullFile, Module, Exports) :-
  749    setup_call_cleanup(
  750        '$set_source_module'(OldModule, system),
  751        setup_call_cleanup(
  752            '$open_source'(FullFile, In, State, [], []),
  753            '$term_in_file'(In, _Read, _RLayout, Term, _TLayout, _Stream,
  754                            [FullFile], []),
  755            '$close_source'(State, true)),
  756        '$set_source_module'(OldModule)),
  757    (   Term = (:- module(Module, Exports))
  758    ->  !
  759    ;   nonvar(Term),
  760        skip_header(Term)
  761    ->  fail
  762    ;   '$domain_error'(module_header, Term)
  763    ).
  764
  765skip_header(begin_of_file).
  766
  767
  768:- dynamic printed/3.  769:- volatile printed/3.  770
  771autoload_error(Context, Error) :-
  772    suppress(Context, Error),
  773    !.
  774autoload_error(Context, Error) :-
  775    get_time(Now),
  776    assertz(printed(Context, Error, Now)),
  777    print_message(warning, error(autoload(Error), autoload(Context))).
  778
  779suppress(Context, Error) :-
  780    printed(Context, Error, Printed),
  781    get_time(Now),
  782    (   Now - Printed < 1
  783    ->  true
  784    ;   retractall(printed(Context, Error, _)),
  785        fail
  786    ).
  787
  788
  789		 /*******************************
  790		 *            CALLBACK		*
  791		 *******************************/
  792
  793:- public
  794    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.
  803set_autoload(FlagValue) :-
  804    current_prolog_flag(autoload, FlagValue),
  805    !.
  806set_autoload(FlagValue) :-
  807    \+ autoload_in(FlagValue, explicit, any),
  808    !,
  809    setup_call_cleanup(
  810        nb_setval('$autoload_disabling', true),
  811        materialize_autoload(Count),
  812        nb_delete('$autoload_disabling')),
  813    print_message(informational, autoload(disabled(Count))).
  814set_autoload(_).
  815
  816materialize_autoload(Count) :-
  817    State = state(0),
  818    forall(current_predicate(M:'$autoload'/3),
  819           materialize_autoload(M, State)),
  820    arg(1, State, Count).
  821
  822materialize_autoload(M, State) :-
  823    (   current_autoload(M:File, Context, Import),
  824        library_info(File, Context, FullFile, _LoadModule, _Exports),
  825        arg(1, State, N0),
  826        N is N0+1,
  827        nb_setarg(1, State, N),
  828        (   Import == all
  829        ->  verbose_autoload(M:all, FullFile),
  830            use_module(M:FullFile)
  831        ;   Import = import(Preds)
  832        ->  verbose_autoload(M:Preds, FullFile),
  833            use_module(M:FullFile, Preds)
  834        ),
  835        fail
  836    ;   true
  837    ),
  838    abolish(M:'$autoload'/3).
  839
  840
  841		 /*******************************
  842		 *          AUTOLOAD/2		*
  843		 *******************************/
  844
  845autoload(M:File) :-
  846    (   \+ autoload_in(M, explicit)
  847    ;   nb_current('$autoload_disabling', true)
  848    ),
  849    !,
  850    use_module(M:File).
  851autoload(M:File) :-
  852    '$must_be'(filespec, File),
  853    source_context(Context),
  854    (   current_autoload(M:File, _, import(all))
  855    ->  true
  856    ;   assert_autoload(M:'$autoload'(File, Context, all))
  857    ).
  858
  859autoload(M:File, Imports) :-
  860    (   \+ autoload_in(M, explicit)
  861    ;   nb_current('$autoload_disabling', true)
  862    ),
  863    !,
  864    use_module(M:File, Imports).
  865autoload(M:File, Imports0) :-
  866    '$must_be'(filespec, File),
  867    valid_imports(Imports0, Imports),
  868    source_context(Context),
  869    register_autoloads(Imports, M, File, Context),
  870    (   current_autoload(M:File, _, import(Imports))
  871    ->  true
  872    ;   assert_autoload(M:'$autoload'(File, Context, import(Imports)))
  873    ).
  874
  875source_context(Path:Line) :-
  876    source_location(Path, Line),
  877    !.
  878source_context(-).
  879
  880assert_autoload(Clause) :-
  881    '$initialization_context'(Source, Ctx),
  882    '$store_admin_clause2'(Clause, _Layout, Source, Ctx).
  883
  884valid_imports(Imports0, Imports) :-
  885    '$must_be'(list, Imports0),
  886    valid_import_list(Imports0, Imports).
  887
  888valid_import_list([], []).
  889valid_import_list([H0|T0], [H|T]) :-
  890    '$pi_head'(H0, Head),
  891    '$pi_head'(H, Head),
  892    valid_import_list(T0, T).
 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.
  899register_autoloads([], _, _, _).
  900register_autoloads([PI|T], Module, File, Context) :-
  901    PI = Name/Arity,
  902    functor(Head, Name, Arity),
  903    (   '$get_predicate_attribute'(Module:Head, autoload, 1)
  904    ->  (   current_autoload(Module:_File0, _Ctx0, import(Imports)),
  905            memberchk(PI, Imports)
  906        ->  '$permission_error'(redefine, imported_procedure, PI),
  907            fail
  908        ;   Done = true
  909        )
  910    ;   '$c_current_predicate'(_, Module:Head), % no auto-import
  911        '$get_predicate_attribute'(Module:Head, imported, From)
  912    ->  (   (   '$resolved_source_path'(File, FullFile)
  913            ->  true
  914            ;   '$resolve_source_path'(File, FullFile, [])
  915            ),
  916            module_property(From, file(FullFile))
  917        ->  Done = true
  918        ;   print_message(warning,
  919                          autoload(already_defined(Module:PI, From))),
  920            Done = true
  921        )
  922    ;   true
  923    ),
  924    (   Done == true
  925    ->  true
  926    ;   '$set_predicate_attribute'(Module:Head, autoload, 1)
  927    ),
  928    register_autoloads(T, Module, File, Context).
  929
  930pi_in_exports(PI, Exports) :-
  931    '$member'(E, Exports),
  932    canonical_pi(E, PI),
  933    !.
  934
  935current_autoload(M:File, Context, Term) :-
  936    '$get_predicate_attribute'(M:'$autoload'(_,_,_), defined, 1),
  937    M:'$autoload'(File, Context, Term).
  938
  939		 /*******************************
  940		 *            CHECK		*
  941		 *******************************/
  942
  943warn_autoload(TargetModule, PI) :-
  944    current_prolog_flag(warn_autoload, true),
  945    \+ current_prolog_flag(xref, true),
  946    \+ nb_current('$autoload_warning', true),
  947    '$pi_head'(PI, Head),
  948    source_file(Head, File),
  949    expansion_hook(P),
  950    source_file(P, File),
  951    !,
  952    setup_call_cleanup(
  953        b_setval('$autoload_warning', true),
  954        print_message(warning,
  955                      deprecated(autoload(TargetModule, File, PI, expansion))),
  956        nb_delete('$autoload_warning')).
  957warn_autoload(_, _).
  958
  959expansion_hook(user:goal_expansion(_,_)).
  960expansion_hook(user:goal_expansion(_,_,_,_)).
  961expansion_hook(system:goal_expansion(_,_)).
  962expansion_hook(system:goal_expansion(_,_,_,_)).
  963
  964
  965                 /*******************************
  966                 *             REQUIRE          *
  967                 *******************************/
 require(:ListOfPredIndicators) is det
Register the predicates in ListOfPredIndicators for autoloading using autoload/2 if they are not system predicates.
  974require(M:Spec) :-
  975    (   is_list(Spec)
  976    ->  List = Spec
  977    ;   phrase(comma_list(Spec), List)
  978    ), !,
  979    require(List, M, FromLib),
  980    keysort(FromLib, Sorted),
  981    by_file(Sorted, Autoload),
  982    forall('$member'(File-Import, Autoload),
  983           autoload(M:File, Import)).
  984require(_:Spec) :-
  985    '$type_error'(list, Spec).
  986
  987require([],_, []).
  988require([H|T], M, Needed) :-
  989   '$pi_head'(H, Head),
  990   (   '$get_predicate_attribute'(system:Head, defined, 1)
  991   ->  require(T, M, Needed)
  992   ;   '$pi_head'(Module:Name/Arity, M:Head),
  993       (   '$find_library'(Module, Name, Arity, LoadModule, Library)
  994       ->  (   current_predicate(LoadModule:Name/Arity)
  995           ->  Module:import(LoadModule:Name/Arity),
  996               require(T, M, Needed)
  997           ;   Needed = [Library-H|More],
  998               require(T, M, More)
  999           )
 1000       ;   print_message(error, error(existence_error(procedure, Name/Arity), _)),
 1001           require(T, M, Needed)
 1002       )
 1003   ).
 1004
 1005by_file([], []).
 1006by_file([File-PI|T0], [Spec-[PI|PIs]|T]) :-
 1007    on_path(File, Spec),
 1008    same_file(T0, File, PIs, T1),
 1009    by_file(T1, T).
 1010
 1011on_path(Library, library(Base)) :-
 1012    file_base_name(Library, Base),
 1013    findall(Path, plain_source(library(Base), Path), [Library]),
 1014    !.
 1015on_path(Library, Library).
 1016
 1017plain_source(Spec, Path) :-
 1018    absolute_file_name(Spec, PathExt,
 1019                       [ file_type(prolog),
 1020                         access(read),
 1021                         file_errors(fail),
 1022                         solutions(all)
 1023                       ]),
 1024    file_name_extension(Path, _, PathExt).
 1025
 1026same_file([File-PI|T0], File, [PI|PIs], T) :-
 1027    !,
 1028    same_file(T0, File, PIs, T).
 1029same_file(List, _, [], List).
 1030
 1031comma_list(Var) -->
 1032    { var(Var),
 1033      !,
 1034      '$instantiation_error'(Var)
 1035    }.
 1036comma_list((A,B)) -->
 1037    !,
 1038    comma_list(A),
 1039    comma_list(B).
 1040comma_list(A) -->
 1041    [A]