view dwt/internal/gtk/runtime/Loader.d @ 11:5f725d09c076

Added dynamic loader from gtkd with cleanup and modifications. Tango only support. No OS.d tie-in yet.
author John Reimer<terminal.node@gmail.com>
date Sat, 05 Jan 2008 15:13:44 -0800
parents
children 8cec8f536af3
line wrap: on
line source

/*****************************************************************************

	license:

	version:

	         Dynamic loader for gtk symbol names

	History: 2004-12-11 initial version by John Reimer
			 2005-02-21 class and symbol names change; versioning modification
			 2005-05-05 linux fixes
			 2007-12-23 source cleanup
			 2007-12-30 merge Paths.d into Loader.d
             2008-01-05 Tango only version using tango.sys.SharedLib

	Note: 	Design inspired by Kris Bell's ICU.d, the dynamic loader from
			an early version of mango

******************************************************************************/

module dwt.internal.gtk.runtime.Loader;

private import  tango.io.Stdout,
                tango.sys.SharedLib;
                
/*****************************************************************************

*****************************************************************************/

enum LIBRARY
{
	ATK,
	CAIRO,
	GDK,
	GDKPIXBUF,
	GLIB,
	GMODULE,
	GOBJECT,
	GTHREAD,
	GTK,
	PANGO,
	GLGDK,
	GLGTK,
	GL,
	GLU,
	GLEXT,
	GDA,
	GLADE,
	GSV,
	GSTREAMER,
	GSTINTERFACES
}

/*****************************************************************************

*****************************************************************************/

version (Windows)
{
	const char[][LIBRARY.max+1] importLibs = [
		LIBRARY.ATK:			"libatk-1.0-0.dll",
		LIBRARY.CAIRO:			"libcairo-2.dll",
		LIBRARY.GDK: 			"libgdk-win32-2.0-0.dll",
		LIBRARY.GDKPIXBUF:		"libgdk_pixbuf-2.0-0.dll",
		LIBRARY.GLIB: 			"libglib-2.0-0.dll",
		LIBRARY.GMODULE: 		"libgmodule-2.0-0.dll",
		LIBRARY.GOBJECT:		"libgobject-2.0-0.dll",
		LIBRARY.GTHREAD:		"libgthread-2.0-0.dll",
		LIBRARY.GTK:			"libgtk-win32-2.0-0.dll",
		LIBRARY.PANGO:			"libpango-1.0-0.dll",
		LIBRARY.GLGDK:			"libgdkglext-win32-1.0-0.dll",
		LIBRARY.GLGTK:			"libgtkglext-win32-1.0-0.dll",
		LIBRARY.GL:				"opengl32.dll",
		LIBRARY.GLU:			"glu32.dll",
		LIBRARY.GDA:			"libgda-2.dll",
		LIBRARY.GLADE:			"libglade-2.0.dll",
		LIBRARY.GSV:			"libgtksourceview-1.0-0.dll",
		LIBRARY.GSTREAMER:		"libgstreamer-0.10.dll",
		LIBRARY.GSTINTERFACES:	"libgstinterfaces-0.10.dll"
	];
}

/*****************************************************************************

*****************************************************************************/

version(linux)
{
	const char[][LIBRARY.max+1] importLibs = [
		LIBRARY.ATK:			"libatk-1.0.so",
		LIBRARY.CAIRO:			"libcairo.so.2",
		LIBRARY.GDK:			"libgdk-x11-2.0.so",
		LIBRARY.GDKPIXBUF:		"libgdk_pixbuf-2.0.so",
		LIBRARY.GLIB:			"libglib-2.0.so",
		LIBRARY.GMODULE:		"libgmodule-2.0.so",
		LIBRARY.GOBJECT:		"libgobject-2.0.so",
		LIBRARY.GTHREAD:		"libgthread-2.0.so",
		LIBRARY.GTK:			"libgtk-x11-2.0.so",
		LIBRARY.PANGO:			"libpango-1.0.so",
		LIBRARY.GLGDK:			"libgdkglext-x11-1.0.so",
		LIBRARY.GLGTK:			"libgtkglext-x11-1.0.so",
		LIBRARY.GL:				"libGL.so",
		LIBRARY.GLU:			"libGLU.so",
		LIBRARY.GLEXT:			"libGL.so",
		LIBRARY.GDA:			"libgda-2.so.3",
		LIBRARY.GLADE:			"libglade-2.0.so",
		LIBRARY.GSV:			"libgtksourceview-1.0.so",
		LIBRARY.GSTREAMER:		"libgstreamer-0.10.so",
		LIBRARY.GSTINTERFACES:	"libgstinterfaces-0.10.so"
	];
}

/*****************************************************************************

    getLibraryPath -- place holder for future expansion

******************************************************************************/


version(Windows)
{
	char[] getLibraryPath()
	{
			return "\\Program Files\\GTK2-Runtime\\lib\\";
	}
}

/*****************************************************************************

	getLibraryPath is empty for linux because default path is known by ld

******************************************************************************/

version(linux)
{
	char[] getLibraryPath() { return ""; }
}

/*****************************************************************************

	ProcLink is used to record the library, function, and function name
	that will be loaded by the dynamic loader.

******************************************************************************/

public struct Symbol
{
	char[]  name;
	void**	pointer;
}

/*****************************************************************************

	The Linker class: handles loading of the library and exported functions

******************************************************************************/

public class Linker
{
	static char[][][char[]] loadFailures;

	/*************************************************************************

		Gets all the failed loads for a specific library.  This is filled in
		only if the default onFailure method is used during load.

		returns: an array of the names that failed to load for a specific
		library or null if none was found.

	**************************************************************************/

	public static char[][] getLoadFailures(char[] libName)
	{
		if ( libName in loadFailures )
		{
			return loadFailures[libName];
		}
		else
		{
			return null;
		}
	}

	/*************************************************************************

		Loads all libraries. This is filled in only if the default onFailure
		method is used during load.

		returns: an array of the library names.

	**************************************************************************/

	public static char[][] getLoadLibraries()
	{
		return loadFailures.keys;
	}

	/*************************************************************************

		isPerfectLoad -- Checks if any symbol failed to load.
		Returns: true if ALL symbols loaded.

	**************************************************************************/

	public static bool isPerfectLoad()
	{
		return loadFailures.keys.length == 0;
	}

	/*************************************************************************

	**************************************************************************/

	public static void dumpFailedLoads()
	{
		foreach ( char[] lib ; Linker.getLoadLibraries() )
		{
			foreach ( char[] symbol ; Linker.getLoadFailures(lib) )
			{
				version(Tango)
					Stdout.formatln("failed ({}) {}", lib, symbol).newline;
			}
		}
	}

	/*************************************************************************

	**************************************************************************/

	private SharedLib primaryLib;
	private SharedLib alternateLib;

	private char[]  libraryName;
	private char[]  alternateLibraryName;

	alias void function( char[] libraryName, char[] symbolName, char[] message=null) FailureCallback;

	private FailureCallback onLoadFailure;

	/*************************************************************************

	**************************************************************************/

	this( char[] libraryName, char[] alternateLibraryName=null )
	{
		this(libraryName, alternateLibraryName, &(Linker.defaultFail));
	}

	/*************************************************************************

	**************************************************************************/

	this (char[] libraryName, char[] alternateLibraryName, FailureCallback fn )
	{
		this.libraryName = libraryName;
		this.alternateLibraryName = alternateLibraryName;
		onLoadFailure = fn;

        SharedLib.throwExceptions = false;

		primaryLib = SharedLib.load( this.libraryName );
        
        version(linux)
        {
            if (this.primaryLib is null)
                primaryLib = SharedLib.load( this.libraryName ~ ".0\0" );
        }
    		
        if ( alternateLibraryName !is null )
		{
			alternateLib = SharedLib.load( this.alternateLibraryName );
		}
		
		if (primaryLib is null)
		{
			throw new Exception("Library load failed: " ~ libraryName);
		}
	}

	/*************************************************************************

		Default load failure callback. Logs the symbols that failed to load.

	**************************************************************************/

	static void defaultFail( char[] libraryName, char[] symbolName, char[] message=null )
	{
		if ( !(libraryName in loadFailures) )
		{
			char[][] cc;
			loadFailures[libraryName] = cc;
		}

		loadFailures[libraryName] ~= symbolName.dup;
	}

	/*************************************************************************

		Loads all the symbols for this library.

	**************************************************************************/

	void link( inout Symbol[] symbols )
	{
		foreach( Symbol link; symbols )
		{
			*link.pointer = primaryLib.getSymbol ( (link.name~"\0").ptr);

			if (*link.pointer is null)
			{
				if ( alternateLib !is null )
				{
					*link.pointer = alternateLib.getSymbol( (link.name~"\0").ptr);
                    Stdout("Loader.Linker.link trying alternate lib: ", link.name).newline;
                }
				if (*link.pointer is null)
				{
					onLoadFailure( libraryName, link.name );
				}
			}
		}
	}

}