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-2026, 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(occurs), [sub_term/2]).   49:- autoload(library(option), [option/2, merge_options/3]).   50:- autoload(library(prolog_source), [path_segments_atom/2]).   51:- use_module(library(settings), [setting/2]).   52:- autoload(library(dcg/high_order), [sequence//2, sequence/4]).   53:- autoload(library(error), [must_be/2]).   54:- autoload(library(pce), [get/3, get/4]).

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.
   87% Feature tests
   88component(tcmalloc,
   89          #{ optional:true,
   90             test:test_tcmalloc,
   91             url:'tcmalloc.html',
   92             os:linux
   93           }).
   94component(gmp,
   95          #{ test:current_prolog_flag(bounded, false),
   96             url:'gmp.html'
   97           }).
   98% Packages that depend on foreign libraries
   99component(library(archive), #{features:archive_features}).
  100component(library(cgi), #{}).
  101component(library(crypt), #{}).
  102component(library(bdb), #{}).
  103component(library(double_metaphone), #{}).
  104component(library(editline), #{}).
  105component(library(filesex), #{}).
  106component(library(http/http_stream), #{}).
  107component(library(json), #{}).
  108component(library(http/jquery), #{features:jquery_file}).
  109component(library(isub), #{}).
  110component(library(janus), #{features:python_version}).
  111component(library(jpl), #{}).
  112component(library(memfile), #{}).
  113component(library(odbc), #{}).
  114component(library(pce),
  115          #{pre:use_foreign_library(pce_principal:foreign(pl2xpce)),
  116            url:'xpce.html',
  117            features:pce_features}).
  118component(library(pcre), #{features:pcre_features}).
  119component(library(pdt_console), #{}).
  120component(library(porter_stem), #{}).
  121component(library(process), #{}).
  122component(library(protobufs), #{}).
  123component(library(readutil), #{}).
  124component(library(rlimit), #{os:unix}).
  125component(library(semweb/rdf_db), #{}).
  126component(library(semweb/rdf_ntriples), #{}).
  127component(library(semweb/turtle), #{}).
  128component(library(sgml), #{}).
  129component(library(sha), #{}).
  130component(library(snowball), #{}).
  131component(library(socket), #{}).
  132component(library(ssl), #{features:ssl_version}).
  133component(library(sweep_link), #{features:sweep_emacs_module}).
  134component(library(crypto), #{}).
  135component(library(syslog), #{os:unix}).
  136component(library(table), #{}).
  137component(library(time), #{}).
  138component(library(tipc/tipc), #{os:linux}).
  139component(library(unicode), #{}).
  140component(library(uri), #{}).
  141component(library(uuid), #{}).
  142component(library(yaml), #{}).
  143component(library(zlib), #{}).
  144
  145issue_base('http://www.swi-prolog.org/build/issues/').
  146
  147:- thread_local
  148    issue/1.  149
  150:- meta_predicate
  151    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.

  168check_installation :-
  169    print_message(informational, installation(checking)),
  170    check_installation_(InstallIssues),
  171    check_on_path,
  172    check_config_files(ConfigIssues),
  173    check_autoload,
  174    maplist(print_message(warning), ConfigIssues),
  175    append(InstallIssues, ConfigIssues, Issues),
  176    (   Issues == []
  177    ->  print_message(informational, installation(perfect))
  178    ;   length(Issues, Count),
  179        print_message(warning, installation(imperfect(Count)))
  180    ).
 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).
  190check_installation(Issues) :-
  191    check_installation_(Issues0),
  192    maplist(public_issue, Issues0, Issues).
  193
  194public_issue(installation(Term), Source-Issue) :-
  195    functor(Term, Issue, _),
  196    arg(1, Term, Properties),
  197    Source = Properties.source.
  198
  199check_installation_(Issues) :-
  200    retractall(issue(_)),
  201    forall(component(Source, _Properties),
  202           check_component(Source)),
  203    findall(I, retract(issue(I)), Issues).
  204
  205check_component(Source) :-
  206    component(Source, Properties),
  207    !,
  208    check_component(Source, Properties.put(source,Source)).
  209
  210check_component(_Source, Properties) :-
  211    OS = Properties.get(os),
  212    \+ current_os(OS),
  213    !.
  214check_component(Source, Properties) :-
  215    compound(Source),
  216    !,
  217    check_source(Source, Properties).
  218check_component(Feature, Properties) :-
  219    print_message(informational, installation(checking(Feature))),
  220    (   call(Properties.test)
  221    ->  print_message(informational, installation(ok))
  222    ;   print_issue(installation(missing(Properties)))
  223    ).
  224
  225check_source(Source, Properties) :-
  226    exists_source(Source),
  227    !,
  228    print_message(informational, installation(loading(Source))),
  229    (   run_silent(( (   Pre = Properties.get(pre)
  230                     ->  call(Pre)
  231                     ;   true
  232                     ),
  233                     load_files(Source, [silent(true), if(true)])
  234                   ),
  235                   Properties.put(action, load))
  236    ->  test_component(Properties),
  237        print_message(informational, installation(ok)),
  238        check_features(Properties)
  239    ;   true
  240    ).
  241check_source(_Source, Properties) :-
  242    Properties.get(optional) == true,
  243    !,
  244    print_message(silent,
  245                  installation(optional_not_found(Properties))).
  246check_source(_Source, Properties) :-
  247    print_issue(installation(not_found(Properties))).
  248
  249current_os(unix)    :- current_prolog_flag(unix, true).
  250current_os(windows) :- current_prolog_flag(windows, true).
  251current_os(linux)   :- current_prolog_flag(arch, Arch),
  252                       sub_atom(Arch, _, _, _, linux).
 test_component(+Properties) is semidet
Run additional tests to see whether the component really works.
  258test_component(Dict) :-
  259    Test = Dict.get(test),
  260    !,
  261    call(Test).
  262test_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.
  271check_features(Dict) :-
  272    Test = Dict.get(features),
  273    !,
  274    catch(Test, Error,
  275          ( print_message(warning, Error),
  276            fail)).
  277check_features(_).
 run_silent(:Goal, +Properties) is semidet
Succeed if Goal succeeds and does not print any errors or warnings.
  285run_silent(Goal, Properties) :-
  286    run_collect_messages(Goal, Result, Messages),
  287    (   Result == true,
  288        Messages == []
  289    ->  true
  290    ;   print_issue(installation(failed(Properties, Result, Messages))),
  291        fail
  292    ).
 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.
  304:- thread_local
  305    got_message/1.  306
  307run_collect_messages(Goal, Result, Messages) :-
  308    setup_call_cleanup(
  309        asserta((user:thread_message_hook(Term,Kind,Lines) :-
  310                    error_kind(Kind),
  311                    assertz(got_message(message(Term,Kind,Lines)))), Ref),
  312        (   catch(Goal, E, true)
  313        ->  (   var(E)
  314            ->  Result0 = true
  315            ;   Result0 = exception(E)
  316            )
  317        ;   Result0 = false
  318        ),
  319        erase(Ref)),
  320    findall(Msg, retract(got_message(Msg)), Messages),
  321    Result = Result0.
  322
  323error_kind(warning).
  324error_kind(error).
  325
  326
  327                 /*******************************
  328                 *         SPECIAL TESTS        *
  329                 *******************************/
 test_tcmalloc
  333:- if(current_predicate(malloc_property/1)).  334test_tcmalloc :-
  335    malloc_property('generic.current_allocated_bytes'(Bytes)),
  336    Bytes > 1 000 000.
  337:- else.  338test_tcmalloc :-
  339    fail.
  340:- endif.
 archive_features
Report features supported by library(archive).
  346archive_features :-
  347    tmp_file_stream(utf8, Name, Out),
  348    close(Out),
  349    findall(F, archive_filter(F, Name), Filters),
  350    print_message(informational, installation(archive(filters, Filters))),
  351    findall(F, archive_format(F, Name), Formats),
  352    print_message(informational, installation(archive(formats, Formats))),
  353    delete_file(Name).
  354
  355archive_filter(F, Name) :-
  356    a_filter(F),
  357    catch(archive_open(Name, A, [filter(F)]), E, true),
  358    (   var(E)
  359    ->  archive_close(A)
  360    ;   true
  361    ),
  362    \+ subsumes_term(error(domain_error(filter, _),_), E).
  363
  364archive_format(F, Name) :-
  365    a_format(F),
  366    catch(archive_open(Name, A, [format(F)]), E, true),
  367    (   var(E)
  368    ->  archive_close(A)
  369    ;   true
  370    ),
  371    \+ subsumes_term(error(domain_error(format, _),_), E).
  372
  373a_filter(bzip2).
  374a_filter(compress).
  375a_filter(gzip).
  376a_filter(grzip).
  377a_filter(lrzip).
  378a_filter(lzip).
  379a_filter(lzma).
  380a_filter(lzop).
  381a_filter(none).
  382a_filter(rpm).
  383a_filter(uu).
  384a_filter(xz).
  385
  386a_format('7zip').
  387a_format(ar).
  388a_format(cab).
  389a_format(cpio).
  390a_format(empty).
  391a_format(gnutar).
  392a_format(iso9660).
  393a_format(lha).
  394a_format(mtree).
  395a_format(rar).
  396a_format(raw).
  397a_format(tar).
  398a_format(xar).
  399a_format(zip).
 pcre_features
  403pcre_features :-
  404    findall(X, pcre_missing(X), Missing),
  405    (   Missing == []
  406    ->  true
  407    ;   print_message(warning, installation(pcre_missing(Missing)))
  408    ),
  409    (   re_config(compiled_widths(Widths)),
  410        1 =:= Widths /\ 1
  411    ->  true
  412    ;   print_message(warning, installation(pcre_missing('8-bit support')))
  413    ).
  414
  415pcre_missing(X) :-
  416    pcre_must_have(X),
  417    Term =.. [X,true],
  418    \+ catch(re_config(Term), _, fail).
  419
  420pcre_must_have(unicode).
 pce_features
Report the image formats xpce can save, the sound files it can load and the video codecs it can play and write. These depend on how SDL_image, SDL3_sound and the video library were built.
  428pce_features :-
  429    forall(pce_formats(What, Getter),
  430           (   pce_formats(Getter, Names)
  431           ->  print_message(informational,
  432                             installation(pce_formats(What, Names)))
  433           ;   true
  434           )).
  435
  436pce_formats(image, image_save_formats).
  437pce_formats(sound, sound_file_extensions).
  438pce_formats(video, video_decoders).
  439pce_formats(video_writer, video_encoders).
  440
  441pce_formats(Getter, Names) :-
  442    catch(get(@(display), Getter, Chain), _, fail),
  443    get(Chain, size, N),
  444    findall(Name, ( between(1, N, I),
  445                    get(Chain, nth1, I, Name)
  446                  ), Names).
 ssl_version
  450ssl_version :-
  451    current_prolog_flag(ssl_library_version, SSLVersion),
  452    print_message(informational, installation(version(SSLVersion))).
 jquery_file
Test whether jquery.js can be found
  459jquery_file :-
  460    setting(jquery:version, File),
  461    (   absolute_file_name(js(File), Path, [access(read), file_errors(fail)])
  462    ->  print_message(informational, installation(jquery(found(Path))))
  463    ;   print_message(warning, installation(jquery(not_found(File))))
  464    ).
  465
  466sweep_emacs_module :-
  467    with_output_to(string(S), write_sweep_module_location),
  468    split_string(S, "\n", "\n", [VersionInfo|Modules]),
  469    must_be(oneof(["V 1"]), VersionInfo),
  470    (   maplist(check_sweep_lib, Modules)
  471    ->  print_message(informational, installation(sweep(found(Modules))))
  472    ;   print_message(warning, installation(sweep(not_found(Modules))))
  473    ).
  474
  475check_sweep_lib(Line) :-
  476    sub_atom(Line, B, _, A, ' '),
  477    sub_atom(Line, 0, B, _, Type),
  478    must_be(oneof(['L', 'M']), Type),
  479    sub_atom(Line, _, A, 0, Lib),
  480    exists_file(Lib).
  481
  482python_version :-
  483    py_call(sys:version, Version),
  484    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.
  493check_on_path :-
  494    current_prolog_flag(executable, EXEFlag),
  495    prolog_to_os_filename(EXE, EXEFlag),
  496    file_base_name(EXE, Prog),
  497    absolute_file_name(EXE, AbsExe,
  498                       [ access(execute),
  499                         file_errors(fail)
  500                       ]),
  501    !,
  502    prolog_to_os_filename(AbsExe, OsExe),
  503    (   absolute_file_name(path(Prog), OnPath,
  504                           [ access(execute),
  505                             file_errors(fail)
  506                           ])
  507    ->  (   same_file(EXE, OnPath)
  508        ->  true
  509        ;   absolute_file_name(path(Prog), OnPathAny,
  510                               [ access(execute),
  511                                 file_errors(fail),
  512                                 solutions(all)
  513                               ]),
  514            same_file(EXE, OnPathAny)
  515        ->  print_message(warning, installation(not_first_on_path(OsExe, OnPath)))
  516        ;   print_message(warning, installation(not_same_on_path(OsExe, OnPath)))
  517        )
  518    ;   print_message(warning, installation(not_on_path(OsExe, Prog)))
  519    ).
  520check_on_path.
  521
  522
  523		 /*******************************
  524		 *           RUN TESTS		*
  525		 *******************************/
 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.

When running this predicate the working directory must be writeable and allow for writing executable files. This is due to tests for file system interaction and tests for generating stand-alone executables. Note also that due to its side effects, the predicate should not be invoked twice in the same session.

  548test_installation :-
  549    test_installation([]).
  550
  551test_installation(Options) :-
  552    absolute_file_name(swi(test/test),
  553                       TestFile,
  554                       [ access(read),
  555                         file_errors(fail),
  556                         file_type(prolog)
  557                       ]),
  558    !,
  559    test_installation_run(TestFile, Options).
  560test_installation(_Options) :-
  561    print_message(warning, installation(testing(no_installed_tests))).
  562
  563test_installation_run(TestFile, Options) :-
  564    (   option(package(_), Options)
  565    ->  merge_options(Options,
  566                      [ core(false),
  567                        subdirs(false)
  568                      ], TestOptions)
  569    ;   merge_options(Options,
  570                      [ packages(true)
  571                      ], TestOptions)
  572    ),
  573    load_files(user:TestFile),
  574    current_prolog_flag(verbose, Old),
  575    setup_call_cleanup(
  576        set_prolog_flag(verbose, silent),
  577        user:test([], TestOptions),
  578        set_prolog_flag(verbose, Old)).
  579
  580
  581                 /*******************************
  582                 *            MESSAGES          *
  583                 *******************************/
  584
  585:- multifile
  586    prolog:message//1.  587
  588print_issue(Term) :-
  589    assertz(issue(Term)),
  590    print_message(warning, Term).
  591
  592issue_url(Properties, URL) :-
  593    Local = Properties.get(url),
  594    !,
  595    issue_base(Base),
  596    atom_concat(Base, Local, URL).
  597issue_url(Properties, URL) :-
  598    Properties.get(source) = library(Segments),
  599    !,
  600    path_segments_atom(Segments, Base),
  601    file_name_extension(Base, html, URLFile),
  602    issue_base(Issues),
  603    atom_concat(Issues, URLFile, URL).
  604
  605prolog:message(installation(Message)) -->
  606    message(Message).
  607
  608message(checking) -->
  609    { current_prolog_flag(address_bits, Bits) },
  610    { current_prolog_flag(arch, Arch) },
  611    { current_prolog_flag(home, Home) },
  612    { current_prolog_flag(cpu_count, Cores) },
  613    { current_prolog_flag(build_type, BuildType) -> true ; BuildType = "?" },
  614    [ 'Checking your SWI-Prolog kit for common issues ...'-[], nl, nl ],
  615    [ 'Version: ~`.t~24| '-[] ], '$messages':prolog_message(version), [nl],
  616    [ 'CMake Build type: ~`.t~24| ~w'-[BuildType] ], [nl],
  617    [ 'Address bits: ~`.t~24| ~d'-[Bits] ], [nl],
  618    [ 'Architecture: ~`.t~24| ~w'-[Arch] ], [nl],
  619    [ 'Installed at: ~`.t~24| ~w'-[Home] ], [nl],
  620    [ 'Cores: ~`.t~24| ~w'-[Cores] ], [nl],
  621    [ nl ].
  622message(perfect) -->
  623    [ nl, 'Congratulations, your kit seems sound and complete!'-[] ].
  624message(imperfect(N)) -->
  625    [ 'Found ~w issues.'-[N] ].
  626message(checking(Feature)) -->
  627    [ 'Checking ~w ...'-[Feature], flush ].
  628message(missing(Properties)) -->
  629    [ at_same_line, '~`.t~48| not present'-[] ],
  630    details(Properties).
  631message(loading(Source)) -->
  632    [ 'Loading ~q ...'-[Source], flush ].
  633message(ok) -->
  634    [ at_same_line, '~`.t~48| ok'-[] ].
  635message(optional_not_found(Properties)) -->
  636    [ 'Optional ~q ~`.t~48| not present'-[Properties.source] ].
  637message(not_found(Properties)) -->
  638    [ '~q ~`.t~48| NOT FOUND'-[Properties.source] ],
  639    details(Properties).
  640message(failed(Properties, false, [])) -->
  641    !,
  642    [ at_same_line, '~`.t~48| FAILED'-[] ],
  643    details(Properties).
  644message(failed(Properties, exception(Ex0), [])) -->
  645    !,
  646    { strip_stack(Ex0, Ex),
  647      message_to_string(Ex, Msg) },
  648    [ '~w'-[Msg] ],
  649    details(Properties).
  650message(failed(Properties, true, Messages)) -->
  651    [ at_same_line, '~`.t~48| FAILED'-[] ],
  652    explain(Messages),
  653    details(Properties).
  654message(archive(What, Names)) -->
  655    [ '  Supported ~w: '-[What] ],
  656    list_names(Names).
  657message(pce_formats(image, Formats)) -->
  658    [ '  Images can be saved as: '-[] ],
  659    list_names(Formats).
  660message(pce_formats(sound, [wav])) -->
  661    !,
  662    [ '  Sound files that can be loaded: wav (no SDL3_sound)'-[] ].
  663message(pce_formats(sound, Extensions)) -->
  664    [ '  Sound files that can be loaded: '-[] ],
  665    list_names(Extensions).
  666message(pce_formats(video, [])) -->
  667    !,
  668    [ '  Videos cannot be played (xpce has no video support)'-[] ].
  669message(pce_formats(video, Codecs)) -->
  670    [ '  Video codecs that can be played: '-[] ],
  671    list_names(Codecs).
  672message(pce_formats(video_writer, [])) -->
  673    !,
  674    [ '  Videos cannot be written (no video encoders)'-[] ].
  675message(pce_formats(video_writer, Codecs)) -->
  676    [ '  Video codecs that can be written: '-[] ],
  677    list_names(Codecs).
  678message(pcre_missing(Features)) -->
  679    [ 'Missing libpcre features: '-[] ],
  680    list_names(Features).
  681message(not_first_on_path(EXE, OnPath)) -->
  682    { public_executable(EXE, PublicEXE),
  683      file_base_name(EXE, Prog)
  684    },
  685    [ 'The first ~w on '-[Prog] ], 'PATH', [ ' is ~p, while '-[OnPath], nl ],
  686    [ 'this version is ~p.'-[PublicEXE] ].
  687message(not_same_on_path(EXE, OnPath)) -->
  688    { public_executable(EXE, PublicEXE),
  689      file_base_name(EXE, Prog)
  690    },
  691    [ 'The ~w on '-[Prog] ], 'PATH', [ ' is ~p, while '-[OnPath], nl ],
  692    [ 'this version is ~p.'-[PublicEXE] ].
  693message(not_on_path(EXE, Prog)) -->
  694    { public_bin_dir(EXE, Dir),
  695      prolog_to_os_filename(Dir, OSDir)
  696    },
  697    [ 'Could not find ~w on '-[Prog] ], 'PATH', [ '. '-[], nl ],
  698    [ 'You may wish to add ~p to '-[OSDir] ], 'PATH', [ '. '-[], nl ].
  699message(jquery(found(Path))) -->
  700    [ '  jQuery from ~w'-[Path] ].
  701message(jquery(not_found(File))) -->
  702    [ '  Cannot find jQuery (~w)'-[File] ].
  703message(sweep(found(Paths))) -->
  704    [ '  GNU-Emacs plugin loads'-[] ],
  705    sequence(list_file, Paths).
  706message(sweep(not_found(Paths))) -->
  707    [ '  Could not find all GNU-Emacs libraries'-[] ],
  708    sequence(list_file, Paths).
  709message(testing(no_installed_tests)) -->
  710    [ '  Runtime testing is not enabled.', nl],
  711    [ '  Please recompile the system with INSTALL_TESTS enabled.' ].
  712message(janus(Version)) -->
  713    [ '  Python version ~w'-[Version] ].
  714message(ambiguous_autoload(PI, Paths)) -->
  715    [ 'The predicate ~p can be autoloaded from multiple libraries:'-[PI]],
  716    sequence(list_file, Paths).
  717message(version(Version)) -->
  718    [ '  Using ~w'-[Version] ].
  719message(lib_version(What, Version)) -->
  720    [ '  Using library ~w version ~w'-[What, Version] ].
  721
  722public_executable(EXE, PublicProg) :-
  723    file_base_name(EXE, Prog),
  724    file_directory_name(EXE, ArchDir),
  725    file_directory_name(ArchDir, BinDir),
  726    file_directory_name(BinDir, Home),
  727    file_directory_name(Home, Lib),
  728    file_directory_name(Lib, Prefix),
  729    atomic_list_concat([Prefix, bin, Prog], /, PublicProg),
  730    exists_file(PublicProg),
  731    same_file(EXE, PublicProg),
  732    !.
  733public_executable(EXE, EXE).
  734
  735public_bin_dir(EXE, Dir) :-
  736    public_executable(EXE, PublicEXE),
  737    file_directory_name(PublicEXE, Dir).
  738
  739
  740
  741'PATH' -->
  742    { current_prolog_flag(windows, true) },
  743    !,
  744    [ '%PATH%'-[] ].
  745'PATH' -->
  746    [ '$PATH'-[] ].
  747
  748strip_stack(error(Error, context(prolog_stack(S), Msg)),
  749            error(Error, context(_, Msg))) :-
  750    nonvar(S).
  751strip_stack(Error, Error).
  752
  753details(Properties) -->
  754    { issue_url(Properties, URL), !
  755    },
  756    [ nl, 'See '-[], url(URL) ].
  757details(_) --> [].
  758
  759explain(Messages) -->
  760    { shared_object_error(Messages) },
  761    !,
  762    [nl],
  763    (   { current_prolog_flag(windows, true) }
  764    ->  [ 'Cannot load required DLL'-[] ]
  765    ;   [ 'Cannot load required shared library'-[] ]
  766    ).
  767explain(Messages) -->
  768    print_messages(Messages).
  769
  770shared_object_error(Messages) :-
  771    sub_term(Term, Messages),
  772    subsumes_term(error(shared_object(open, _Message), _), Term),
  773    !.
  774
  775print_messages([]) --> [].
  776print_messages([message(_Term, _Kind, Lines)|T]) -->
  777    Lines, [nl],
  778    print_messages(T).
  779
  780list_names([]) --> [].
  781list_names([H|T]) -->
  782    [ '~w'-[H] ],
  783    (   {T==[]}
  784    ->  []
  785    ;   [ ', '-[] ],
  786        list_names(T)
  787    ).
  788
  789list_file(File) -->
  790    [ nl, '    '-[], url(File) ].
  791
  792
  793		 /*******************************
  794		 *          CONFIG FILES	*
  795		 *******************************/
 check_config_files
Examines the locations of config files. The config files have moved in version 8.1.15
  802check_config_files :-
  803    check_config_files(Issues),
  804    maplist(print_message(warning), Issues).
  805
  806check_config_files(Issues) :-
  807    findall(Issue, check_config_file(Issue), Issues).
  808
  809check_config_file(config(Id, move(Type, OldFile, NewFile))) :-
  810    old_config(Type, Id, OldFile),
  811    access_file(OldFile, exist),
  812    \+ ( new_config(Type, Id, NewFile),
  813         access_file(NewFile, exist)
  814       ),
  815    once(new_config(Type, Id, NewFile)).
  816check_config_file(config(Id, different(Type, OldFile, NewFile))) :-
  817    old_config(Type, Id, OldFile),
  818    access_file(OldFile, exist),
  819    new_config(Type, Id, NewFile),
  820    access_file(NewFile, exist),
  821    \+ 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.
  828update_config_files :-
  829    old_config(Type, Id, OldFile),
  830    access_file(OldFile, exist),
  831    \+ ( new_config(Type, Id, NewFile),
  832         access_file(NewFile, exist)
  833       ),
  834    (   new_config(Type, Id, NewFile),
  835        \+ same_file(OldFile, NewFile),
  836        create_parent_dir(NewFile)
  837    ->  catch(rename_file(OldFile, NewFile), E,
  838              print_message(warning, E)),
  839        print_message(informational, config(Id, moved(Type, OldFile, NewFile)))
  840    ),
  841    fail.
  842update_config_files.
  843
  844old_config(file, init, File) :-
  845    current_prolog_flag(windows, true),
  846    win_folder(appdata, Base),
  847    atom_concat(Base, '/SWI-Prolog/swipl.ini', File).
  848old_config(file, init, File) :-
  849    expand_file_name('~/.swiplrc', [File]).
  850old_config(directory, lib, Dir) :-
  851    expand_file_name('~/lib/prolog', [Dir]).
  852old_config(directory, xpce, Dir) :-
  853    expand_file_name('~/.xpce', [Dir]).
  854old_config(directory, history, Dir) :-
  855    expand_file_name('~/.swipl-dir-history', [Dir]).
  856old_config(directory, pack, Dir) :-
  857    (   catch(expand_file_name('~/lib/swipl/pack', [Dir]), _, fail)
  858    ;   absolute_file_name(swi(pack), Dir,
  859                           [ file_type(directory), solutions(all) ])
  860    ).
  861
  862new_config(file, init, File) :-
  863    absolute_file_name(user_app_config('init.pl'), File,
  864                       [ solutions(all) ]).
  865new_config(directory, lib, Dir) :-
  866    config_dir(user_app_config(lib), Dir).
  867new_config(directory, xpce, Dir) :-
  868    config_dir(user_app_config(xpce), Dir).
  869new_config(directory, history, Dir) :-
  870    config_dir(user_app_config('dir-history'), Dir).
  871new_config(directory, pack, Dir) :-
  872    config_dir([app_data(pack), swi(pack)], Dir).
  873
  874config_dir(Aliases, Dir) :-
  875    is_list(Aliases),
  876    !,
  877    (   member(Alias, Aliases),
  878        absolute_file_name(Alias, Dir,
  879                           [ file_type(directory), solutions(all) ])
  880    *-> true
  881    ;   member(Alias, Aliases),
  882        absolute_file_name(Alias, Dir,
  883                           [ solutions(all) ])
  884    ).
  885config_dir(Alias, Dir) :-
  886    (   absolute_file_name(Alias, Dir,
  887                           [ file_type(directory), solutions(all) ])
  888    *-> true
  889    ;   absolute_file_name(Alias, Dir,
  890                           [ solutions(all) ])
  891    ).
  892
  893create_parent_dir(NewFile) :-
  894    file_directory_name(NewFile, Dir),
  895    create_parent_dir_(Dir).
  896
  897create_parent_dir_(Dir) :-
  898    exists_directory(Dir),
  899    '$my_file'(Dir),
  900    !.
  901create_parent_dir_(Dir) :-
  902    file_directory_name(Dir, Parent),
  903    Parent \== Dir,
  904    create_parent_dir_(Parent),
  905    make_directory(Dir).
  906
  907prolog:message(config(Id, Issue)) -->
  908    [ 'Config: '-[] ],
  909    config_description(Id),
  910    config_issue(Issue).
  911
  912config_description(init) -->
  913    [ '(user initialization file) '-[], nl ].
  914config_description(lib) -->
  915    [ '(user library) '-[], nl ].
  916config_description(pack) -->
  917    [ '(add-ons) '-[], nl ].
  918config_description(history) -->
  919    [ '(command line history) '-[], nl ].
  920config_description(xpce) -->
  921    [ '(gui) '-[], nl ].
  922
  923config_issue(move(Type, Old, New)) -->
  924    [ '  found ~w "~w"'-[Type, Old], nl ],
  925    [ '  new location is "~w"'-[New] ].
  926config_issue(moved(Type, Old, New)) -->
  927    [ '  found ~w "~w"'-[Type, Old], nl ],
  928    [ '  moved to new location "~w"'-[New] ].
  929config_issue(different(Type, Old, New)) -->
  930    [ '  found different ~w "~w"'-[Type, Old], nl ],
  931    [ '  new location is "~w"'-[New] ].
  932
  933		 /*******************************
  934		 *         AUTO LOADING		*
  935		 *******************************/
 check_autoload
Find possible ambiguous predicates in the autoload index.
  941check_autoload :-
  942    findall(Name/Arity, '$in_library'(Name, Arity, _Path), PIs),
  943    msort(PIs, Sorted),
  944    clumped(Sorted, Clumped),
  945    sort(2, >=, Clumped, ClumpedS),
  946    ambiguous_autoload(ClumpedS).
  947
  948ambiguous_autoload([PI-N|T]) :-
  949    N > 1,
  950    !,
  951    warn_ambiguous_autoload(PI),
  952    ambiguous_autoload(T).
  953ambiguous_autoload(_).
  954
  955warn_ambiguous_autoload(PI) :-
  956    PI = Name/Arity,
  957    findall(PlFile,
  958            ( '$in_library'(Name, Arity, File),
  959              file_name_extension(File, pl, PlFile)
  960            ), PlFiles),
  961    print_message(warning, installation(ambiguous_autoload(PI, PlFiles)))