Skip to content

DLLImport fails on Linux #768

@sandsalamand

Description

@sandsalamand

I'm using Steamworks.NET Standalone version 2025.163.0 on Linux with Godot. The project builds, but at runtime, I get errors:

  ERROR: [Steamworks.NET] Could not load [lib]steam_api.dll/so/dylib. It's likely not in the correct location. Refer to the README for more details.

  ERROR: System.DllNotFoundException: Unable to load shared library 'steam_api' or one of its dependencies. In order to help diagnose loading problems, consider using a tool like strace. If you're using glibc, consider setting the LD_DEBUG environment variable:

  ERROR: /usr/lib/dotnet/shared/Microsoft.NETCore.App/9.0.11/steam_api.so: cannot open shared object file: No such file or directory

  ERROR: /usr/lib/dotnet/shared/Microsoft.NETCore.App/9.0.11/libsteam_api.so: cannot open shared object file: No such file or directory

  ERROR: /usr/lib/dotnet/shared/Microsoft.NETCore.App/9.0.11/steam_api: cannot open shared object file: No such file or directory

  ERROR: /usr/lib/dotnet/shared/Microsoft.NETCore.App/9.0.11/libsteam_api: cannot open shared object file: No such file or directory 

I created a Post-Build copy script for libsteam_api.so and steam_appid.txt, and I verified that they are being copied into the output directory.

The problem:
DLLImport is searching the wrong location for libsteam_api.so. I think it's on these lines: It's searching in /usr/lib/dotnet/ instead of the project root. I verified that this is the problem by setting the LD_LIBRARY_PATH environment variable, which DLLImport uses to determine where to search.

Temp workaround:
When LD_LIBRARY_PATH is set to the project root and libsteam_api.so is in the project root, the game runs fine.

Real solutions:

  1. Add [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)] above the DLLImport lines in Steamworks.NET.

  2. Alternatively, SteamManager.cs can be modified (tested and working on Godot Linux, untested on other platforms):

    private void HookSteamDllResolver()
	{
		NativeLibrary.SetDllImportResolver(typeof(SteamAPI).Assembly, (libraryName, assembly, searchPath) =>
		{
			// Ignore assemblies that are not the Steam API library (might be unnecessary)
			if (libraryName != "steam_api") return IntPtr.Zero;

			// Determine the correct filename based on the platform
			string nativeFile = "steam_api64.dll"; // Default Windows
			
			if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
			{
				nativeFile = "libsteam_api.so";
			}
			else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
			{
				nativeFile = "libsteam_api.dylib";
			}

			// Check next to the executing assembly
			string localPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, nativeFile);
			if (File.Exists(localPath))
			{
				GD.Print("Found it in executing assembly directory");
				return NativeLibrary.Load(localPath);
			}

			// Failed to find it
			return IntPtr.Zero;
		});
	}

	public override void _EnterTree()
	{
		if (Instance == null)
			Instance = this;
		else
		{
			QueueFree();
			return;
		}

		HookSteamDllResolver();

		...
	}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions