(Last updated: February 12, 2019)
LOOT Icon

About

LOOT is a tool used to organize mods in Fallout 3+4, and The Elder Scrolls 4+5 (Oblivion and Skyrim). Mods often have to be loaded in a specific order to work properly, some mods aren't compatible with each other, and in general it can be a bit of work to try and manage all that manually. LOOT uses a curated database of information about mods to set up the load order properly with the click of a button.

Unfortunately for Linux users, unlike the Fallout and TES series, modern versions of LOOT don't actually work at all in Wine/Proton (though someone's partial success with v0.11.0 implies that more recent efforts might not have been trying hard enough). When run in an empty WINEPREFIX, it'll start but be unable to read game data, and when run in a WINEPREFIX which has an installed game, it'll just crash right away.

Fortunately, LOOT does work on Linux natively, though they don't provide official builds on that platform. There's at least one place which provides unofficial snapshot builds, though I haven't tried it out and didn't save the link, so you're on your own for Googling that one. Building LOOT on a Linux box isn't entirely straightforward but it's not awful, either. Here's how!

NOTE: This was written in early February 2019. Given that we're talking about building a package direct from Github, the exact advice in here could certainly get stale -- buyer beware if you're reading this in the future. The line numbers I mention, in particular, are likely to change. The current LOOT version as of writing is 0.14.3.

(I tend to be pretty wordy when doing documentation... Don't be afraid of the length of this page. It's really not bad!)

Step 1: Grabbing the Project and Dependencies

You'll need to compile two projects: libloot, the base library which provides all the backend data functionality, and loot, the frontend and GUI. The processes for both are nearly identical. Do a git clone on both of those projects to get a local copy of the repos.

As the READMEs for both projects imply, there's no user-level automated build process, but you can look into the .travis.yml file to get a feel for what's required and what the steps are[1]. The important bits for us are the addons -> apt -> packages section (which tells us some of the dependencies), the before_install and install sections (to tell us some more dependencies), and the before_script and script sections which is where the actual compilation happens.

The dependencies inside the .travis.yml file are for a Debian or Ubuntu system (not sure which), so the package names may not apply directly, but here's the full list specified there:

  • g++-8
  • gcc-8
  • libasound2-dev
  • libbz2-dev
  • libgconf2-dev
  • libgtk2.0-dev
  • libhttp-parser-dev
  • libnss3-dev
  • libssh2-1-dev
  • libssl-dev
  • libx11-dev
  • libxss-dev
  • libxtst-dev

Additionally, we can glean some other dependencies from some of the other sections, namely:

  • CMake, a software building framework.
  • Rust, a programming language that provides some of the base libraries for libloot.
  • Cargo, a package manager for Rust libraries.
  • cbindgen, a tool to allow C/C++ applications to make use of Rust libraries.
  • Boost, a collection of C++ libraries.
  • Yarn, a package manager for Javascript libraries and apps.

Those may be available via your distro's package manager (some, like CMake, Rust, and BOOST, almost certainly are). The Travis script installs them by grabbing from various URLs around the internet, so if you're missing one, you can always just use the same URLs found in there. I've omitted some extra libraries/programs related to documentation, since I didn't care enough to build the docs myself -- things like Doxygen and Sphinx. You're on your own for building docs, though it should be pretty straightforward. Note that Sphinx is a Python project, installed via Python's pip, bringing the language count in LOOT to at least four, and the package manager count to at least four as well (counting your distro's native one).

Step 2: Building libloot

The basic process for both libloot and loot is theoretically quite simple. Just:

$ cd [path_to_git_checkout]
$ mkdir build
$ cd build
$ cmake .. && make all

The process will end up pulling various Rust dependencies from the internet using Cargo; they'll get stored within the build directory itself. You may want to check to see if that's all you have to do, but I personally had to alter one value inside CMakeLists.txt before the compilation would proceed -- most likely due to different software versions on my Arch desktop than the Debian/Ubuntu/whatever systems which their Travis CI was using.

Specifically, around line 340 in CMakeLists.txt, where it's defining the variable LOOT_LIBS, I needed to add boost_thread or else libloot wouldn't link properly. The complete stanza looks like:

IF (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    set (CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH};.")
    set (CMAKE_BUILD_WITH_INSTALL_RPATH ON)

    set (LOOT_LIBS ssl
                   curl
                   z
                   crypto
                   rt
                   pthread
                   icuuc
                   icui18n
                   ssh2
                   http_parser
                   stdc++fs
                   boost_thread)

    IF (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
        set (LOOT_LIBS ${LOOT_LIBS} supc++)
    ENDIF ()
ENDIF ()

The only bit added there was boost_thread. Once that's changed, clear out your build directory if you'd already tried building once, run the few steps above, and you should eventually end up with a file libloot.so inside the build dir.

Step 3: Pretend to package libloot

The main LOOT project's CMakeLists.txt file is hardcoded to grab an archive of a precompiled libloot and use that while compiling the main GUI app. There is, I am sure, a graceful way to get around that requirement, but I just went ahead and created my own tgz of libloot for LOOT to use, which mimics the structure of the one it would otherwise pull from the internet.

The structure of the tgz should have a main directory (whose name doesn't really matter -- I called mine libloot-compiled) which contains libloot.so from the build directory, and a copy of the include directory from the top-level project. It'll probably be around 6MB or so when you're done (if using gzip for compression, anyway). Leave that anywhere convenient on your filesystem.

Step 4: Building loot

One change you'll have to make to loot's CMakeLists.txt file is pointing it at your packaged libloot. Around line 67 there's a stanza which defines where to grab the package, depending on if you're on Windows or not. I just changed the non-Windows one to a file:// URL pointing at my file. Here's the full stanza for me:

if (CMAKE_SYSTEM_NAME MATCHES "Windows")
    set(LIBLOOT_URL "https://github.com/loot/libloot/releases/download/0.14.4/libloot-0.14.4-0-gda80a78_dev-win32.7z")
else()
    set(LIBLOOT_URL "file:///usr/local/dv/LOOT/libloot-compiled.tar.gz")
endif()

Obviously you'd substitute your actual path. At this point, you can go ahead and try the usual steps, if you like:

$ cd [path_to_git_checkout]
$ mkdir build
$ cd build
$ cmake .. && make all

This process will pull in a bunch of dependencies using the Yarn package manager, including a Chromium Embedded Framework (yes, like the browser) managed by Spotify, of all places. It's a bit heavier of a build than libloot was. As with Rust/Cargo, these will all just get stored within the build dir itself.

On my system, like with libloot, I also needed to add a couple things to its link list in order for the compilation process to finish properly. Around line 289 is where this is defined, and on my system I needed to add three libraries: icuuc, icui18n, and boost_thread. The full stanza looks like:

IF (CMAKE_COMPILER_IS_GNUCXX)
    set (CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH};.")
    set (CMAKE_BUILD_WITH_INSTALL_RPATH ON)

    set (LOOT_LIBS pthread http_parser ssh2 stdc++fs icuuc icui18n boost_thread)
    set (LOOT_GUI_LIBS X11 ${LOOT_LIBS})
    set (LOOT_TEST_LIBS ${LOOT_LIBS})
ENDIF ()

The only change there is the addition of icuuc icui18n boost_thread. At this point, clear out your build dir if need be, and re-run those few steps. If you're lucky, you'll end up with a LOOT binary in the build dir.

Step 5: Running LOOT

We're not quite done yet. One oddity of using Chromium Embedded Framework as a base for the GUI is that it really wants you to use a sandboxed Chrome process to run everything, which you may see in the build directory as chrome-sandbox. If you just run the LOOT binary without doing anything else, you'll get an error that it wants the chrome-sandbox binary to be setuid root. (This may actually be distro-dependant - it happend on my Arch system but not an Ubuntu system of one of the LOOT devs.)

You can, um, go ahead and do that if you really want to. There are good reasons to do so for a variety of applications. Me, I think it's insane for an app like this which just sorts mod dependencies. Fortunately, the app supports the flag --no-sandbox which disables the requirement of having a SUID root application installed. So I'd recommend running it like:

$ ./LOOT --no-sandbox

We're still not quite done yet, alas. You'll now at least have the app open, and you can plug in an installation directory for any supported game that you may have installed:

Skyrim, configured in LOOT

Now if you hit "Apply" and go back to the main screen, you may find that the application crashes. If you're intrepid, you'll find the logfile ~/.config/LOOT/LOOTDebugLog.txt which will contain a hint: you have to manually configure a "local path" for the games you've configured. This is something which happens automatically on Windows but has to be manually done on Linux.

The "local path" it's talking about is the path to the directory where the game (or at least Skyrim) stores its mod load order. Other supported games may not require this (I seem to think Oblivion just uses file modification times, perhaps?). For Skyrim, at least, this is going to be inside your Wine root's drive_c/users/[username]/Local Settings/Application Data/Skyrim.

The file to edit is ~/.config/LOOT/settings.toml, and the attribute you'll change is local_path in the stanza which matches the game you're interested in. For instance, my Skyrim stanza in there now looks like this:

[[games]]
    path = "/usr/local/games/Steam/SteamApps/common/Skyrim"
    repo = "https://github.com/loot/skyrim.git"
    type = "Skyrim"
    local_path = "/usr/local/games/Steam/SteamApps/compatdata/72850/pfx/drive_c/users/steamuser/Local Settings/Application Data/Skyrim"
    folder = "Skyrim"
    registry = "Software\\Bethesda Softworks\\Skyrim\\Installed Path"
    branch = "v0.14"
    minimumHeaderVersion = 0.93999999761581421
    name = "TES V: Skyrim"
    master = "Skyrim.esm"

Now, finally, you should be able to start up LOOT again (making sure to disable that sandbox), and it should be able to start doing its thing. Whew!

Step 6: Stuff I Didn't Do / Conclusion

At this point, you can run LOOT directly from the build directory of the main loot project. I haven't looked into installing this in a more "permanent" place, or into system dirs or anything. I'm personally happy to just leave it there, so installation of any sort is left as an exercise for the reader.

I also intentionally ignored any documentation-building steps. I don't think they'd be difficult but I just didn't want to bother. This, too, is left as an exercise for the reader, if you care.

Regardless, that's it! I suspect at some point this whole process may get streamlined a bit, but at least once you've gone through the process once, it's not bad. Feel free to contact me if you find anything in error here, or if this becomes out of date without me noticing.

Footnotes

Footnote 1: Travis CI is a "continuous integration" system which is used to continually test the build process of a source tree as code is checked in. A build gets kicked off with every commit. This can be used to provide easy binary snapshots, but is also quite handy for making sure your changes haven't caused any inadvertent compilation problems.

Changelog

February 12, 2019
  • Initial post