View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker and Richard O'Keefe
    4    E-mail:        J.Wielemaker@cs.vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2014-2023, VU University Amsterdam
    7                              CWI, Amsterdam
    8			      SWI-Prolog Solutions b.v.
    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(check_installation,
   38          [ check_installation/0,
   39            check_installation/1,               % -Issues
   40            check_config_files/0,
   41            update_config_files/0,
   42            test_installation/0,
   43            test_installation/1                 % +Options
   44          ]).   45:- autoload(library(apply), [maplist/2, maplist/3]).   46:- autoload(library(archive), [archive_open/3, archive_close/1]).   47:- autoload(library(lists), [append/3, member/2]).   48:- autoload(library(option), [option/2, merge_options/3]).   49:- autoload(library(prolog_source), [path_segments_atom/2]).   50:- use_module(library(settings), [setting/2]).   51:- autoload(library(dcg/high_order), [sequence//2, sequence/4]).   52:- autoload(library(error), [must_be/2]).

Check installation issues and features

This library performs checks on the installed system to verify which optional components are available and whether all libraries that load shared objects/DLLs can be loaded. */

 component(?Component, -Features) is nondet
This predicate describes the test components. Features is a dict with the following components:
test:Goal
(Additional) test that must succeed for the component to be functional.
url:URL
URL with additional information, relative to http://www.swi-prolog.org/build/issues/. If not provided, the library file with extension .html is used.
optional:true
If the library does not exist, do not complain.
os:OS
One of windows, unix or linux. If present, the component is only checked for if we are running on a version of the specified operating system.
features:Goal
After successful evaluation that loading and basic operation of the component succeeds, run this to check additional features.
   85% Feature tests
   86component(tcmalloc,
   87          _{ optional:true,
   88             test:test_tcmalloc,
   89             url:'tcmalloc.html',
   90             os:linux
   91           }).
   92component(gmp,
   93          _{ test:current_prolog_flag(bounded, false),
   94             url:'gmp.html'
   95           }).
   96% Packages that depend on foreign libraries
   97component(library(archive), _{features:archive_features}).
   98component(library(cgi), _{}).
   99component(library(crypt), _{}).
  100component(library(bdb), _{}).
  101component(library(double_metaphone), _{}).
  102component(library(filesex), _{}).
  103component(library(http/http_stream), _{}).
  104component(library(http/json), _{}).
  105component(library(http/jquery), _{features:jquery_file}).
  106component(library(isub), _{}).
  107component(library(jpl), _{}).
  108component(library(memfile), _{}).
  109component(library(odbc), _{}).
  110component(library(pce),
  111          _{pre:use_foreign_library(pce_principal:foreign(pl2xpce)),
  112            url:'xpce.html'}).
  113component(library(pcre), _{features:pcre_features}).
  114component(library(pdt_console), _{}).
  115component(library(porter_stem), _{}).
  116component(library(process), _{}).
  117component(library(protobufs), _{}).
  118component(library(editline), _{os:unix}).
  119component(library(readline), _{os:unix}).
  120component(library(readutil), _{}).
  121component(library(rlimit), _{os:unix}).
  122component(library(semweb/rdf_db), _{}).
  123component(library(semweb/rdf_ntriples), _{}).
  124component(library(semweb/turtle), _{}).
  125component(library(sgml), _{}).
  126component(library(sha), _{}).
  127component(library(snowball), _{}).
  128component(library(socket), _{}).
  129component(library(ssl), _{}).
  130component(library(sweep_link), _{features:sweep_emacs_module}).
  131component(library(crypto), _{}).
  132component(library(syslog), _{os:unix}).
  133component(library(table), _{}).
  134component(library(time), _{}).
  135component(library(tipc/tipc), _{os:linux}).
  136component(library(unicode), _{}).
  137component(library(uri), _{}).
  138component(library(uuid), _{}).
  139component(library(zlib), _{}).
  140component(library(yaml), _{}).
  141component(library(janus), _{features:python_version}).
  142
  143issue_base('http://www.swi-prolog.org/build/issues/').
  144
  145:- thread_local
  146    issue/1.  147
  148:- meta_predicate
  149    run_silent(0, +).
 check_installation is det
Check features of the installed system. Performs the following tests:
  1. Test whether features that depend on optional libraries are present (e.g., unbounded arithmetic support)
  2. Test that all standard libraries that depend on foreign code are present.
  3. provides a test_installation predicate to run the tests at runtime if the system was built with -DINSTALL_TESTS

If issues are found it prints a diagnostic message with a link to a wiki page with additional information about the issue.

  166check_installation :-
  167    print_message(informational, installation(checking)),
  168    check_installation_(InstallIssues),
  169    check_on_path,
  170    check_config_files(ConfigIssues),
  171    check_autoload,
  172    maplist(print_message(warning), ConfigIssues),
  173    append(InstallIssues, ConfigIssues, Issues),
  174    (   Issues == []
  175    ->  print_message(informational, installation(perfect))
  176    ;   length(Issues, Count),
  177        print_message(warning, installation(imperfect(Count)))
  178    ).
 check_installation(-Issues:list(pair)) is det
As check_installation/0, but additionally returns a list of Component-Problem pairs. Problem is one of optional_not_found (optional component is not present), not_found (component is not present) or failed (component is present but cannot be loaded).
  188check_installation(Issues) :-
  189    check_installation_(Issues0),
  190    maplist(public_issue, Issues0, Issues).
  191
  192public_issue(installation(Term), Source-Issue) :-
  193    functor(Term, Issue, _),
  194    arg(1, Term, Properties),
  195    Source = Properties.source.
  196
  197check_installation_(Issues) :-
  198    retractall(issue(_)),
  199    forall(component(Source, _Properties),
  200           check_component(Source)),
  201    findall(I, retract(issue(I)), Issues).
  202
  203check_component(Source) :-
  204    component(Source, Properties),
  205    !,
  206    check_component(Source, Properties.put(source,Source)).
  207
  208check_component(_Source, Properties) :-
  209    OS = Properties.get(os),
  210    \+ current_os(OS),
  211    !.
  212check_component(Source, Properties) :-
  213    compound(Source),
  214    !,
  215    check_source(Source, Properties).
  216check_component(Feature, Properties) :-
  217    print_message(informational, installation(checking(Feature))),
  218    (   call(Properties.test)
  219    ->  print_message(informational, installation(ok))
  220    ;   print_issue(installation(missing(Properties)))
  221    ).
  222
  223check_source(Source, Properties) :-
  224    exists_source(Source),
  225    !,
  226    print_message(informational, installation(loading(Source))),
  227    (   run_silent(( (   Pre = Properties.get(pre)
  228                     ->  call(Pre)
  229                     ;   true
  230                     ),
  231                     load_files(Source, [silent(true), if(not_loaded)])
  232                   ),
  233                   Properties.put(action, load))
  234    ->  test_component(Properties),
  235        print_message(informational, installation(ok)),
  236        check_features(Properties)
  237    ;   true
  238    ).
  239check_source(_Source, Properties) :-
  240    Properties.get(optional) == true,
  241    !,
  242    print_message(silent,
  243                  installation(optional_not_found(Properties))).
  244check_source(_Source, Properties) :-
  245    print_issue(installation(not_found(Properties))).
  246
  247current_os(unix)    :- current_prolog_flag(unix, true).
  248current_os(windows) :- current_prolog_flag(windows, true).
  249current_os(linux)   :- current_prolog_flag(arch, Arch),
  250                       sub_atom(Arch, _, _, _, linux).
 test_component(+Properties) is semidet
Run additional tests to see whether the component really works.
  256test_component(Dict) :-
  257    Test = Dict.get(test),
  258    !,
  259    call(Test).
  260test_component(_).
 check_features(+Properties) is semidet
Check for additional features of the components.
See also
- check_component/1 should be used for checking that the component works.
  269check_features(Dict) :-
  270    Test = Dict.get(features),
  271    !,
  272    catch(Test, Error,
  273          ( print_message(warning, Error),
  274            fail)).
  275check_features(_).
 run_silent(:Goal, +Properties) is semidet
Succeed if Goal succeeds and does not print any errors or warnings.
  283run_silent(Goal, Properties) :-
  284    run_collect_messages(Goal, Result, Messages),
  285    (   Result == true,
  286        Messages == []
  287    ->  true
  288    ;   print_issue(installation(failed(Properties, Result, Messages))),
  289        fail
  290    ).
 run_collect_messages(Goal, Result, Messages) is det
Run Goal, unify Result with true, false or exception(Error) and messages with a list of generated error and warning messages. Each message is a term:
message(Term,Kind,Lines)
See also
- message_hook/3.
  302:- thread_local
  303    got_message/1.  304
  305run_collect_messages(Goal, Result, Messages) :-
  306    setup_call_cleanup(
  307        asserta((user:thread_message_hook(Term,Kind,Lines) :-
  308                    error_kind(Kind),
  309                    assertz(got_message(message(Term,Kind,Lines)))), Ref),
  310        (   catch(Goal, E, true)
  311        ->  (   var(E)
  312            ->  Result0 = true
  313            ;   Result0 = exception(E)
  314            )
  315        ;   Result0 = false
  316        ),
  317        erase(Ref)),
  318    findall(Msg, retract(got_message(Msg)), Messages),
  319    Result = Result0.
  320
  321error_kind(warning).
  322error_kind(error).
  323
  324
  325                 /*******************************
  326                 *         SPECIAL TESTS        *
  327                 *******************************/
 test_tcmalloc
  331:- if(current_predicate(malloc_property/1)).  332test_tcmalloc :-
  333    malloc_property('generic.current_allocated_bytes'(Bytes)),
  334    Bytes > 1 000 000.
  335:- else.  336test_tcmalloc :-
  337    fail.
  338:- endif.
 archive_features
Report features supported by library(archive).
  344archive_features :-
  345    tmp_file_stream(utf8, Name, Out),
  346    close(Out),
  347    findall(F, archive_filter(F, Name), Filters),
  348    print_message(informational, installation(archive(filters, Filters))),
  349    findall(F, archive_format(F, Name), Formats),
  350    print_message(informational, installation(archive(formats, Formats))),
  351    delete_file(Name).
  352
  353archive_filter(F, Name) :-
  354    a_filter(F),
  355    catch(archive_open(Name, A, [filter(F)]), E, true),
  356    (   var(E)
  357    ->  archive_close(A)
  358    ;   true
  359    ),
  360    \+ subsumes_term(error(domain_error(filter, _),_), E).
  361
  362archive_format(F, Name) :-
  363    a_format(F),
  364    catch(archive_open(Name, A, [format(F)]), E, true),
  365    (   var(E)
  366    ->  archive_close(A)
  367    ;   true
  368    ),
  369    \+ subsumes_term(error(domain_error(format, _),_), E).
  370
  371a_filter(bzip2).
  372a_filter(compress).
  373a_filter(gzip).
  374a_filter(grzip).
  375a_filter(lrzip).
  376a_filter(lzip).
  377a_filter(lzma).
  378a_filter(lzop).
  379a_filter(none).
  380a_filter(rpm).
  381a_filter(uu).
  382a_filter(xz).
  383
  384a_format('7zip').
  385a_format(ar).
  386a_format(cab).
  387a_format(cpio).
  388a_format(empty).
  389a_format(gnutar).
  390a_format(iso9660).
  391a_format(lha).
  392a_format(mtree).
  393a_format(rar).
  394a_format(raw).
  395a_format(tar).
  396a_format(xar).
  397a_format(zip).
 pcre_features
  401pcre_features :-
  402    findall(X, pcre_missing(X), Missing),
  403    (   Missing == []
  404    ->  true
  405    ;   print_message(warning, installation(pcre_missing(Missing)))
  406    ),
  407    (   re_config(compiled_widths(Widths)),
  408        1 =:= Widths /\ 1
  409    ->  true
  410    ;   print_message(warning, installation(pcre_missing('8-bit support')))
  411    ).
  412
  413pcre_missing(X) :-
  414    pcre_must_have(X),
  415    Term =.. [X,true],
  416    \+ catch(re_config(Term), _, fail).
  417
  418pcre_must_have(unicode).
 jquery_file
Test whether jquery.js can be found
  424jquery_file :-
  425    setting(jquery:version, File),
  426    (   absolute_file_name(js(File), Path, [access(read), file_errors(fail)])
  427    ->  print_message(informational, installation(jquery(found(Path))))
  428    ;   print_message(warning, installation(jquery(not_found(File))))
  429    ).
  430
  431sweep_emacs_module :-
  432    with_output_to(string(S), write_sweep_module_location),
  433    split_string(S, "\n", "\n", [VersionInfo|Modules]),
  434    must_be(oneof(["V 1"]), VersionInfo),
  435    (   maplist(check_sweep_lib, Modules)
  436    ->  print_message(informational, installation(sweep(found(Modules))))
  437    ;   print_message(warning, installation(sweep(not_found(Modules))))
  438    ).
  439
  440check_sweep_lib(Line) :-
  441    sub_atom(Line, B, _, A, ' '),
  442    sub_atom(Line, 0, B, _, Type),
  443    must_be(oneof(['L', 'M']), Type),
  444    sub_atom(Line, _, A, 0, Lib),
  445    exists_file(Lib).
  446
  447python_version :-
  448    py_call(sys:version, Version),
  449    print_message(informational, installation(janus(Version))).
 check_on_path
Validate that Prolog is installed in $PATH. Only performed if the running executable is a normal executable file, assuming some special installation such as the WASM version otherwise.
  458check_on_path :-
  459    current_prolog_flag(executable, EXEFlag),
  460    prolog_to_os_filename(EXE, EXEFlag),
  461    file_base_name(EXE, Prog),
  462    absolute_file_name(EXE, AbsExe,
  463                       [ access(execute),
  464                         file_errors(fail)
  465                       ]),
  466    !,
  467    prolog_to_os_filename(AbsExe, OsExe),
  468    (   absolute_file_name(path(Prog), OnPath,
  469                           [ access(execute),
  470                             file_errors(fail)
  471                           ])
  472    ->  (   same_file(EXE, OnPath)
  473        ->  true
  474        ;   absolute_file_name(path(Prog), OnPathAny,
  475                               [ access(execute),
  476                                 file_errors(fail),
  477                                 solutions(all)
  478                               ]),
  479            same_file(EXE, OnPathAny)
  480        ->  print_message(warning, installation(not_first_on_path(OsExe, OnPath)))
  481        ;   print_message(warning, installation(not_same_on_path(OsExe, OnPath)))
  482        )
  483    ;   print_message(warning, installation(not_on_path(OsExe, Prog)))
  484    ).
  485check_on_path.
  486
  487
  488		 /*******************************
  489		 *           RUN TESTS		*
  490		 *******************************/
 test_installation is semidet
 test_installation(+Options) is semidet
Run regression tests in the installed system. Requires the system to be built using
cmake -DINSTALL_TESTS=ON

Options processed:

packages(+Boolean)
When false, do not test the packages
package(+Package)
Only test package package.
  507test_installation :-
  508    test_installation([]).
  509
  510test_installation(Options) :-
  511    absolute_file_name(swi(test/test),
  512                       TestFile,
  513                       [ access(read),
  514                         file_errors(fail),
  515                         file_type(prolog)
  516                       ]),
  517    !,
  518    test_installation_run(TestFile, Options).
  519test_installation(_Options) :-
  520    print_message(warning, installation(testing(no_installed_tests))).
  521
  522test_installation_run(TestFile, Options) :-
  523    (   option(package(_), Options)
  524    ->  merge_options(Options,
  525                      [ core(false),
  526                        subdirs(false)
  527                      ], TestOptions)
  528    ;   merge_options(Options,
  529                      [ packages(true)
  530                      ], TestOptions)
  531    ),
  532    load_files(user:TestFile),
  533    current_prolog_flag(verbose, Old),
  534    setup_call_cleanup(
  535        set_prolog_flag(verbose, silent),
  536        user:test([], TestOptions),
  537        set_prolog_flag(verbose, Old)).
  538
  539
  540                 /*******************************
  541                 *            MESSAGES          *
  542                 *******************************/
  543
  544:- multifile
  545    prolog:message//1.  546
  547print_issue(Term) :-
  548    assertz(issue(Term)),
  549    print_message(warning, Term).
  550
  551issue_url(Properties, URL) :-
  552    Local = Properties.get(url),
  553    !,
  554    issue_base(Base),
  555    atom_concat(Base, Local, URL).
  556issue_url(Properties, URL) :-
  557    Properties.get(source) = library(Segments),
  558    !,
  559    path_segments_atom(Segments, Base),
  560    file_name_extension(Base, html, URLFile),
  561    issue_base(Issues),
  562    atom_concat(Issues, URLFile, URL).
  563
  564prolog:message(installation(Message)) -->
  565    message(Message).
  566
  567message(checking) -->
  568    { current_prolog_flag(address_bits, Bits) },
  569    { current_prolog_flag(arch, Arch) },
  570    { current_prolog_flag(home, Home) },
  571    { current_prolog_flag(cpu_count, Cores) },
  572    [ 'Checking your SWI-Prolog kit for common issues ...'-[], nl, nl ],
  573    [ 'Version: ~`.t~24| '-[] ], '$messages':prolog_message(version), [nl],
  574    [ 'Address bits: ~`.t~24| ~d'-[Bits] ], [nl],
  575    [ 'Architecture: ~`.t~24| ~w'-[Arch] ], [nl],
  576    [ 'Installed at: ~`.t~24| ~w'-[Home] ], [nl],
  577    [ 'Cores: ~`.t~24| ~w'-[Cores] ], [nl],
  578    [ nl ].
  579message(perfect) -->
  580    [ nl, 'Congratulations, your kit seems sound and complete!'-[] ].
  581message(imperfect(N)) -->
  582    [ 'Found ~w issues.'-[N] ].
  583message(checking(Feature)) -->
  584    [ 'Checking ~w ...'-[Feature], flush ].
  585message(missing(Properties)) -->
  586    [ at_same_line, '~`.t~48| not present'-[] ],
  587    details(Properties).
  588message(loading(Source)) -->
  589    [ 'Loading ~q ...'-[Source], flush ].
  590message(ok) -->
  591    [ at_same_line, '~`.t~48| ok'-[] ].
  592message(optional_not_found(Properties)) -->
  593    [ 'Optional ~q ~`.t~48| not present'-[Properties.source] ].
  594message(not_found(Properties)) -->
  595    [ '~q ~`.t~48| NOT FOUND'-[Properties.source] ],
  596    details(Properties).
  597message(failed(Properties, false, [])) -->
  598    !,
  599    [ at_same_line, '~`.t~48| FAILED'-[] ],
  600    details(Properties).
  601message(failed(Properties, exception(Ex0), [])) -->
  602    !,
  603    { strip_stack(Ex0, Ex),
  604      message_to_string(Ex, Msg) },
  605    [ '~w'-[Msg] ],
  606    details(Properties).
  607message(failed(Properties, true, Messages)) -->
  608    [ at_same_line, '~`.t~48| FAILED'-[] ],
  609    explain(Messages),
  610    details(Properties).
  611message(archive(What, Names)) -->
  612    [ '  Supported ~w: '-[What] ],
  613    list_names(Names).
  614message(pcre_missing(Features)) -->
  615    [ 'Missing libpcre features: '-[] ],
  616    list_names(Features).
  617message(not_first_on_path(EXE, OnPath)) -->
  618    { public_executable(EXE, PublicEXE),
  619      file_base_name(EXE, Prog)
  620    },
  621    [ 'The first ~w on '-[Prog] ], 'PATH', [ ' is ~p, while '-[OnPath], nl ],
  622    [ 'this version is ~p.'-[PublicEXE] ].
  623message(not_same_on_path(EXE, OnPath)) -->
  624    { public_executable(EXE, PublicEXE),
  625      file_base_name(EXE, Prog)
  626    },
  627    [ 'The ~w on '-[Prog] ], 'PATH', [ ' is ~p, while '-[OnPath], nl ],
  628    [ 'this version is ~p.'-[PublicEXE] ].
  629message(not_on_path(EXE, Prog)) -->
  630    { public_bin_dir(EXE, Dir),
  631      prolog_to_os_filename(Dir, OSDir)
  632    },
  633    [ 'Could not find ~w on '-[Prog] ], 'PATH', [ '. '-[], nl ],
  634    [ 'You may wish to add ~p to '-[OSDir] ], 'PATH', [ '. '-[], nl ].
  635message(jquery(found(Path))) -->
  636    [ '  jQuery from ~w'-[Path] ].
  637message(jquery(not_found(File))) -->
  638    [ '  Cannot find jQuery (~w)'-[File] ].
  639message(sweep(found(Paths))) -->
  640    [ '  GNU-Emacs plugin loads'-[] ],
  641    sequence(list_file, Paths).
  642message(sweep(not_found(Paths))) -->
  643    [ '  Could not find all GNU-Emacs libraries'-[] ],
  644    sequence(list_file, Paths).
  645message(testing(no_installed_tests)) -->
  646    [ '  Runtime testing is not enabled.', nl],
  647    [ '  Please recompile the system with INSTALL_TESTS enabled.' ].
  648message(janus(Version)) -->
  649    [ '  Python version ~w'-[Version] ].
  650message(ambiguous_autoload(PI, Paths)) -->
  651    [ 'The predicate ~p can be autoloaded from multiple libraries:'-[PI]],
  652    sequence(list_file, Paths).
  653
  654public_executable(EXE, PublicProg) :-
  655    file_base_name(EXE, Prog),
  656    file_directory_name(EXE, ArchDir),
  657    file_directory_name(ArchDir, BinDir),
  658    file_directory_name(BinDir, Home),
  659    file_directory_name(Home, Lib),
  660    file_directory_name(Lib, Prefix),
  661    atomic_list_concat([Prefix, bin, Prog], /, PublicProg),
  662    exists_file(PublicProg),
  663    same_file(EXE, PublicProg),
  664    !.
  665public_executable(EXE, EXE).
  666
  667public_bin_dir(EXE, Dir) :-
  668    public_executable(EXE, PublicEXE),
  669    file_directory_name(PublicEXE, Dir).
  670
  671
  672
  673'PATH' -->
  674    { current_prolog_flag(windows, true) },
  675    !,
  676    [ '%PATH%'-[] ].
  677'PATH' -->
  678    [ '$PATH'-[] ].
  679
  680strip_stack(error(Error, context(prolog_stack(S), Msg)),
  681            error(Error, context(_, Msg))) :-
  682    nonvar(S).
  683strip_stack(Error, Error).
  684
  685details(Properties) -->
  686    { issue_url(Properties, URL), !
  687    },
  688    [ nl, 'See ~w'-[URL] ].
  689details(_) --> [].
  690
  691explain(Messages) -->
  692    { Messages = [message(error(shared_object(open, _Message), _), _, _)|_]
  693    },
  694    !,
  695    [nl],
  696    (   { current_prolog_flag(windows, true) }
  697    ->  [ 'Cannot load required DLL'-[] ]
  698    ;   [ 'Cannot load required shared library'-[] ]
  699    ).
  700explain(Messages) -->
  701    print_messages(Messages).
  702
  703print_messages([]) --> [].
  704print_messages([message(_Term, _Kind, Lines)|T]) -->
  705    Lines, [nl],
  706    print_messages(T).
  707
  708list_names([]) --> [].
  709list_names([H|T]) -->
  710    [ '~w'-[H] ],
  711    (   {T==[]}
  712    ->  []
  713    ;   [ ', '-[] ],
  714        list_names(T)
  715    ).
  716
  717list_file(File) -->
  718    [ nl, '    '-[], url(File) ].
  719
  720
  721		 /*******************************
  722		 *          CONFIG FILES	*
  723		 *******************************/
 check_config_files
Examines the locations of config files. The config files have moved in version 8.1.15
  730check_config_files :-
  731    check_config_files(Issues),
  732    maplist(print_message(warning), Issues).
  733
  734check_config_files(Issues) :-
  735    findall(Issue, check_config_file(Issue), Issues).
  736
  737check_config_file(config(Id, move(Type, OldFile, NewFile))) :-
  738    old_config(Type, Id, OldFile),
  739    access_file(OldFile, exist),
  740    \+ ( new_config(Type, Id, NewFile),
  741         access_file(NewFile, exist)
  742       ),
  743    once(new_config(Type, Id, NewFile)).
  744check_config_file(config(Id, different(Type, OldFile, NewFile))) :-
  745    old_config(Type, Id, OldFile),
  746    access_file(OldFile, exist),
  747    new_config(Type, Id, NewFile),
  748    access_file(NewFile, exist),
  749    \+ same_file(OldFile, NewFile).
 update_config_files
Move config files from their old location to the new if the file or directory exists in the old location but not in the new.
  756update_config_files :-
  757    old_config(Type, Id, OldFile),
  758    access_file(OldFile, exist),
  759    \+ ( new_config(Type, Id, NewFile),
  760         access_file(NewFile, exist)
  761       ),
  762    (   new_config(Type, Id, NewFile),
  763        \+ same_file(OldFile, NewFile),
  764        create_parent_dir(NewFile)
  765    ->  catch(rename_file(OldFile, NewFile), E,
  766              print_message(warning, E)),
  767        print_message(informational, config(Id, moved(Type, OldFile, NewFile)))
  768    ),
  769    fail.
  770update_config_files.
  771
  772old_config(file, init, File) :-
  773    current_prolog_flag(windows, true),
  774    win_folder(appdata, Base),
  775    atom_concat(Base, '/SWI-Prolog/swipl.ini', File).
  776old_config(file, init, File) :-
  777    expand_file_name('~/.swiplrc', [File]).
  778old_config(directory, lib, Dir) :-
  779    expand_file_name('~/lib/prolog', [Dir]).
  780old_config(directory, xpce, Dir) :-
  781    expand_file_name('~/.xpce', [Dir]).
  782old_config(directory, history, Dir) :-
  783    expand_file_name('~/.swipl-dir-history', [Dir]).
  784old_config(directory, pack, Dir) :-
  785    (   catch(expand_file_name('~/lib/swipl/pack', [Dir]), _, fail)
  786    ;   absolute_file_name(swi(pack), Dir,
  787                           [ file_type(directory), solutions(all) ])
  788    ).
  789
  790new_config(file, init, File) :-
  791    absolute_file_name(user_app_config('init.pl'), File,
  792                       [ solutions(all) ]).
  793new_config(directory, lib, Dir) :-
  794    config_dir(user_app_config(lib), Dir).
  795new_config(directory, xpce, Dir) :-
  796    config_dir(user_app_config(xpce), Dir).
  797new_config(directory, history, Dir) :-
  798    config_dir(user_app_config('dir-history'), Dir).
  799new_config(directory, pack, Dir) :-
  800    config_dir([app_data(pack), swi(pack)], Dir).
  801
  802config_dir(Aliases, Dir) :-
  803    is_list(Aliases),
  804    !,
  805    (   member(Alias, Aliases),
  806        absolute_file_name(Alias, Dir,
  807                           [ file_type(directory), solutions(all) ])
  808    *-> true
  809    ;   member(Alias, Aliases),
  810        absolute_file_name(Alias, Dir,
  811                           [ solutions(all) ])
  812    ).
  813config_dir(Alias, Dir) :-
  814    (   absolute_file_name(Alias, Dir,
  815                           [ file_type(directory), solutions(all) ])
  816    *-> true
  817    ;   absolute_file_name(Alias, Dir,
  818                           [ solutions(all) ])
  819    ).
  820
  821create_parent_dir(NewFile) :-
  822    file_directory_name(NewFile, Dir),
  823    create_parent_dir_(Dir).
  824
  825create_parent_dir_(Dir) :-
  826    exists_directory(Dir),
  827    '$my_file'(Dir),
  828    !.
  829create_parent_dir_(Dir) :-
  830    file_directory_name(Dir, Parent),
  831    Parent \== Dir,
  832    create_parent_dir_(Parent),
  833    make_directory(Dir).
  834
  835prolog:message(config(Id, Issue)) -->
  836    [ 'Config: '-[] ],
  837    config_description(Id),
  838    config_issue(Issue).
  839
  840config_description(init) -->
  841    [ '(user initialization file) '-[], nl ].
  842config_description(lib) -->
  843    [ '(user library) '-[], nl ].
  844config_description(pack) -->
  845    [ '(add-ons) '-[], nl ].
  846config_description(history) -->
  847    [ '(command line history) '-[], nl ].
  848config_description(xpce) -->
  849    [ '(gui) '-[], nl ].
  850
  851config_issue(move(Type, Old, New)) -->
  852    [ '  found ~w "~w"'-[Type, Old], nl ],
  853    [ '  new location is "~w"'-[New] ].
  854config_issue(moved(Type, Old, New)) -->
  855    [ '  found ~w "~w"'-[Type, Old], nl ],
  856    [ '  moved to new location "~w"'-[New] ].
  857config_issue(different(Type, Old, New)) -->
  858    [ '  found different ~w "~w"'-[Type, Old], nl ],
  859    [ '  new location is "~w"'-[New] ].
  860
  861		 /*******************************
  862		 *         AUTO LOADING		*
  863		 *******************************/
 check_autoload
Find possible ambiguous predicates in the autoload index.
  869check_autoload :-
  870    findall(Name/Arity, '$in_library'(Name, Arity, _Path), PIs),
  871    msort(PIs, Sorted),
  872    clumped(Sorted, Clumped),
  873    sort(2, >=, Clumped, ClumpedS),
  874    ambiguous_autoload(ClumpedS).
  875
  876ambiguous_autoload([PI-N|T]) :-
  877    N > 1,
  878    !,
  879    warn_ambiguous_autoload(PI),
  880    ambiguous_autoload(T).
  881ambiguous_autoload(_).
  882
  883warn_ambiguous_autoload(PI) :-
  884    PI = Name/Arity,
  885    findall(PlFile,
  886            ( '$in_library'(Name, Arity, File),
  887              file_name_extension(File, pl, PlFile)
  888            ), PlFiles),
  889    print_message(warning, installation(ambiguous_autoload(PI, PlFiles)))