Hi Dimitris,

thanks for the long explanation.

As you can see from my example, I build the library with the
    -undefined dynamic_lookup
flag to clang, so this should be compatible with your (3) option if I understand you correctly. Compiling/linking this way should allow the use of dlopen(3) from UFFI during the execution of Pharo code, exactly as I try to simulate with my small test programs.

Pharo complains about not being able to load the module (the library), even if it appears in the Pharo main folder. It does not report whether it cannot find it or if it cannot bind it using dlopen(3).

Moreover, it is unclear to me how Pharo interacts with DYLD_LIBRARY_PATH (on macOS) or LD_LIBRARY_PATH (on Linux) environment variables if they are set.

In other words, Where does it search for libraries?



Anyway, I'll try your script on cmake.


Regards
MO




for use with dlopen()

On 2018-10-17 11:32, Dimitris Chloupis wrote:
I advice first of all the use of CMake , you can thank me later.

CMake if you are not aware is the standard build system for C/C++ , it makes it super easy to build and compile projects so you dont have to do what you are doing, call the compiler and pass the inifite amount of compiler flags that it needs.

To understand how to build a library you have to understand first what a library is.

Libraries used by Pharo are known as either Shared Libraries on Macos (dylib) and Linux (so) but Dynamically Linked Libraries on Windows (DLLs). They are executables designed to be called from another executable (this includes another library as well).

Those libraries operate in 3 modes
1) Static linking
2) semi dynamic linking
3) dynamic linking

(1) may come as suprise but yes those libraries can be linked to the executable and build inside the exrecutable. But in our case we done want that because it would mean to rebuild the VM. (2) is not what we want either because eventhough it builds the library independently generating the usual exetension files I mentioned above it includes its symbole table in the executable so you wont have to do what UFFI does, wrap or map your code to those library functions. The equivelant for Pharo would mean that we would not need UFFI at all but we do need to rebuld the VM to include ths symbol table. The symbole table basically includes the name of the functions, their signatures (type of arguments) and their corresponing adresses in memory needed to access them.

(3) is what UFFI does, in that cause the executable is not affected at all so you dont need to to rebuild the vm. But you do need to know where to find the library , to access its symbol table and make sure the variables your executable uses match the type and signature in the symbol table or else the executable wont able to locate and correctly call these functions. Of course libraries can contain structs and global variables as well but the concept is the same. Now this messy part is handled by the UFFI although barely because it still needs from you to provide the correct signature to the function.

I am giving you the long version because you have to make sure you build you library with (3) way and not (2). (1) can be easily avoid but it is easy to mix (2) and (3). From there on its easy , locating the library is provided as a string returned by a method , see how UFFI utilises LibC for example and from there on you just convert the signatures to symbol arrays as described by the UFFI tutorials.

For cmake you only need to use -> add_library(libraryname MODULE ${SRC} ). You can find a CmakeList.txt file that I use here https://gist.github.com/kilon/ff4b973bdeb3b0c0253ac373a4b2506a

If you are wondering why its so big, its because the project I link against is huge and because I move the DLL to its build folder instead of building it in the same folder as my source code. It CMake's why of keeping things seperate and organised. Observe also that I use dll exension for Windows and MacOS, The extensions plays no role so I decided to go for the same extension to save time although usually its preferable go for the standard extensions.

Beware that if your library uses any external code even parts of the C standard library those will have to be included , usually you need only the header files, which is what SET INC is doing in my example, while SET SRC includes only the library files. The inclusion of headers is super important because they are used to build the symbol table which is the most important part of the library. Without a correctly build symbol table the library is useless even when used from C/C++.

On Wed, Oct 17, 2018 at 11:09 AM Michel Onoff <michel.on...@web.de <mailto:michel.on...@web.de>> wrote:

    Hello,

    I've made some attempts to use the Pharo FFI. I've gone through the
    documentation [1] and tried some examples.

    While the documentation is quite clear about using external libraries
    from Pharo, it lacks details on how to build own libraries to be used
    from Pharo.

    Specifically, I'm trying to build on all supported platforms, namely
    macOS, Windows and Linux. Currently I've got Linux and Windows under
    control, but I cannot find a systematic way to build on macOS.

    Here's an example for a library that I can use from a small test
    program
    but not from Pharo. Unfortunately, the diagnostic on Pharo is not
    detailed: it simply reports that it cannot load the module.


    clang -I <include-path> -O3 -c <source-path>
    ...
    clang -dynamiclib <object-files> -o lib<name>.dylib -undefined
    dynamic_lookup

    cp lib<name>.dylib <pharo-folder>


    Is there good documentation about how to correctly build libraries so
    that they can be used from Pharo?

    Alternatively, are there details on how Pharo FFI searches for
    libraries
    and links them in the Pharo process?


    Regards
    MO

    ----

    [1] https://files.pharo.org/books-pdfs/booklet-uFFI/UFFIDRAFT.pdf




Reply via email to