Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor denoLoadLibrary and add documentation #39

Merged
merged 2 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading