Ann: SWI-Prolog 10.1.11

SWI-Prolog Changelog since version 10.1.10

This release provides several improvements required by the SWI-Prolog
MCP server (pack mcp): support for HTTP SSE (Server Sent Events) and
additional APIs for various normally interactive tools (help,
profiler, coverage analysis, linter (check/0)) to allows LLMs to use
the stdin MCP server to query running Prolog processes.

The Windows version should now be able to run from a UNC path.

A major cleanup of open issues (dropped from 134 to less than 60) on
GitHub. Most were closed as already fixed, irrelevant, stale, etc.
A handful has been fixed.

Enjoy --- Jan

Highlights

  • FIXED: PL_initialise() no longer changes the process
    LC_NUMERIC locale (#1093), so embedders keep the C locale for
    atof() and printf("%f").

  • FIXED: clause indexing bug where a deep list index preempted
    a deterministic primary argument, leaving a spurious choice point
    (#1386).

  • FIXED: wrap_predicate/4 on meta-predicates now carries the
    module/determinism qualification, so tracing foldl/4 and friends
    resolves higher-order goals in the correct module (#1245).

  • FIXED: Windows UNC support for relative file names and shared
    object loading; absolute_file_name/3, access_file/2,
    open_shared_object/2 and use_foreign_library/1 now work when
    the working directory is a UNC path.

  • FIXED: nb_setval/2 did not duplicate a plain attributed
    variable (#1359).

  • FIXED: is_stream/1 crash on a standard stream alias whose
    slot is NULL.

  • FIXED: PL_get_stream() verifies the returned stream has the
    requested input/output mode (#1233) and rejects invalid modes.

  • FIXED: PL_get_text() with only CVT_STRING now raises
    type_error(string, X).

  • FIXED: number_string/2 type error (#695).

  • FIXED (clib): process_create/3 restores the signal mask in
    the child before exec, so the new process’s ITIMER_PROF timer
    actually delivers ticks and profile/1 no longer divides by zero.

  • FIXED (pack): dependency resolution now considers already
    installed packs when a pack’s requires is only discovered after
    download (e.g. installed from a URL).

  • FIXED (xpce terminal): DEC application cursor mode sent digit
    0 instead of capital O, so every arrow key in vim insert
    mode dropped back to normal mode and ran the wrong command.

  • ADDED (http): library(http/sse) server-sent events helper,
    honouring the http:cors setting.

  • ADDED: prolog_edit:locations/2 and help_apropos/4.

  • DOC: clarified absolute_file_name/3 default behaviour when
    the spec resolves to a directory (#782), and --home / the home
    Prolog flag in both the manual and the swipl(1) man page (#793).

  • BUILD: detect Intel-Mac Homebrew at /usr/local for dependency
    paths, fixing a broken Ninja graph on Intel Macs. Cross-build
    Prolog steps use a native friend with correct library and
    foreign search paths (#1503).

    Enjoy — Jan

Full ChangeLog

  • FIXED: #726 Less confusing message for unbound type in a
    type_error(Expected,Found) error.

  • BUILD: Setup library and foreign search paths in the build tree For
    cross-compilation using the native friend to run the Prolog steps
    of build, we need to setup library to point at the current (cross)
    target and foreign to point at the directories holding the foreign
    modules of the native friend.

  • BUILD: #1503 Simplify the way we setup paths for running in the
    build directory. The now aproach should notably fix getting paths
    setup correctly for running the Prolog build steps using a native
    friend
    , providing the ability to do cross building where we cannot
    run the cross-compiled executable and therefore use a native friend
    to perform these steps.

  • FIXED: #1093 PL_initialise() no longer mutates the process LC_NUMERIC
    locale initLocale() used to call setlocale(LC_NUMERIC, “”) to bootstrap
    the default PL_locale from localeconv(). As a side effect it changed
    the embedder’s process-wide decimal separator, breaking atof()
    and printf(“%f”) in host code that expects the C locale. Read the
    environment’s numeric conventions via newlocale()/uselocale() (POSIX
    2008) instead, with a save/setlocale/restore fallback under L_LOCALE
    for platforms without them. locale_create/3 uses the same helper.

  • FIXED: #1386 candidate deep list index preempting deterministic primary
    For a small static predicate whose primary argument discriminates
    but whose non-primary compound argument shares a top-level functor
    across clauses, set_candidate_indexes() emits a list hash index on
    the compound argument. At call time existing_hash() matched that
    index (top-level functor bound), the deep drill entered a sub-list
    whose inner arguments were variables, and the recursion fell back
    to next_clause_unindexed(), leaving a spurious choice point on the
    non-matching clause.

  • FIXED: #1245 wrap_predicate/4 supervisor to carry meta/det qualification
    prefix. $c_wrap_predicate/5 installed a bare S_CALLWRAPPER supervisor,
    bypassing the S_MQUAL/S_LMQUAL prefix that chainPredicateSupervisor()
    normally prepends for meta-predicates. Tracing a meta-predicate such
    as foldl/4 therefore lost the caller-module context on higher-order
    arguments, so the wrapped goal looked up prolog_trace:my_plus/3 rather
    than user:my_plus/3.

  • FIXED: PL_get_stream() invalid mode detection.

  • FIXED: #1233 PL_get_stream() to verify returned stream has correct
    (input/output) mode.

  • FIXED: #1359 nb_setval/2 did not duplicate a plain attvar.

  • DOC: #782 absolute_file_name/3 default behavior when spec resolves to a
    directory The docs claimed the predicate “only returns non-directories”
    unless file_type(directory) is given or access is none. Since the
    default access is none, that “unless” clause covers the default –
    but readers naturally miss it. Also, the file_type section stated
    the opposite of what the code does regarding when file_type(regular)
    is the default.

  • DOC: #793 clarify --home and the home Prolog flag Explain what
    the home directory is used for (boot.prc, library/) and distinguish
    the two forms of --home: with =DIR sets the home directory (and
    adds SWI_HOME_DIR to the environment); without argument reports
    the located home directory. Cross-reference the --home option,
    the home Prolog flag, and the findhome section from each other.
    Update both the swipl(1) man page and the user manual.

  • FIXED: Windows: UNC support for relative file names and shared object
    loading. When the process working directory is a UNC path (e.g. set
    via a Windows shortcut’s “Start in” field), resolving a relative
    file name via absolute_file_name/3, access_file/2 and friends failed,
    and open_shared_object/2, use_foreign_library/1 could not load DLLs
    identified by a UNC path.

  • FIXED: #695 number_string/2: correct type error.

  • FIXED: PL_get_text() with only CVT_STRING to return
    type_error(string, X)

  • FIXED: pack installer: consider installed packs when resolving
    dependencies When installing a pack whose requires only becomes known
    after download (e.g. installed from a URL), download_plan/3 recursed
    into pack_resolve/5 with only the just-downloaded plan as Existing,
    losing the list of locally installed packs. Dependencies already
    satisfied by an installed pack were then presented as fresh installs
    and, if the user declined, the whole install failed.

  • FIXED: require_prolog_version/2: Git version comparison.

  • BUILD: detect Intel-Mac Homebrew at /usr/local for dependency paths On
    Intel Macs, Homebrew installs to /usr/local rather than /opt/homebrew.
    The auto-detection in Darwin.cmake only checked /opt/homebrew,
    so Intel Mac users fell through to MACOSX_DEPENDENCIES_FROM=None,
    leaving LibArchive (and OpenSSL, BDB) unfound by CMake. This caused
    a broken man/archive file dependency in the Ninja build graph and a
    ninja failure.

  • ADDED: prolog_edit:locations/2, provide data access to location
    discovery.

  • ADDED: help_apropos/4, providing access to the apropos database.

  • FIXED: is_stream/1: crash when querying a standard stream alias whose
    slot is NULL. In a thread created without PL_THREAD_CUR_STREAMS the
    protocol slot is never copied, and freeStream() also resets it to
    NULL when the protocol stream is closed. get_stream_handle() then
    dereferenced LD->IO.streams[n] without a NULL check. The downstream
    code already treats NULL as “no such stream”, so just guard the
    SIO_CMAGIC test.

Package clib

  • FIXED: process_create/3: restore signal mask in child before
    exec SIGPROF is blocked around fork() to keep profiler ticks from
    interrupting it, but the previous mask was only restored in the parent.
    The child therefore inherited SIGPROF blocked across execve(), so the
    new process’s ITIMER_PROF profiler ran but no ticks were ever delivered.
    profile/1 then divided by zero in prolog_profile:show_profile_/1.

Package cpp

  • TEST: Fixed PL_get_stream() calls asking for the wrong in/out stream.

Package http

  • ADDED: library(http/sse): honour http:cors setting in sse_open/0,1
    Browser-based EventSource clients on a different origin need an
    Access-Control-Allow-Origin response header. sse_open/0,1 now calls
    cors_enable/0 from library(http/http_cors), so the existing http:cors
    setting controls whether the header is emitted. Non-browser clients
    and same-origin pages are unaffected (default setting is ).

  • ADDED: library(http/sse): high-level helper for Server-Sent Events
    sse_open/0,1 emits the response headers and switches the CGI output
    stream into event_stream transfer mode. sse_send/1,2 writes events
    given as a dict (with optional event, data, id, retry and comment
    keys), an atom/string, or a list of events, splitting multi-line data
    on ‘\n’ into separate “data:” lines. sse_comment/1,2 emits a heartbeat.

  • FIXED: cgi_stream: stop emitting a second header block when an
    event_stream handler returns For event_stream responses the headers are
    sent by cgi_hook(send_header) when the transfer encoding is selected,
    and each subsequent write is flushed straight through to the client.
    cgi_close() was still calling the send_header hook again, producing
    a spurious extra HTTP header block at the end of the body. Skip the
    call for event_stream; the chunked path is already special-cased.

Package xpce

  • FIXED: terminal: send capital ‘O’, not digit ‘0’, in DECCKM arrow
    keys In DEC application cursor mode (DECCKM, \e[?1h), arrow / Home /
    End should send SS3 sequences \eOA \eOB \eOC \eOD \eOH \eOF, but we
    sent the digit zero instead of capital O. Vim enables DECCKM via
    terminfo’s smkx, so every arrow press in insert mode bounced vim out
    of insert mode and ran “0” / “A” as normal-mode commands.

  • ENHANCED: terminal: DCS swallow, CSI intermediate bytes and OSC 10/11
    Vi/vim probes the terminal with sequences our parser did not recognise,
    which surfaced as ESCP, ESC\, Unknown ANSI CSI: \e[0% and Unknown OSC command: 11 messages, and left vim guessing the colour scheme.
    Handle them:

  • FIXED: Prevent help_message window from being destroyed.

Today’s update to the swipl-devel repository fails during the QLF compile phase on my macOS system (both M4 and Intel, running macOS Tahoe 26.3).

The build fails with the following error: ERROR: -g qlf_make: No permission to redefine module 'pce_edit' (Already loaded from .../home/xpce/prolog/lib/swi_edit.pl)

This occurs even after a full git clean -fdx and a fresh cmake configuration. It appears to be a regression in the current bootstrap sequence.

Thanks for reporting. Pushed a fix. I thought a module name was misspelled … Anyway, pce_edit.pl was obsolete stuff and is now removed. Using an incremental build you have to remove the pce_edit.pl link in home before rebuilding. Either find the file or simply do rm -r home/xpce to remove all xpce files. It will rebuild them :slight_smile: