Shared Libraries - DOS


A shared library is compiled code that can be loaded and used later when running an executable.

Description:
DOS supports shared libraries (dynamic link libraries) with some limitations compared to Linux and Windows. The DOS target uses the dxe3gen utility from DJ's GNU Programming Platform (DJGPP) for creating a DXE file (shared library).

Supported
Limitations
DXE3GEN
dxe3gen is a utility which allows you to create files which contain dynamically loadable code (DXE). DXE is used as a synonym for `dynamically loadable executable module'. See dxe3gen.

dxe3gen expects that DXE_LD_LIBRARY_PATH to be set. If the environment variable is not already set, fbc will set the variable to fbc's library path before invoking dxe3gen.

In fbc standalone set-up, custom linker script dxe.ld is expected to be present in fbc's library path since dxe3gen will invoke 'ld' linker to generate and executable, which in turn is converted to a .DXE file.

Shared Library Using Run-time Dynamic Loading
In this first example, we use d1.bas source for the DXE and m1.bas for the test. This example will also work on Linux and Windows with no changes, however, differences are noted in the example sources.

$ fbc d1.bas, on DOS, will produce d1.dxe dynamic link library and libd1_il.a import library.
$ fbc m1.bas, on DOS, will produce m1.exe executable.

Library loading and function pointer loading is handled manually by the user at run-time.

'' d1.bas - dynamic link library

'' tell fbc to build a dynamic link library
#cmdline "-dll"

'' on DOS:
''   - creates d1.dxe (dynamic link library)
''   - creates libd1_il.a (import library)
'' on Windows:
''   - creates d1.dll (dynamic link library)
''   - creates libd1.dll.a (import library)
''   - either d1.dll or libd1.dll.a must be found to link an
''     executable using d1.dll
''   - d1.dll must be found to load and run an executable
''     using d1.dll
'' on Linux:
''   - creates libd1.so (dynamic link library)
''   - libd1.so must be found to load and run an executable
''     using libd1.do
''   - $ LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./executable

Sub proc_d1( ByRef fromproc As Const String ) Export
    Print __FILE__ & " : " & __FUNCTION__ & " @ " & _
        Hex(ProcPtr(proc_d1),SizeOf(Any Ptr)*2) & _
        " called from: " & fromproc
End Sub


'' m1.bas - dynamically load "D1" library and symbol "PROC_D1" at run time
''
'' library loading and symbol pointers are managed
'' manually by the user.

#define NULL 0

'' variable to hold a handle to the loaded dynamic link libray
Dim library As Any Ptr

'' prototype the function pointer
Type PROC_D1_PTR As Sub( ByRef from As Const String )

'' variable to hold a pointer to the sub/function in the dll
Dim proc_d1 As PROC_D1_PTR

'' some differences in naming between DOS and other targets,
'' so assign the names to some constants so the build process
'' can work on DOS and other targets:
#ifdef __FB_DOS__
    Const D1_DLL_NAME = "d1.dxe"
    Const PROC_D1_NAME = "_PROC_D1"
#else
    Const D1_DLL_NAME = "d1"
    Const PROC_D1_NAME = "PROC_D1"
#endif

'' try to load in the libray
library = DyLibLoad( D1_DLL_NAME )

If( library = NULL ) Then
    Print "unable to load library " + D1_DLL_NAME
    End 1
End If

'' get a function pointer to the procedure defined in the DXE
proc_d1 = DyLibSymbol( library, PROC_D1_NAME )
If( proc_d1 = NULL ) Then
    Print "unable to load symbol " + PROC_D1_NAME
    End 1
End If

'' call the loaded procedure
proc_d1( __FILE__ & " : " & __FUNCTION__ )

'' release the library
DyLibFree( library )


Shared Library Using Import Library
In this example, we use d1.bas source (from above) for the DXE and m2.bas below for the test. This example will also work on Linux and Windows with no changes, however, differences are noted in the example sources.

$ fbc d1.bas (from above), on DOS, will produce d1.dxe dynamic link library and libd1_il.a import library.
$ fbc m2.bas, on DOS, will produce m2.exe executable.

Library loading and function exports are handled automatically by the executable loader and run time start up code. The include file d1.bi is not strictly needed, however is good practice to have a single place where functions are declared so there are no mismatches between usage across multiple modules.

'' d1.bi - include file for d1.bas declarations
#pragma once
Declare Sub proc_d1( ByRef from As Const String )


'' m2.bas - link to import library

'' use an import library for d1.dxe/d1.dll/d1.so
''
'' library loading and symbol pointers are managed
'' automatically by the operating system and/or
'' runtime start-up code.

'' import libraries are named differently on
'' DOS compared to other targets.  Or in case of
'' at least win/linux not actually needed.  On DOS
'' #inclib will cause linker to look for libd1_il.a
'' when linking this executable.  The import library includes
'' some start-up code to export functions from the dynamic
'' link library when it is loaded at runtime.
#ifdef __FB_DOS__
    #inclib "d1_il"
#else
    #inclib "d1"
#endif

'' include declarations for the library from a header
#include once "d1.bi"

'' call the function in the DLL
proc_d1( __FILE__ & " : " & __FUNCTION__ )

#ifdef __FB_DOS__

'' add a module constructor to initialize the exports from
'' rtlib at run time.  Should be the first call made.
'' Careful: module constructor order is not guaranteed so
'' this is likely the only constructor that can be present
'' in the entire application, aside from the implicit
'' constructors in the DXE file that initialize it's exports.
''
Private Sub __fb_init_libfb_dxe Constructor
    DyLibLoad( "" )
End Sub

#endif


Version:
See also:
Back to Programmer's Guide
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki



sf.net phatcode