Skip to content

Commit

Permalink
Refactor denoLoadLibrary and add documentation (#39)
Browse files Browse the repository at this point in the history
* Refactored getLibraryPaths

* Update Readme.me
  • Loading branch information
smack0007 authored Sep 5, 2024
1 parent 7e57c28 commit adb4c66
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 27 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.lib/
bin/
ext/SDL/include/
tmp/
Expand Down
21 changes: 21 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,27 @@ Located in the directory [examples/getting-started](examples/getting-started/) a
a project up and running. Copy these files onto your computer and start the project with `deno task start`. You should
see a window with `SDL_ts` as the title.

### Loading shared libraries

Unless `libraryPath` is specified in the `Init` functions, `SDL_ts` will attempt to "find" the SDL shared libraries by
determining the prefix and file extension appropriate for the operating system and looking in a set of different places
also based on the operating system. The places where the shared libraries are searched for can be influenced by the
environment variable [`SDL_TS_LIBRARY_PATH`](#sdl-ts-library-path).

#### libraryPath

The `Init` functions (i.e. `SDL_Init`) have in their `options` object a `libraryPath` property. This property should be
a path to the shared library and `SDL_ts` will make no attempt to guess where the library should be loaded from. This
means it's up to the caller of the `Init` function to account for changes in the name of the library between the
different platforms. For example the shared library on Linux is called `libSDL2.so` and Windows it is called `SDL2.dll`.
There is a `lib` prefix on Linux and on Windows the file extension is `.dll` instead of `.so`.

#### SDL_TS_LIBRARY_PATH

The environmnet variable `SDL_TS_LIBRARY_PATH` can be used to instruct SDL_ts where the SDL shared libraries should be
loaded from. See [deno.json](deno.json). All example projects will load the SDL shared libraries from the `.lib`
directory if it exists.

### Loading only required functions

Per default `SDL.Init` (or `IMG.Init` or `TTF.Init`) will load all known functions from the SDL assemblies. This can be
Expand Down
15 changes: 7 additions & 8 deletions deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,13 @@
"check": "deno check",
"codegen": "cd ./tools && deno run --unstable-ffi --allow-run -R -W $DENO_FLAGS ./codegen.ts",
"codegen-scraper": "cd ./tools && deno run -R -W --allow-run ./codegen-scraper.ts",
"run:init": "deno run --allow-net -R=. -W=. ./init.ts ./tmp/init",
"run:doom-fire": "cd ./examples/doom-fire && deno run --unstable-ffi -E --allow-ffi -R=../.. $DENO_FLAGS ./main.ts",
"run:hello-world": "cd ./examples/hello-world && deno run --unstable-ffi -E --allow-ffi -R=../.. $DENO_FLAGS ./main.ts",
"run:hello-world-async": "cd ./examples/hello-world-async && deno run --unstable-ffi -E --allow-ffi -R=../.. $DENO_FLAGS ./main.ts",
"run:play-wav": "cd ./examples/play-wav && deno run --unstable-ffi -E --allow-ffi -R=../.. $DENO_FLAGS ./main.ts",
"run:renderer": "cd ./examples/renderer && deno run --unstable-ffi -E --allow-ffi -R=../.. $DENO_FLAGS ./main.ts",
"run:same-game": "cd ./examples/same-game && deno run --unstable-ffi -E --allow-ffi -R=../.. $DENO_FLAGS ./main.ts",
"run:version": "cd ./examples/version && deno run --unstable-ffi -E --allow-ffi -R=../.. $DENO_FLAGS ./main.ts",
"run:doom-fire": "cd ./examples/doom-fire && SDL_TS_LIBRARY_PATH=$INIT_CWD/.lib deno run --unstable-ffi -E --allow-ffi -R=../.. $DENO_FLAGS ./main.ts",
"run:hello-world": "cd ./examples/hello-world && SDL_TS_LIBRARY_PATH=$INIT_CWD/.lib deno run --unstable-ffi -E --allow-ffi -R=../.. $DENO_FLAGS ./main.ts",
"run:hello-world-async": "cd ./examples/hello-world-async && SDL_TS_LIBRARY_PATH=$INIT_CWD/.lib deno run --unstable-ffi -E --allow-ffi -R=../.. $DENO_FLAGS ./main.ts",
"run:play-wav": "cd ./examples/play-wav && SDL_TS_LIBRARY_PATH=$INIT_CWD/.lib deno run --unstable-ffi -E --allow-ffi -R=../.. $DENO_FLAGS ./main.ts",
"run:renderer": "cd ./examples/renderer && SDL_TS_LIBRARY_PATH=$INIT_CWD/.lib deno run --unstable-ffi -E --allow-ffi -R=../.. $DENO_FLAGS ./main.ts",
"run:same-game": "cd ./examples/same-game && SDL_TS_LIBRARY_PATH=$INIT_CWD/.lib deno run --unstable-ffi -E --allow-ffi -R=../.. $DENO_FLAGS ./main.ts",
"run:version": "cd ./examples/version && SDL_TS_LIBRARY_PATH=$INIT_CWD/.lib deno run --unstable-ffi -E --allow-ffi -R=../.. $DENO_FLAGS ./main.ts",
"test": "deno test --unstable-ffi --allow-ffi"
}
}
44 changes: 25 additions & 19 deletions src/deno/_library.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { join } from "@std/path";
import { join, SEPARATOR } from "@std/path";
import { SDLError } from "../error.ts";
import { DynamicLibrary, DynamicLibraryInterface } from "../_library.ts";
import { ENV_LIBRARY_PATH } from "../_constants.ts";
Expand All @@ -11,7 +11,7 @@ const WINDOWS_LIBRARY_PATHS: string[] = [];
const UNIX_LIBRARY_PATHS: string[] = [
"/usr/local/lib",
"/usr/lib64",
"/home/linuxbrew/.linuxbrew/lib"
"/home/linuxbrew/.linuxbrew/lib",
];

const MACOS_LIBRARY_PATHS: string[] = [
Expand All @@ -31,35 +31,34 @@ function getLibrarySuffix(): string {
return ".so";
}

function getLibraryPaths(libraryName: string, libraryPath?: string): string[] {
function getLibraryPaths(libraryName: string): string[] {
const libraryPrefix = !IS_WINDOWS ? "lib" : "";
const librarySuffix = getLibrarySuffix();
const fullLibraryName = libraryPrefix + libraryName + librarySuffix;

const libraryPaths: string[] = [];

const os = Deno.build.os;
const arch = "x64"; // TODO: Detect this somehow.
// Try and load it from the same directory.
// NOTE: Using `join` here doesn't seem to work as it was just returning the file without the ./
libraryPaths.push(`.${SEPARATOR}${fullLibraryName}`);

if (libraryPath) {
libraryPaths.push(join(libraryPath, os, arch, fullLibraryName));
// Then look and see if SDL_TS_LIBRARY_PATH was specified.
const envLibraryPath = Deno.env.get(ENV_LIBRARY_PATH);
if (envLibraryPath) {
libraryPaths.push(join(envLibraryPath, fullLibraryName));
}

libraryPaths.push(join(".", fullLibraryName));
// Next try and load it globally
libraryPaths.push(fullLibraryName);

if (!IS_WINDOWS && !IS_MAC) {
// On Debain libSDL2_image and libSDL2_ttf only have symbolic links with this format.
// On Debain libSDL2_image and libSDL2_ttf only have symbolic links with this format so
// search for those globally as well.
libraryPaths.push(
libraryPrefix + libraryName + "-2.0" + librarySuffix + ".0"
);
}

libraryPath = Deno.env.get(ENV_LIBRARY_PATH);

if (libraryPath) {
libraryPaths.push(join(libraryPath, os, arch, fullLibraryName));
}

if (!IS_WINDOWS) {
const ldLibraryPath = Deno.env.get("LD_LIBRARY_PATH");

Expand Down Expand Up @@ -100,14 +99,21 @@ export function denoLoadLibrary<T extends DynamicLibraryInterface>(
symbols: T,
libraryPath?: string
): DynamicLibrary<T> {
const libraryPaths = getLibraryPaths(libraryName, libraryPath);
const libraryPaths = libraryPath
? [libraryPath]
: getLibraryPaths(libraryName);
const errors: Record<string, Error> = {};

for (const libraryPath of libraryPaths) {
try {
// Cast the symbols as any in order to prevent a type checking bug.
// deno-lint-ignore no-explicit-any
return Deno.dlopen(libraryPath, symbols as any) as DynamicLibrary<T>;
const result = Deno.dlopen(
libraryPath,
// Cast the symbols as any in order to prevent a type checking bug.
// deno-lint-ignore no-explicit-any
symbols as any
) as DynamicLibrary<T>;
console.debug(`SDL_ts: Loaded ${libraryName} from "${libraryPath}"`);
return result;
} catch (error) {
errors[libraryPath] = error;
}
Expand Down

0 comments on commit adb4c66

Please sign in to comment.