Repository: scipy/scipy

Issue:
BUG: Windows Built SciPy can't import _fblas via pip install .
### Describe your issue.

After building SciPy main branch, installing it systemwide via `pip install .` leads to broken import. This happens even building NumPy locally with the locally built OpenBLAS. 

```python
In [6]: np.show_config()
blas_armpl_info:
  NOT AVAILABLE
blas_mkl_info:
  NOT AVAILABLE
blis_info:
  NOT AVAILABLE
openblas_info:
    library_dirs = ['C:\\Users\\ilhan\\Documents\\GitHub\\numpy\\build\\openblas_info']
    libraries = ['openblas_info']
    language = f77
    define_macros = [('HAVE_CBLAS', None)]
blas_opt_info:
    library_dirs = ['C:\\Users\\ilhan\\Documents\\GitHub\\numpy\\build\\openblas_info']
    libraries = ['openblas_info']
    language = f77
    define_macros = [('HAVE_CBLAS', None)]
lapack_armpl_info:
  NOT AVAILABLE
lapack_mkl_info:
  NOT AVAILABLE
openblas_lapack_info:
    library_dirs = ['C:\\Users\\ilhan\\Documents\\GitHub\\numpy\\build\\openblas_lapack_info']
    libraries = ['openblas_lapack_info']
    language = f77
    define_macros = [('HAVE_CBLAS', None)]
lapack_opt_info:
    library_dirs = ['C:\\Users\\ilhan\\Documents\\GitHub\\numpy\\build\\openblas_lapack_info']
    libraries = ['openblas_lapack_info']
    language = f77
    define_macros = [('HAVE_CBLAS', None)]
Supported SIMD extensions in this NumPy install:
    baseline = SSE,SSE2,SSE3
    found = SSSE3,SSE41,POPCNT,SSE42,AVX,F16C,FMA3,AVX2,AVX512F,AVX512CD,AVX512_SKX,AVX512_CLX,AVX512_CNL,AVX512_ICL
    not found =
```

### Reproducing Code Example

```python
C:\Users\ilhan\Documents\GitHub\scipy [main ≡]> $env:PKG_CONFIG_PATH="C:\opt\64\lib\pkgconfig\"
C:\Users\ilhan\Documents\GitHub\scipy [main ≡]> $env:CC="x86_64-w64-mingw32-gcc";$env:CXX="x86_64-w64-mingw32-g++"
C:\Users\ilhan\Documents\GitHub\scipy [main ≡]> pip install .
Processing c:\users\ilhan\documents\github\scipy
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Requirement already satisfied: numpy>=1.19.5 in c:\users\ilhan\appdata\local\programs\python\python310\lib\site-packages\numpy-1.24.0.dev0+695.g50a74fb65-py3.10-win-amd64.egg (from scipy==1.10.0.dev0) (1.24.0.dev0+695.g50a74fb65)
Building wheels for collected packages: scipy
  Building wheel for scipy (pyproject.toml) ... done
  Created wheel for scipy: filename=scipy-1.10.0.dev0-cp310-cp310-win_amd64.whl size=47000726 sha256=35808c560f2e33dafe3ced612713c8565d77b105aec693124ae4d13cde1afdb8
  Stored in directory: C:\Users\ilhan\AppData\Local\Temp\pip-ephem-wheel-cache-04ckr_zh\wheels\63\13\46\e3e2e5525b45f526ecce5f57def1f4d2068c8fc759a4aae4eb
Successfully built scipy
Installing collected packages: scipy
Successfully installed scipy-1.10.0.dev0
```


### Error message

```shell
C:\Users\ilhan\Documents> ipython
Python 3.10.6 (tags/v3.10.6:9c7b4bd, Aug  1 2022, 21:53:49) [MSC v.1932 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import scipy.linalg as la
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
Input In [1], in <cell line: 1>()
----> 1 import scipy.linalg as la

File ~\AppData\Local\Programs\Python\Python310\lib\site-packages\scipy\linalg\__init__.py:197, in <module>
      1 """
      2 ====================================
      3 Linear algebra (:mod:`scipy.linalg`)
   (...)
    194
    195 """  # noqa: E501
--> 197 from ._misc import *
    198 from ._cythonized_array_utils import *
    199 from ._basic import *

File ~\AppData\Local\Programs\Python\Python310\lib\site-packages\scipy\linalg\_misc.py:3, in <module>
      1 import numpy as np
      2 from numpy.linalg import LinAlgError
----> 3 from .blas import get_blas_funcs
      4 from .lapack import get_lapack_funcs
      6 __all__ = ['LinAlgError', 'LinAlgWarning', 'norm']

File ~\AppData\Local\Programs\Python\Python310\lib\site-packages\scipy\linalg\blas.py:213, in <module>
    210 import numpy as _np
    211 import functools
--> 213 from scipy.linalg import _fblas
    214 try:
    215     from scipy.linalg import _cblas

ImportError: DLL load failed while importing _fblas: The specified module could not be found.
```


### SciPy/NumPy/Python version information

main, main, '3.10.6 (tags/v3.10.6:9c7b4bd, Aug  1 2022, 21:53:49) [MSC v.1932 64 bit (AMD64)]'


Discussion:
I don't have enough time/patience to troubleshoot it anymore so better ignore it for now. 
In case you do have time to go back -I bet your import error is because the relevant openblas.dll is not in the DLL path.  I use https://pypi.org/project/dll-diagnostics/ to check that kind of thing.  If you build from source, you have to copy the DLL somewhere on the load path, unless you're using the `dev.py` script, and the `--win-cp-openblas` flag, that does that job for you.





Cool. Didn't know about `dll-diagnostics`, looks really useful. 

> unless you're using the dev.py script, and the --win-cp-openblas flag, that does that job for you.

Another interesting flag that I didn't know. I'll give it a try later. 
I used the flag and for the build-install I think it does something correct though I couldn't find the place it copied the DLL and it said OpenBLAS copied. But my repo folder `C:\Users\ilhan\Documents\GitHub\scipy\build-install\Lib\site-packages\scipy\.libs` is still empty. 

```python
    @classmethod
    def copy_openblas(cls, dirs):
        """
        Copies OpenBLAS DLL to the SciPy install dir, and also overwrites the
        default `_distributor_init.py` file with the one
        we use for wheels uploaded to PyPI so that DLL gets loaded.

        Assumes pkg-config is installed and aware of OpenBLAS.
        """
        # Get OpenBLAS lib path from pkg-config
        cmd = ['pkg-config', '--variable', 'libdir', 'openblas']
        result = subprocess.run(cmd, capture_output=True, text=True)
        if result.returncode != 0:
            print(result.stderrr)
            return result.returncode

        openblas_lib_path = Path(result.stdout.strip())
        if not openblas_lib_path.stem == 'lib':
            raise RuntimeError(
                f'Expecting "lib" at end of "{openblas_lib_path}"')

        # Look in bin subdirectory for OpenBLAS binaries.
        bin_path = openblas_lib_path.parent / 'bin'
        # Locate, make output .libs directory in Scipy install directory.
        scipy_path = dirs.site / 'scipy'
        libs_path = scipy_path / '.libs'
        libs_path.mkdir(exist_ok=True)
        # Copy DLL files from OpenBLAS install to scipy install .libs subdir.
        for dll_fn in bin_path.glob('*.dll'):
            out_fname = libs_path / dll_fn.parts[-1]
            print(f'Copying {dll_fn} to {out_fname}')
            out_fname.write_bytes(dll_fn.read_bytes())

        # Write _distributor_init.py to scipy install dir;
        # this ensures the .libs file is on the DLL search path at run-time,
        # so OpenBLAS gets found
        openblas_support = import_module_from_path(
            'openblas_support',
            dirs.root / 'tools' / 'openblas_support.py')
        openblas_support.make_init(scipy_path)
        return 0
```

This business doesn't seem to be running on `pip install .` but I can't say if I understood things correctly.
No, the copy doesn't run with `pip install .` - only with that flag when calling `dev.py`.  Otherwise you'd have to do the copy by hand, to some directory on the DLL path - see the instructions in the Scipy wiki page I pointed to before.

The flag makes the script copy the openblas file to `scipy/.libs` and makes a `_distributor_init.py` file in the scipy directory that pre-loads the DLL from the `.libs` directory when importing scipy:

https://github.com/scipy/scipy/blob/main/tools/openblas_support.py#L206
Yes that's true but even then I don't see it in my build-install directory after dev.py finishes off with OpenBLAS copied and Installation successful. That is to say, it says it copied but the `libs` folder is empty. 
How puzzling!   What directory does it say it copied to (message of form "Copying <openblas.dll> to <something>/scipy/.libs/<openblas.dll> ?   Does the Scipy import now work?


This is all I get from the compilation and I don't get any such messages. I'll hack into dev.py to print the full paths when I have time. 

```bash
C:\Users\ilhan\Documents\GitHub\scipy [main ≡]> $env:CC="x86_64-w64-mingw32-gcc";$env:CXX="x86_64-w64-mingw32-g++"
C:\Users\ilhan\Documents\GitHub\scipy [main ≡]> $env:PKG_CONFIG_PATH="C:\opt\64\lib\pkgconfig\"
C:\Users\ilhan\Documents\GitHub\scipy [main ≡]> python dev.py build --win-cp-openblas
💻  meson setup C:\Users\ilhan\Documents\GitHub\scipy\build --prefix C:\Users\ilhan\Documents\GitHub\scipy\build-installThe Meson build system
Version: 0.63.1
Source dir: C:\Users\ilhan\Documents\GitHub\scipy
Build dir: C:\Users\ilhan\Documents\GitHub\scipy\build
Build type: native build
Project name: SciPy
Project version: 1.10.0.dev0
C compiler for the host machine: x86_64-w64-mingw32-gcc (gcc 12.2.0 "x86_64-w64-mingw32-gcc (Rev1, Built by MSYS2 project) 12.2.0")
C linker for the host machine: x86_64-w64-mingw32-gcc ld.bfd 2.39
C++ compiler for the host machine: x86_64-w64-mingw32-g++ (gcc 12.2.0 "x86_64-w64-mingw32-g++ (Rev1, Built by MSYS2 project) 12.2.0")
C++ linker for the host machine: x86_64-w64-mingw32-g++ ld.bfd 2.39
Host machine cpu family: x86_64
Host machine cpu: x86_64
Compiler for C supports arguments -Wno-unused-but-set-variable: YES
Library m found: YES
Fortran compiler for the host machine: gfortran (gcc 12.2.0 "GNU Fortran (Rev1, Built by MSYS2 project) 12.2.0")
Fortran linker for the host machine: gfortran ld.bfd 2.39
Program cython found: YES (C:\Users\ilhan\AppData\Local\Programs\Python\Python310\Scripts\cython.EXE)
Program pythran found: YES (C:\Users\ilhan\AppData\Local\Programs\Python\Python310\Scripts\pythran.EXE)
Program scipy/_build_utils/copyfiles.py found: YES (C:\Users\ilhan\AppData\Local\Programs\Python\Python310\python.exe C:\Users\ilhan\Documents\GitHub\scipy\scipy/_build_utils/copyfiles.py)
Program python3 found: YES (C:\Users\ilhan\AppData\Local\Programs\Python\Python310\python.exe)
WARNING: You should add the boolean check kwarg to the run_command call.
         It currently defaults to false,
         but it will default to true in future releases of meson.
         See also: https://github.com/mesonbuild/meson/issues/9300
Library npymath found: YES
Library npyrandom found: YES
Found pkg-config: C:\msys64\ucrt64\bin\pkg-config.EXE (1.8.0)
Run-time dependency openblas found: YES 0.3.21
Dependency openblas found: YES 0.3.21 (cached)
Program _build_utils/cythoner.py found: YES (C:\Users\ilhan\AppData\Local\Programs\Python\Python310\python.exe C:\Users\ilhan\Documents\GitHub\scipy\scipy\_build_utils/cythoner.py)
Checking for function "open_memstream" : NO
Configuring messagestream_config.h using configuration
Checking for size of "void*" : 8
Run-time dependency threads found: YES
Checking for size of "void*" : 8
Dependency threads found: YES unknown (cached)
Compiler for C supports arguments -Wno-unused-but-set-variable: YES (cached)
Compiler for C supports arguments -Wno-unused-but-set-variable: YES (cached)
Compiler for C++ supports arguments -Wno-format-truncation: YES
Compiler for C++ supports arguments -Wno-class-memaccess: YES
Build targets in project: 206

SciPy 1.10.0.dev0

  User defined options
    prefix: C:\Users\ilhan\Documents\GitHub\scipy\build-install

Found ninja-1.10.2.git.kitware.jobserver-1 at C:\Users\ilhan\AppData\Local\Programs\Python\Python310\Scripts\ninja.EXE
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_lib_pxd' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_lib_pxd' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_ufuncs_pxi_pxd' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_ufuncs_pxi_pxd' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_ufuncs_pxi_pxd' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_ufuncs_pxi_pxd' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target 'cython_linalg' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target 'cython_linalg' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target 'cython_linalg' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target 'cython_linalg' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_ufuncs_pxi_pxd' has more than one output! Using the first one.
WARNING: custom_target '_stats_pxd' has more than one output! Using the first one.
WARNING: custom_target 'cython_special' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_stats_gen_pyx' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_stats_gen_pyx' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_stats_gen_pyx' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_stats_gen_pyx' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_stats_gen_pyx' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_stats_gen_pyx' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_stats_gen_pyx' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_stats_gen_pyx' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_stats_gen_pyx' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_lib_pxd' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_spatial_pxd' has more than one output! Using the first one.
WARNING: custom_target '_lib_pxd' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target 'cython_linalg' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target 'cython_linalg' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target 'cython_linalg' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_spatial_pxd' has more than one output! Using the first one.
WARNING: custom_target '_lib_pxd' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target 'cython_linalg' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target 'cython_linalg' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target 'cython_linalg' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_lib_pxd' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_dummy_init_cyoptimize' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
WARNING: custom_target '_cython_tree' has more than one output! Using the first one.
Meson build setup OK
💻  ninja -C C:\Users\ilhan\Documents\GitHub\scipy\build
ninja: Entering directory `C:\Users\ilhan\Documents\GitHub\scipy\build'
[123/1562] Compiling C object scipy/linalg/_matfuncs_sqrtm_triu.cp310-win_amd64.pyd.p/meson-generated__matfuncs_sqrtm_triu.c.obj
In file included from C:\Users\ilhan\AppData\Local\Programs\Python\Python310\lib\site-packages\numpy-1.24.0.dev0+695.g50a74fb65-py3.10-win-amd64.egg\numpy\core\include/numpy/ndarraytypes.h:1940,
                 from C:\Users\ilhan\AppData\Local\Programs\Python\Python310\lib\site-packages\numpy-1.24.0.dev0+695.g50a74fb65-py3.10-win-amd64.egg\numpy\core\include/numpy/ndarrayobject.h:12,
                 from C:\Users\ilhan\AppData\Local\Programs\Python\Python310\lib\site-packages\numpy-1.24.0.dev0+695.g50a74fb65-py3.10-win-amd64.egg\numpy\core\include/numpy/arrayobject.h:5,
                 from scipy/linalg/_matfuncs_sqrtm_triu.cp310-win_amd64.pyd.p/_matfuncs_sqrtm_triu.c:746:
C:\Users\ilhan\AppData\Local\Programs\Python\Python310\lib\site-packages\numpy-1.24.0.dev0+695.g50a74fb65-py3.10-win-amd64.egg\numpy\core\include/numpy/npy_1_7_deprecated_api.h:14:9: note: '#pragma message: C:\Users\ilhan\AppData\Local\Programs\Python\Python310\lib\site-packages\numpy-1.24.0.dev0+695.g50a74fb65-py3.10-win-amd64.egg\numpy\core\include/numpy/npy_1_7_deprecated_api.h(14) : Warning Msg: Using deprecated NumPy API, disable it with #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION'
   14 | #pragma message(_WARN___LOC__"Using deprecated NumPy API, disable it with " \
      |         ^~~~~~~
[125/1562] Compiling C object scipy/linalg/_solve_toeplitz.cp310-win_amd64.pyd.p/meson-generated__solve_toeplitz.c.obj


[snipped all the compiler warnings]

NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION'
   15 |                          "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION")
      |                                                                             ^
scipy/optimize/_highs/_highs_wrapper.cp310-win_amd64.pyd.p/_highs_wrapper.cpp: In function 'PyObject* __Pyx_Import(PyObject*, PyObject*, int)':
scipy/optimize/_highs/_highs_wrapper.cp310-win_amd64.pyd.p/_highs_wrapper.cpp:25733:31: warning: comparing the result of pointer addition '(((const char*)"scipy.optimize._highs.cython.src._highs_wrapper") + 5
' and NULL [-Waddress]
25733 |             if ((1) && (strchr(__Pyx_MODULE_NAME, '.'))) {
      |                        ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
[1562/1562] Linking target scipy/optimize/_highs/_highs_wrapper.cp310-win_amd64.pyd
Build OK
💻  meson install -C build
Installing, see meson-install.log...
Installation OK
OpenBLAS copied
C:\Users\ilhan\Documents\GitHub\scipy [main ≡]>
```

![image](https://user-images.githubusercontent.com/1303842/187195717-fecd139e-12a4-400e-8de1-cd3243c7fa68.png)

At a random guess:

```python
bin_path = openblas_lib_path.parent / 'bin'
```

this location is empty (or at least empty of `*.dll`'s).

```python
for dll_fn in bin_path.glob('*.dll'):
```

This has no sanity check that the glob matched anything.
I probably need to reopen this as I replicated the missing dll situation to a code piece in `dev.py`

It is the pathlib glob returning a path object that is not understood properly by the file system

```python
In [61]: openblas_lib_path
Out[61]: WindowsPath('/c/opt/64/lib')  # This is correct

In [62]: bin_path = openblas_lib_path.parent / 'bin'

In [63]: bin_path
Out[63]: WindowsPath('/c/opt/64/bin') # Also correct

In [64]: for x in bin_path.glob('*.dll'):
    ...:     print(x)
    ...:

In [65]: # No dll's found though libopenblas.dll is sitting at that target

In []: list(bin_path.glob('*.dll'))
Out[75]: []
```

This probably because of 

```
In [73]: bin_path.absolute()
Out[73]: WindowsPath('C:/c/opt/64/bin')

# Interesting let's check the openblas_lib_path
In [78]: openblas_lib_path
Out[78]: WindowsPath('/c/opt/64/lib')

list(openblas_lib_path.glob('*.*'))
Out[79]: []  # Ha! so the strip from stdout is the culprit
```

So let me skip the drive letter

```
openblas_lib_path = Path(result.stdout.strip()[2:]).resolve()  # Skip the drive part of the path -> /c

In [93]: openblas_lib_path
Out[93]: WindowsPath('C:/opt/64/lib')

In [94]: list(openblas_lib_path.glob('*.*'))
Out[94]:
[WindowsPath('C:/opt/64/lib/libopenblas.a'),
 WindowsPath('C:/opt/64/lib/libopenblas.dll.a'),
 WindowsPath('C:/opt/64/lib/libopenblas_skylakexp-r0.3.21.a')]

```

I don't know if this is a robust way of getting rid of the drive letter but then things go back to normal.

```
Copying C:\opt\64\bin\libopenblas.dll to C:\Users\ilhan\Documents\GitHub\scipy\build-install\Lib\site-packages\scipy\.libs\libopenblas.dll
OpenBLAS copied
```
After fixing the issue now I have a different error coming from the distributor_init which is 

```python
C:\Users\ilhan\Documents\GitHub\scipy\build-install\Lib\site-packages [main ≡ +0 ~1 -0 !]> ipython
Python 3.10.6 (tags/v3.10.6:9c7b4bd, Aug  1 2022, 21:53:49) [MSC v.1932 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import scipy.linalg as la
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
Input In [1], in <cell line: 1>()
----> 1 import scipy.linalg as la

File ~\Documents\GitHub\scipy\build-install\Lib\site-packages\scipy\__init__.py:132, in <module>
    129 from scipy.version import version as __version__
    131 # Allow distributors to run custom init code
--> 132 from . import _distributor_init
    133 del _distributor_init
    135 from scipy._lib import _pep440

File ~\Documents\GitHub\scipy\build-install\Lib\site-packages\scipy\_distributor_init.py:26, in <module>
     21 if os.path.isdir(libs_dir):
     22     for filename in glob.glob(os.path.join(libs_dir,
     23                                            '*openblas*dll')):
     24         # NOTE: would it change behavior to load ALL
     25         # DLLs at this path vs. the name restriction?
---> 26         WinDLL(os.path.abspath(filename))
     27         DLL_filenames.append(filename)
     28 if len(DLL_filenames) > 1:

File ~\AppData\Local\Programs\Python\Python310\lib\ctypes\__init__.py:374, in CDLL.__init__(self, name, mode, handle, use_errno, use_last_error, winmode)
    371 self._FuncPtr = _FuncPtr
    373 if handle is None:
--> 374     self._handle = _dlopen(self._name, mode)
    375 else:
    376     self._handle = handle

FileNotFoundError: Could not find module 'C:\Users\ilhan\Documents\GitHub\scipy\build-install\Lib\site-packages\scipy\.libs\libopenblas.dll' (or one of its dependencies). Try using the full path with constructor syntax.
```

But it is there 

![image](https://user-images.githubusercontent.com/1303842/189521159-52027dec-eb75-4e98-ac81-caaf801dd5d9.png)

So probably a similar thing going on I'll dig a bit more

Also when system installed via `pip install .` there is no `.libs` folder 

![image](https://user-images.githubusercontent.com/1303842/189522768-590774b8-b449-4f20-8ecb-09ad1296b29c.png)

@matthew-brett Do we still need to copy `openblas.a` file to Python libs folder in the meson way like we used to do? 
Actually `distributor_init.py` should be using os.add_dll_directory() I think. 
This is getting a bit annoying with system install of SciPy and I don't understand why this is becoming so difficult with Windows. 

After building SciPy with `python dev.py build` the meson install puts things under the `build-install` folder. If all defaults are used this gets things under library without the openblas copy.

Then if I'm not using conda or venv or anything just vanilla Python installation on a system that I would like to use SciPy too, things get messed up. If I add 

```
python .\dev.py --install-prefix C:\Users\ilhan\AppData\Local\Programs\Python\Python310 build
```
to install things under native Python packages, pip doesn't recognize this installation and also still the _fblas missing library error is generated though I have it, in fact I build the openblas myself and placed openblas.a file everywhere I can think of. Then I tried the `meson install` way with DESTDIR option also leading to the same thing. 

Alternatively, pip install . doesn't do the right thing either and still get missing _fblas and some other dependencies when `import scipy` is triggered. Following the docs, and adding `build` I tried the `python -m build` way too but ended up not finding `mesonpy` backend. 

It seems to me that the only way to do it is via building a wheel first and then using that but that led to other issues that I am still not sure if I understand.

What is the pip command for installing the package? 


I think the way to do a development build with OpenBLAS:
```
python dev.py build --win-cp-openblas
```
after that, openblas should have been copied to the right place within `build-install`, and regular `python dev.py xxx` should work.

For Pip, one should either build the wheel like we do in CI or have `libopenblas.dll` in a place that's on the default library search path (in that case a regular `pip install .` should do). For CI, this is the relevant snippet:
```
      - name: post-install
        run: |
          $scipy_path = "${env:installed_path}\scipy"
          $libs_path = "${scipy_path}\.libs"
          mkdir ${libs_path}
          $ob_path = (pkg-config --variable libdir openblas) -replace "lib", "bin"
          cp $ob_path/*.dll $libs_path
          # Write _distributor_init.py to scipy dir to load .libs DLLs.
          & python tools\openblas_support.py --write-init $scipy_path
```
I think there is nothing specific to SciPy here, the problem is the regular one on Windows: there is nothing like RPATH support, so the shared libraries one need must be either vendored or in a default system location.
Oh I forgot, there is a third way, using `cibuildwheel --platform windows`. That should automatically get the vendoring right, because it does exactly what our official wheel build machinery does. It's working for @tylerjereddy on Windows, because he is using it for the current 1.10.0 release debugging. So maybe nicer than dealing with manual vendoring.

Resolving patch:
diff --git a/dev.py b/dev.py
--- a/dev.py
+++ b/dev.py
@@ -558,19 +558,39 @@ def copy_openblas(cls, dirs):
         default `_distributor_init.py` file with the one
         we use for wheels uploaded to PyPI so that DLL gets loaded.
 
-        Assumes pkg-config is installed and aware of OpenBLAS.
+        Assumes pkg-config is installed and aware of OpenBLAS. 
+
+        The "dirs" parameter is typically a "Dirs" object with the
+        structure as the following, say, if dev.py is run from the
+        folder "repo":
+
+        dirs = Dirs(
+            root=WindowsPath('C:/.../repo'),
+            build=WindowsPath('C:/.../repo/build'),
+            installed=WindowsPath('C:/.../repo/build-install'),
+            site=WindowsPath('C:/.../repo/build-install/Lib/site-packages'
+            )
+
         """
         # Get OpenBLAS lib path from pkg-config
         cmd = ['pkg-config', '--variable', 'libdir', 'openblas']
         result = subprocess.run(cmd, capture_output=True, text=True)
+        # pkg-config does not return any meaningful error message if fails
         if result.returncode != 0:
-            print(result.stderrr)
+            print('"pkg-config --variable libdir openblas" '
+                  'command did not manage to find OpenBLAS '
+                  'succesfully. Try running manually on the '
+                  'command prompt for more information.')
             return result.returncode
 
-        openblas_lib_path = Path(result.stdout.strip())
+        # Skip the drive letter of the path -> /c to get Windows drive
+        # to be appended correctly to avoid "C:\c\..." from stdout.
+        openblas_lib_path = Path(result.stdout.strip()[2:]).resolve()
         if not openblas_lib_path.stem == 'lib':
-            raise RuntimeError(
-                f'Expecting "lib" at end of "{openblas_lib_path}"')
+            raise RuntimeError('"pkg-config --variable libdir openblas" '
+                               'command did not return a path ending with'
+                               ' "lib" folder. Instead it returned '
+                               f'"{openblas_lib_path}"')
 
         # Look in bin subdirectory for OpenBLAS binaries.
         bin_path = openblas_lib_path.parent / 'bin'
@@ -580,8 +600,8 @@ def copy_openblas(cls, dirs):
         libs_path.mkdir(exist_ok=True)
         # Copy DLL files from OpenBLAS install to scipy install .libs subdir.
         for dll_fn in bin_path.glob('*.dll'):
-            out_fname = libs_path / dll_fn.parts[-1]
-            print(f'Copying {dll_fn} to {out_fname}')
+            out_fname = libs_path / dll_fn.name
+            print(f'Copying {dll_fn} ----> {out_fname}')
             out_fname.write_bytes(dll_fn.read_bytes())
 
         # Write _distributor_init.py to scipy install dir;


Test patch: