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', []).
  458
  459exports(File, Module, Exports) :-
  460    (   current_prolog_flag(xref, Old)
  461    ->  true
  462    ;   Old = false
  463    ),
  464    setup_call_cleanup(
  465        set_prolog_flag(xref, true),
  466        snapshot(exports_(File, Module, Exports)),
  467        set_prolog_flag(xref, Old)).
  468
  469exports_(File, Module, Exports) :-
  470    State = state(true, _, []),
  471    (   '$source_term'(File,
  472                       _Read,_RLayout,
  473                       Term,_TermLayout,
  474                       _Stream,
  475                       [ syntax_errors(quiet)
  476                       ]),
  477        (   Term = (:- module(M,Public)),
  478            is_list(Public),
  479            arg(1, State, true)
  480        ->  nb_setarg(1, State, false),
  481            nb_setarg(2, State, M),
  482            nb_setarg(3, State, Public),
  483            fail
  484        ;   nb_setarg(1, State, false),
  485            fail
  486        ;   Term = (:- export(PI)),
  487            ground(PI)
  488        ->  arg(3, State, E0),
  489            '$append'(E0, [PI], E1),
  490            nb_setarg(3, State, E1),
  491            fail
  492        ;   Term = (:- use_foreign_library(Lib)),
  493            nonvar(Lib),
  494            arg(2, State, M),
  495            atom(M)
  496        ->  catch('$syspreds':use_foreign_library_noi(M:Lib), error(_,_), true),
  497            fail
  498        ;   Term = (:- Directive),
  499            nonvar(Directive)
  500        ->  fail
  501        ;   !
  502        )
  503    ;   true
  504    ),
  505    arg(2, State, Module),
  506    arg(3, State, Exports).
  507
  508
  509                 /*******************************
  510                 *            EXTENDING         *
  511                 *******************************/
 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.

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