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