1. If you wanted to distribute a dll
- Posted by xecronix Sep 12, 2015
- 1713 views
If you wrote a DLL or wrapped a DLL for other Euphoria developers to use, where would you expect the DLL to reside on the target machine? For example, say you wrapped libcurl and wanted to distribute the DLL along with your curl.e file. That way you could be sure that the user of your wrapper is using the correct version of the DLL you wrapped.
Some Possible locations:
- Wherever DLLs are located normally on the system. The problem with this solution that the user may already have a version of the DLL and that version is not 100% compatible with your wrapper. Or later he installs a version of the DLL that causes instability. The benefit is if you didn't write the code for the DLL or someone else is maintaining it you wont need to distribute bug fixes.
- Wherever Euphoria is installed. For example, by default Euphoria installed on my system in /usr/local/share/euphoria. So a good place to put the DLL might be /usr/local/share/euphoria/bin
- Wherever your wrapper is installed. I like this idea a lot. Say your wrapper is installed in /usr/local/share/euphoria/include/curl. Then you might expect to find your DLL in /usr/local/share/euphoria/include/curl/curl.dll. What I like most about this solution is that you can dynamically figure out where the DLL should be based on the return value from include_paths function. What I don't like about this solution is that a DLL is not an include file.
2. Re: If you wanted to distribute a dll
- Posted by petelomax Sep 12, 2015
- 1723 views
- Wherever your wrapper is installed. I like this idea a lot.
That is instantly my first and only choice.
The ancients had a belief that several applications could "share" a dll, as long as it was in some central shared common directory, and thus save a few measly KB of your precious RAM, which was the only possible benefit ever on offer, and quite seriously not worth it anymore (unless perhaps you are talking about half a dozen different 500MB dlls).
C:\Windows\system32 got a fair bit messier with syswow64, but (as mentioned) more critically that and euphoria/bin open the door to "dll hell", though I doubt you will ever need a euphoria/binwow64.
Of course what you should really, really do, honest guv, is stick it in the GAC under a nice new GUID on every install so that everyone can have 87 different versions of your dll - not really.
Pete
EDIT: I was also going to say my second choice would be to store it wherever and save the full directory path in HKLM\SOFTWARE\Euphoria\dllname\version, and enumerate/load from that, but only if you really really need to.
3. Re: If you wanted to distribute a dll
- Posted by xecronix Sep 12, 2015
- 1705 views
This seems like a reasonable place to start:
namespace libhelper include std/filesys.e public function include_derived_ext_paths(sequence libdir, sequence lib) sequence inc_paths = include_paths(1) sequence retval = {} retval = append(retval, sprintf("%s.%s", {lib, SHARED_LIB_EXT})) sequence current = join_path({current_dir(), sprintf("%s.%s", {lib, SHARED_LIB_EXT})}) retval = append(retval, current) for i = 1 to length(inc_paths) do sequence inc_path = inc_paths[i] sequence last_char = {inc_path[$]} if equal(last_char, SLASH) then inc_path = inc_path[1..$-1] end if retval = append(retval, join_path({inc_path, libdir, "ext", sprintf("%s.%s", {lib, SHARED_LIB_EXT})})) end for return retval end function
So passing
include_derived_ext_paths(coollib, coollib)
yeilds
{ "coollib.so", "/home/ronald/my/current/working/dir/coollib.so", "/home/ronald/my/current/working/dir/coollib/ext/coollib.so", "/usr/local/share/euphoria/include/coollib/ext/coollib.so" }
4. Re: If you wanted to distribute a dll
- Posted by ghaberek (admin) Sep 14, 2015
- 1627 views
I see only two options here:
- place all Euphoria-specific shared libraries in the BIN dirctory and the wrapper files in the INCLUDE directory
- optionally, place the wrapper files within a new directory (e.g. "CURL")
- place the shared libraries and include files directly within your application directory
The key takeaway here is, an application should not be looking all over the place for its shared libraries. One could get into trouble when encountering the wrong (i.e. incompatible) version of a shared library. This is especially true when moving from one distro to the next and across major generations of a distro with grossly disparate libraries.
If we agree that all Euphoria shared libraries go into one of two known safe locations, then things should work out well. If we start venturing into the realm of system-wide shared libraries, then we have a problem. One caveat to this is if the shared library wrapper is using a distro-provided library, like CURL or ZLIB.
All that being said, this is a problem that is best solved by some sort of package management system, which could install or provide dependencies as needed depending on the system. We need to download CURL or ZLIB on Windows, but we'll use the system libraries on Linux.
-Greg
5. Re: If you wanted to distribute a dll
- Posted by xecronix Sep 14, 2015
- 1606 views
I see only two options here:
- place all Euphoria-specific shared libraries in the BIN dirctory and the wrapper files in the INCLUDE directory
- optionally, place the wrapper files within a new directory (e.g. "CURL")
I like this idea but not as much as the putting the dll in a "ext" directory included with the library. The idea is it should be as easy as possible for developers using my library to include the lib in the application they write.
The Only 2 concerns I have with your proposed approach is
- it seems to muddy the Euphoria bin directory which presents some challenges when upgrading from version to version of Euphoria.
- it doesn't allow the user to have more than one version of the same wrapper. IE version 1.0 and version 2.0 of the wrapper for the guitar lib I wrote for the recent mini guide.
I would consider point one more of a nuisance than a real problem. But point 2 feels like a real problem. On linux this is solved with shared object naming conventions and symlinks. This concept doesn't really port well to Windows. Windows solves this problem by loading dll xyz.dll based on where it exists on the file system. This doesn't port well to Linux but is easily duplicated programatically.
- place the shared libraries and include files directly within your application directory
I can't agree with you more on this point. Say you write an application that uses my library or my wrapper. To bundle my wrapper/lib all you should need to do is place the wrapper directory in the include_paths and you're done. That's my goal anyway.
The key takeaway here is, an application should not be looking all over the place for its shared libraries. One could get into trouble when encountering the wrong (i.e. incompatible) version of a shared library. This is especially true when moving from one distro to the next and across major generations of a distro with grossly disparate libraries.
If we agree that all Euphoria shared libraries go into one of two known safe locations, then things should work out well. If we start venturing into the realm of system-wide shared libraries, then we have a problem. One caveat to this is if the shared library wrapper is using a distro-provided library, like CURL or ZLIB.
Absolutely correct. I feel like there is only 1 safe place to put the dll most of the time. And while I'm super flexible on what that place is named or where it exists in the file system hierarchy that place should be part of the wrapper directory structure. Other "reasonable places" are an attempt to not go against the grain. Developers and users are used to putting dlls in certain places and expecting things to just work.
All that being said, this is a problem that is best solved by some sort of package management system, which could install or provide dependencies as needed depending on the system. We need to download CURL or ZLIB on Windows, but we'll use the system libraries on Linux.
I agree again. This is actually a goal of mine. I'm working on porting the Ruby Gem concept to Euphoria. You can see some of my notes on the topic on my OpenEuphoria wiki page if you'd like. It's called the EuDrop Project. The project is very raw at the moment. I'm still defining scope. But there is a wiki page for it if you'd like to peek.
Funny how things turn out sometimes. euLibCurl.e is actually the wrapper I'm looking at now and is the topic of the next part of Complete Guide to Using DLLs in OpenEuphoria series.
I'm glad we're getting this chance to discuss this now.
6. Re: If you wanted to distribute a dll
- Posted by ghaberek (admin) Sep 14, 2015
- 1638 views
public function include_derived_ext_paths(sequence libdir, sequence lib) -- *snip* --
This does not currently work on Windows. The join_path() function adds a leading backslash to the path if the first element is not a root directory (i.e. C:\).
include std/console.e include std/filesys.e display( join_path({ "C:\\", "Euphoria", "bin" }) ) display( join_path({ "C:\\Euphoria", "bin" }) ) maybe_any_key()
C:\Euphoria\bin \C:\Euphoria\bin
I suggest adding an ifdef WINDOWS block to handle this accordingly for now.
namespace libhelper include std/filesys.e public function include_derived_ext_paths(sequence libdir, sequence lib) sequence inc_paths = include_paths(1) sequence retval = {} sequence dll_name = sprintf("%s.%s", {lib, SHARED_LIB_EXT}) retval = append(retval, dll_name) sequence current = join_path({current_dir(), dll_name}) ifdef WINDOWS then if current[1] = '\\' then -- trim leading backslash character current = current[2..$] end if end ifdef retval = append(retval, current) for i = 1 to length(inc_paths) do sequence inc_path = inc_paths[i] sequence last_char = {inc_path[$]} if equal(last_char, SLASH) then inc_path = inc_path[1..$-1] end if retval = append(retval, join_path({inc_path, libdir, "ext", dll_name})) end for return retval end function
-Greg
7. Re: If you wanted to distribute a dll
- Posted by xecronix Sep 14, 2015
- 1612 views
public function include_derived_ext_paths(sequence libdir, sequence lib) -- *snip* --
This does not currently work on Windows. The join_path() function adds a leading backslash to the path if the first element is not a root directory (i.e. C:\).
*snip*
I suggest adding an ifdef WINDOWS block to handle this accordingly for now.
ifdef WINDOWS then if current[1] = '\\' then -- trim leading backslash character current = current[2..$] end if end ifdef
-Greg
Good idea. I pushed the change.