How to resolve the algorithm Call a function in a shared library step by step in the Wren programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Call a function in a shared library step by step in the Wren programming language

Table of Contents

Problem Statement

Show how to call a function in a shared library (without dynamically linking to it at compile-time). In particular, show how to call the shared library function if the library is available, otherwise use an internal equivalent function. This is a special case of calling a foreign language function where the focus is close to the ABI level and not at the normal API level.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Call a function in a shared library step by step in the Wren programming language

Source code in the wren programming language

/* Call_a_function_in_a_shared_library.wren */

var RTLD_LAZY = 1

foreign class DL {
    construct open(file, mode) {}

    foreign call(symbol, arg)

    foreign close()
}

class My {
    static openimage(s) {
        System.print("internal openimage opens %(s)...")
        if (!__handle) __handle = 0
        __handle = __handle + 1
        return __handle - 1
    }
}

var file = "fake.img"
var imglib = DL.open("./fakeimglib.so", RTLD_LAZY)
var imghandle = (imglib != null) ? imglib.call("openimage", file) : My.openimage(file)
System.print("opened with handle %(imghandle)")
if (imglib != null) imglib.close()


/*
    gcc -c -fpic fakeimglib.c
    gcc -shared fakeimglib.o -o fakeimglib.so
*/
#include <stdio.h>

int openimage(const char *s) {
    static int handle = 100;
    fprintf(stderr, "opening %s\n", s);
    return handle++;
}


/* gcc Call_a_function_in_a_shared_library.c -o Call_a_function_in_a_shared_library -ldl -lwren -lm */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include "wren.h"

/* C <=> Wren interface functions */

void C_dlAllocate(WrenVM* vm) {
    const char *file = wrenGetSlotString(vm, 1);
    int mode = (int)wrenGetSlotDouble(vm, 2);
    void *imglib = dlopen(file, mode);
    if (imglib == NULL) wrenSetSlotNull(vm, 0);
    void** pimglib = (void**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(void*));
    *pimglib = imglib;
}

void C_call(WrenVM* vm) {
    void *imglib = *(void**)wrenGetSlotForeign(vm, 0);
    const char *symbol = wrenGetSlotString(vm, 1);
    const char *arg = wrenGetSlotString(vm, 2);
    int (*extopenimage)(const char *);
    extopenimage = dlsym(imglib, symbol);
    int imghandle = extopenimage(arg);
    wrenSetSlotDouble(vm, 0, (double)imghandle);
}

void C_close(WrenVM* vm) {
    void *imglib = *(void**)wrenGetSlotForeign(vm, 0);
    dlclose(imglib);
}

WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {
    WrenForeignClassMethods methods;
    methods.finalize = NULL;
    if (strcmp(module, "main") == 0) {
        if (strcmp(className, "DL") == 0) {
            methods.allocate = C_dlAllocate;
        }
    }
    return methods;
}

WrenForeignMethodFn bindForeignMethod(
    WrenVM* vm,
    const char* module,
    const char* className,
    bool isStatic,
    const char* signature) {
    if (strcmp(module, "main") == 0) {
        if (strcmp(className, "DL") == 0) {
            if (!isStatic && strcmp(signature, "call(_,_)") == 0) return C_call;
            if (!isStatic && strcmp(signature, "close()") == 0)   return C_close;
        }
    }
    return NULL;
}

static void writeFn(WrenVM* vm, const char* text) {
    printf("%s", text);
}

void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
    switch (errorType) {
        case WREN_ERROR_COMPILE:
            printf("[%s line %d] [Error] %s\n", module, line, msg);
            break;
        case WREN_ERROR_STACK_TRACE:
            printf("[%s line %d] in %s\n", module, line, msg);
            break;
        case WREN_ERROR_RUNTIME:
            printf("[Runtime Error] %s\n", msg);
            break;
    }
}

char *readFile(const char *fileName) {
    FILE *f = fopen(fileName, "r");
    fseek(f, 0, SEEK_END);
    long fsize = ftell(f);
    rewind(f);
    char *script = malloc(fsize + 1);
    fread(script, 1, fsize, f);
    fclose(f);
    script[fsize] = 0;
    return script;
}

int main(int argc, char **argv) {
    WrenConfiguration config;
    wrenInitConfiguration(&config);
    config.writeFn = &writeFn;
    config.errorFn = &errorFn;
    config.bindForeignClassFn = &bindForeignClass;
    config.bindForeignMethodFn = &bindForeignMethod;
    WrenVM* vm = wrenNewVM(&config);
    const char* module = "main";
    const char* fileName = "Call_a_function_in_a_shared_library.wren";
    char *script = readFile(fileName);
    WrenInterpretResult result = wrenInterpret(vm, module, script);
    switch (result) {
        case WREN_RESULT_COMPILE_ERROR:
            printf("Compile Error!\n");
            break;
        case WREN_RESULT_RUNTIME_ERROR:
            printf("Runtime Error!\n");
            break;
        case WREN_RESULT_SUCCESS:
            break;
    }
    wrenFreeVM(vm);
    free(script);
    return 0;
}


  

You may also check:How to resolve the algorithm Substitution cipher step by step in the D programming language
You may also check:How to resolve the algorithm Strip whitespace from a string/Top and tail step by step in the Ruby programming language
You may also check:How to resolve the algorithm 99 bottles of beer step by step in the AutoIt programming language
You may also check:How to resolve the algorithm Arithmetic-geometric mean step by step in the SQL programming language
You may also check:How to resolve the algorithm Anagrams step by step in the Vedit macro language programming language