tldr: If Black Mesa on Steam doesn’t start, and the log says something about missing radeon drivers (like libGL error: unable to load driver: radeonsi_dri.so and some extra text), remove libstdc++.so.6 in your “~/.steam/steam/steamapps/common/Black Mesa/bin/”. It should start normally now. Below is how I found out and fixed it for myself.

I found out today that Black Mesa now runs on Linux. Awesome! Why didn’t anyone tell me? I had to randomly look at the Steam page to see it. I immediately bought it since I remember it being such a great remake, and being disappointed I couldn’t play it when I switched to Linux.

Screenshot from Black Mesa, showing the lobby at the start of the game.

So, I downloaded the game/mod, started it from the Steam UI, and … it didn’t start. Turns out, like I’ve had before with games ported to Linux, this is one of those games that has trouble starting out of the box. Luckily, I’ve fixed such cases before so I was confident I could fix it this time. In addition I thought I’d document it this time in case others have similar issues. To show how to fix this particular issue and to show the process of fixing it when you don’t know the issue. I’m trying to make it as beginner friendly as possible. This is an intro to debugging game issues on Linux, so for veterans this will all be very basic information.

The first thing you need is some information about what’s going wrong. Sadly, Steam itself doesn’t provide any way to view the textual output of the program if there’s a problem. In my view that’s a flaw, considering they still happen often enough and non-technical users probably don’t know how to find it themselves. Simply having the game you just bought not start is not a nice user experience. But luckily we can get around Steam and open the game directly in a terminal to get (hopefully) a clear error log.

First we need to get to the directory where Steam installs the game. They’re usually in a subdirectory in ~/.steam/steam/steamapps/common. And yes, I see there’s a “Black Mesa” directory here. Let’s open it. Inside are 3 potential launchers: bms.sh, bms_linux and srcds_linux. srcds_linux seems like it’s for the dedicated server(ds), so let’s ignore it. bms_linux is likely the actual executable, while bms.sh is probably a script setting up the environment to run bms_linux correctly. I’ve seen this set up before with many Linux games that pack their own libraries. Libraries are pieces of code that can be shared between programs. Immediately a potential issue comes to mind: libraries being loaded incorrectly by the bms.sh script. This is probably the most common issue with games not starting on Linux.

But let’s look at the output of trying to run bms.sh. To get the output we’ll need to open a shell/terminal here. My file manager (Thunar) allows me to open a shell by pressing right mouse button on a directory and clicking “Open Terminal Here”. If yours doesn’t, you’ll just have to open a terminal normally (often ctrl+alt+t, or search for a program called terminal and run it). and just type cd "~/.steam/steam/steamapps/common/Black Mesa/" (and Enter of course) to get to the directory.

We can run bms.sh by typing ./bms.sh. This is the output this command gave me:

libGL error: unable to load driver: radeonsi_dri.so
libGL error: driver pointer missing
libGL error: failed to load driver: radeonsi
libGL error: unable to load driver: swrast_dri.so
libGL error: failed to load driver: swrast
X Error of failed request:  BadValue (integer parameter out of range for operation)
  Major opcode of failed request:  155 (GLX)
  Minor opcode of failed request:  3 (X_GLXCreateContext)
  Value in failed request:  0x0
  Serial number of failed request:  92
  Current serial number in output stream:  93

Aha, finally some information about our error! Now if your error is completely different, you’ll need to do something else to fix it than we are doing here. But maybe the process can still be educational.

There’s one thing I recognized immediately: radeon driver issues. And of course. This is a common bug with Steam. I’ve often had it with trying to install earlier versions of Steam on my Ubuntu 16.04. It has to do with graphics drivers Steam supports. Back when it came out, Ubuntu 14.04 supported AMD’s proprietary graphics drivers. But Ubuntu 14.04’s version of libc++ (a central system library) was too old for Steam, so Steam packed its own version of the library. Then came Ubuntu 16.04, which dropped the proprietary drivers since the open source drivers had gotten a lot better. This turned out to be a problem with Steam, since its shipped version of libc++ still referenced the proprietary drivers! The common fix for Steam was to remove its shipped libc++ so that Ubuntu’s version of the library would be used instead (its version was now good for running Steam anyway). It seems this has been fixed in recent Steam versions, but the problem probably still exists in some Steam games. Let’s go on.

One thing I wanted to check was to just run ./bms_linux directly. It may seems strange but I’ve had something alike happen with GOG’s Linux version of Grim Fangango Remastered. I couldn’t get the startup script to work at all, but just running the executable directly had it work immediately! So I tried it. Output:

./bms_linux: error while loading shared libraries: libtcmalloc_minimal.so.4: cannot open shared object file: No such file or directory

Oops! Seems Black Mesa does need some libraries we don’t have. Specifically, libtcmalloc_minimal.so.4. Let’s see if anything else is missing. You can see all libraries for an executable using the ldd command. Here was my output for ldd ./bms_linux:

    linux-gate.so.1 =>  (0xf7724000)
    libtcmalloc_minimal.so.4 => not found
    libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xf76ec000)
    libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xf76cc000)
    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7514000)
    /lib/ld-linux.so.2 (0x565cd000)

Hm, seems that only the tcmalloc library is missing. Maybe I could get by with only adding that one.

I checked the bms.sh script to see where it was getting its own libraries from. You can open it with any text editor or viewer. I used less from the command line. You can use it like this: less bms.sh (and use pageup and pagedown to navigate, and q to exit). It’s not a big script, but there’s still quite some fluff in it. Luckily, there’s only one thing we need to be interested in, and that’s the LD_LIBRARY_PATH. This is a special environment variable that tells the linker where to get its libraries (that are shown by ldd). We see this line:

   export LD_LIBRARY_PATH="${GAMEROOT}"/bin:$LD_LIBRARY_PATH

Seems like ${GAMEROOT} is the game directory, then it’s just the subdirectory bin. Alright. Checking out that directory in our file browser, we see loads of library files (ending with .so) and some other files. Among the files is libtcmalloc_minimal.so.4. Ah, luckily it’s among these files, otherwise we’d have to install it ourselves. That could be tricky if it’s not in our package repositories. Now, since this package was the only one reported missing by ldd, I wanted to try and see if Black Mesa would start if I only added this library, and that all the rest was just extra fluff. I could move or copy this library somewhere else, and change the LD_LIBRARY_PATH to that directory so the game would only load that one (aside from system libraries). I’m going to do something similar, but I’ll link to the file instead.

Linking is creating a file that simply links to another file. This is more lightweight than copying since you’re not copying the entire file, and it keeps the original bin directory in tact so I don’t have to move things back. Great! To create a link in the terminal, we can use ln. We’re going to use it with some command line options. -r makes the link relative to our current directory, and -s makes the link symbolic rather than a hard link (we normally only really want symbolic links). Be sure to do this from the root game directory. We can use this as ln -rs bin/libtcmalloc_minimal.so.4 .. This created a link in our current directory(.) to the bin/libtcmalloc_minimal.so.4 file. Now if you’re writing that and you think it’s annoying to type that much, simply press tab after writing bin/libtc and the terminal will autocomplete it for you.

So now I made a link to the file in the game root directory, where our executable is also located. We want to run the executable with the LD_LIBRARY_PATH set to “.”, our current directory. We can override environment variables while running the program by prepending them to the program, like so: LD_LIBRARY_PATH=. ./bms_linux. Here’s the output of that command for me:

SDL video target is 'x11'
SDL video target is 'x11'
This system supports the OpenGL extension GL_EXT_framebuffer_object.
This system supports the OpenGL extension GL_EXT_framebuffer_blit.
This system supports the OpenGL extension GL_EXT_framebuffer_multisample.
This system DOES NOT support the OpenGL extension GL_APPLE_fence.
This system DOES NOT support the OpenGL extension GL_NV_fence.
This system supports the OpenGL extension GL_ARB_sync.
This system supports the OpenGL extension GL_EXT_draw_buffers2.
This system DOES NOT support the OpenGL extension GL_EXT_bindable_uniform.
This system DOES NOT support the OpenGL extension GL_APPLE_flush_buffer_range.
This system supports the OpenGL extension GL_ARB_map_buffer_range.
This system supports the OpenGL extension GL_ARB_vertex_buffer_object.
This system supports the OpenGL extension GL_ARB_occlusion_query.
This system DOES NOT support the OpenGL extension GL_APPLE_texture_range.
This system DOES NOT support the OpenGL extension GL_APPLE_client_storage.
This system DOES NOT support the OpenGL extension GL_ARB_uniform_buffer.
This system supports the OpenGL extension GL_ARB_vertex_array_bgra.
This system supports the OpenGL extension GL_EXT_vertex_array_bgra.
This system supports the OpenGL extension GL_ARB_framebuffer_object.
This system DOES NOT support the OpenGL extension GL_GREMEDY_string_marker.
This system supports the OpenGL extension GL_ARB_debug_output.
This system DOES NOT support the OpenGL extension GL_EXT_direct_state_access.
This system DOES NOT support the OpenGL extension GL_NV_bindless_texture.
This system supports the OpenGL extension GL_AMD_pinned_memory.
This system supports the OpenGL extension GL_EXT_framebuffer_multisample_blit_scaled.
This system supports the OpenGL extension GL_EXT_texture_sRGB_decode.
This system supports the OpenGL extension GL_NVX_gpu_memory_info.
This system supports the OpenGL extension GL_ATI_meminfo.
This system supports the OpenGL extension GL_EXT_texture_compression_s3tc.
This system supports the OpenGL extension GL_EXT_texture_compression_dxt1.
This system supports the OpenGL extension GL_ANGLE_texture_compression_dxt3.
This system supports the OpenGL extension GL_ANGLE_texture_compression_dxt5.
This system supports the OpenGL extension GL_ARB_buffer_storage.
This system DOES NOT support the OpenGL extension GLX_EXT_swap_control_tear.
OpenGL: Gallium 0.4 on AMD PITCAIRN (DRM 2.43.0 / 4.4.0-75-generic, LLVM 3.8.0) 3.0 Mesa 12.0.6 (3.0.0)
GL_NV_bindless_texture: DISABLED
GL_AMD_pinned_memory: DISABLED
GL_ARB_buffer_storage: AVAILABLE
GL_EXT_texture_sRGB_decode: AVAILABLE
AppFramework : Unable to load module engine.so!
Unable to load interface VCvarQuery001 from engine.so, requested from EXE.

That’s a lot more! The program is actually starting up a bit now. But it’s still not actually starting: The final 2 lines in the log shows something about the issue. The executable is loading something from engine.so, which it can’t get! It seems there’s more libraries being loaded, but in a dynamic way so that ldd doesn’t show they’re missing. engine.so is also a library that’s present in the bin directory. So we can start the tedious process of adding libraries until the executable starts working.

That’s no fun though! So I checked the bin directory instead for libraries that were likely to cause issues. Maybe it’d be easier to throw one out rather than adding them in one at a time. Then I saw libstdc++.so.6 in there, and remembered that this library often caused issues with Steam when bundled with it.

I could have just removed it. But what if that made the issue worse? Instead, I decided to link all libraries in a different directory and then just remove the link to libstdc++.so.6. That would allow me to play around with what libraries to load without actually messing up anything. These are the steps:

mkdir bin_test
cd bin_test
ln -rs ../bin/* .
cd ..
LD_LIBRARY_PATH=bin_test ./bms_linux

I wasn’t certain this would work, but yes, it started! It always feels good when you fixed an issue yourself, and I was lucky this was just a simple one to fix. I played around a bit for the first levels and nothing went wrong, so I assume this was the only thing that was wrong.

Now, to also fix starting Black Mesa from the Steam interface (and not have to remember my unique command for starting the game each time). I went to edit the bms.sh script. I just edited the /bin in the LD_LIBRARY_PATH line to /bin_test, and did the same for the DYLD_LIBRARY_PATH (probably not needed, but just in case, seems like a variant). Now, Black Mesa can start by just running it from Steam. Of course other people can just fix it by removing bin/libc++.so.6, which is a far simpler operation, but we couldn’t do that because we weren’t sure yet that this was the correct fix. We could have broken it even more! That’s bad!

A final word. One could say it’s bad that this kind of stuff is sometimes necessary to run a game on Linux. After all, I just paid 20 euros for a working game, not for an exercise in debugging. That’s true, but sadly Linux is a rather difficult platform to support. Mainly due to its fragmentation with library versions and packages. And most gamers and developers run Windows, even if they support Linux, so Linux will definitely be less tested. For now, we’ll have to accept that this is sometimes part of getting a game to run. Luckily there’s always Steam Support if nothing you do seems to work. But on the other hand, this sort of thing is a great way to learn more about Linux and become a more empowered user, especially if you succeed in fixing it yourself (with the help of internet of course). While going through this issue, we already learned a bit about the terminal, LD_LIBRARY_PATH and symbolic links, and we looked at and edited a Bash script. Of course I already knew about those things in this case, but I had to learn them in similar ways. I think debugging such issues is a great opportunity for learning and personal growth, if you let it be.

Questions, comments? Send me a mail or a tweet. Contact info at the bottom of each page.