arpack-ng icon indicating copy to clipboard operation
arpack-ng copied to clipboard

Build static lib without blas

Open Fabian188 opened this issue 5 years ago • 16 comments

Expected behavior

Do this.

Actual behavior

Fails without system lib and ignores BLAS_blas_LIBRARY

Where/how to reproduce the problem

  • arpack-ng: 3.7.0

I build static arpack as a cmake external project to be linkend to our own software. All works fine, but on one gitlab-runner, I have no direct access to, arpack does not build because FindBLAS() fails in CMakeLists.txt:169 (find_package)

Unfortunately I have no system available without any libblas to reproduce the error.

I provide -DBLAS_blas_LIBRARY:FILEPATH=${BLAS_LIBRARY} where ${BLAS_LIBRARY} is our own built blas (static) but this seems to be ignored. Probably something dynamic is expected?

My Understanding is, that blas is not needed for building libarpack.a as we provide blas when we link our application where arpack is part of. Is this right?

I assume arpack needs blas for the examples, but I don't enable them. If this is the case, I ask for having the option to build libarpack.a without providing blas.

Fabian188 avatar Aug 07 '20 22:08 Fabian188

blas is not needed for building libarpack.a, ..., I assume arpack needs blas for the examples,

You are probably right. Propose a PR (cmake should be easy, autotools likely less !...) and add a no-example-no-blas job in .travis.yml to check it out.

fghoussen avatar Aug 08 '20 15:08 fghoussen

Sorry, thats to much of a burden for me - I'm not involved in arpack development at all, nor do I know how to edit .yml.

Fabian188 avatar Aug 08 '20 19:08 Fabian188

I'm not involved in arpack development at all

Nobody is anymore ! All people are volunteers here.

fghoussen avatar Aug 08 '20 20:08 fghoussen

I know its volunteers, but some have a glue about what is done, others don't (me, when it comes to arpack) :)

I created a patch for myself which enables SYSTEM_BLAS and SYSTEM_LAPACK again, wich was commented 5 years ago. However, some SYSTEM_* stuff is still commented and I don't understand their implications.

Doing this, libarpack.a is built.

I also had to add option(TESTS "..") to prevent some tests which require blas as they have a add_exeecutable(). I did not test this further, e.g. in combination with MPI.

So far it works for me, probably someone with more knowledge about arpack build system wants to have a look at it an possibly apply it.

arpack_no_system_blas_patch.txt

Fabian188 avatar Aug 09 '20 13:08 Fabian188

Changing dependencies could be costly-to-endless (not really motivating...) : CMake may be easy, autotools likely not... You added SYSTEM_BLAS and SYSTEM_LAPACK "only" for building without BLAS/LAPACK ?

I know its volunteers, but some have a glue about what is done, others don't

Yeah... I know too a bunch of glued-depressing walking dead F77 maniacs...

fghoussen avatar Aug 09 '20 16:08 fghoussen

I don't know what you want to say with autotools. Apparently there are more build options than cmake?

Yes I "added" SYSTEM_* to build w/o blas/lapack. The code was already there but commented 5 years ago. It is on by default to have the same default behavior as before. blas/lapack is required the for testing, which was done before automatically. I even suggest to switch off TESTS by default (as are the examples) as the lib is what one usually wants. But I do not know, what this bug_158, ... stuff ist.

Fabian188 avatar Aug 09 '20 16:08 Fabian188

I suppose what you want is not possible : you should try to check your environment or to set hints (from or outside your external project) for FindBLAS() to find something (setting BLA_STATIC=ON if you need *.a ?). This may be the baseline problem you actually have, or, the problem may lie in FindBLAS.cmake (called from external project ?) : did you report to cmake on a dummy case ?

  1. all tests are binaries which use libarpack.a/so.

  2. libarpack.a contains the same things than libarpack.so (only loading / symbol-export is handled differently)

  3. libarpack.so seems to export symbols from BLAS/LAPACK, so, that libarpack.so (as libarpack.a) seems to need BLAS/LAPACK

> nm -gD /tmp/local/lib/libarpack.so | grep axpy
2:                 U caxpy_
34:                 U daxpy_
108:                 U saxpy_
165:                 U zaxpy_
> nm -gD /tmp/local/lib/libarpack.so | grep laset
15:                 U claset_
56:                 U dlaset_
129:                 U slaset_
179:                 U zlaset_

Removing BLAS/LAPACK as a dependency may be painfull... For realizing they are indeed needed

> git grep axpy SRC/
SRC/cnaitr.f:c     caxpy   Level 1 BLAS that computes a vector triad.
SRC/cnaitr.f:      external   caxpy, ccopy, cscal, csscal, cgemv, cgetv0,
...
> git grep lamch SRC/dnaupd.f
SRC/dnaupd.f:c     dlamch   LAPACK routine that determines machine constants.
SRC/dnaupd.f:     &           dlamch
SRC/dnaupd.f:      external   dlamch
SRC/dnaupd.f:         if (tol .le. zero)                        tol = dlamch ('EpsMach')

I don't know what you want to say with autotools

autotools is the set of autoconf (which produces configure), automake (based on Makefile.am) and autoheader. CMake is maintained and is meant for the same things than autotools which is no more maintained.

fghoussen avatar Aug 09 '20 20:08 fghoussen

I think we have a misunderstanding.

  • I need a static libarpack.a to be built which I can link to my own application.
  • I provide blas to my own application (usually mkl or openblas)
  • the current arpack 3.7.0 requires in line 169 unconditionally a system blas to be found by cmake. This is the case, because conditional "find_package(BLAS REQUIRED)" by SYSTEM_BLAS was removed 5 years ago.
  • For this reason, building arpack fails with 3.7.0 on our gitlab-runners which have no system blas. They need no system blas, because we provide it building our application.
  • Our objective is to have a libarpack.a. To build this, no blas is needed! One needs blas only when linking libarpack to a application. This is the case for examples and tests. The examples could be disabled, I added TESTS to also disable the tests.
  • With my patch one can build libarpack.a on a system without system blas.
  • This solution works for me.
  • I believe the hardcoded requirement for system blas is 3.7.0 should not be, as it is not required for libarpack, which is, what most arpack users might want. I did not test for the dynamic case.
  • To your point 3, I think the U means, that arpack uses blas (when running), which is clear. It's just not required to build the lib.

I hope for a discussion on this issue and I thank you for your discussion.

Fabian188 avatar Aug 09 '20 21:08 Fabian188

Not clear enough to me. Your problem looks really like a pure cmake problem, not an arpack-ng problem. Seems you need :

  • Either to set hints and/or relevant environment variables (CMAKE_PREFIX_PATH, BLAS_LIBRARY, ... - https://stackoverflow.com/questions/19858134/how-to-share-variables-between-different-cmake-files/19859882#19859882) inside your CMakeLists.txt between your find_package(BLAS) and your find_package(arpack-ng) so that arpack-ng knows already where to find BLAS/LAPACK when he needs them (If I understand correctly what you do in the CMakeLists.txt of your app)

  • Reduce your problem and report to cmake

Using imported targets (to reuse BLAS/LAPACK already found) in arpack-ng may help : test this 2-minutes patch #282 to know.

One needs blas only when linking libarpack to a application.

If you end-up with a libarpack.a which can not be used because BLAS/LAPACK are missing and which can not be tested what's the point ?! You try to create something nobody can do anything with... Because you miss the real problem

fghoussen avatar Aug 10 '20 20:08 fghoussen

If you end-up with a libarpack.a which can not be used because BLAS/LAPACK are missing and which can not be tested what's the point ?! You try to create something nobody can do anything with... Because you miss the real problem

Please believe me, that's wrong.

  • BLAS/ARPACK is NOT required to build the libs but only for the tests and examples.
  • The libarpack is the same, independent if BLAS/ARPACK is on the system or not.
  • Therefore I added in my patch the option TESTS, to have only the lib an no examples and no tests
  • I have no cmake issue or cmake bug at all. In current 3.7.0 in line 169 find_package(BLAS REQUIRED) always wants a system blas. But this is not needed without tests and examples.

All I want is an option to build libarpack on a system without BLAS/LAPACK. And I know that this works, as I do it with my patch at the moment. My patch has as default the old behaviour - hence tests are built and for that BLAS/LAPACK is required.

It makes no sense to enforce BLAS/LAPACK of only libarpack is build and BLAS/LAPACK are note used for that build.

Fabian188 avatar Aug 11 '20 20:08 Fabian188

When I run arpack with my patch as cmake .. -DSYSTEM_BLAS=OFF -DSYSTEM_LAPACK=OFF -DTESTS=OFF -DEXAMPLES=OFF I get after make clean; make

...
[ 98%] Building Fortran object CMakeFiles/arpack.dir/staini.f.o
[100%] Linking Fortran static library libarpack.a
[100%] Built target arpack

With EXAMPLES or TESTS on libarpack is built, but tests and/or examples fail. Here for examples

cmake .. -DSYSTEM_BLAS=OFF -DSYSTEM_LAPACK=OFF -DTESTS=OFF -DEXAMPLES=ON
...
[ 31%] Building Fortran object CMakeFiles/arpack.dir/staini.f.o
[ 32%] Linking Fortran static library libarpack.a
[ 32%] Built target arpack
Scanning dependencies of target ssdrv3
[ 33%] Building Fortran object CMakeFiles/ssdrv3.dir/EXAMPLES/SYM/ssdrv3.f.o
[ 33%] Linking Fortran executable Examples/sym/ssdrv3
Undefined symbols for architecture x86_64:
  "_saxpy_", referenced from:
      _MAIN__ in ssdrv3.f.o
      _ssapps_ in libarpack.a(ssapps.f.o)
...

You see, libarpack is built. And same is with TESTS on

cmake .. -DSYSTEM_BLAS=OFF -DSYSTEM_LAPACK=OFF -DTESTS=ON -DEXAMPLES=OFF
...
[ 82%] Building Fortran object CMakeFiles/arpack.dir/staini.f.o
[ 83%] Linking Fortran static library libarpack.a
[ 83%] Built target arpack
[ 84%] Building Fortran object CMakeFiles/bug_142_gen.dir/TESTS/bug_142_gen.f.o
[ 85%] Linking Fortran executable Tests/bug_142_gen
Undefined symbols for architecture x86_64:
  "_daxpy_", referenced from:
      _MAIN__ in bug_142_gen.f.o
      _dnaitr_ in libarpack.a(dnaitr.f.o)
      _dnapps_ in libarpack.a(dnapps.f.o)
...

Again libarpack.a is built nicely, it's just the tests that fail to link.

Clearly BLAS/LAPACK is needed for any application linking arpack - just nut to build libarpack itself.

@fghoussen could I convince you?

Fabian188 avatar Aug 11 '20 20:08 Fabian188

Please believe me

I believe no one but the code. Arpack's API are the *[ae]upd, git grep external SRC/*[ae]upd.f shows already lots of BLAS/LAPACK hits (*ger, *lacpy, ...): arpack (the core of it - not the tests of it) needs BLAS/LAPACK.

All I want is an option to build libarpack on a system without BLAS/LAPACK.

There is no way you get that, as, there's no way you can build a house without walls. But, you may get a way to give arpack what you already found (so that arpack no more need to search): I believe cmake targets is the right tool for that.

@fghoussen could I convince you?

Not at all. Your problem is pure cmake: it has nothing to do with arpack. Your problem is that you have concurrent find_package at different cmake levels :

find_package(A)
find_package(B) # where B needs A.

In your case, A = BLAS and B = ARPACK. Now Say A = BLAS, say B = LAPACK, and say that FindLAPACK.cmake calls find_package(BLAS) (it could be the case, but, it's not as LAPACK ships his own BLAS) : you'll get the exact same problem... And arpack is not involved here as this is a very generic problem : if you'd ask cmake people, they may answer you "find_package should now set targets: in B, search for A only if its target is not set, then use A target instead of A variables" that is "if you found A before elsewhere, in B you can reuse it as is (as target is some kind of alias)"

fghoussen avatar Aug 12 '20 17:08 fghoussen

I believe no one but the code. Arpack's API are the *[ae]upd, git grep external SRC/*[ae]upd.f shows already lots of BLAS/LAPACK hits (*ger, *lacpy, ...): arpack (the core of it - not the tests of it) needs BLAS/LAPACK.

Then it makes no sense to discuss here any more. I'm sure I'm right, your're sure your're right. I give my point a last time, and this are my arguments: a) To run functions from libarpack, one needs blas/lapack, because arpack depends on them. Here we have common understanding. b) To build libarpack, blas/lapack are not required - they are only required at runtime of arpack. Here we apparently have different understanding. I claim, I'm right, because this is how libraries work - the code from the libs are needed only at linking (static libs) or even at runtime (dynamic libs). I showed above, that libarpack was successfully built. c) Therefore I claim, I have no cmake issue. The find_package(A,B) fail, as the gitlabrunner has no system blas and lapack, so cmake cannot find anything. All is proved for me, as my patch works for me.

I think the only way to continue are more people sharing their thoughts and knowledge.

Fabian188 avatar Aug 12 '20 18:08 Fabian188

There's no right or wrong ?!... CMake evolves to "modern CMake" as it learns from it's errors : CMake fix same rules from anybody https://levelup.gitconnected.com/simple-modern-cmake-tutorial-b0c1c362cd2c

fghoussen avatar Aug 13 '20 12:08 fghoussen

I submitted a pull request that decouples the BLAS/LAPACK dependencies when the user does not need tests or examples. I have tried the resulting libarpack.[a|so] and it is working fine, as it should, but it would be nice if somebody could double-check.

(...) Arpack's API are the *[ae]upd, git grep external SRC/*[ae]upd.f shows already lots of BLAS/LAPACK hits (*ger, *lacpy, ...): arpack (the core of it - not the tests of it) needs BLAS/LAPACK.

These are references to BLAS/LAPACK functions that are not needed at compile-time of SRC/*[ae]upd.f. They are not needed at link-time of libarpack.[a|so] either. BLAS/LAPACK are only needed during link-time of the executable consuming libarpack, that is, when the references to (*ger, *lacpy, ...) present in libarpack need to be resolved. The consumer of libarpack must then link with -l <path>/libarpack.[a|so] -llapack -lblas (or -lopenblas or whichever the user likes) to avoid getting undefined references.

As it is done currently the lines CMakeLists.txt:309,310, will hard-code the path of whatever BLAS/LAPACK libraries were found with find_package a bit further up, as seen with ldd

>> ldd libarpack.so
        linux-vdso.so.1 (0x00007ffd383bf000)
*       libmkl_gf_lp64.so => /opt/intel/mkl/lib/intel64/libmkl_gf_lp64.so (0x00007fc1bd891000)
*       libmkl_gnu_thread.so => /opt/intel/mkl/lib/intel64/libmkl_gnu_thread.so (0x00007fc1bc046000)
*       libmkl_core.so => /opt/intel/mkl/lib/intel64/libmkl_core.so (0x00007fc1b7dfc000)
        libgomp.so.1 => /usr/lib/x86_64-linux-gnu/libgomp.so.1 (0x00007fc1b7dba000)
        libgfortran.so.5 => /usr/lib/x86_64-linux-gnu/libgfortran.so.5 (0x00007fc1b7af2000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc1b79a3000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc1b77af000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc1b77a9000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc1b7786000)
        libquadmath.so.0 => /usr/lib/x86_64-linux-gnu/libquadmath.so.0 (0x00007fc1b773c000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fc1b7721000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fc1be467000)

This is an unnecessary constraint, making the library less flexible. At least that's my current understanding.

DavidAce avatar Mar 06 '21 11:03 DavidAce

Thank you very much!

Fabian188 avatar Mar 07 '21 00:03 Fabian188