Sweep-module.so from the development release (9.4.2-1) not usable on macOS from emacs

As sweep is, more-or-less, recommended on the SWI-Prolog site and my preferred editor is indeed emacs, I tried to install the sweeprolog-mode, but failed to get things working.

I’m running on macOS 14.4.1 on Intel and arm64 CPU architecture.
I’ve installed:

Using MELPA I installed the sweeprolog package version 0.27.5. The only thing I needed to change is the swipl executable path from execute-path to /Applications/SWI-Prolog.app/Contents/MacOS/swipl

From this point I open a file and do M-x sweeprolog-mode, only to hear a bell and see in the Message buffer the following information being dumped (a little bit reformatted to make readable):

sweeprolog--load-module: Module could not be opened: "/Applications/SWI-Prolog.app/Contents/swipl/lib/fat-darwin/[sweep-module.so](http://sweep-module.so/)", "dlopen(/Applications/SWI-Prolog.app/Contents/swipl/lib/fat-darwin/[sweep-module.so](http://sweep-module.so/), 0x0009): Library not loaded: @rpath/libswipl.9.dylib

Referenced from: <43E45864-FF50-3BD1-A3FA-566C137489CF> /Applications/SWI-Prolog.app/Contents/swipl/lib/fat-darwin/[sweep-module.so](http://sweep-module.so/)

Reason: tried: 
'/System/Library/Frameworks/libswipl.9.dylib' (no such file, not in dyld cache),
'/System/Volumes/Preboot/Cryptexes/OS/System/Library/Frameworks/libswipl.9.dylib' (no such file),

Error during redisplay: (jit-lock-function 1) signaled (module-open-failed "/Applications/SWI-Prolog.app/Contents/swipl/lib/fat-darwin/[sweep-module.so](http://sweep-module.so/)" "dlopen(/Applications/SWI-Prolog.app/Contents/swipl/lib/fat-darwin/[sweep-module.so](http://sweep-module.so/), 0x0009): Library not loaded: @rpath/libswipl.9.dylib

Because I followed Eshel Yaron’s website on sweep during the installation, I emailed him and in the ensuing discussion he tends to agree with me that probably the @rpath linker setting in the build for sweep-module.so is probably wrong. (FYI, Eshel reported that he could reproduce the problem using the same build)

Developers on MacOS hate the SIP and tend to disable it thus allowing environment variables to point to dynamic libraries so the loader can find dylibs. But distributing static and dynamic libraries wil pose problems for users who (must) have SIP enabled. Because this is a trap I stepped in myself once to many, I enable SIP and learned to live with the limitations it imposed, and to take care of the correct settings during build.

In summary: the sweep-module.so from SWI-Prolog 9.4.2-1 is not usable on MacOS under common conditions (i.e. SIP enabled or no ld specific environment variables for dynamic library search paths).

/Twan

Hi Twan,

Thanks for following up with this issue here.
I think it’s worth noting that you’re using the “fat” app bundle, presumably from SWI-Prolog downloads. That’s the build with which I could reproduce this issue.
@jan do you think it’d be possible to change the rpath settings of the shared libraries in the bundle to allow loading sweep-module and libswipl from Emacs? I’m not very well versed in the CMake machinery but if it’s not an easy fix I can look into it and try to come up with something.

@oskardrums, thanks for picking up this issue. PceEmacs is usable up to a point (certainly for learning!) but a in bit more serious development, one would like to have a bit more “power” and flexibility at hand.

#fat app bundle
With regard to installing the ‘fat’ app bundle, it is essentially the only one (publicly?) available for download for MacOS!

#other modules
I’ld like to note that all libraries under fat-darwin are probably built under the same @rpath settings. And as the JPL module is of particular interest to me, though I haven’t had time to experiment with that yet, I hope I don’t experience similar problems.

/Twan

I see. The problem is that sweep-module.so links @rpath/libswipl.9.dylib. As Emacs is the main executable, @rpath points at the RPATH of Emacs.

JPL indeed has a similar issue. That is resolved using library(jpl_config), which uses install_name_tool to edit the binary.

I guess that is what we need to do here as well. Does this work:

install_name_tool sweep-module.so -change @rpath/libswipl.9.dylib /Applications/SWI-Prolog.app/Contents/Frameworks/libswipl.9.dylib

Alternatively, we could use this. That might be even better. It loading sweep works, we still might have problems loading the other plugins as our @rpath is wrong.

install_name_tool sweep-module.so -add_rpath /Applications/SWI-Prolog.app/Contents/Frameworks

You seem to understand fairly well what is going on, so maybe you can experiment a little and suggest a way out?

Thanks for taking a look.

Modifying sweep-module alone is not enough, unfortunately, since it depends on libswipl, which in turn tries to load libgmp from a location that is relative to the @executable_path.
A couple of install_name_tool libswipl -change commands can solve that too, and Sweep loads successfully.
Of course, hard-coding the absolute path /Applications/SWI-Prolog.app/Contents/ kinda hinders the relocatable nature of the app bundle. What do you think about using library-relative locations (with @loader_path) instead of executable-relative locations? That seems to work nicely even when the bundle is located elsewhere.

1 Like

That seems to be the way out. I didn’t know about @loader_path. Not sure where that needs to be done. There is both some CMake magic and scripts/macosx_bundle_fixup.sh involved. This script adds Qt and the dylibs from other dependencies to the bundle.

It seems from CMake, we only do (in cmake/port/Darwin.cmake)

  set(CMAKE_MACOSX_RPATH ON)

Possibly we should simply extend macosx_bundle_fixup.sh to set the paths the way we want them?

@oskardrums In reference to MacOS: Installing Frameworks ; if the intended is to share the libraries in fat-darwin amongst other applications and prorams on a MacOS system, I’afraid it is a losing proposition to keep shared libraries on MacOS in the application bundle’s Framework directory.

The current thinking at Apple is clearly geared towards sandboxed applications meaning that applications are using their “own” resource and/or use external (w.r.t to the scope of their sandbox) resources only by special permission or intermediation by specific security-focus services of MacOS. So, any attempt to deviate too much from their intended “architecture” is likely to run in constraints imposed on the system to enhance its security.

I think, but that could mean a significant overhaul of your development setup, you should split up the application bundle into

  1. Put the SWI-Prolog user facing applications in the SWI-Prolog.app bundle. That is, the ones based on Qt and X. The specific Qt and X libraries used for these applications are probably best left in the application bundle’s Frameworks directory,

  2. make the rest a “global” framework bundle installed in/Library/Frameworks. This is very similar to how the python distribution by python.org for MacOS is organised. MacPorts takes a similar approach. Applications with a graphical UIF are made application bundles and put in /Applications, other stuff is put under a common path /opt, and dylibs have absolute paths in their load commands.

Even though I suspect Apple from “nefarious” commercial reasons to put this kind of hurdles on dylib loading paths, there are genuine security reasons to do so. Having said that, when developing I too yearn for the past where MacOS was still more *nix like.

A bit of a warning: Much of Apple’s technical developer documentation relevant for this subject has now the status “archived”. I couldn’t find “current” documentation on frameworks and the current constraints applicable to frameworks.

/Twan

I see. That might indeed be the direction to go as we have similar problems making the bundle talk to Java, Python, R, etc.

In there is anyone who knows or likes to learn how to set this up, please step forward. I’m happy to explain the Prolog part of the setup. I’d be a lot happier if I do not need to make another deep dive into Apples policies :frowning:

@jan I’m considering to give it a try, but at this moment it would mean a pretty serious commitment of time.

My first (big) step would be to disentangle the Qt- and X-applications from the “core” SWI-Prolog parts and make that SWI-Prolog core a MacOS Framework reflecting the “architecture” of, say, Python. That in itself would be already a useful “product”.

The second (big) step would be to resurrect the X-applications as they are an important part of the SWI-Prolog tooling.

Personally, I have no interest in the Qt-application itself (I prefer the terminal version as its line editor works way beter). But when a proper SWI-Prolog Framework is available the adaption should be very easy.

In investigating how to perform the first step I’ll allow myself to deviate from the current “SWI-Prolog” conventions to achieve a workable MacOS Framework deliverable. And I’ll be happy to share the insights gained during that process with the regular maintainers (at this moment in time I can only guess who :wink: )

Currently my intended interest in Prolog is not directed to maintain a useful implementation on Apple MacOS ;-), but as “universal query language” for a semantic description of popular modelling language models and its metamodel. Which in itself is part of a long ongoing (private) research project. But I expect be done with a month or so with the current effort.

In other words, to be continued around the end of June.

/Twan

1 Like

Hi @twan, Thanks for considering. The plan sounds like big improvement. My main concern is that we keep something that is easily installed and gives the full user experience. That surely includes SWI-Prolog’s X (xpce) component. I don’t know what people think about the Qt console. Personally I agree with your observation that the terminal is typically easier to work with. But, surely beginners may like the menus and sometimes being able to open a second console while your application is running is quite nice.

There is no reason to hurry. I do not plan to make any changes that affect the packaging (except fixing immediate serious problems should these be reported).

Perhaps I’m missing a few terminal tricks, but the two things I find most vexing about the MacOS Terminal application:

  1. Can’t position the cursor using the mouse for editing the current input line; using the arrow keys for this is pretty tedious.
  2. No File menu for consulting/reloading. So no access to file selection dialog and no ability to define shortcut keys for these functions.

For all its issues, the Qt console just feels more intuitive to me - just like a simple text editor for input purposes.

Thanks for the observation. I said “personal”. I do most with the keyboard, so reusing commands means ^R to search and Emacs style editing. Reloading files is provided by make/0:

 ?- make.

Initial files are loaded by starting using (multiple files can be given, but that is rare).

swipl myfile.pl ...

If you need something on the file system, TAB based completion completes on file names (as well as atoms). To me, that is all comfortable. Others have different preferences, so we should not drop the Qt console :slight_smile: Yet other prefer the Emacs Prolog shell :slight_smile: They all have advantages and disadvantages …

One thing that makes file loading on the MacOS Terminal bearable is that I can drag any file from the Finder to the terminal and it expands to the absolute file path at the cursor position. Some prep work is required because you have to enclose it in square brackets (list) and quotes (string) to consult it, but that’s pretty manageable.

On MacOs you can reposition the cursor at the input focus (active command prompt) by hitting the end-key on a full keyboard (the key with an “underlined” vertical down arrow) or fn-down arrow key on other keyboards.

I think what you mean is that you can reposition the window view to the current input cursor position, but that’s not really what I want. I’d like to position the input cursor at an arbitrary position in the current input line using the mouse.

Just figured it out - I can use the Option key with a mouse click on the input line to position the cursor.