View source with formatted comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        jan@swi-prolog.org
    5    WWW:           https://www.swi-prolog.org
    6    Copyright (c)  1995-2026, University of Amsterdam
    7                              VU University Amsterdam
    8                              CWI, Amsterdam
    9                              SWI-Prolog Solutions b.v.
   10    All rights reserved.
   11
   12    Redistribution and use in source and binary forms, with or without
   13    modification, are permitted provided that the following conditions
   14    are met:
   15
   16    1. Redistributions of source code must retain the above copyright
   17       notice, this list of conditions and the following disclaimer.
   18
   19    2. Redistributions in binary form must reproduce the above copyright
   20       notice, this list of conditions and the following disclaimer in
   21       the documentation and/or other materials provided with the
   22       distribution.
   23
   24    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   25    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   26    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   27    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   28    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   29    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   30    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   31    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   32    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   34    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   35    POSSIBILITY OF SUCH DAMAGE.
   36*/
   37
   38:- module(shlib,
   39          [ load_foreign_library/1,     % :LibFile
   40            load_foreign_library/2,     % :LibFile, +Options
   41            unload_foreign_library/1,   % +LibFile
   42            unload_foreign_library/2,   % +LibFile, +UninstallFunc
   43            current_foreign_library/2,  % ?LibFile, ?Public
   44            foreign_library_property/2, % ?File:atom, ?Property
   45            reload_foreign_libraries/0,
   46                                        % Directives
   47            use_foreign_library/1,      % :LibFile
   48            use_foreign_library/2       % :LibFile, +Options
   49          ]).   50:- if(current_predicate(win_add_dll_directory/2)).   51:- export(win_add_dll_directory/1).   52:- endif.   53
   54:- autoload(library(error),[existence_error/2]).   55:- autoload(library(lists),[member/2,reverse/2]).   56
   57%:- set_prolog_flag(generate_debug_info, false).
   58
   59/** <module> Utility library for loading foreign objects (DLLs, shared objects)
   60
   61This   section   discusses   the   functionality   of   the   (autoload)
   62library(shlib), providing an interface to   manage  shared libraries. We
   63describe the procedure for using a foreign  resource (DLL in Windows and
   64shared object in Unix) called =mylib=.
   65
   66First, one must  assemble  the  resource   and  make  it  compatible  to
   67SWI-Prolog.  The  details  for   this    vary   between  platforms.  The
   68``swipl-ld(1)`` utility can be used to  deal   with  this  in a portable
   69manner. The typical commandline is:
   70
   71```
   72swipl-ld -shared -o mylib file.{c,o,cc,C} ...
   73```
   74
   75Make  sure  that  one  of   the    files   provides  a  global  function
   76``install_mylib()``  that  initialises  the  module    using   calls  to
   77PL_register_foreign(). Below is a simple example file ``mylib.c``, which
   78prints a "hello" message. Note that we use SWI-Prolog's Sprintf() rather
   79than  C  standard  printf()  to  print    the  outout  through  Prolog's
   80`current_output`  stream,  making  the  example    work  in  a  windowed
   81environment. The standard C printf() works in a console environment, but
   82this bypasses Prolog's output redirection.  Also   note  the  use of the
   83standard C ``bool`` type, which is supported  in 9.2.x and more actively
   84promoted in the 9.3.x development series.
   85
   86```
   87#include <SWI-Prolog.h>
   88#include <SWI-Stream.h>
   89#include <stdbool.h>
   90
   91static foreign_t
   92pl_say_hello(term_t to)
   93{ char *s;
   94
   95  if ( PL_get_chars(to, &s, CVT_ALL|REP_UTF8) )
   96  { Sprintf("hello %Us", s);
   97
   98    return true;
   99  }
  100
  101  return false;
  102}
  103
  104install_t
  105install_mylib(void)
  106{ PL_register_foreign("say_hello", 1, pl_say_hello, 0);
  107}
  108```
  109
  110Now write a file mylib.pl:
  111
  112```
  113:- module(mylib, [ say_hello/1 ]).
  114:- use_foreign_library(foreign(mylib)).
  115```
  116
  117The file mylib.pl can be loaded as a normal Prolog file and provides the
  118predicate defined in C. The generated   ``mylib.so`` (or ``.dll``, etc.)
  119must be placed in a directory searched  for using the Prolog search path
  120`foreign` (see absolute_file_name/3). To  load   this  from  the current
  121directory, we can use the ``-p alias=dir`` option:
  122
  123```
  124swipl -p foreign=. mylib.pl
  125?- say_hello(world).
  126hello world
  127true.
  128```
  129*/
  130
  131:- meta_predicate
  132    load_foreign_library(:),
  133    load_foreign_library(:, +).  134
  135:- dynamic
  136    loading/1,                      % Lib
  137    error/2,                        % File, Error
  138    foreign_predicate/2,            % Lib, Pred
  139    current_library/5.              % Lib, Entry, Path, Module, Handle
  140
  141:- volatile                             % Do not store in state
  142    loading/1,
  143    error/2,
  144    foreign_predicate/2,
  145    current_library/5.  146
  147:- '$notransact'((loading/1,
  148                  error/2,
  149                  foreign_predicate/2,
  150                  current_library/5)).  151
  152:- (   current_prolog_flag(open_shared_object, true)
  153   ->  true
  154   ;   print_message(warning, shlib(not_supported)) % error?
  155   ).  156
  157% The flag `res_keep_foreign` prevents deleting  temporary files created
  158% to load shared objects when set  to   `true`.  This  may be needed for
  159% debugging purposes.
  160
  161:- create_prolog_flag(res_keep_foreign, false,
  162                      [ keep(true) ]).  163
  164
  165%!  use_foreign_library(+FileSpec) is det.
  166%!  use_foreign_library(+FileSpec, +Options:list) is det.
  167%
  168%   Load and install a foreign   library as load_foreign_library/1,2 and
  169%   register the installation using  initialization/2   with  the option
  170%   `now`. This is similar to using:
  171%
  172%   ```
  173%   :- initialization(load_foreign_library(foreign(mylib))).
  174%   ```
  175%
  176%   but using the initialization/1 wrapper  causes   the  library  to be
  177%   loaded _after_ loading of the file in which it appears is completed,
  178%   while use_foreign_library/1 loads the   library  _immediately_. I.e.
  179%   the difference is only relevant if the   remainder  of the file uses
  180%   functionality of the C-library.
  181%
  182%   As of SWI-Prolog 8.1.22, use_foreign_library/1,2 is in provided as a
  183%   built-in predicate that, if necessary,   loads  library(shlib). This
  184%   implies that these directives can be used without explicitly loading
  185%   library(shlib) or relying on demand loading.
  186
  187
  188                 /*******************************
  189                 *           DISPATCHING        *
  190                 *******************************/
  191
  192%!  find_library(+LibSpec, -Lib, -Delete) is det.
  193%
  194%   Find a foreign library from LibSpec.  If LibSpec is available as
  195%   a resource, the content of the resource is copied to a temporary
  196%   file and Delete is unified with =true=.
  197
  198find_library(Spec, TmpFile, true) :-
  199    '$rc_handle'(Zipper),
  200    term_to_atom(Spec, Name),
  201    setup_call_cleanup(
  202        zip_lock(Zipper),
  203        setup_call_cleanup(
  204            open_foreign_in_resources(Zipper, Name, In),
  205            setup_call_cleanup(
  206                tmp_file_stream(binary, TmpFile, Out),
  207                copy_stream_data(In, Out),
  208                close(Out)),
  209            close(In)),
  210        zip_unlock(Zipper)),
  211    !.
  212find_library(Spec, Lib, Copy) :-
  213    absolute_file_name(Spec, Lib0,
  214                       [ file_type(executable),
  215                         access(read),
  216                         file_errors(fail)
  217                       ]),
  218    !,
  219    lib_to_file(Lib0, Lib, Copy).
  220find_library(Spec, Spec, false) :-
  221    atom(Spec),
  222    !.                  % use machines finding schema
  223find_library(foreign(Spec), Spec, false) :-
  224    atom(Spec),
  225    !.                  % use machines finding schema
  226find_library(Spec, _, _) :-
  227    throw(error(existence_error(source_sink, Spec), _)).
  228
  229%!  lib_to_file(+Lib0, -Lib, -Copy) is det.
  230%
  231%   If Lib0 is not a regular file  we   need  to  copy it to a temporary
  232%   regular file because dlopen()  and   Windows  LoadLibrary() expect a
  233%   file name. On some systems this can   be  avoided. Roughly using two
  234%   approaches (after discussion with Peter Ludemann):
  235%
  236%     - On FreeBSD there is shm_open() to create an anonymous file in
  237%       memory and than fdlopen() to link this.
  238%     - In general, we could redefine the system calls open(), etc. to
  239%       make dlopen() work on non-files.  This is highly non-portably
  240%       though.
  241%     - We can mount the resource zip using e.g., `fuse-zip` on Linux.
  242%       This however fails if we include the resources as a string in
  243%       the executable.
  244%
  245%   @see https://github.com/fancycode/MemoryModule for Windows
  246
  247lib_to_file(Res, TmpFile, true) :-
  248    sub_atom(Res, 0, _, _, 'res://'),
  249    !,
  250    setup_call_cleanup(
  251        open(Res, read, In, [type(binary)]),
  252        setup_call_cleanup(
  253            tmp_file_stream(binary, TmpFile, Out),
  254            copy_stream_data(In, Out),
  255            close(Out)),
  256        close(In)).
  257lib_to_file(Lib, Lib, false).
  258
  259
  260open_foreign_in_resources(Zipper, ForeignSpecAtom, Stream) :-
  261    term_to_atom(foreign(Name), ForeignSpecAtom),
  262    zipper_members_(Zipper, Entries),
  263    entries_for_name(Entries, Name, Entries1),
  264    compatible_architecture_lib(Entries1, Name, CompatibleLib),
  265    zipper_goto(Zipper, file(CompatibleLib)),
  266    zipper_open_current(Zipper, Stream,
  267                        [ type(binary),
  268                          release(true)
  269                        ]).
  270
  271%!  zipper_members_(+Zipper, -Members) is det.
  272%
  273%   Simplified version of zipper_members/2 from library(zip). We already
  274%   have a lock  on  the  zipper  and   by  moving  this  here  we avoid
  275%   dependency on another library.
  276%
  277%   @tbd: should we cache this?
  278
  279zipper_members_(Zipper, Members) :-
  280    zipper_goto(Zipper, first),
  281    zip_members__(Zipper, Members).
  282
  283zip_members__(Zipper, [Name|T]) :-
  284    zip_file_info_(Zipper, Name, _Attrs),
  285    (   zipper_goto(Zipper, next)
  286    ->  zip_members__(Zipper, T)
  287    ;   T = []
  288    ).
  289
  290
  291%!  compatible_architecture_lib(+Entries, +Name, -CompatibleLib) is det.
  292%
  293%   Entries is a list of entries  in   the  zip  file, which are already
  294%   filtered to match the  shared  library   identified  by  `Name`. The
  295%   filtering is done by entries_for_name/3.
  296%
  297%   CompatibleLib is the name of the  entry   in  the  zip file which is
  298%   compatible with the  current  architecture.   The  compatibility  is
  299%   determined according to the description in qsave_program/2 using the
  300%   qsave:compat_arch/2 hook.
  301%
  302%   The entries are of the form 'shlib(Arch, Name)'
  303
  304compatible_architecture_lib([], _, _) :- !, fail.
  305compatible_architecture_lib(Entries, Name, CompatibleLib) :-
  306    current_prolog_flag(arch, HostArch),
  307    (   member(shlib(EntryArch, Name), Entries),
  308        qsave_compat_arch1(HostArch, EntryArch)
  309    ->  term_to_atom(shlib(EntryArch, Name), CompatibleLib)
  310    ;   existence_error(arch_compatible_with(Name), HostArch)
  311    ).
  312
  313qsave_compat_arch1(Arch1, Arch2) :-
  314    qsave:compat_arch(Arch1, Arch2), !.
  315qsave_compat_arch1(Arch1, Arch2) :-
  316    qsave:compat_arch(Arch2, Arch1), !.
  317
  318%!  qsave:compat_arch(Arch1, Arch2) is semidet.
  319%
  320%   User definable hook to establish if   Arch1 is compatible with Arch2
  321%   when running a shared object. It is used in saved states produced by
  322%   qsave_program/2 to determine which shared object to load at runtime.
  323%
  324%   @see `foreign` option in qsave_program/2 for more information.
  325
  326:- multifile qsave:compat_arch/2.  327
  328qsave:compat_arch(A,A).
  329
  330entries_for_name([], _, []).
  331entries_for_name([H0|T0], Name, [H|T]) :-
  332    shlib_atom_to_term(H0, H),
  333    match_filespec(Name, H),
  334    !,
  335    entries_for_name(T0, Name, T).
  336entries_for_name([_|T0], Name, T) :-
  337    entries_for_name(T0, Name, T).
  338
  339shlib_atom_to_term(Atom, shlib(Arch, Name)) :-
  340    sub_atom(Atom, 0, _, _, 'shlib('),
  341    !,
  342    term_to_atom(shlib(Arch,Name), Atom).
  343shlib_atom_to_term(Atom, Atom).
  344
  345match_filespec(Name, shlib(_,Name)).
  346
  347base(Path, Base) :-
  348    atomic(Path),
  349    !,
  350    file_base_name(Path, File),
  351    file_name_extension(Base, _Ext, File).
  352base(_/Path, Base) :-
  353    !,
  354    base(Path, Base).
  355base(Path, Base) :-
  356    Path =.. [_,Arg],
  357    base(Arg, Base).
  358
  359entry(_, Function, Function) :-
  360    Function \= default(_),
  361    !.
  362entry(Spec, default(FuncBase), Function) :-
  363    base(Spec, Base),
  364    atomic_list_concat([FuncBase, Base], '_', Function).
  365entry(_, default(Function), Function).
  366
  367                 /*******************************
  368                 *          (UN)LOADING         *
  369                 *******************************/
  370
  371%!  load_foreign_library(:FileSpec) is det.
  372%!  load_foreign_library(:FileSpec, +Options:list) is det.
  373%
  374%   Load a _|shared object|_ or _DLL_.  After loading the Entry function
  375%   is called without arguments. The default  entry function is composed
  376%   from =install_=, followed by the file base-name. E.g., the load-call
  377%   below  calls  the  function  =|install_mylib()|=.  If  the  platform
  378%   prefixes extern functions with =_=,  this   prefix  is  added before
  379%   calling. Options provided are below.  Other   options  are passed to
  380%   open_shared_object/3.
  381%
  382%     - install(+Function)
  383%       Installation function to use.  Default is default(install),
  384%       which derives the function from FileSpec.
  385%
  386%   ```
  387%       ...
  388%       load_foreign_library(foreign(mylib)),
  389%       ...
  390%   ```
  391%
  392%   @arg  FileSpec is a specification for absolute_file_name/3.  If searching
  393%         the file fails, the plain name is passed to the OS to try the default
  394%         method of the OS for locating foreign objects.  The default definition
  395%         of file_search_path/2 searches <prolog home>/lib/<arch> on Unix and
  396%         <prolog home>/bin on Windows.
  397%
  398%   @see  use_foreign_library/1,2 are intended for use in directives.
  399
  400load_foreign_library(Library) :-
  401    load_foreign_library(Library, []).
  402
  403load_foreign_library(Module:LibFile, InstallOrOptions) :-
  404    (   is_list(InstallOrOptions)
  405    ->  Options = InstallOrOptions
  406    ;   Options = [install(InstallOrOptions)]
  407    ),
  408    with_mutex('$foreign',
  409               load_foreign_library(LibFile, Module, Options)).
  410
  411load_foreign_library(LibFile, _Module, _) :-
  412    current_library(LibFile, _, _, _, _),
  413    !.
  414load_foreign_library(LibFile, Module, Options) :-
  415    retractall(error(_, _)),
  416    find_library(LibFile, Path, Delete),
  417    asserta(loading(LibFile)),
  418    retractall(foreign_predicate(LibFile, _)),
  419    catch(Module:open_shared_object(Path, Handle, Options), E, true),
  420    (   nonvar(E)
  421    ->  delete_foreign_lib(Delete, Path),
  422        assert(error(Path, E)),
  423        fail
  424    ;   delete_foreign_lib(Delete, Path)
  425    ),
  426    !,
  427    '$option'(install(DefEntry), Options, default(install)),
  428    (   entry(LibFile, DefEntry, Entry),
  429        Module:call_shared_object_function(Handle, Entry)
  430    ->  retractall(loading(LibFile)),
  431        assert_shlib(LibFile, Entry, Path, Module, Handle)
  432    ;   foreign_predicate(LibFile, _)
  433    ->  retractall(loading(LibFile)),    % C++ object installed predicates
  434        assert_shlib(LibFile, 'C++', Path, Module, Handle)
  435    ;   retractall(loading(LibFile)),
  436        retractall(foreign_predicate(LibFile, _)),
  437        close_shared_object(Handle),
  438        findall(Entry, entry(LibFile, DefEntry, Entry), Entries),
  439        throw(error(existence_error(foreign_install_function,
  440                                    install(Path, Entries)),
  441                    _))
  442    ).
  443load_foreign_library(LibFile, _, _) :-
  444    retractall(loading(LibFile)),
  445    (   error(_Path, E)
  446    ->  retractall(error(_, _)),
  447        throw(E)
  448    ;   throw(error(existence_error(foreign_library, LibFile), _))
  449    ).
  450
  451delete_foreign_lib(true, Path) :-
  452    \+ current_prolog_flag(res_keep_foreign, true),
  453    !,
  454    catch(delete_file(Path), _, true).
  455delete_foreign_lib(_, _).
  456
  457
  458%!  unload_foreign_library(+FileSpec) is det.
  459%!  unload_foreign_library(+FileSpec, +Exit:atom) is det.
  460%
  461%   Unload a _shared object_ or _DLL_.  After calling the Exit function,
  462%   the shared object is removed  from   the  process.  The default exit
  463%   function  is  composed  from  `uninstall_`,  followed  by  the  file
  464%   base-name.
  465
  466unload_foreign_library(LibFile) :-
  467    unload_foreign_library(LibFile, default(uninstall)).
  468
  469unload_foreign_library(LibFile, DefUninstall) :-
  470    with_mutex('$foreign', do_unload(LibFile, DefUninstall)).
  471
  472do_unload(LibFile, DefUninstall) :-
  473    current_library(LibFile, _, _, Module, Handle),
  474    retractall(current_library(LibFile, _, _, _, _)),
  475    (   entry(LibFile, DefUninstall, Uninstall),
  476        Module:call_shared_object_function(Handle, Uninstall)
  477    ->  true
  478    ;   true
  479    ),
  480    abolish_foreign(LibFile),
  481    close_shared_object(Handle).
  482
  483abolish_foreign(LibFile) :-
  484    (   retract(foreign_predicate(LibFile, Module:Head)),
  485        functor(Head, Name, Arity),
  486        abolish(Module:Name, Arity),
  487        fail
  488    ;   true
  489    ).
  490
  491system:'$foreign_registered'(M, H) :-
  492    (   loading(Lib)
  493    ->  true
  494    ;   Lib = '<spontaneous>'
  495    ),
  496    assert(foreign_predicate(Lib, M:H)).
  497
  498assert_shlib(File, Entry, Path, Module, Handle) :-
  499    retractall(current_library(File, _, _, _, _)),
  500    asserta(current_library(File, Entry, Path, Module, Handle)).
  501
  502
  503                 /*******************************
  504                 *       ADMINISTRATION         *
  505                 *******************************/
  506
  507%!  current_foreign_library(?File, ?Public)
  508%
  509%   Query currently loaded shared libraries.
  510
  511current_foreign_library(File, Public) :-
  512    current_library(File, _Entry, _Path, _Module, _Handle),
  513    findall(Pred, foreign_predicate(File, Pred), Public).
  514
  515%!  foreign_library_property(?File, ?Property) is nondet.
  516%
  517%   True when Property is  a  property   of  the  foreign  library File.
  518%   Currently defined properties are:
  519%
  520%     - module(Module)
  521%       Module context into which the library was loaded
  522%     - entry(Entry)
  523%       Name of the _install_ function used.
  524%     - absolute_file_name(Path)
  525%       Absolute file name for File when known.
  526%     - predicate(Pred)
  527%       Predicate registered by calling the entry function.
  528
  529foreign_library_property(File, module(Module)) :-
  530    current_library(File, _Entry, _Path, Module, _Handle).
  531foreign_library_property(File, entry(Entry)) :-
  532    current_library(File, Entry, _Path, _Module, _Handle).
  533foreign_library_property(File, absolute_file_name(Path)) :-
  534    current_library(File, _Entry, Path, _Module, _Handle).
  535foreign_library_property(File, predicate(Pred)) :-
  536    current_library(File, _Entry, _Path, _Module, _Handle),
  537    foreign_predicate(File, Pred).
  538
  539
  540                 /*******************************
  541                 *            RELOAD            *
  542                 *******************************/
  543
  544%!  reload_foreign_libraries
  545%
  546%   Reload all foreign libraries loaded (after restore of a state
  547%   created using qsave_program/2.
  548
  549reload_foreign_libraries :-
  550    findall(lib(File, Entry, Module),
  551            (   retract(current_library(File, Entry, _, Module, _)),
  552                File \== -
  553            ),
  554            Libs),
  555    reverse(Libs, Reversed),
  556    reload_libraries(Reversed).
  557
  558reload_libraries([]).
  559reload_libraries([lib(File, Entry, Module)|T]) :-
  560    (   load_foreign_library(File, Module, [install(Entry)])
  561    ->  true
  562    ;   print_message(error, shlib(File, load_failed))
  563    ),
  564    reload_libraries(T).
  565
  566
  567                 /*******************************
  568                 *     CLEANUP (WINDOWS ...)    *
  569                 *******************************/
  570
  571/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  572Called from Halt() in pl-os.c (if it  is defined), *after* all at_halt/1
  573hooks have been executed, and after   dieIO(),  closing and flushing all
  574files has been called.
  575
  576On Unix, this is not very useful, and can only lead to conflicts.
  577- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  578
  579unload_all_foreign_libraries :-
  580    current_prolog_flag(unload_foreign_libraries, true),
  581    !,
  582    forall(current_library(File, _, _, _, _),
  583           unload_foreign(File)).
  584unload_all_foreign_libraries.
  585
  586%!  unload_foreign(+File)
  587%
  588%   Unload the given foreign file and all `spontaneous' foreign
  589%   predicates created afterwards. Handling these spontaneous
  590%   predicates is a bit hard, as we do not know who created them and
  591%   on which library they depend.
  592
  593unload_foreign(File) :-
  594    unload_foreign_library(File),
  595    (   clause(foreign_predicate(Lib, M:H), true, Ref),
  596        (   Lib == '<spontaneous>'
  597        ->  functor(H, Name, Arity),
  598            abolish(M:Name, Arity),
  599            erase(Ref),
  600            fail
  601        ;   !
  602        )
  603    ->  true
  604    ;   true
  605    ).
  606
  607
  608:- if(current_predicate(win_add_dll_directory/2)).  609
  610%!  win_add_dll_directory(+AbsDir) is det.
  611%
  612%   Add AbsDir to the directories where   dependent DLLs are searched on
  613%   Windows systems. This  call  uses   the  AddDllDirectory()  API when
  614%   provided. On older Windows systems it extends ``%PATH%``.
  615%
  616%   @error existence_error(directory, AbsDir) if the target directory
  617%   does not exist.
  618%   @error domain_error(absolute_file_name, AbsDir) if AbsDir is not an
  619%   absolute file name.
  620
  621win_add_dll_directory(Dir) :-
  622    win_add_dll_directory(Dir, _),
  623    !.
  624win_add_dll_directory(Dir) :-
  625    prolog_to_os_filename(Dir, OSDir),
  626    getenv('PATH', Path0),
  627    atomic_list_concat([Path0, OSDir], ';', Path),
  628    setenv('PATH', Path).
  629
  630% Environments such as MSYS2 and  CONDA   install  DLLs in some separate
  631% directory. We add these directories to   the  search path for indirect
  632% dependencies from ours foreign plugins.
  633
  634add_dll_directories :-
  635    current_prolog_flag(msys2, true),
  636    !,
  637    env_add_dll_dir('MINGW_PREFIX', '/bin').
  638add_dll_directories :-
  639    current_prolog_flag(conda, true),
  640    !,
  641    env_add_dll_dir('CONDA_PREFIX', '/Library/bin'),
  642    ignore(env_add_dll_dir('PREFIX', '/Library/bin')).
  643add_dll_directories.
  644
  645env_add_dll_dir(Var, Postfix) :-
  646    getenv(Var, Prefix),
  647    atom_concat(Prefix, Postfix, Dir),
  648    win_add_dll_directory(Dir).
  649
  650:- initialization
  651    add_dll_directories.  652
  653:- endif.  654
  655		 /*******************************
  656		 *          SEARCH PATH		*
  657		 *******************************/
  658
  659:- dynamic
  660    user:file_search_path/2.  661:- multifile
  662    user:file_search_path/2.  663
  664:- if((current_prolog_flag(apple, true),
  665       current_prolog_flag(bundle, true))).  666user:file_search_path(foreign, swi('../../PlugIns/swipl')).
  667:- elif(current_prolog_flag(apple_universal_binary, true)).  668user:file_search_path(foreign, swi('lib/fat-darwin')).
  669:- elif((current_prolog_flag(windows, true),
  670	 current_prolog_flag(bundle, true))).  671user:file_search_path(foreign, swi(bin)).
  672:- else.  673user:file_search_path(foreign, swi(ArchLib)) :-
  674    current_prolog_flag(arch, Arch),
  675    atom_concat('lib/', Arch, ArchLib).
  676:- endif.  677
  678                 /*******************************
  679                 *            MESSAGES          *
  680                 *******************************/
  681
  682:- multifile
  683    prolog:message//1,
  684    prolog:error_message//1.  685
  686prolog:message(shlib(LibFile, load_failed)) -->
  687    [ '~w: Failed to load file'-[LibFile] ].
  688prolog:message(shlib(not_supported)) -->
  689    [ 'Emulator does not support foreign libraries' ].
  690
  691prolog:error_message(existence_error(foreign_install_function,
  692                                     install(Lib, List))) -->
  693    [ 'No install function in ~q'-[Lib], nl,
  694      '\tTried: ~q'-[List]
  695    ]