Swift 5.2 and Fedora Linux – REPL issues

Swift 5.2 (and quickly followed up with Swift 5.2.1) were released in late March and, while it is packaged up and ready-to-go as an RPM for Fedora/CentOS/RHEL users, it's not "ready to go" insofar as not all the functionality works. Specifically, while the package does compile Swift code, the REPL does not work. I've been trying to discern why for a long time and, while I have figured out how to make it work, it would not pass muster as a distro-provided RPM. At the moment I'm not quite sure what to do and would appreciate any feedback on how to proceed.

Prelude - What's going on here?

I have a public repo that contains all the scripts, patches, etc., that is used to build Swift for Fedora (along with CentOS and RHEL, but I'm just going to keep saying Fedora; assume the other two distros as well) and I have been tracking 5.2 development in its own branch while 5.1.x was still considered production. On first blush, 5.2 didn't have many significant changes over the 5.1.x versions, but while it was relatively easy to get the entire toolchain to compile and build, the REPL in 5.2 was broken from the very start.

"Broken" is a loaded word and I should note that, built as-is without any patches to relocate Swift executables, everything works fine. Hunky-dory. Woo. For background, the Swift toolchain, as provided by Apple for Ubuntu, for example, has its own usr directory structure (e.g. usr/bin,usr/include, etc.) and is meant to be extracted, as-is, under a "safe" location like, say, /usr/local/swift and then set the path to include /usr/local/swift/usr/bin and congratulations, you have a working Swift installation. Unfortunately, Fedora forbids packages installing their files into /usr/local and as a consequence, has to live in the regular /usr where it can hobnob with other installed packages like Vim, cat and Clang.

Ah, and there's the issue. Clang, LLVM, and LLDB can be installed independently and in a case of who-got-there-first (spoiler: not Swift) those packages have a pretty clear lock on the executable names. Clang itself isn't the issue, it's LLDB with its accompanying lldb, lldb-server, etc., that can live in /usr/bin and since Swift provides its own custom lldb for the REPL, attempting to have both installed doesn't work. So, as part of the packaging of Swift for Fedora, I discovered that swift looks for lldb in the same directory. This patch, which I've used since the beginning of the Swift package for Fedora, changes the location to /usr/libexec/swift-lldb so as to keep Swift's lldb out of the way of the official LLDB package. More-or-less, that was the toughest nut to crack; the second more difficult aspect of packaging Swift was preventing the .so files Swift places in usr/lib in being installed in /usr/lib, as they are technically 64-bit and should go in /usr/lib64, but attempts to put the files there did not work (I forget the exact reasons, it was awhile ago).

Where We're At In FedoraLand

So that brings us to Swift 5.2.1. As mentioned above, compiling Swift programs works fine, but if you want to use the REPL, you are greeted with error: Could not construct an expression context for the REPL.. After many experiments (a fair number of Docker containers were used as there it's safe to really muck around in /usr/lib etc.) I have determined how to "fix" the install to make it work (if you want to follow along, you can get the container here):

            1. Move the lib* files from /usr/lib/swift into /usr/lib
            2. Run ldconfig to rebuild the cache
            3. Run ln -s /usr/lib/swift/clang /usr/lib/clang. This was gleamed by examining previous patches, the Swift source, and trial and error. It is our first "breaking" change insofar as Clang, if installed, would have created /usr/lib/clang already.
            4. Try running swift now. You will get a new error: error: REPL executable does not exist: '/usr/bin/repl_swift'. This is surprising, the package puts lldb in /usr/libexec/swift-lldb and I figured that it would look for companion executables, similar to how swift does it, in the same directory (and that is how it works in Swift 5.1.x).
            5. Okay, well, let's do a symlink: ln -s /usr/libexec/swift-lldb/repl_swift /usr/bin/repl_swift. Yay, now we have a new error: error: failed to launch REPL process: process launch failed: unable to locate lldb-server.
            6. Right, so, let's do the same thing again: ln -s /usr/libexec/swift-lldb/lldb-server /usr/bin/lldb-server. Now we're really in a pickle because lldb-server is an existing LLDB executable, so there's no way packaging the file in this location is going to work.
            7. Try swift again, and behold!
              Welcome to Swift version 5.2.1 (swift-5.2.1-RELEASE).
              Type :help for assistance.
              1>

The REPL now works! I've run through a couple of test suites and everything works as expected, with all the nice changes 5.2 brought to the language.

Well, That's Nice. But What's Wrong?

This is where I'm stuck. The *.so files, as packaged for Fedora, are in /usr/lib/swift-lldb and I have an ld conf file that is installed to make them findable; indeed, if a file is renamed or moved, trying to run swift complains that the .so file can't be found (which is the correct behavior).

It seems like we're back to programs looking for files in hard-coded places, but for library files? Seems...unlikely. But yet after many attempts to make it work and keep the files in /usr/lib/swift-lldb, I've made zero progress. If anything, the library files are found in the right place, if you believe the output from strace (which has been invaluable for troubleshooting) but it's only when they're moved to /usr/lib, per the steps above, that things start to work. Then there's the surprising insistence on looking for repl_swift and lldb-server in /usr/bin; no amount of cajoling can get lldb to notice them, sitting happily next to it, in /usr/libexec/swift-lldb.

So What Now?

Well, I think my go-at-it-alone approach is not working anymore; a lot of time has been spent with little progress. I'm hoping that Linus's Law can apply here and someone sees what I've been missing and we can get a working REPL that doesn't intrude on other packages and ship 5.2.1 to Fedora users.