DynLoad is a cross-platform system for dynamically loading arbitrary libraries.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dirkson 6b5fea0096 Brought up to -w flag spec 8 months ago
genfiles Fixed symbol/dynobj mixup 1 year ago
include Added xlib_nuklear genfile. Adjusted dynload.h 2 years ago
src Brought up to -w flag spec 8 months ago
.gitignore Ncurses 1 year ago
LICENSE Initial commit. Non-functional 2 years ago
README.md Removed travis integration 1 year ago
build Updating osmia 8 months ago
meson.build Brought up to -w flag spec 8 months ago

README.md

libdynload

DynLoad is a cross-platform system for dynamically loading arbitrary libraries.

Tell dynloadgen some information about your library. It uses that info to create a C header file. That header file allows libdynload to dynamically load your library.

DynLoad is minimal and written in C89. It’s MIT licensed, and intended to be statically compiled. DynLoad and its generated files should work on POSIX operating systems (linux, bsd, osx, etc.) and windows.

dynload() and dynunload() are not thread-safe; They must be allowed to complete fully before any threads attempt to interact with the dynamically loaded library. Other than that, using LibDynLoad should not affect the thread-safety of a library.

Libraries loaded with LibDynLoad maintain their original symbol names. This means that tutorials or code implemented with static or dynamic linking in mind should continue to function unchanged after implementing dynamic loading through LibDynLoad.

Why?

Most of the time, Dynamic Linking is preferrable to Dynamic Loading, and should be used in preference to dynload.

However some software needs to run on operating systems it was not compiled on, and as a result may not know for certain which libraries are and are not available to use. In this case, dynamic linking would cause the software to fail to run entirely if the target system were missing a linked library. Operating systems handle this differently, but the most common result is to fail to run the executable with either no error message, or an error message that does not mention which library is missing.

Static Linking is the usual solution to this issue. But Static Linking increases file size, prevents operating system memory optimizations, prevents users from upgrading libraries separately from software, and can have insurmountable licensing incompatibilities with the LGPL and similar licenses. LibDynLoad itself should be compatible with any common license.

Dynamic Loading, and libDynLoad, allows you to attempt to use a library without making your code dependent on that library to run. If a library is unavable at runtime, your code can fall back to other libraries or display an enlightening error to the user. Examples of software that might benefit from dynamic loading for these reasons are the Steam client, games sold through Steam, Unity games, the Unity development environment, context creation libraries like glfw, etc.

Additionally, if some large required library is not required for interactivity, delayed dynamic loading of that library may reduce the time between running a program and the user being able to interact with the program, when compared to both Static Linking and Dynamic Linking.

HowTo

Install “Meson” and “Ninja” for the build system. The build system will automatically detect and use gcc-musl if available.

./build r

./release/dynloadgen genfiles/xaw.gen

Example

genfiles/xaw.gen

# Changing order of headers, preprocessor, or dynamicobjects is fine
# The following "xaw" is the name of the library
xaw {

    # Dynamic objects are checked in-order
    dynobj {
        libXaw.so.7
        libXaw.so
    }

    # For your convenience, you can spread your defines out over multiple lines
    # The brackets are important, even if you don't have defines.
    # "clang" would also be valid, and is the only preprocessor that could work for C++
    gcc {
        #-DSOMEDEFINE
        #-DSOMEOTHERDEFINE
    }

    # dynloadgen will only search for symbols inside the headers you tell it to.
    # It WILL, however, use the preprocessor to pull in associated headers automatically.
    # Most projects won't need multiple headers, but some, like Xaw, do.
    /usr/include/X11/Xaw/XawInit.h {
        XtAppInitialize
        XtCreateManagedWidget
        XtAppMainLoop
        XtRealizeWidget
        #Accidentally inserting arbitrary names won't cause fatal errors
        #Bob
    }
    # dynload can handle both function and non-function symbols (Like "labelWidgetClass")
    /usr/include/X11/Xaw/Label.h {
        labelWidgetClass
    }
    # Full paths are fine - dynloadgen will figure it out.
    /usr/include/X11/Xaw/Box.h {
        boxWidgetClass
        #But using the same symbol twice in the same file would cause a fatal error.
        #Bob
    }   
    /usr/include/X11/Xaw/Command.h {
        commandWidgetClass
    }   
}  

Now we run our dynamic loader generator on the input files:

./release/dynloadgen genfiles/xaw.gen

It makes a directory named “dynload_xaw”, with dynload_xaw.h in it.

$ ls dynload_xaw/
dynload_xaw.h

To use these files, insert the header file into your build system. Then call: dynload(&dynload_xaw)

example.c:

#include <dynload.h>
#include "dynload_xaw.h"

int main()
{
	dynload(&dynload_xaw);
	Widget toplevel = XtAppInitialize(...
	return 0;
}

We’ll also need to link in libdynload.a for “dynload()” to function. It can be found after a build in release/libdynload.a or debug/libdynload.a

FAQ

Q: Why are function pointers stored in void* arrays, rather than directly in the structs?

A: Doing it this way allows for substantially less generated code, and reuse of the dynload_load/unload code. It also almost forces you to use the provided macros, keeping your own code more readable and maintainable.

TODO / Known issues

  • Dynload should resolve when handed a symlink. dlopen does not for some insane reason, so currently dynload does not.
  • LibDynLoad does not understand extensions, such as opengl’s glGetString(GL_EXTENSIONS)
  • LibDynLoad provides no asyncronous loading, which may be useful for performance-inspired loading of large libraries.

  • Currently, C++ librares are out of reach. However, these pages may provide insight for the future:

  • DynLoadGen is not currently cross platform in any real way.

  • DynLoadGen is not a full C parser, and thus fails to make correct typedefs for some rare but possible C code:

    • If some expression is directly in front of a desired symbol, on the same line.

    • If a non-function desired symbol contains something like: [23]

  • SDF is not a widely used format. Some other human-readable format should be used.