The SDL3 Storage API looks interesting, but how do I load a shared library with it? I already load all files and shaders with it and it feels wrong to me to throw away the path safety when loading a library.
Yes, so long as it is moved back to a local file with an Absolute Address after fetching it;
Steps:
- Load the binary [so,dll] file into a char * buffer.
- Write that buffer to a storage file using SDL_StorageAPI. - If this is a steam-connected program, it will be automatically stored in the steam-cloud, otherwise it is likely going to the same place returned by SDL_GetPrefPath().
- When the game loads again, read back the shared.so from the storage API into a similar char * buffer.
- Binary-write that data back into a .so file on the local drive, a good path might be
SDL_GetPrefPath() + "/plugins/
but anywhere that gives you an absolute path will work.
The shared library does not need to be executable when dynamically loaded, so it’s OK if it loses permissions in the process.
File: shared.cpp → shared.so
#include <SDL3/SDL.h>
extern "C"
{
void function()
{
SDL_Log("This function exists in a .so file");
}
}
compile using $ g++ -shared -fPIC shared.cpp -lSDL3 -o shared.so
File: test.cpp → a.out
On Run: shared.so → SDL_GetPrefPath(“SDL_Test”, “storageExample”) + “fin.so”
#include <SDL3/SDL.h>
#include <vector>
#include <fstream>
void (*func)(void);
int main()
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Storage * tstore = SDL_OpenTitleStorage(NULL, 0);
// storage may be in the steam cloud, so wait until open
while(!SDL_StorageReady(tstore))
{
SDL_Delay(2);
}
SDL_Storage * user = SDL_OpenUserStorage("SDL_Test", "storageExample", 0);
while(!SDL_StorageReady(user))
{
SDL_Delay(2);
}
size_t fileSize;
std::ifstream ifile("shared.so", std::ios_base::binary);
if(ifile.good())
{
ifile.seekg(0, ifile.end);
fileSize = ifile.tellg();
ifile.seekg(0, ifile.beg);
char * bin = new char [fileSize];
ifile.read(bin, fileSize);
SDL_WriteStorageFile(user, "shared.so", bin, fileSize);
while(!(SDL_StorageReady(user)))
{
SDL_Delay(2);
}
char * out = new char [fileSize];
SDL_ReadStorageFile(user, "shared.so", out, fileSize);
while(!(SDL_StorageReady(user)))
{
SDL_Delay(2);
}
std::string pluginPath;
pluginPath = SDL_GetPrefPath("SDL_Test", "storageExample");
pluginPath += "fin.so";
SDL_Log("Saving plugin as %s", pluginPath.c_str());
std::ofstream ofile(pluginPath.c_str(), std::ios_base::binary);
ofile.write(out, fileSize);
SDL_SharedObject * handle = SDL_LoadObject(pluginPath.c_str());
if(handle)
{
func = (void(*)()) SDL_LoadFunction(handle, "function");
if(func)
{
SDL_Log("Now calling plugin func from file called %s", pluginPath.c_str());
func();
}
else
{
SDL_Log("The Function failed to load");
}
}
else
{
SDL_Log("Failed to load object file");
SDL_Log("%s", SDL_GetError());
}
}
else
{
SDL_Log("Could not open shared.so to read");
}
SDL_CloseStorage(user);
SDL_CloseStorage(tstore);
SDL_Quit();
}
Note that the shared.so file went to fin.so as the final destination file to avoid a name collision in SDL_GetPrefPath(), and to show that the copy is what is running. A little bit of version-control and moving the result to the “plugins” folder mentioned in my previous post should work too.