Closed ilayn closed 1 year ago
@ilayn, your libopenblas.dll isn't build statically. The means that all gcc runtime libraries should be statically linked into libopenblas.dll with the help of the '-static' flag. With that you can get rid of the dependancies of the 4 aforementioned DLLs.
Statically linking gcc libraries is usually not recommended, but for this use case static linking it is essential, otherwise you enter a never ending DLL hell.
Those are common dependencies of fortran code used by LAPACK. @martin-frbg builds SF binaries and knows how to avoid them. You can build against omnipresent MSVCRT using fake cross-compilation like CC=gcc FC=gfortran HOSTCC=gcc (none of you LDFLAGS seem needed at all)
SKYLAKEX is autodetected target. something like TARGET=GENERIC DYNAMIC_ARCH=1 would be handy if you want to redist library to older computers.
Thanks for the responses,
@ilayn, your libopenblas.dll isn't build statically.
Could you also let me know what I should use? I thought LDFLAGS was supposed to take care of this.
You can build against omnipresent MSVCRT using fake cross-compilation like CC=gcc FC=gfortran HOSTCC=gcc (none of you LDFLAGS seem needed at all)
Apologies I don't know enough about the toolchain to appreciate this comment. But to be perfectly honest with you, I don't think I want to understand it either. So far all my efforts practically led to more confusion and that's why I want to get away from any of this fortran business on windows and fortran in general.
My ultimate goal is to compile https://github.com/SLICOT/SLICOT-Reference and wrap into a Python library as we do for SciPy but I have to confess the documentation world when it comes to compilers and linkers is just terrible. So this is my first step of many other issues. If I can fix this then f2py
then meson
then finally cibuildwheel
would need to work.
https://github.com/SLICOT/SLICOT-Reference/blob/main/make.inc
(fix the issues) you need to use NO_SHARED=1 parameter to build static openblas library. Your LDFLAGS will not work. You need to rename resulting .dll.a file into .obj in case it is not found. Also NUM_THREADS=256 should be used for redist lib in addition to fixed TARGET+DYNAMIC_ARCH. EDIT: genuine appologies for not understanding firsthand you want static file.
(improve?) you certainly need to rewite intel-compiler+static libs with that and dynamic dll-s. I get a feeling that clang+flang is better choice to go from start to champion, but I might be wrong. You still need mingw for scripting used in build and gnu make (CC=clang.exe FC=flang.exe HOSTCC=gcc.exe), builtin CFLAGS should already have most of your flags esp ones solving issues.
(what numpy scipy does) They just fetch anaconda build of openblas, sometimes people land with divergent versions aka DLL hell. Check their scripts. Actually in scope I think you can borrow their approach. We know how to recover version numbers from anaconda hashes.
@brada4, statically linking the GCCs libraries into libopenblas.dll and building a static import library for OpenBLAS are different things.
What one needs for the windows scipy use case with the default CPython implementation in mind (not the msys2 variant) are the flags for the linking step: -static -static-libgcc
as done in https://github.com/MacPython/openblas-libs
I'm not sure if this works with LDFLAGS
, mayby I should try out myself. I'm quite sure -lucrt
is not needed anymore if the latest msys2 ucrt64 toolchain is used.
Thanks again for the pointers,
in fact the make
command I've given above is stolen from MacPython build_openblas.sh
script under tools
(flattened for my case). But somehow that is working but if I do it manually it doesn't. Hence my confusion but let me try again with TARGET+DYNAMIC_ARCH
which is also included in that script and I omitted hoping to get a more specific build for my machine.
@brada, I know that Flang is now able to compile some Fortan programs but is not production ready right now. At least this was discussed at phoronix recently. The lfortran community also works on scipy compatibilty, but they are nort there yet.
However: the msys2 ucrt64 toolchain (gcc, gfortan) is a very solid foundation for these kind of developments.
@ilayn, can you try out the following Makefile
patch in exports
?
$ diff -rupN Makefile.orig Makefile
--- Makefile.orig 2022-11-03 21:37:39.000000000 +0100
+++ Makefile 2022-09-30 11:29:29.402812900 +0200
@@ -119,11 +119,21 @@ dll : ../$(LIBDLLNAME)
# in their import table. By instead using a stable name it is possible to
# upgrade between library versions, without needing to re-link an application.
# For more details see: https://github.com/xianyi/OpenBLAS/issues/127.
+ifeq ($(DEBUG), 1)
../$(LIBDLLNAME) : ../$(LIBNAME) $(LIBPREFIX).def dllinit.$(SUFFIX)
$(RANLIB) ../$(LIBNAME)
$(CC) $(CFLAGS) $(LDFLAGS) $(LIBPREFIX).def dllinit.$(SUFFIX) \
- -shared -o ../$(LIBDLLNAME) -Wl,--out-implib,../$(IMPLIBNAME) \
+ -shared -static -static-libgfortran -o ../$(LIBDLLNAME) \
+ -Wl,--out-implib,../$(IMPLIBNAME) -Wl,--defsym,quadmath_snprintf=snprintf \
-Wl,--whole-archive ../$(LIBNAME) -Wl,--no-whole-archive $(FEXTRALIB) $(EXTRALIB)
+else
+../$(LIBDLLNAME) : ../$(LIBNAME) $(LIBPREFIX).def dllinit.$(SUFFIX)
+ $(RANLIB) ../$(LIBNAME)
+ $(CC) $(CFLAGS) $(LDFLAGS) $(LIBPREFIX).def dllinit.$(SUFFIX) \
+ -shared -static -static-libgfortran -o ../$(LIBDLLNAME) -Wl,--out-implib,../$(IMPLIBNAME) \
+ -Wl,--defsym,quadmath_snprintf=snprintf -Wl,-gc-sections -Wl,-S \
+ -Wl,--whole-archive ../$(LIBNAME) -Wl,--no-whole-archive $(FEXTRALIB) $(EXTRALIB)
+endif
$(LIBPREFIX).def : $(GENSYM)
./$(GENSYM) win2k $(ARCH) dummy $(EXPRECISION) $(NO_CBLAS) $(NO_LAPACK) $(NO_LAPACKE) $(NEED2UNDERSCORES) $(ONLY_CBLAS) "$(SYMBOLPREFIX)" "$(SYMBOLSUFFIX)" $(BUILD_LAPACK_DEPRECATED) $(BUILD_BFLOAT16) $(BUILD_SINGLE) $(BUILD_DOUBLE) $(BUILD_COMPLEX) $(BUILD_COMPLEX16) > $(@F)
There is no need to complicate matters with clang/flang and/or a DYNAMIC_ARCH build. carlkl's suggestion should work I think - and please make sure you are building 0.3.21 and not some outdated version(or wait a few hours for 0.3.22)
Indeed, I'm following exactly the build script of MacPython. I was wondering whether I made an obvious mistake through choosing wrong toolchain etc. but apparently not. I'll try @carlkl's suggestion after this build is finished.
If the static-libgfortran option fails to work (ISTR it stopped working in newer gfortran version since they added libquadmath) you could also try -static-libgcc -Wl,-Bstatic -lgfortran -lquadmath -lm
. Or as a last resort build with NOFORTRAN=1 which will fall back to a f2c-translated copy of LAPACK 3.9.0 instead of the current LAPACK 3.11.0.
I don't know what changed but SciPy now working properly before I tried @carlkl's change. So that is a clear progress and thank you all for the pointers. This is my command ran on MSYS2 UCRT 64 terminal
make BINARY=64 MAX_STACK_ALLOC=2048 USE_OPENMP=0 \
NO_WARMUP=1 NO_AFFINITY=1 BUILD_LAPACK_DEPRECATED=1\
LDFLAGS="-lucrt -static -static-libgcc" \
COMMON_OPT="-O2 -fno-asynchronous-unwind-tables"\
FCOMMON_OPT="-O2 -fno-asynchronous-unwind-tables -frecursive -ffpe-summary=invalid,zero"
Now, just to test if I can link to it, I just wanted to test the following program specifically selected to have only BLAS dependency -> https://github.com/SLICOT/SLICOT-Reference/blob/main/src/MB01OE.f
It's fairly simple and I just wanted to see if I can compile it and I think you will get more information from this dump
gfortran -v -static .\MB01OE.f -o mb01oe.o -L"C:\opt\64\lib" -lopenblas
Probably this is my main problem that I partially fixed with the latest build but not exactly yet.
@ilayn, I guess your test program should be linked with this set of libraries (or similar):
-lopenblas -lgfortran -lmingwex -lmsvcrt -lm
Or if it is only a fortran subroutine -shared
has to be given to the command line.
Ha! indeed -shared
solved the issue. So apologies for a final question before we close this one. Does this -shared points to shared openblas dependency such that I have to carry around openblas with it?
@ilayn, with -shared
, the linker will produce a shared library with the extension .dll
on Windows OS (or .pyd
in case of Python extension binaries). And this shared library may of course depend on other user-defined DLLs. It is the responsibility of the linker to resolve all symbols and dependencies. Finally, dlldiag
is the tool to show all dependencies.
Perfect thank you!
For some time now, I am trying to find the right way to build OpenBLAS to link to SciPy. This used to be quite straightforward then things changed in many places and I lost track of what actually made the difference and now when I build OpenBLAS it doesn't link properly.
I recently started to check what the actual DLL is made up of in terms of dependencies using
dlldiag
or Dependencies GUI. Here is one that actually works that I download from https://github.com/MacPython/openblas-libs . The relevant build scripts are in thetools
folder withbuild_openblas.sh
When I look at those dll's here is the result
Then I build my own copy first with the following pretending to mimic above
and all goes well. However when I try to use it with SciPy I get
which only happens when I use my own baked build. But goes through with the MacPython copies. This led me to believe that something is wrong on my build hence here is my dll's trace
So the only difference is
api-ms-win-security-systemfunctions-l1-1-0 Loaded successfully
line pops up as a difference but I don't think this is actually a problem per se. But in general, when I run a barebonemake
command things switch toskylakex
which is I think expected anyways. But it also brings in these fine dependenciesNow I don't know if any of this is relevant or not and to be honest I am starting to lose track what I am actually trying to achieve. Apologies for the vagueness but I guess my concrete question is that do you see any issues so far?
Please feel free to close it if there is nothing sticking out.