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.
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++.