-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added LAPACK library detection mechanisms to compile and test library… #19
Open
KJ7LNW
wants to merge
2
commits into
PDLPorters:master
Choose a base branch
from
KJ7LNW:lapack-detect
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Commits on Jul 27, 2022
-
Added LAPACK library detection mechanisms to compile and test library…
… success. Unified @pkgs list into @libsets in find_libs() to group libraries by dependency. Compatibility with the 0.33 release is important across multiple UNIX deployments. The first section discusses how the new code is equivalent to the old code in terms of functionality, while extending the detection to make actual FORTRAN calls to test that the libraries work. In addition, libraries with multiple dependencies are tested together instead _and_ independently, instead of _only_ independently as previously designed. This commit is documented in sections 1. Overview of the current implementaiton 2. Design goals for the new implementation 3. Devel::CheckLib limitations 4. Implementation details 5. Validation ORIGINAL IMPLEMENTATION ======================= The previous code was as follows. The indented lines are original code, unindented lines are commentary. There are 3 major parts to the original library detection mechanism: # Part 1: This section tries to find LAPACK by searching # for -llapack and -lblas. If neither PkgConfig->find(), # ExtUtils::PkgConfig->libs, nor `pkg-config` can find the # libraries, then '-L/usr/lib/atlas -llapack -lblas -latlas' # is forced as a default: my @pkgs = qw(lapack blas); our $libs0 = ( eval {require PkgConfig; join ' ', map PkgConfig->find($_)->get_ldflags, @pkgs} || eval {require ExtUtils::PkgConfig; join ' ', map ExtUtils::PkgConfig->libs($_), @pkgs} || `pkg-config @pkgs --libs` || '-L/usr/lib/atlas -llapack -lblas -latlas' # Finally, any FORTRAN libraries are added to $lib0: ) . ' ' . ExtUtils::F77->runtime; # The next anonymous code block is in two parts: our $inc = '-DF77_USCORE='. (ExtUtils::F77->trail_ ? '_' : ''); { # Part 2a: use check_lib() to strip any libraries added above # (lapack, blas) that fail to link as tested by check_lib(). # They may fail to link for one of two reasons. Either (a) they # do not exist on the host, or (b) that fail to link independently # (ie, lapack may depend on blas or vice-versa): # work around Devel::CheckLib not doing Text::ParseWords::shellwords use Text::ParseWords qw(shellwords); my @libpath = grep -d, map {my $r=$_;$r=~s/^-L//?$r:()} my @sw = shellwords $libs0; my @lib = grep check_lib(lib=>$_), map {my $r=$_;$r=~s/^-l//?$r:()} @sw; $libs0 = join ' ', (map qq{-L"$_"}, @libpath), (map "-l$_", @lib); # Part 2b: Emit a warning and `exit 0` if compilation fails. # This is a sticky issue, because Devel::CheckLib has some very old # known bugs. Notably, RT75803: (10 years ago): "Allow function # option to be used without lib option". Simply stated, if 'lib=>' # is not passed to check_lib_or_exit() then it will do nothing, # and return success. PDL::LinearAlgebra commit 1d25c1b _does_ # have a 'lib=>' option, but _it was removed_ in e1b6576, at # which point the following code may as well have been deleted: my $f77_uscore = (ExtUtils::F77->trail_ ? '_' : ''); check_lib_or_exit( ldflags => $libs0, header => [($^O =~ /MSWin/ ? 'float.h' : ()), qw(stdio.h math.h)], function => ... ) } So we can distill the above code down to two items: 1. Add the FORTRAN libs determined by ExtUtils::F77 2. Add -llapack, -lblas, and -latlas if `pkg-config` cannot find them. NEW DESIGN ========== The new design intends to satisfy the following: 1. Define an array of reasonable library combinations that are compatible with existing UNIX deployments 2. By default, the first successful library is selected. - A library is "successful" if it can compile and link FORTRAN functions. 3. Allow users who have multiple LAPACK/BLAS implementations to select a specific implementation if they wish. 4. Provide adequate debug output for troubleshooting test reports. 5. Linux and other UNIXen that support compling and linking with `-l<lib>` and `-L<dir>` linker options are treated the same. While there may be special cases for libraries (openblas vs atlas), there is no special-case for UNIX-like operating systems. 6. Library detection/selection for Windows will not be modified. 7. Safety: Use shell_quote/shellwords to make sure library paths are clean. BUGS IN Devel::CheckLib ======================= (They are commented in the code as well, so pasted here for good visibility) In addition, Devel::CheckLib fails to provide `argc` to main() before about v1.11, so a Devel::CheckLib version requirement was added. IMPLEMENTATION ============== We have written a wrapper `new_check_lib()` around Devel::CheckLib::check_lib() to work around the issues above. This is the comment in the code: Configurability with environment variables: 1. PDL_LA_LDFLAGS='-L<dir> -l<lib>...': The user can set this to specify their own linker flags (for example, to link with the Intel MKL library). 2. PDL_LA_DEBUG=1: Pass `debug=>1` to Devel::CheckLib::check_lib() 3. PDL_LA_LIB_INDEX=<n>: Select a LAPACK/BLAS library. When Makefile.PL runs it emits output like the following. The user can specify PDL_LA_LIB_INDEX=<n> to choose the implementation that succeeded. This defaults to 0 if not specified: [0] found (openblaso): -Llibgfortran.a -L/usr/lib -L/opt/intel/compilers_and_libraries_2020.4.304/linux/mkl/lib/intel64_lin/ -lgfortran -lm -lopenblaso missing (openblas_openmp) [1] found (tatlas): -Llibgfortran.a -L/usr/lib -L/opt/intel/compilers_and_libraries_2020.4.304/linux/mkl/lib/intel64_lin/ -L/usr/lib64/atlas/ -lgfortran -lm -ltatlas [2] found (openblasp): -Llibgfortran.a -L/usr/lib -L/opt/intel/compilers_and_libraries_2020.4.304/linux/mkl/lib/intel64_lin/ -lgfortran -lm -lopenblasp missing (openblas_pthreads) [3] found (openblas): -Llibgfortran.a -L/usr/lib -L/opt/intel/compilers_and_libraries_2020.4.304/linux/mkl/lib/intel64_lin/ -lgfortran -lm -lopenblas missing (openblas_serial) [4] found (satlas): -Llibgfortran.a -L/usr/lib -L/opt/intel/compilers_and_libraries_2020.4.304/linux/mkl/lib/intel64_lin/ -L/usr/lib64/atlas/ -lgfortran -lm -lsatlas [5] found (atlas): -Llibgfortran.a -L/usr/lib -L/opt/intel/compilers_and_libraries_2020.4.304/linux/mkl/lib/intel64_lin/ -L/usr/lib64/atlas/ -lgfortran -lm -lsatlas missing (lapack_atlas) [6] found (lapack): -Llibgfortran.a -L/usr/lib -L/opt/intel/compilers_and_libraries_2020.4.304/linux/mkl/lib/intel64_lin/ -lgfortran -lm -llapack missing (blas) [7] found (lapack blas): -Llibgfortran.a -L/usr/lib -L/opt/intel/compilers_and_libraries_2020.4.304/linux/mkl/lib/intel64_lin/ -lgfortran -lm -llapack -lblas [8] found (lapack blas atlas): -Llibgfortran.a -L/usr/lib -L/opt/intel/compilers_and_libraries_2020.4.304/linux/mkl/lib/intel64_lin/ -L/usr/lib64/atlas/ -lgfortran -lm -llapack -lblas -lsatlas [9] found (mkl_rt): -Llibgfortran.a -L/usr/lib -L/opt/intel/compilers_and_libraries_2020.4.304/linux/mkl/lib/intel64_lin/ -lgfortran -lm -lmkl_rt Safety: - -L flags are passed before -l flags so the linker can know the paths before hunting for the libraries. - Any linker options that match neither `-l<lib>` nor `-L<dir>` are passed verbatim. - Options are handled as lists except when generating an LDFLAGS-style output, in which case `shell_quote` and `shellwords` are used to properly parse and escape the input and output. The library detection code at the top of `Makefile.PL` is now a single line: our $libs0 = find_libs(ExtUtils::F77->runtime, $ENV{PDL_LA_LDFLAGS}); The list of available library combinations are in `@libsets` atop of `find_libs()`: my @libsets = ( # Empty case if PDL_LA_LDFLAGS satisfies the build [], # Threaded OpenBLAS/ATLAS ['openblaso'], ['tatlas'], # [ ... many others ...] # And finally the options from the original implementation if none of the above options match: ['blas'], ['lapack', 'blas'], ['lapack', 'blas', 'atlas'], # Experimental Intel Math Kernel Library support: ['mkl_rt'], ); Notable changes: FORTRAN check function: Added library code to test `dgebal_` existence Added note about compile problems when missing a leading empty line Added 'return 0' to the end Calls to ExtUtils::F77->trail_ ? '_' : '' were replaced with $f77_uscore Notes: The windows library detection was not modified in this patch. The 'shellwords' work-around was not changed, but the diff looks that way VALIDATION ========== The following library combinations pass `make test` on my Oracle Linux 8 deployment: for i in {0..8}; do export i; echo === $i; (PDL_LA_LIB_INDEX=$i perl Makefile.PL && make -j100 && make test) 2>&1 | grep -P 'will use|ok$' -A1; done 1. -Llibgfortran.a -L/usr/lib -lgfortran -lm -lopenblaso 2. -Llibgfortran.a -L/usr/lib -L/usr/lib64/atlas/ -lgfortran -lm -ltatlas 3. -Llibgfortran.a -L/usr/lib -lgfortran -lm -lopenblasp 4. -Llibgfortran.a -L/usr/lib -lgfortran -lm -lopenblas 5. -Llibgfortran.a -L/usr/lib -L/usr/lib64/atlas/ -lgfortran -lm -lsatlas 6. -Llibgfortran.a -L/usr/lib -L/usr/lib64/atlas/ -lgfortran -lm -lsatlas 7. -Llibgfortran.a -L/usr/lib -lgfortran -lm -llapack 8. -Llibgfortran.a -L/usr/lib -lgfortran -lm -llapack -lblas 9. -Llibgfortran.a -L/usr/lib -L/usr/lib64/atlas/ -lgfortran -lm -llapack -lblas -lsatlas t/1.t ....... ok t/cgtsv.t ... ok t/gtsv.t .... ok t/legacy.t .. ok All tests successful. In addition, the following Ubuntu/Debian distributions have been tested, all you need to install is `libopenblas-dev` to build LAPACK+BLAS successfully: grep -B4 'All tests' */root/pdl*/build.log bionic-i386/root/pdl-linearalgebra/build.log-t/1.t ....... ok bionic-i386/root/pdl-linearalgebra/build.log-t/cgtsv.t ... ok bionic-i386/root/pdl-linearalgebra/build.log-t/gtsv.t .... ok bionic-i386/root/pdl-linearalgebra/build.log-t/legacy.t .. ok bionic-i386/root/pdl-linearalgebra/build.log:All tests successful. -- bionic/root/pdl-linearalgebra/build.log-t/1.t ....... ok bionic/root/pdl-linearalgebra/build.log-t/cgtsv.t ... ok bionic/root/pdl-linearalgebra/build.log-t/gtsv.t .... ok bionic/root/pdl-linearalgebra/build.log-t/legacy.t .. ok bionic/root/pdl-linearalgebra/build.log:All tests successful. -- bullseye-i386/root/pdl-linearalgebra/build.log-t/1.t ....... ok bullseye-i386/root/pdl-linearalgebra/build.log-t/cgtsv.t ... ok bullseye-i386/root/pdl-linearalgebra/build.log-t/gtsv.t .... ok bullseye-i386/root/pdl-linearalgebra/build.log-t/legacy.t .. ok bullseye-i386/root/pdl-linearalgebra/build.log:All tests successful. -- bullseye/root/pdl-linearalgebra/build.log-t/1.t ....... ok bullseye/root/pdl-linearalgebra/build.log-t/cgtsv.t ... ok bullseye/root/pdl-linearalgebra/build.log-t/gtsv.t .... ok bullseye/root/pdl-linearalgebra/build.log-t/legacy.t .. ok bullseye/root/pdl-linearalgebra/build.log:All tests successful. -- buster-i386/root/pdl-linearalgebra/build.log-t/1.t ....... ok buster-i386/root/pdl-linearalgebra/build.log-t/cgtsv.t ... ok buster-i386/root/pdl-linearalgebra/build.log-t/gtsv.t .... ok buster-i386/root/pdl-linearalgebra/build.log-t/legacy.t .. ok buster-i386/root/pdl-linearalgebra/build.log:All tests successful. -- buster/root/pdl-linearalgebra/build.log-t/1.t ....... ok buster/root/pdl-linearalgebra/build.log-t/cgtsv.t ... ok buster/root/pdl-linearalgebra/build.log-t/gtsv.t .... ok buster/root/pdl-linearalgebra/build.log-t/legacy.t .. ok buster/root/pdl-linearalgebra/build.log:All tests successful. -- focal/root/pdl-linearalgebra/build.log-t/1.t ....... ok focal/root/pdl-linearalgebra/build.log-t/cgtsv.t ... ok focal/root/pdl-linearalgebra/build.log-t/gtsv.t .... ok focal/root/pdl-linearalgebra/build.log-t/legacy.t .. ok focal/root/pdl-linearalgebra/build.log:All tests successful. -- xenial-i386/root/pdl-linearalgebra/build.log-t/1.t ....... ok xenial-i386/root/pdl-linearalgebra/build.log-t/cgtsv.t ... ok xenial-i386/root/pdl-linearalgebra/build.log-t/gtsv.t .... ok xenial-i386/root/pdl-linearalgebra/build.log-t/legacy.t .. ok xenial-i386/root/pdl-linearalgebra/build.log:All tests successful. -- xenial/root/pdl-linearalgebra/build.log-t/1.t ....... ok xenial/root/pdl-linearalgebra/build.log-t/cgtsv.t ... ok xenial/root/pdl-linearalgebra/build.log-t/gtsv.t .... ok xenial/root/pdl-linearalgebra/build.log-t/legacy.t .. ok xenial/root/pdl-linearalgebra/build.log:All tests successful.
Eric Wheeler committedJul 27, 2022 Configuration menu - View commit details
-
Copy full SHA for 485d38d - Browse repository at this point
Copy the full SHA 485d38dView commit details
Commits on Jul 30, 2022
-
Added String::ShellQuote dependency
Eric Wheeler committedJul 30, 2022 Configuration menu - View commit details
-
Copy full SHA for 7ba193b - Browse repository at this point
Copy the full SHA 7ba193bView commit details
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.