#if defined _WIN32 || defined __CYGWIN__
  #define DLL_PUBLIC __declspec(dllexport)
#else
  #if defined __GNUC__
    #define DLL_PUBLIC __attribute__ ((visibility("default")))
  #else
    #pragma message ("Compiler does not support symbol visibility.")
    #define DLL_PUBLIC
  #endif
#endif

#if defined(_WIN32) || defined(__CYGWIN__)

#include <stdio.h>

typedef int (*fptr) (void);

#ifdef __CYGWIN__

#include <dlfcn.h>

fptr find_any_f (const char *name) {
    return (fptr) dlsym(RTLD_DEFAULT, name);
}
#else /* _WIN32 */

#include <windows.h>
#include <tlhelp32.h>

static wchar_t*
win32_get_last_error (void)
{
    wchar_t *msg = NULL;

    FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER
                    | FORMAT_MESSAGE_IGNORE_INSERTS
                    | FORMAT_MESSAGE_FROM_SYSTEM,
                    NULL, GetLastError (), 0,
                    (LPWSTR) &msg, 0, NULL);
    return msg;
}

/* Unlike Linux and OS X, when a library is loaded, all the symbols aren't
 * loaded into a single namespace. You must fetch the symbol by iterating over
 * all loaded modules. Code for finding the function from any of the loaded
 * modules is taken from gmodule.c in glib */
fptr find_any_f (const char *name) {
    fptr f;
    HANDLE snapshot;
    MODULEENTRY32 me32;

    snapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0);
    if (snapshot == (HANDLE) -1) {
        wchar_t *msg = win32_get_last_error();
        printf("Could not get snapshot: %S\n", msg);
        return 0;
    }

    me32.dwSize = sizeof (me32);

    f = NULL;
    if (Module32First (snapshot, &me32)) {
        do {
            if ((f = (fptr) GetProcAddress (me32.hModule, name)) != NULL)
                break;
        } while (Module32Next (snapshot, &me32));
    }

    CloseHandle (snapshot);
    return f;
}
#endif

int DLL_PUBLIC func(void) {
    fptr f;

    f = find_any_f ("func_from_language_runtime");
    if (f != NULL)
        return f();
    printf ("Could not find function\n");
    return 1;
}

#else
/*
 * Shared modules often have references to symbols that are not defined
 * at link time, but which will be provided from deps of the executable that
 * dlopens it. We need to make sure that this works, i.e. that we do
 * not pass -Wl,--no-undefined when linking modules.
 */
int func_from_language_runtime(void);

int DLL_PUBLIC func(void) {
    return func_from_language_runtime();
}
#endif
