1. Creating and using a .DLL/.SO?
- Posted by jeremy (admin) Dec 24, 2008
- 1150 views
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
2. Re: Creating and using a .DLL/.SO?
- Posted by jeremy (admin) Dec 24, 2008
- 1223 views
Um,
Never mind, user error, it works.
Jeremy
3. Re: Creating and using a .DLL/.SO?
- Posted by jimcbrown (admin) Dec 24, 2008
- 1222 views
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.
4. Re: Creating and using a .DLL/.SO?
- Posted by jeremy (admin) Dec 24, 2008
- 1220 views
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
5. Re: Creating and using a .DLL/.SO?
- Posted by jeremy (admin) Dec 24, 2008
- 1198 views
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
6. Re: Creating and using a .DLL/.SO?
- Posted by ghaberek (admin) Dec 24, 2008
- 1125 views
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...
-Greg
7. Re: Creating and using a .DLL/.SO?
- Posted by mattlewis (admin) Dec 25, 2008
- 1174 views
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...
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:
- 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
8. Re: Creating and using a .DLL/.SO?
- Posted by jeremy (admin) Dec 25, 2008
- 1118 views
- Last edited Dec 26, 2008
I do think that global/public/export functions/procedures should be created in the dll/so as is, right? w/no name mangling?
Jeremy
9. Re: Creating and using a .DLL/.SO?
- Posted by ghaberek (admin) Dec 25, 2008
- 1125 views
- Last edited Dec 26, 2008
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
10. Re: Creating and using a .DLL/.SO?
- Posted by jeremy (admin) Dec 25, 2008
- 1119 views
- Last edited Dec 26, 2008
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
11. Re: Creating and using a .DLL/.SO?
- Posted by mattlewis (admin) Dec 26, 2008
- 1102 views
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
12. Re: Creating and using a .DLL/.SO?
- Posted by bernie Dec 26, 2008
- 1085 views
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.
13. Re: Creating and using a .DLL/.SO?
- Posted by jeremy (admin) Dec 26, 2008
- 1108 views
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
14. Re: Creating and using a .DLL/.SO?
- Posted by jeremy (admin) Dec 26, 2008
- 1093 views
... 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
15. Re: Creating and using a .DLL/.SO?
- Posted by jimcbrown (admin) Dec 26, 2008
- 1102 views
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.
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
16. Re: Creating and using a .DLL/.SO?
- Posted by jeremy (admin) Dec 26, 2008
- 1117 views
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
17. Re: Creating and using a .DLL/.SO?
- Posted by jimcbrown (admin) Dec 26, 2008
- 1146 views
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).
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.
18. Re: Creating and using a .DLL/.SO?
- Posted by jeremy (admin) Dec 26, 2008
- 1109 views
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
19. Re: Creating and using a .DLL/.SO?
- Posted by mattlewis (admin) Dec 26, 2008
- 1128 views
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
20. Re: Creating and using a .DLL/.SO?
- Posted by mattlewis (admin) Dec 26, 2008
- 1102 views
... 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
21. Re: Creating and using a .DLL/.SO?
- Posted by mattlewis (admin) Dec 26, 2008
- 1098 views
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
22. Re: Creating and using a .DLL/.SO?
- Posted by mattlewis (admin) Dec 26, 2008
- 1097 views
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
23. Re: Creating and using a .DLL/.SO?
- Posted by jimcbrown (admin) Dec 26, 2008
- 1111 views
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.
24. Re: Creating and using a .DLL/.SO?
- Posted by mattlewis (admin) Dec 26, 2008
- 1122 views
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
25. Re: Creating and using a .DLL/.SO?
- Posted by jeremy (admin) Dec 26, 2008
- 1105 views
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 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.
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
26. Re: Creating and using a .DLL/.SO?
- Posted by jimcbrown (admin) Dec 26, 2008
- 1098 views
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.
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).
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?
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?
27. Re: Creating and using a .DLL/.SO?
- Posted by jimcbrown (admin) Dec 26, 2008
- 1095 views
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???
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.
28. Re: Creating and using a .DLL/.SO?
- Posted by jeremy (admin) Dec 26, 2008
- 1100 views
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
29. Re: Creating and using a .DLL/.SO?
- Posted by mattlewis (admin) Dec 26, 2008
- 1095 views
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