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-2019, VU University Amsterdam
    7                              CWI, Amsterdam
    8    All rights reserved.
    9
   10    Redistribution and use in source and binary forms, with or without
   11    modification, are permitted provided that the following conditions
   12    are met:
   13
   14    1. Redistributions of source code must retain the above copyright
   15       notice, this list of conditions and the following disclaimer.
   16
   17    2. Redistributions in binary form must reproduce the above copyright
   18       notice, this list of conditions and the following disclaimer in
   19       the documentation and/or other materials provided with the
   20       distribution.
   21
   22    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   23    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   24    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   25    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   26    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   27    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   28    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   29    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   30    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   32    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   33    POSSIBILITY OF SUCH DAMAGE.
   34*/
   35
   36:- module(check_installation,
   37          [ check_installation/0,
   38            check_installation/1,               % -Issues
   39            check_config_files/0,
   40            update_config_files/0,
   41            test_installation/0,
   42            test_installation/1                 % +Options
   43          ]).   44:- autoload(library(apply),[maplist/2,maplist/3]).   45:- autoload(library(archive),[archive_open/3,archive_close/1]).   46:- autoload(library(lists),[append/3,member/2]).   47:- autoload(library(option),[option/2,merge_options/3]).   48:- autoload(library(pcre),[re_config/1]).   49:- autoload(library(prolog_source),[path_segments_atom/2]).   50:- use_module(library(settings),[setting/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.
   83% Feature tests
   84component(tcmalloc,
   85          _{ optional:true,
   86             test:test_tcmalloc,
   87             url:'tcmalloc.html'
   88           }).
   89component(gmp,
   90          _{ test:current_prolog_flag(bounded, false),
   91             url:'gmp.html'
   92           }).
   93% Packages that depend on foreign libraries
   94component(library(archive), _{features:archive_features}).
   95component(library(cgi), _{}).
   96component(library(crypt), _{}).
   97component(library(bdb), _{}).
   98component(library(double_metaphone), _{}).
   99component(library(filesex), _{}).
  100component(library(http/http_stream), _{}).
  101component(library(http/json), _{}).
  102component(library(http/jquery), _{features:jquery_file}).
  103component(library(isub), _{}).
  104component(library(jpl), _{}).
  105component(library(memfile), _{}).
  106component(library(odbc), _{}).
  107component(library(pce),
  108          _{pre:use_foreign_library(pce_principal:foreign(pl2xpce)),
  109            url:'xpce.html'}).
  110component(library(pcre), _{features:pcre_features}).
  111component(library(pdt_console), _{}).
  112component(library(porter_stem), _{}).
  113component(library(process), _{}).
  114component(library(protobufs), _{}).
  115component(library(editline), _{os:unix}).
  116component(library(readline), _{os:unix}).
  117component(library(readutil), _{}).
  118component(library(rlimit), _{os:unix}).
  119component(library(semweb/rdf_db), _{}).
  120component(library(semweb/rdf_ntriples), _{}).
  121component(library(semweb/turtle), _{}).
  122component(library(sgml), _{}).
  123component(library(sha), _{}).
  124component(library(snowball), _{}).
  125component(library(socket), _{}).
  126component(library(ssl), _{}).
  127component(library(crypto), _{}).
  128component(library(syslog), _{os:unix}).
  129component(library(table), _{}).
  130component(library(time), _{}).
  131component(library(tipc/tipc), _{os:linux}).
  132component(library(unicode), _{}).
  133component(library(uri), _{}).
  134component(library(uuid), _{}).
  135component(library(zlib), _{}).
  136component(library(yaml), _{}).
  137
  138issue_base('http://www.swi-prolog.org/build/issues/').
  139
  140:- thread_local
  141    issue/1.  142
  143:- meta_predicate
  144    run_silent(0, +).
 check_installation
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.

  161check_installation :-
  162    print_message(informational, installation(checking)),
  163    check_installation_(InstallIssues),
  164    check_on_path,
  165    check_config_files(ConfigIssues),
  166    maplist(print_message(warning), ConfigIssues),
  167    append(InstallIssues, ConfigIssues, Issues),
  168    (   Issues == []
  169    ->  print_message(informational, installation(perfect))
  170    ;   length(Issues, Count),
  171        print_message(warning, installation(imperfect(Count)))
  172    ).
 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).
  182check_installation(Issues) :-
  183    check_installation_(Issues0),
  184    maplist(public_issue, Issues0, Issues).
  185
  186public_issue(installation(Term), Source-Issue) :-
  187    functor(Term, Issue, _),
  188    arg(1, Term, Properties),
  189    Source = Properties.source.
  190
  191check_installation_(Issues) :-
  192    retractall(issue(_)),
  193    forall(component(Source, _Properties),
  194           check_component(Source)),
  195    findall(I, retract(issue(I)), Issues).
  196
  197check_component(Source) :-
  198    component(Source, Properties),
  199    !,
  200    check_component(Source, Properties.put(source,Source)).
  201
  202check_component(Source, Properties) :-
  203    compound(Source),
  204    !,
  205    check_source(Source, Properties).
  206check_component(Feature, Properties) :-
  207    print_message(informational, installation(checking(Feature))),
  208    (   call(Properties.test)
  209    ->  print_message(informational, installation(ok))
  210    ;   print_issue(installation(missing(Properties)))
  211    ).
  212
  213check_source(_Source, Properties) :-
  214    OS = Properties.get(os),
  215    \+ current_os(OS),
  216    !.
  217check_source(Source, Properties) :-
  218    exists_source(Source),
  219    !,
  220    print_message(informational, installation(loading(Source))),
  221    (   run_silent(( (   Pre = Properties.get(pre)
  222                     ->  call(Pre)
  223                     ;   true
  224                     ),
  225                     load_files(Source, [silent(true), if(not_loaded)])
  226                   ),
  227                   Properties.put(action, load))
  228    ->  test_component(Properties),
  229        print_message(informational, installation(ok)),
  230        check_features(Properties)
  231    ;   true
  232    ).
  233check_source(_Source, Properties) :-
  234    Properties.get(optional) == true,
  235    !,
  236    print_message(silent,
  237                  installation(optional_not_found(Properties))).
  238check_source(_Source, Properties) :-
  239    print_issue(installation(not_found(Properties))).
  240
  241current_os(unix)    :- current_prolog_flag(unix, true).
  242current_os(windows) :- current_prolog_flag(windows, true).
  243current_os(linux)   :- current_prolog_flag(arch, Arch), sub_atom(Arch, _, _, _, linux).
 test_component(+Properties) is semidet
Run additional tests to see whether the component really works.
  249test_component(Dict) :-
  250    Test = Dict.get(test),
  251    !,
  252    call(Test).
  253test_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.
  262check_features(Dict) :-
  263    Test = Dict.get(features),
  264    !,
  265    call(Test).
  266check_features(_).
 run_silent(:Goal, +Properties) is semidet
Succeed if Goal succeeds and does not print any errors or warnings.
  274run_silent(Goal, Properties) :-
  275    run_collect_messages(Goal, Result, Messages),
  276    (   Result == true,
  277        Messages == []
  278    ->  true
  279    ;   print_issue(installation(failed(Properties, Result, Messages))),
  280        fail
  281    ).
 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.
  293:- thread_local
  294    got_message/1.  295
  296run_collect_messages(Goal, Result, Messages) :-
  297    setup_call_cleanup(
  298        asserta((user:thread_message_hook(Term,Kind,Lines) :-
  299                    error_kind(Kind),
  300                    assertz(got_message(message(Term,Kind,Lines)))), Ref),
  301        (   catch(Goal, E, true)
  302        ->  (   var(E)
  303            ->  Result0 = true
  304            ;   Result0 = exception(E)
  305            )
  306        ;   Result0 = false
  307        ),
  308        erase(Ref)),
  309    findall(Msg, retract(got_message(Msg)), Messages),
  310    Result = Result0.
  311
  312error_kind(warning).
  313error_kind(error).
  314
  315
  316                 /*******************************
  317                 *         SPECIAL TESTS        *
  318                 *******************************/
 test_tcmalloc
  322:- if(current_predicate(malloc_property/1)).  323test_tcmalloc :-
  324    malloc_property('generic.current_allocated_bytes'(Bytes)),
  325    Bytes > 1 000 000.
  326:- else.  327test_tcmalloc :-
  328    fail.
  329:- endif.
 archive_features
Report features supported by library(archive).
  335archive_features :-
  336    tmp_file_stream(utf8, Name, Out),
  337    close(Out),
  338    findall(F, archive_filter(F, Name), Filters),
  339    print_message(informational, installation(archive(filters, Filters))),
  340    findall(F, archive_format(F, Name), Formats),
  341    print_message(informational, installation(archive(formats, Formats))),
  342    delete_file(Name).
  343
  344archive_filter(F, Name) :-
  345    a_filter(F),
  346    catch(archive_open(Name, A, [filter(F)]), E, true),
  347    (   var(E)
  348    ->  archive_close(A)
  349    ;   true
  350    ),
  351    \+ subsumes_term(error(domain_error(filter, _),_), E).
  352
  353archive_format(F, Name) :-
  354    a_format(F),
  355    catch(archive_open(Name, A, [format(F)]), E, true),
  356    (   var(E)
  357    ->  archive_close(A)
  358    ;   true
  359    ),
  360    \+ subsumes_term(error(domain_error(format, _),_), E).
  361
  362a_filter(bzip2).
  363a_filter(compress).
  364a_filter(gzip).
  365a_filter(grzip).
  366a_filter(lrzip).
  367a_filter(lzip).
  368a_filter(lzma).
  369a_filter(lzop).
  370a_filter(none).
  371a_filter(rpm).
  372a_filter(uu).
  373a_filter(xz).
  374
  375a_format('7zip').
  376a_format(ar).
  377a_format(cab).
  378a_format(cpio).
  379a_format(empty).
  380a_format(gnutar).
  381a_format(iso9660).
  382a_format(lha).
  383a_format(mtree).
  384a_format(rar).
  385a_format(raw).
  386a_format(tar).
  387a_format(xar).
  388a_format(zip).
 pcre_features
  392pcre_features :-
  393    findall(X, pcre_missing(X), Missing),
  394    (   Missing == []
  395    ->  true
  396    ;   print_message(warning, installation(pcre_missing(Missing)))
  397    ),
  398    (   re_config(compiled_widths(Widths)),
  399        1 =:= Widths /\ 1
  400    ->  true
  401    ;   print_message(warning, installation(pcre_missing('8-bit support')))
  402    ).
  403
  404pcre_missing(X) :-
  405    pcre_must_have(X),
  406    Term =.. [X,true],
  407    \+ catch(re_config(Term), _, fail).
  408
  409pcre_must_have(unicode).
 jquery_file
Test whether jquery.js can be found
  415jquery_file :-
  416    setting(jquery:version, File),
  417    (   absolute_file_name(js(File), Path, [access(read), file_errors(fail)])
  418    ->  print_message(informational, installation(jquery(found(Path))))
  419    ;   print_message(warning, installation(jquery(not_found(File))))
  420    ).
 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.
  429check_on_path :-
  430    current_prolog_flag(executable, EXEFlag),
  431    prolog_to_os_filename(EXE, EXEFlag),
  432    file_base_name(EXE, Prog),
  433    absolute_file_name(EXE, AbsExe,
  434                       [ access(execute),
  435                         file_errors(fail)
  436                       ]),
  437    !,
  438    prolog_to_os_filename(AbsExe, OsExe),
  439    (   absolute_file_name(path(Prog), OnPath,
  440                           [ access(execute),
  441                             file_errors(fail)
  442                           ])
  443    ->  (   same_file(EXE, OnPath)
  444        ->  true
  445        ;   absolute_file_name(path(Prog), OnPathAny,
  446                               [ access(execute),
  447                                 file_errors(fail),
  448                                 solutions(all)
  449                               ]),
  450            same_file(EXE, OnPathAny)
  451        ->  print_message(warning, installation(not_first_on_path(OsExe, OnPath)))
  452        ;   print_message(warning, installation(not_same_on_path(OsExe, OnPath)))
  453        )
  454    ;   print_message(warning, installation(not_on_path(OsExe, Prog)))
  455    ).
  456check_on_path.
  457
  458
  459		 /*******************************
  460		 *           RUN TESTS		*
  461		 *******************************/
 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.
  478test_installation :-
  479    test_installation([]).
  480
  481test_installation(Options) :-
  482    absolute_file_name(swi(test/test),
  483                       TestFile,
  484                       [ access(read),
  485                         file_errors(fail),
  486                         file_type(prolog)
  487                       ]),
  488    !,
  489    test_installation_run(TestFile, Options).
  490test_installation(_Options) :-
  491    print_message(warning, installation(testing(no_installed_tests))).
  492
  493test_installation_run(TestFile, Options) :-
  494    (   option(package(_), Options)
  495    ->  merge_options(Options,
  496                      [ core(false),
  497                        subdirs(false)
  498                      ], TestOptions)
  499    ;   merge_options(Options,
  500                      [ packages(true)
  501                      ], TestOptions)
  502    ),
  503    load_files(user:TestFile),
  504    current_prolog_flag(verbose, Old),
  505    setup_call_cleanup(
  506        set_prolog_flag(verbose, silent),
  507        user:test([], TestOptions),
  508        set_prolog_flag(verbose, Old)).
  509
  510
  511                 /*******************************
  512                 *            MESSAGES          *
  513                 *******************************/
  514
  515:- multifile
  516    prolog:message//1.  517
  518print_issue(Term) :-
  519    assertz(issue(Term)),
  520    print_message(warning, Term).
  521
  522issue_url(Properties, URL) :-
  523    Local = Properties.get(url),
  524    !,
  525    issue_base(Base),
  526    atom_concat(Base, Local, URL).
  527issue_url(Properties, URL) :-
  528    Properties.get(source) = library(Segments),
  529    !,
  530    path_segments_atom(Segments, Base),
  531    file_name_extension(Base, html, URLFile),
  532    issue_base(Issues),
  533    atom_concat(Issues, URLFile, URL).
  534
  535prolog:message(installation(Message)) -->
  536    message(Message).
  537
  538message(checking) -->
  539    { current_prolog_flag(address_bits, Bits) },
  540    { current_prolog_flag(arch, Arch) },
  541    { current_prolog_flag(home, Home) },
  542    { current_prolog_flag(cpu_count, Cores) },
  543    [ 'Checking your SWI-Prolog kit for common issues ...'-[], nl, nl ],
  544    [ 'Version: ~`.t~24| '-[] ], '$messages':prolog_message(version), [nl],
  545    [ 'Address bits: ~`.t~24| ~d'-[Bits] ], [nl],
  546    [ 'Architecture: ~`.t~24| ~w'-[Arch] ], [nl],
  547    [ 'Installed at: ~`.t~24| ~w'-[Home] ], [nl],
  548    [ 'Cores: ~`.t~24| ~w'-[Cores] ], [nl],
  549    [ nl ].
  550message(perfect) -->
  551    [ nl, 'Congratulations, your kit seems sound and complete!'-[] ].
  552message(imperfect(N)) -->
  553    [ 'Found ~w issues.'-[N] ].
  554message(checking(Feature)) -->
  555    [ 'Checking ~w ...'-[Feature], flush ].
  556message(missing(Properties)) -->
  557    [ at_same_line, '~`.t~48| not present'-[] ],
  558    details(Properties).
  559message(loading(Source)) -->
  560    [ 'Loading ~q ...'-[Source], flush ].
  561message(ok) -->
  562    [ at_same_line, '~`.t~48| ok'-[] ].
  563message(optional_not_found(Properties)) -->
  564    [ 'Optional ~q ~`.t~48| not present'-[Properties.source] ].
  565message(not_found(Properties)) -->
  566    [ '~q ~`.t~48| NOT FOUND'-[Properties.source] ],
  567    details(Properties).
  568message(failed(Properties, false, [])) -->
  569    !,
  570    [ at_same_line, '~`.t~48| FAILED'-[] ],
  571    details(Properties).
  572message(failed(Properties, exception(Ex0), [])) -->
  573    !,
  574    { strip_stack(Ex0, Ex),
  575      message_to_string(Ex, Msg) },
  576    [ '~w'-[Msg] ],
  577    details(Properties).
  578message(failed(Properties, true, Messages)) -->
  579    [ at_same_line, '~`.t~48| FAILED'-[] ],
  580    explain(Messages),
  581    details(Properties).
  582message(archive(What, Names)) -->
  583    [ '  Supported ~w: '-[What] ],
  584    list_names(Names).
  585message(pcre_missing(Features)) -->
  586    [ 'Missing libpcre features: '-[] ],
  587    list_names(Features).
  588message(not_first_on_path(EXE, OnPath)) -->
  589    { public_executable(EXE, PublicEXE),
  590      file_base_name(EXE, Prog)
  591    },
  592    [ 'The first ~w on '-[Prog] ], 'PATH', [ ' is ~p, while '-[OnPath], nl ],
  593    [ 'this version is ~p.'-[PublicEXE] ].
  594message(not_same_on_path(EXE, OnPath)) -->
  595    { public_executable(EXE, PublicEXE),
  596      file_base_name(EXE, Prog)
  597    },
  598    [ 'The ~w on '-[Prog] ], 'PATH', [ ' is ~p, while '-[OnPath], nl ],
  599    [ 'this version is ~p.'-[PublicEXE] ].
  600message(not_on_path(EXE, Prog)) -->
  601    { public_bin_dir(EXE, Dir),
  602      prolog_to_os_filename(Dir, OSDir)
  603    },
  604    [ 'Could not find ~w on '-[Prog] ], 'PATH', [ '. '-[], nl ],
  605    [ 'You may wish to add ~p to '-[OSDir] ], 'PATH', [ '. '-[], nl ].
  606message(jquery(found(Path))) -->
  607    [ '  jQuery from ~w'-[Path] ].
  608message(jquery(not_found(File))) -->
  609    [ '  Cannot find jQuery (~w)'-[File] ].
  610message(testing(no_installed_tests)) -->
  611    [ '  Runtime testing is not enabled.', nl],
  612    [ '  Please recompile the system with INSTALL_TESTS enabled.' ].
  613
  614
  615public_executable(EXE, PublicProg) :-
  616    file_base_name(EXE, Prog),
  617    file_directory_name(EXE, ArchDir),
  618    file_directory_name(ArchDir, BinDir),
  619    file_directory_name(BinDir, Home),
  620    file_directory_name(Home, Lib),
  621    file_directory_name(Lib, Prefix),
  622    atomic_list_concat([Prefix, bin, Prog], /, PublicProg),
  623    exists_file(PublicProg),
  624    same_file(EXE, PublicProg),
  625    !.
  626public_executable(EXE, EXE).
  627
  628public_bin_dir(EXE, Dir) :-
  629    public_executable(EXE, PublicEXE),
  630    file_directory_name(PublicEXE, Dir).
  631
  632
  633
  634'PATH' -->
  635    { current_prolog_flag(windows, true) },
  636    !,
  637    [ '%PATH%'-[] ].
  638'PATH' -->
  639    [ '$PATH'-[] ].
  640
  641strip_stack(error(Error, context(prolog_stack(S), Msg)),
  642            error(Error, context(_, Msg))) :-
  643    nonvar(S).
  644strip_stack(Error, Error).
  645
  646details(Properties) -->
  647    { issue_url(Properties, URL), !
  648    },
  649    [ nl, 'See ~w'-[URL] ].
  650details(_) --> [].
  651
  652explain(Messages) -->
  653    { Messages = [message(error(shared_object(open, _Message), _), _, _)|_]
  654    },
  655    !,
  656    [nl],
  657    (   { current_prolog_flag(windows, true) }
  658    ->  [ 'Cannot load required DLL'-[] ]
  659    ;   [ 'Cannot load required shared library'-[] ]
  660    ).
  661explain(Messages) -->
  662    print_messages(Messages).
  663
  664print_messages([]) --> [].
  665print_messages([message(_Term, _Kind, Lines)|T]) -->
  666    Lines, [nl],
  667    print_messages(T).
  668
  669list_names([]) --> [].
  670list_names([H|T]) -->
  671    [ '~w'-[H] ],
  672    (   {T==[]}
  673    ->  []
  674    ;   [ ', '-[] ],
  675        list_names(T)
  676    ).
  677
  678
  679		 /*******************************
  680		 *          CONFIG FILES	*
  681		 *******************************/
 check_config_files
Examines the locations of config files. The config files have moved in version 8.1.15
  688check_config_files :-
  689    check_config_files(Issues),
  690    maplist(print_message(warning), Issues).
  691
  692check_config_files(Issues) :-
  693    findall(Issue, check_config_file(Issue), Issues).
  694
  695check_config_file(config(Id, move(Type, OldFile, NewFile))) :-
  696    old_config(Type, Id, OldFile),
  697    access_file(OldFile, exist),
  698    \+ ( new_config(Type, Id, NewFile),
  699         access_file(NewFile, exist)
  700       ),
  701    once(new_config(Type, Id, NewFile)).
  702check_config_file(config(Id, different(Type, OldFile, NewFile))) :-
  703    old_config(Type, Id, OldFile),
  704    access_file(OldFile, exist),
  705    new_config(Type, Id, NewFile),
  706    access_file(NewFile, exist),
  707    \+ 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.
  714update_config_files :-
  715    old_config(Type, Id, OldFile),
  716    access_file(OldFile, exist),
  717    \+ ( new_config(Type, Id, NewFile),
  718         access_file(NewFile, exist)
  719       ),
  720    (   new_config(Type, Id, NewFile),
  721        \+ same_file(OldFile, NewFile),
  722        create_parent_dir(NewFile)
  723    ->  catch(rename_file(OldFile, NewFile), E,
  724              print_message(warning, E)),
  725        print_message(informational, config(Id, moved(Type, OldFile, NewFile)))
  726    ),
  727    fail.
  728update_config_files.
  729
  730old_config(file, init, File) :-
  731    current_prolog_flag(windows, true),
  732    win_folder(appdata, Base),
  733    atom_concat(Base, '/SWI-Prolog/swipl.ini', File).
  734old_config(file, init, File) :-
  735    expand_file_name('~/.swiplrc', [File]).
  736old_config(directory, lib, Dir) :-
  737    expand_file_name('~/lib/prolog', [Dir]).
  738old_config(directory, xpce, Dir) :-
  739    expand_file_name('~/.xpce', [Dir]).
  740old_config(directory, history, Dir) :-
  741    expand_file_name('~/.swipl-dir-history', [Dir]).
  742old_config(directory, pack, Dir) :-
  743    (   catch(expand_file_name('~/lib/swipl/pack', [Dir]), _, fail)
  744    ;   absolute_file_name(swi(pack), Dir,
  745                           [ file_type(directory), solutions(all) ])
  746    ).
  747
  748new_config(file, init, File) :-
  749    absolute_file_name(user_app_config('init.pl'), File,
  750                       [ solutions(all) ]).
  751new_config(directory, lib, Dir) :-
  752    config_dir(user_app_config(lib), Dir).
  753new_config(directory, xpce, Dir) :-
  754    config_dir(user_app_config(xpce), Dir).
  755new_config(directory, history, Dir) :-
  756    config_dir(user_app_config('dir-history'), Dir).
  757new_config(directory, pack, Dir) :-
  758    config_dir([app_data(pack), swi(pack)], Dir).
  759
  760config_dir(Aliases, Dir) :-
  761    is_list(Aliases),
  762    !,
  763    (   member(Alias, Aliases),
  764        absolute_file_name(Alias, Dir,
  765                           [ file_type(directory), solutions(all) ])
  766    *-> true
  767    ;   member(Alias, Aliases),
  768        absolute_file_name(Alias, Dir,
  769                           [ solutions(all) ])
  770    ).
  771config_dir(Alias, Dir) :-
  772    (   absolute_file_name(Alias, Dir,
  773                           [ file_type(directory), solutions(all) ])
  774    *-> true
  775    ;   absolute_file_name(Alias, Dir,
  776                           [ solutions(all) ])
  777    ).
  778
  779create_parent_dir(NewFile) :-
  780    file_directory_name(NewFile, Dir),
  781    create_parent_dir_(Dir).
  782
  783create_parent_dir_(Dir) :-
  784    exists_directory(Dir),
  785    '$my_file'(Dir),
  786    !.
  787create_parent_dir_(Dir) :-
  788    file_directory_name(Dir, Parent),
  789    Parent \== Dir,
  790    create_parent_dir_(Parent),
  791    make_directory(Dir).
  792
  793prolog:message(config(Id, Issue)) -->
  794    [ 'Config: '-[] ],
  795    config_description(Id),
  796    config_issue(Issue).
  797
  798config_description(init) -->
  799    [ '(user initialization file) '-[], nl ].
  800config_description(lib) -->
  801    [ '(user library) '-[], nl ].
  802config_description(pack) -->
  803    [ '(add-ons) '-[], nl ].
  804config_description(history) -->
  805    [ '(command line history) '-[], nl ].
  806config_description(xpce) -->
  807    [ '(gui) '-[], nl ].
  808
  809config_issue(move(Type, Old, New)) -->
  810    [ '  found ~w "~w"'-[Type, Old], nl ],
  811    [ '  new location is "~w"'-[New] ].
  812config_issue(moved(Type, Old, New)) -->
  813    [ '  found ~w "~w"'-[Type, Old], nl ],
  814    [ '  moved to new location "~w"'-[New] ].
  815config_issue(different(Type, Old, New)) -->
  816    [ '  found different ~w "~w"'-[Type, Old], nl ],
  817    [ '  new location is "~w"'-[New] ]