1. RE: Using shared objects

>From: Ron Weidner <guest at RapidEuphoria.com>
>Reply-To: EUforum at topica.com
>To: EUforum at topica.com
>Subject: Using shared objects
>Date: Thu, 02 Jun 2005 13:29:46 -0700
>
>posted by: Ron Weidner <nova812 at hotmail.com>
>
>I have some shared object written in C.  Below is the code.
>What I want is to write a euphoria include that maps the
>shared object to euphoria.
>

You will probably need to rewrite the C code slightly, like so:

#include <stdio.h>
#define NUM_DOG 10

__declspec(dllexport) void __stdcall mush(char**, int);
__declspec(dllexport) int __stdcall bark();

__declspec(dllexport) void __stdcall mush(char* dogs[], int len)
{
	int i;
	printf("Number of dogs: %d \n", len );
	for (i=0; i < len; i++)
	{
		printf("Dog named: %s starts mushing...\n", dogs[i]);
	}
}

__declspec(dllexport) int __stdcall bark()
{
	return 1;
}

Note that the __declspec and the __stdcall are Windows-specific, and you 
would probably need to use something different in GCC to make sure a 
function name is exported and not mangled.

The following can be put in your dog.e:

include dll.e
include machine.e

atom dogLib
if platform() = 2 then
    dogLib = open_dll("dog.dll")
elsif platform() = 3 then
    -- You would need to use "./dog.so" here if dog.so is in the current 
directory...
    dogLib = open_dll("dog.so")
end if

constant
mush_ = define_c_proc(dogLib, "mush", {C_POINTER, C_INT}),
bark_ = define_c_func(dogLib, "bark", {}, C_INT)

global procedure mush(sequence p)
    atom lp
    sequence lps
    integer len
    len = length(p)
    lp = allocate(len * 4)
    lps = repeat(0, len)
    for loop = 1 to len do
        lps[loop] = allocate_string(p[loop])
    end for
    poke4(lp, lps)
    c_proc(mush_, {lp, len})
    for loop = 1 to len do
        free(lps[loop])
    end for
    free(lp)
end procedure

global function bark()
    return c_func(bark_, {})
end function



And then of course, you can run your program like you said.

>include dog.e
>if atom(bark()) then
>	mush({"scooby", "dino", "astro", "spike"}) --notice the absence of arg 2
>end if
>
></eucode>
{{{

>

~[ WingZone ]~
http://wingzone.tripod.com/

new topic     » topic index » view message » categorize

2. RE: Using shared objects

Thank you! Your code worked perfectly.  

I didn't test on Windows.  (I don't have a windows box
at the moment to test on) So I'm not sure about the 
whole bit about ...

__declspec(dllexport) void __stdcall

But, if I had to guess, (and this is only a guess) you
should only need that stuff if and only if you are
using a c++ compiler as opposed to a c compiler.  I
compiled the dog.so using GCC which is a C compiler 
and didn't need to make any changes to the C code. I
suspect if I compiled using g++, I would need to 
make some changes.

I studied your code, cross referenced it with the eu docs, 
and now I'm goint to take a crack at explaining it.  Let
me know if I'm close.

atom dogLib  -- used like a pointer
-- You would need to use "./dog.so" here if dog.so 
-- is actually in the current directory or you could
-- use ./somedir/dog.so if the .so is nested deeper
-- relative to the current directory 

-- load the dll and return a pointer to its mem location
dogLib = open_dll("./dog.so")  

-- This is like porting the C header files to Euphoria
constant
mush_ = define_c_proc(dogLib, "mush", {C_POINTER, C_INT}),
bark_ = define_c_func(dogLib, "bark", {}, C_INT)

global procedure mush(sequence p)
    atom lp         -- used as a pointer
    sequence lps    -- used as an array of pointers
integer len     -- len of p where p is expected to be a sequence of
    sequences
    len = length(p)
    
    -- create a pointer to a block of mem 4 bytes long * the len of p
    -- the reason for 4 bytes is because that's the size of a pointer
    lp = allocate(len * 4) 
    
    -- delete any garbage in the memory locations
    lps = repeat(0, len)
    
    -- start making pointers to each sequence in p
    for loop = 1 to len do
        
	-- allocate enough mem for p[loop] + 1, strcpy the val
	-- in p[loop] & "\0" to that location and return a
	-- pointer to it.
        lps[loop] = allocate_string(p[loop]) 
	
    end for
    
    -- poke4(atom where_p, object what)  
    -- put the 4 pointers just created into the lp mem location
    poke4(lp, lps)
    
    -- call the c function (procedure since the C return val is void)
    c_proc(mush_, {lp, len}) 
    
    -- look ma... mem leaks in euphoria are posible. :)
    for loop = 1 to len do
        free(lps[loop])  -- free the strings
    end for
    
    free(lp)  -- free the mem storing pointers to the strings
end procedure -- how'd I do??

global function bark()
    return c_func(bark_, {})
end function


new topic     » goto parent     » topic index » view message » categorize

3. RE: Using shared objects

Ron Weidner wrote:
> }}}
<eucode>
> atom dogLib  -- used like a pointer
> -- You would need to use "./dog.so" here if dog.so 
> -- is actually in the current directory or you could
> -- use ./somedir/dog.so if the .so is nested deeper
> -- relative to the current directory 
> 
> -- load the dll and return a pointer to its mem location
> dogLib = open_dll("./dog.so")  
> 
> -- This is like porting the C header files to Euphoria
> constant
> mush_ = define_c_proc(dogLib, "mush", {C_POINTER, C_INT}),
> bark_ = define_c_func(dogLib, "bark", {}, C_INT)
> 
> global procedure mush(sequence p)
>     atom lp         -- used as a pointer
>     sequence lps    -- used as an array of pointers
>     integer len     -- len of p where p is expected to be a sequence of
>     sequences
>     len = length(p)
>     
>     -- create a pointer to a block of mem 4 bytes long * the len of p
>     -- the reason for 4 bytes is because that's the size of a pointer
>     lp = allocate(len * 4) 
>     
>     -- delete any garbage in the memory locations
>     lps = repeat(0, len)
</eucode>
{{{


lps = repeat(0,len) doesn't delete any garbage in the memory location, it
creates
a euphoria sequence of len, filled with 0's.  In other words, if len is 4, you
get lps = {0,0,0,0}

>     -- start making pointers to each sequence in p
>     for loop = 1 to len do
>         
> 	-- allocate enough mem for p[loop] + 1, strcpy the val
> 	-- in p[loop] & "\0" to that location and return a
> 	-- pointer to it.
>         lps[loop] = allocate_string(p[loop]) 
> 	
>     end for
>     
>     -- poke4(atom where_p, object what)  
>     -- put the 4 pointers just created into the lp mem location
>     poke4(lp, lps)
>     
>     -- call the c function (procedure since the C return val is void)
>     c_proc(mush_, {lp, len}) 
>     
>     -- look ma... mem leaks in euphoria are posible. :)
>     for loop = 1 to len do
>         free(lps[loop])  -- free the strings
>     end for


Memory Leaks are possible in Euphoria, yes.  But Memory leaks are only
possible during the execution of Euphoria, at the end of the execution of
your Euphoria program, any memory allocated BY the Interpreter, will get
freed automatically.  Any memory allocated by External C libraries, must
maintain their own memory cleanup, as Euphoria has no clue about the
memory allocated by them.

>     free(lp)  -- free the mem storing pointers to the strings
> end procedure -- how'd I do??
> 
> global function bark()
>     return c_func(bark_, {})
> end function
> 
> <font color="#330033">

</font>

Other then the two points I made, you are exactly right on the money for the
rest of the stuff.

Mario Steele
http://enchantedblade.trilake.net
Attaining World Dominiation, one byte at a time...

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu