1. Creating and using a .DLL/.SO?

Shouldn't this work:

-- hello.e 
global procedure hello() 
    puts(1, "Hello, World!\n") 
end procedure 
 
-- myprog.ex 
atom lib = open_dll("hello.dll") 
atom fHello = define_c_proc(lib, "hello", {}) 
? fHello 

To compile and run:

C:\MyProg > ecw -dll hello.e 
C:\MyProg > emake 
C:\MyProg > excw myprog.ex 
-1 

As you can see, the open_dll call suceeded but the define_c_proc failed. Any thoughts?

Jeremy

new topic     » topic index » view message » categorize

2. Re: Creating and using a .DLL/.SO?

Um,

Never mind, user error, it works.

Jeremy

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

3. Re: Creating and using a .DLL/.SO?

jeremy said...

Shouldn't this work: <snip>

As you can see, the open_dll call suceeded but the define_c_proc failed. Any thoughts?

Jeremy

I'm not sure what the "correct" way to do it is.

Looking at the translated c source, hello seems to have been renamed to _1hello, which is probably the cause of the failed define_c_proc call.

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

4. Re: Creating and using a .DLL/.SO?

Ok, so it's not really user error. The code works on Windows, but not Linux. So that we can have the full code (typed the other one in), I'll paste the code here that works in Windows but not in Linux.

-- hello.e 
global procedure hello() 
    puts(1, "Hello, WOrld!\n") 
end procedure 
 
-- myprog.ex 
include std/dll.e 
 
atom lib = open_dll("./hello.so") 
atom fHello = define_c_proc(lib, "hello", {}) 
? {lib, fHello} 
c_proc(fHello, {}) 

Note: the .so in the above code is .so on the Linux copy and .dll on the Windows copy.

The output of the windows version is:

{9043968,12} 
Hello, World! 

The output of the linux version is:

{135587536,-1} 
 
myprog.ex:6 
c_proc/c_func: bad routine number (-1) 
 
--> See ex.err 

Jeremy

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

5. Re: Creating and using a .DLL/.SO?

jimcbrown said...

I'm not sure what the "correct" way to do it is.

Looking at the translated c source, hello seems to have been renamed to _1hello, which is probably the cause of the failed define_c_proc call.

Jim,

On windows, such name changing is not necessary but on Linux, the name change is required. So, define_c_proc(lib, "hello", {}) works on Windows, fails on Linux. define_c_proc(lib, "_1hello", {}) works on Linux but fails on Windows.

Jeremy

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

6. Re: Creating and using a .DLL/.SO?

Since we're doing all this work on the version 4.0, couldn't we make the translator automatically output a wrapper file for the library? Say, all global constants and routines, then build the simple wrapper routines? That's always been a pipe dream of mine... getlost

-Greg

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

7. Re: Creating and using a .DLL/.SO?

ghaberek said...

Since we're doing all this work on the version 4.0, couldn't we make the translator automatically output a wrapper file for the library? Say, all global constants and routines, then build the simple wrapper routines? That's always been a pipe dream of mine... getlost

Yeah, that's a good idea. I think we need to revisit the translator output for dll/so's (and I think there was some traffic on the devs list previously, but I don't think we ever did anything). It's probably a good stopgap for an idea I had for post-4.0. I put something up on the wiki, though I'm not sure anyone has really looked at it:

  1. Compile a euphoria include as a dll.
  • Translator adds a function that returns data about the public / exported routines, which the interpreter adds to the symbol table as special euphoria routines
  • User can call compiled routines like normal euphoria routines, and the interpreter handles the call transparently
  • Possibly use ifdefs to determine whether regular interpreted or compiled library to be used (if available)
  • Add a lib/ dir in the euphoria directory structure as a place for the compiled libs to live, or possibly specify other locations through config file

Basically, I'm looking at ways to blur the line between translated and interpreted code, and to get them to run together. This will be helpful for other things, such as having dynamic code execution, or for being able to shroud a library, and include it similarly to how we did so pre-2.5.

Matt

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

8. Re: Creating and using a .DLL/.SO?

I do think that global/public/export functions/procedures should be created in the dll/so as is, right? w/no name mangling?

Jeremy

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

9. Re: Creating and using a .DLL/.SO?

I like Matt's thinking on this... let's have a standard exported symbol table in the DLL/SO that the Interpreter reads as part of an open_dll() call, which it then automatically imports and makes available. Seamless...

-Greg

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

10. Re: Creating and using a .DLL/.SO?

How will this work when I want to load multiple dll/so files that have the same function names? For instance:

dbi_pgsql.so, dbi_mysql.so, dbi_sqlite.so, dbi_eds.so:

dbi_open(), dbi_query(), dbi_close()

In code, I could do something like:

public function dbi_load_driver(sequence name) 
   atom driver_id = open_dll("mod_" & name) 
   return { 
       driver_id, 
       define_c_func(driver_id, "dbi_open", ...), 
       ... 
   } 
end function 
 
public function dbi_open(driver, ...) 
    return c_func(driver[FUNC_DBI_OPEN], ...) 
end function 
 
... 

Thus, a Euphoria program could connect to multiple database servers/files at the same time, varrying, and have no idea what the actual underlying database would be. A common interface, loaded at runtime. The application could be extended for database support far beyond what the original author ever knew. Simply develop a new, conforming DBI driver and the application would be able to then access that database.

So, in this case, I would not want the contents of the mod_pgsql.so and mod_mysql.so automatically available to the runtime. I would think this type of thing would happen frequently. For instance, any type of pluggable module. Say you have a modular system to load a file: mod_text.so, mod_rtf.so, mod_html.so, mod_xml.so, etc... All of them would include a function called: open_file()... and would return some type of common data type for your application. I may want to open/parse html files, xml, rtf, etc... all at the same time, so all modules would be loaded, but all have the exact same function names.

Jeremy

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

11. Re: Creating and using a .DLL/.SO?

jeremy said...

How will this work when I want to load multiple dll/so files that have the same function names? For instance:

My basic idea is to create a system where the user can't even tell the difference between using an interpreted vs translated include file. There would probably be a runtime switch or something, and some magic that happens behind the scenes to merge the symbol table of your interpreted application and the translated includes so that from a usage point of view, there's really no difference, except that you get a faster application. I'd imagine that the standard library would be installed this way, so that you could use it out of the box.

If there were namespace conflicts, they'd be resolved the same way they are now. There are definitely a lot of details to be worked out, but I think it's possible to integrate translated and interpreted code in the same application.

Basically, the translated library would define some extra functions, where the application would ask for the symbols it makes visible to other code, and the parser would make appropriate entries for the symbol table. When you need to call a translated routine, it would mark that as special, and make a callback like call to it.

Matt

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

12. Re: Creating and using a .DLL/.SO?

Why not just allow a user to create include files that are compiled
to IL code that just expose their PUBLIC functions/procedures names.
Then the interpreter or translator could easily use them in DLLs or
programs.

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

13. Re: Creating and using a .DLL/.SO?

mattlewis said...

My basic idea is to create a system where the user can't even tell the difference between using an interpreted vs translated include file.

...

I do not see how this would handle:

open_dll("dbi_mysql.so") 
open_dll("dbi_pgsql.so") 
open_dll("dbi_eds.so") 

Where all three .so files defined 20 functions/procedures of the exact same name. If the plan is to allow namespaces on these, then that would make life pretty difficult to make transparent calls. For instance, to further the above code, the programmer would have to know what database backend was being used:

mysql:dbi_open() 
pgsql:dbi_open() 
eds:dbi_open() 

The whole idea of many plugin modules, dbi interfaces, etc... is to make it so the programmer could care less what module/dbi interface was being used.

Jeremy

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

14. Re: Creating and using a .DLL/.SO?

mattlewis said...

... There are definitely a lot of details to be worked out, but I think it's possible to integrate translated and interpreted code in the same application.

For now (today, tomorrow, 4.0a3), wouldn't it be best to just fix the name mangling problem? i.e. this code:

-- mod_hello.e 
public procedure hello() 
    puts(1, "Hello, World!\n") 
end procedure 

When compiled to a .dll, produces a .dll that has the procedure "hello" exported. When compiled to a .so, produces a .so that has the procedure "_1hello" exported.

Jeremy

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

15. Re: Creating and using a .DLL/.SO?

Why would you use open_dll() to include a translated include file?

I thought you'd just do

include dbi_mysql.so as mysql 

and that'd signal to the interpreter to attempt to call the translator hooks to cause the seamless integration (whereas the open_dll() call would work, but then you'd still have to deal with calling the translated code as C code from inside the euphoria code).

Also, once the infrastructure for translated includes is in place, I don't see why

include dbi_mysql.il as mysql 

would be a problem either.

jeremy said...
mattlewis said...

My basic idea is to create a system where the user can't even tell the difference between using an interpreted vs translated include file.

...

I do not see how this would handle:

open_dll("dbi_mysql.so") 
open_dll("dbi_pgsql.so") 
open_dll("dbi_eds.so") 

Where all three .so files defined 20 functions/procedures of the exact same name. If the plan is to allow namespaces on these, then that would make life pretty difficult to make transparent calls. For instance, to further the above code, the programmer would have to know what database backend was being used:

mysql:dbi_open() 
pgsql:dbi_open() 
eds:dbi_open() 

The whole idea of many plugin modules, dbi interfaces, etc... is to make it so the programmer could care less what module/dbi interface was being used.

Jeremy

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

16. Re: Creating and using a .DLL/.SO?

jimcbrown said...

Why would you use open_dll() to include a translated include file?

I thought you'd just do

include dbi_mysql.so as mysql 

That seems like a nice way to simply include compiled code, however, it does not allow any type of dynamic module loading. For instance, take eudoc. It has source code parsers, each parser has a function called parse(sequence filename) and it returns a sequence structured property for eudoc. Here's how I would envision something like that working:

enum PARSER_FEXT, PARSER_FUNC_ID 
sequence parsers = {} 
 
procedure load_parser_modules() 
  sequence files = dir("parser_*.so") 
  for file in files do 
    atom lib = open_dll(file[FILENAME]) 
    atom init_func = c_func(lib, "init", ...) 
    sequence parser_info = c_func(init_func, ...) 
    parsers &= { parser_info[PARSER_NAME], parser_info[FILE_EXTENSION], 
        c_func(lib, "parse", ...) } 
  end for 
end procedure 
 
-- Now later in code: 
 
function parse(sequence filename) 
  atom parser = find_parser_in_parsers_sequence(filename) 
  return c_func(parser, {filename}) 
end function 

That of course is not all legit code, but could easily be. So, in this case we may have a parser for Euphoria, C, Makefile, Text files, Creole files, HTML files, or whatever. EuDoc could be used for *any* language, as long as a parser is written for it. In this example (a very viable and common use of loadable modules) the user of the loadable module does not want the functions embedded, nor does he/she want to handle them by namespaces. Further, they want to load them dynamically (i.e. not knowing what they are at the time of writing the code).

Jeremy

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

17. Re: Creating and using a .DLL/.SO?

jeremy said...

That seems like a nice way to simply include compiled code, however, it does not allow any type of dynamic module loading. For instance, take eudoc. It has source code parsers, each parser has a function called parse(sequence filename) and it returns a sequence structured property for eudoc.

So, in this case we may have a parser for Euphoria, C, Makefile, Text files, Creole files, HTML files, or whatever. EuDoc could be used for *any* language, as long as a parser is written for it. In this example (a very viable and common use of loadable modules) the user of the loadable module does not want the functions embedded, nor does he/she want to handle them by namespaces. Further, they want to load them dynamically (i.e. not knowing what they are at the time of writing the code).

Jeremy

This is a good point. We currently don't have a way to do this with pure eu code (although ifdef comes pretty close). It seems silly to require translation to make this work though (although I admit that requiring translation is also the easiest of all the solutions to allow dynamic pluggable modules).

jeremy said...

Here's how I would envision something like that working:

enum PARSER_FEXT, PARSER_FUNC_ID 
sequence parsers = {} 
 
procedure load_parser_modules() 
  sequence files = dir("parser_*.so") 
  for file in files do 
    atom lib = open_dll(file[FILENAME]) 
    atom init_func = c_func(lib, "init", ...) 
    sequence parser_info = c_func(init_func, ...) 
    parsers &= { parser_info[PARSER_NAME], parser_info[FILE_EXTENSION], 
        c_func(lib, "parse", ...) } 
  end for 
end procedure 
 
-- Now later in code: 
 
function parse(sequence filename) 
  atom parser = find_parser_in_parsers_sequence(filename) 
  return c_func(parser, {filename}) 
end function 

That of course is not all legit code, but could easily be.

Why wouldn't that work now? Other than some trivial shorthand and the _1hello bug/issue, that code looks like it would run today.

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

18. Re: Creating and using a .DLL/.SO?

jimcbrown said...

Why wouldn't that work now? Other than some trivial shorthand and the _1hello bug/issue, that code looks like it would run today.

Yes, with some trivial solution to the _1hello vs. hello bug, this would run just fine today. I guess my whole point to this thread is, why don't we fix the _1hello vs. hello bug before 4.0a3 instead of focusing on a new automated system right now. I have not looked at the code yet producing the _1 bug, I'll do that shortly. I thought that some may know exactly where that problem is. The translator is an area that I have spent hardly no time in.

Jeremy

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

19. Re: Creating and using a .DLL/.SO?

jeremy said...
mattlewis said...

My basic idea is to create a system where the user can't even tell the difference between using an interpreted vs translated include file.

...

I do not see how this would handle:

open_dll("dbi_mysql.so") 
open_dll("dbi_pgsql.so") 
open_dll("dbi_eds.so") 

Where all three .so files defined 20 functions/procedures of the exact same name. If the plan is to allow namespaces on these, then that would make life pretty difficult to make transparent calls. For instance, to further the above code, the programmer would have to know what database backend was being used:

mysql:dbi_open() 
pgsql:dbi_open() 
eds:dbi_open() 

The whole idea of many plugin modules, dbi interfaces, etc... is to make it so the programmer could care less what module/dbi interface was being used.

Yes, this is a separate issue. My short answer would be that the translated version would be handled (from the user's perspective) the same as it would be if your modulized data access layer were interpreted.

Matt

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

20. Re: Creating and using a .DLL/.SO?

jeremy said...
mattlewis said...

... There are definitely a lot of details to be worked out, but I think it's possible to integrate translated and interpreted code in the same application.

For now (today, tomorrow, 4.0a3), wouldn't it be best to just fix the name mangling problem? i.e. this code:

-- mod_hello.e 
public procedure hello() 
    puts(1, "Hello, World!\n") 
end procedure 

When compiled to a .dll, produces a .dll that has the procedure "hello" exported. When compiled to a .so, produces a .so that has the procedure "_1hello" exported.

Jeremy

Yes, this is something that we should fix.

Matt

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

21. Re: Creating and using a .DLL/.SO?

jimcbrown said...

Why would you use open_dll() to include a translated include file?

I thought you'd just do

include dbi_mysql.so as mysql 

Actually, my idea was to have (ignore the 'modulization' issue that Jeremy was talking about for now):

include dbi_mysql.e as mysql 

And there would be some configuration option to check for installed (in a specific place) translated include files, so that from the user's point of view, there's no difference in usage.

Matt

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

22. Re: Creating and using a .DLL/.SO?

jeremy said...

That seems like a nice way to simply include compiled code, however, it does not allow any type of dynamic module loading.

Yes, true dynamic module loading is going to require an eval-like capability, I think, though I suspect that some of the stuff that will need to be developed for the transparent use of translated code will probably be useful for eval stuff, too.

Matt

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

23. Re: Creating and using a .DLL/.SO?

jeremy said...

For now (today, tomorrow, 4.0a3), wouldn't it be best to just fix the name mangling problem? <snip> When compiled to a .dll, produces a .dll that has the procedure "hello" exported. When compiled to a .so, produces a .so that has the procedure "_1hello" exported.

Jeremy

Both versions of the C source have it as _1hello. It is named _1hello in the translated C code regardless of platform.

The difference is, the Windows version writes out a .def file that exports _1hello as hello when we are compiling a dll. When compiling a shared object (.so) there is no exports file for Unix, so we are stuck with _1hello. This looks quite difficult to fix on the Unix side short of truly naming the object without the _1 prefix (but then doing this affects the Windows code).

See Write_def_file() in source/c_decl.e for the actual code.

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

24. Re: Creating and using a .DLL/.SO?

jimcbrown said...

Both versions of the C source have it as _1hello. It is named _1hello in the translated C code regardless of platform.

The difference is, the Windows version writes out a .def file that exports _1hello as hello when we are compiling a dll. When compiling a shared object (.so) there is no exports file for Unix, so we are stuck with _1hello. This looks quite difficult to fix on the Unix side short of truly naming the object without the _1 prefix (but then doing this affects the Windows code).

See Write_def_file() in source/c_decl.e for the actual code.

There's also the issue of possibly conflicting names. And I believe that gcc prefixes an underscore (though maybe not in all situations). Perhaps the best thing to do is just to output the .e wrapper that handles the imports correctly. We could also do a regular C header (.h) fileprobably optional.

The wrapper could be possibly multiple files with a "lib" prefix. The multiple files would allow us to replicate the namespaces. Or we could change the default namespace to be changeable within a file.

Matt

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

25. Re: Creating and using a .DLL/.SO?

mattlewis said...

There's also the issue of possibly conflicting names.

We run that risk right now on Windows, because an export.def file is created that looks like this:

EXPORTS 
hello = _1hello 

and you could presumably have:

EXPORTS 
hello = _1hello 
hello = _2hello 
hello = _3hello 

mattlewis said...

And I believe that gcc prefixes an underscore (though maybe not in all situations).

So far that has not been the case with the .so files I have created on Linux. However, none have been extensive, they have been simple tests. We are outputting _1hello and that's what is being "exported" from the .so.

mattlewis said...

Perhaps the best thing to do is just to output the .e wrapper that handles the imports correctly. We could also do a regular C header (.h) fileprobably optional.

The wrapper could be possibly multiple files with a "lib" prefix. The multiple files would allow us to replicate the namespaces. Or we could change the default namespace to be changeable within a file.

I'm not sure what you mean here. Sorry.

Jeremy

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

26. Re: Creating and using a .DLL/.SO?

mattlewis said...

There's also the issue of possibly conflicting names.

In regards to reserved words in C but usable names in eu, I like the approach that CName() takes. At least it is well defined.

In regards to "reserved" words (like fopen() or dlopen() ) I'm not sure should be done. Mangling (as above) is probably the safest option though.

In regards to conflicting names within the eu code itself (public function ftakes() in file ftakes.e conflicting with public function ftakes() in file outtakes.e for example, included in a.e and b.e respectively and used only there and then a.e and b.e are included in main.ex) this is a tricky situation. Back when we had only global it was a lot easier, but having namespaces makes even this hard. In this case, we need a way to have the user (the one translating the code into a dll/so) specify what to do. There's no way to "do the right thing" and have everybody be happy.

mattlewis said...

And I believe that gcc prefixes an underscore (though maybe not in all situations).

This is only an issue when mixing and matching compilers. This is actually an ELF standard (meaning all C compilers for all Unix platforms that output ELF binaries will name the functions in the same way), so I believe an issue would only ever arise when using gcc and Windows (e.g. mingw to translate eu to a dll).

mattlewis said...

Perhaps the best thing to do is just to output the .e wrapper that handles the imports correctly. We could also do a regular C header (.h) fileprobably optional.

I guess by .e wrapper you mean outputting a .e file that has the correct open_dll() and define_c_func()/proc() calls to call the dll from within eu code?

How would one call the dll from C code without a .h wrapper?

mattlewis said...

The wrapper could be possibly multiple files with a "lib" prefix. The multiple files would allow us to replicate the namespaces. Or we could change the default namespace to be changeable within a file.

Matt

I'm not sure I follow. What would this mean?

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

27. Re: Creating and using a .DLL/.SO?

jeremy said...
mattlewis said...

There's also the issue of possibly conflicting names.

We run that risk right now on Windows, because an export.def file is created that looks like this:

EXPORTS 
hello = _1hello 

and you could presumably have:

EXPORTS 
hello = _1hello 
hello = _2hello 
hello = _3hello 

And this actually works???

jeremy said...
mattlewis said...

And I believe that gcc prefixes an underscore (though maybe not in all situations).

So far that has not been the case with the .so files I have created on Linux. However, none have been extensive, they have been simple tests. We are outputting _1hello and that's what is being "exported" from the .so.

The way ELF works, the prefix _ is appended to all C symbols by default - so when C code interacts the prefix is invisible. It is only when you are dealing with assembly language and linking that you have to worry about it (I guess dlopen() and dlsym() handle this transparently). I think Watcom behaves similarly.

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

28. Re: Creating and using a .DLL/.SO?

jimcbrown said...
jeremy said...

We run that risk right now on Windows, because an export.def file is created that looks like this:

......

and you could presumably have:

EXPORTS 
hello = _1hello 
hello = _2hello 
hello = _3hello 

And this actually works???

Not that I know of, I was just saying that we do not guard against such a thing, so naming a C function "hello" twice would err out either way.

Jeremy

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

29. Re: Creating and using a .DLL/.SO?

jeremy said...
mattlewis said...

Perhaps the best thing to do is just to output the .e wrapper that handles the imports correctly. We could also do a regular C header (.h) fileprobably optional.

The wrapper could be possibly multiple files with a "lib" prefix. The multiple files would allow us to replicate the namespaces. Or we could change the default namespace to be changeable within a file.

I'm not sure what you mean here. Sorry.

I'm basically talking about a wrapper to make the resulting compiled library easy to use with other euphoria code (open_dll, define_c_*, etc).

Matt

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

Search



Quick Links

User menu

Not signed in.

Misc Menu