
How to fix errors like this in R packages with FORTRAN code:

I believe they were first noted here:
https://developer.r-project.org/Blog/public/2019/05/15/gfortran-issues-with-lapack/index.html

And CRAN sent some R package maintainers notes like this:

================
Prof Brian Ripley
May 29, 2019, 10:31 PM
to Wei-Chen, Claudia, Trevor, Berend, Gianluca, Meabh, Kyle, Drew, Roger, me, CRAN

These packages both link to BLAS/LAPACK and include their own copies of 
some BLAS/LAPACK routines, in most cases without crediting the 
authors/copyright holders in the DESCRIPTION file.

Please remove the duplication (or if the routines are altered, rename 
them and credit them) by July 1.

QZ.out:(.text+0x0): multiple definition of `zggbak_'
QZ.out:(.text+0x0): multiple definition of `ztgevc_'
QZ.out:(.text+0x0): multiple definition of `zggbal_'
QZ.out:(.text+0x0): multiple definition of `zgetc2_'
QZ.out:(.text+0x0): multiple definition of `zgesc2_'
QZ.out:(.text+0x0): multiple definition of `zgghrd_'
QZ.out:(.text+0x0): multiple definition of `ztgex2_'
QZ.out:(.text+0x0): multiple definition of `ztgexc_'
QZ.out:(.text+0x0): multiple definition of `zhgeqz_'
QZ.out:(.text+0x0): multiple definition of `ztrsyl_'
QZ.out:(.text+0x0): multiple definition of `zlatdf_'
QZ.out:(.text+0x0): multiple definition of `ztgsy2_'
QZ.out:(.text+0x0): multiple definition of `ztgsyl_'
QZ.out:(.text+0x0): multiple definition of `ztgsen_'
QZ.out:(.text+0x0): multiple definition of `ztrsen_'
QZ.out:(.text+0x0): multiple definition of `zunmhr_'
QZ.out:(.text+0x0): multiple definition of `zgees_'
QZ.out:(.text+0x0): multiple definition of `zgges_'
QZ.out:(.text+0x0): multiple definition of `zggev_'
QZ.out:(.text+0x0): multiple definition of `zgerc_'
QZ.out:(.text+0x0): multiple definition of `zgeru_'
edesign.out:(.text+0x0): multiple definition of `dscal_'
gam.out:(.text+0x0): multiple definition of `daxpy_'
gam.out:(.text+0x0): multiple definition of `dcopy_'
gam.out:(.text+0x0): multiple definition of `ddot_'
gam.out:(.text+0x0): multiple definition of `dnrm2_'
gam.out:(.text+0x0): multiple definition of `drot_'
gam.out:(.text+0x0): multiple definition of `drotg_'
gam.out:(.text+0x0): multiple definition of `dscal_'
gam.out:(.text+0x0): multiple definition of `dswap_'
geigen.out:(.text+0x0): multiple definition of `zggbak_'
geigen.out:(.text+0x0): multiple definition of `ztgevc_'
geigen.out:(.text+0x0): multiple definition of `zggbal_'
geigen.out:(.text+0x0): multiple definition of `zgetc2_'
geigen.out:(.text+0x0): multiple definition of `zgesc2_'
geigen.out:(.text+0x0): multiple definition of `zgghrd_'
geigen.out:(.text+0x0): multiple definition of `ztgex2_'
geigen.out:(.text+0x0): multiple definition of `ztgexc_'
geigen.out:(.text+0x0): multiple definition of `zhgeqz_'
geigen.out:(.text+0x0): multiple definition of `zlatdf_'
geigen.out:(.text+0x0): multiple definition of `ztgsy2_'
geigen.out:(.text+0x0): multiple definition of `ztgsyl_'
geigen.out:(.text+0x0): multiple definition of `ztgsen_'
geigen.out:(.text+0x0): multiple definition of `zgges_'
geigen.out:(.text+0x0): multiple definition of `zggev_'
islasso.out:(.text+0x0): multiple definition of `dnrm2_'
kexpmv.out:(.text+0x0): multiple definition of `daxpy_'
kexpmv.out:(.text+0x0): multiple definition of `dcopy_'
kexpmv.out:(.text+0x0): multiple definition of `ddot_'
kexpmv.out:(.text+0x0): multiple definition of `dgemm_'
kexpmv.out:(.text+0x0): multiple definition of `dgemv_'
kexpmv.out:(.text+0x0): multiple definition of `dnrm2_'
kexpmv.out:(.text+0x0): multiple definition of `dscal_'
mrgsolve.out:(.text+0x0): multiple definition of `daxpy_'
mrgsolve.out:(.text+0x0): multiple definition of `dcopy_'
mrgsolve.out:(.text+0x0): multiple definition of `ddot_'
mrgsolve.out:(.text+0x0): multiple definition of `dnrm2_'
mrgsolve.out:(.text+0x0): multiple definition of `dscal_'
mrgsolve.out:(.text+0x0): multiple definition of `idamax_'
pbdBASE.out:(.text+0x0): multiple definition of `dlarrc_'
pbdBASE.out:(.text+0x0): multiple definition of `dlarrk_'
pbdBASE.out:(.text+0x0): multiple definition of `dlarra_'
pbdBASE.out:(.text+0x0): multiple definition of `dlarrd_'
quantreg.out:(.text+0x0): multiple definition of `dasum_'
quantreg.out:(.text+0x0): multiple definition of `daxpy_'
quantreg.out:(.text+0x0): multiple definition of `ddot_'
quantreg.out:(.text+0x0): multiple definition of `dscal_'
quantreg.out:(.text+0x0): multiple definition of `dswap_'
quantreg.out:(.text+0x0): multiple definition of `idamax_'
rexpokit.out:(.text+0x0): multiple definition of `lsame_'
rexpokit.out:(.text+0x0): multiple definition of `dasum_'
rexpokit.out:(.text+0x0): multiple definition of `daxpy_'
rexpokit.out:(.text+0x0): multiple definition of `dcopy_'
rexpokit.out:(.text+0x0): multiple definition of `ddot_'
rexpokit.out:(.text+0x0): multiple definition of `dgemm_'
rexpokit.out:(.text+0x0): multiple definition of `dgemv_'
rexpokit.out:(.text+0x0): multiple definition of `dnrm2_'
rexpokit.out:(.text+0x0): multiple definition of `dscal_'
rexpokit.out:(.text+0x0): multiple definition of `dswap_'
rexpokit.out:(.text+0x0): multiple definition of `idamax_'

To reproduce these, use R-devel configured with --enable-lto=check 
(which probably requires Linux and recent gcc/gfortran): full 
installation logs using GCC 13.2 can be seen at 
https://www.stats.ox.ac.uk/pub/bdr/LTO2 .
================

================
Compilation logs for CRAN packages using x86_64 Fedora 28 Linux built with
configure --enable-lto and config.site:

CFLAGS="-g -O2 -Wall -pedantic -mtune=native"
FFLAGS="-g -O2 -mtune=native -Wall -pedantic"
CXXFLAGS="-g -O2 -Wall -pedantic -mtune=native -Wno-ignored-attributes -Wno-deprecated-declarations -Wno-parentheses"
JAVA_HOME=/usr/lib/jvm/jre-11
AR=gcc-ar
RANLIB=gcc-ranlib

Using gcc/gfortran 13.2.1.

Look for [-Wlto-type-mismatch] warnings.  In some cases these involve
Fortran CHARACTER arguments where the length is passed as a 'hidden'
argument at the end, giving mismatches such as

sblas.f:3951:14: note: type ‘long int’ should match type ‘void’

To work around these, define USE_FC_LEN_T and include Rconfig.h
(perhaps via R.h) before including BLAS.h or Lapack.h or your own
C proptypes for Fortran functions.  Then amend the actual calls to include
character length arguments: see the example of src/library/stats/src/rWishart.c
in the R sources.
================

================
Prof Brian Ripley
Sat, Jun 1, 5:29 PM
to Charles, Pedro, Houtao, Daniel, Luigi, Karline, Niels, Chong, Luca, Robert, Zhu, Ruben, Karsten, Bruce, me, Xianhong, Greg, CRAN

This concerns packages

LogicReg RMCriteria RRF appell cglasso deTestSet expoRkit gss mclust 
monomvn mpath npsp qMRI repeated rexpokit rgcvpack snpRF

See the 'Additional issues' or directly 
https://www.stats.ox.ac.uk/pub/bdr/LTO/ (including the README.TXT).

Many of the things newly detected in gcc/gfortran 9 are mismatches in 
Fortran calls: check the types (e.g. INTEGER vs DOUBLE PRECISION vs 
REAL) including return values.  Or C-Fortran mismatches: e.g. INTEGER 
does not correspond to unsigned int *.

Please correct ASAP and before July 1 to safely retain the package on CRAN.
================



The very limited online commentary on these problems seems to be
talking about C calls of FORTRAN functions, which involves something
about an implicit argument about the length of a character variable, 
apparently fixable with something like BIND(C)...I didn't bother digging
further as my issues appeared in pure FORTRAN.

The warnings I got appeared in my R package, rexpokit, which wraps
part of Roger Sidje's FORTRAN EXPOKIT library for fast matrix exponentiation.

After a failed attempt at fixing the issue by e.g. splitting ZSWAP:

=========
    o In lapack.f and blas_mod.f, converted:
    o ZSWAP to ZSWAPX (for 5-argument inputs) and
    o ZSWAPY (for 6-argument inputs), in attempt to fix LTO
      warnings about not matching original declaration, e.g.:
        type of "zswapy" does not match 
        original declaration [-Wlto-type-mismatch]
        call zswapy(k-1,b(k),a(1,k),1,b(1),1)
        lapack/blas_mod.f:961: note: "zswapy" was previously declared here
        subroutine  zswapy (n,m,zx,incx,zy,incy)
=========

...I still got the errors below:

====================
lapack/lapack.f:1179: warning: type of "zswapy" does not match 
original declaration [-Wlto-type-mismatch]
                 call zswapy(k-1,b(k),a(1,k),1,b(1),1)

lapack/blas_mod.f:961: note: "zswapy" was previously declared here
        subroutine  zswapy (n,m,zx,incx,zy,incy)

lapack/blas_mod.f:961: note: code may be misoptimized unless 
-fno-strict-aliasing is used



my_expokit.f:1147: warning: type of "zswapx" does not match original 
declaration [-Wlto-type-mismatch]
            call ZSWAPX(m-i+1,wsp(ih+(i-1)*m+i-1),m,wsp(ih+(i-1)*m+i),m)
lapack/blas_mod.f:926: note: "zswapx" was previously declared here
        subroutine  zswapx (n,zx,incx,zy,incy)

lapack/blas_mod.f:926: note: code may be misoptimized unless 
-fno-strict-aliasing is used



my_expokit.f:1154: warning: type of "zaxpx" does not match original 
declaration [-Wlto-type-mismatch]
           call ZAXPX(m-i,tmpc,wsp(ih+i*m+i-1),m,wsp(ih+i*m+i),m )


lapack/blas_mod.f:443: note: "zaxpx" was previously declared here
        subroutine zaxpx(n,za,zx,incx,zy,incy)

lapack/blas_mod.f:443: note: code may be misoptimized unless 
-fno-strict-aliasing is used
====================




In the end, these were the keys for me to solve this:


1. I have Mac OSX 10.14, not LINUX, so it wasn't obvious from the CRAN maintainer messages
if I could even reproduce the errors.  But I eventually did.

1a. To reproduce the errors, I had to install gcc13.2 (including gfortran),
using the commands here:

* Download the newest GCC
https://gcc.gnu.org/install/download.html

* NOT NEEDED APPARENTLY: Installed go for Mac 12.4, e.g. go1.5, 
go1.5.darwin-amd64.pkg	Installer	macOS	x86-64	74MB	0d37bb75adc6eb2ce72fc500a0584b20618abf1d

https://go.dev/dl/


* 2023-11-22_WORKS then:

https://gcc.gnu.org/wiki/InstallingGCC
===============================
tar xzf gcc-13.2.0.tar.gz
cd gcc-13.2.0
./contrib/download_prerequisites
cd ..
mkdir objdir
cd objdir
# DOESN'T WORK: $PWD/../gcc-13.2.0/configure --prefix=$HOME/GCC-13.2.0 --enable-languages=c,c++,fortran,go

# WORKS:
$PWD/../gcc-13.2.0/configure --prefix=$HOME/GCC-13.2.0 --enable-languages=c,c++,fortran,lto

make
make install
===============================



1b. Then I had to compile all the .f and .cpp files in Mac Terminal by hand (replace "username" with your username):

===========================
cd /GitHub/rexpokit/src

rm *.o
rm *.so
rm lapack/*.o
rm lapack/*.so

/usr/local/gcc-13.2.0/bin/gfortran-13.2  -fno-optimize-sibling-calls -fstrict-aliasing -fpic  -g -O2 -Wall -pedantic -mtune=native -flto -c lapack/blas_mod.f -o lapack/blas_mod.o

/usr/local/gcc-13.2.0/bin/gfortran-13.2  -fno-optimize-sibling-calls  -fpic  -g -O2 -Wall -pedantic -mtune=native -flto -c lapack/lapack.f -o lapack/lapack.o

/usr/local/gcc-13.2.0/bin/gfortran-13.2  -fno-optimize-sibling-calls  -fpic  -g -O2 -Wall -pedantic -mtune=native -flto -c lapack/mataid.f -o lapack/mataid.o

/usr/local/gcc-13.2.0/bin/gfortran-13.2  -fno-optimize-sibling-calls  -fpic  -g -O2 -Wall -pedantic -mtune=native -flto -c lapack/my_expokit.f -o lapack/my_expokit.o

/usr/local/gcc-13.2.0/bin/gfortran-13.2  -fno-optimize-sibling-calls  -fpic  -g -O2 -Wall -pedantic -mtune=native -flto -c my_matexp.f -o my_matexp.o

/usr/local/gcc-13.2.0/bin/gfortran-13.2  -fno-optimize-sibling-calls  -fpic  -g -O2 -Wall -pedantic -mtune=native -flto -c itscale5.f -o itscale5.o

/usr/local/gcc-13.2.0/bin/gcc-13.2 -std=gnu++11 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG  -I"/Users/username/GCC-13.2.0/include" -DNDEBUG  -I"/Library/Frameworks/R.framework/Versions/3.6/Resources/library/Rcpp/include/" -DNDEBUG -I"/Library/Frameworks/R.framework/Versions/3.6/PrivateHeaders"  -I"/Library/Frameworks/R.framework/Versions/3.6/PrivateHeaders/R_ext" -I/usr/local/include -DUSE_TYPE_CHECKING_STRICT -fno-optimize-sibling-calls -fpic  -g -O2 -Wall -pedantic -flto -c coo.cpp -o coo.o

/usr/local/gcc-13.2.0/bin/g++-13.2 -std=gnu++11 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG  -I"/Library/Frameworks/R.framework/Versions/3.6/Resources/library/Rcpp/include/" -DNDEBUG -I"/Library/Frameworks/R.framework/Versions/3.6/PrivateHeaders"  -I"/Library/Frameworks/R.framework/Versions/3.6/PrivateHeaders/R_ext" -I/usr/local/include -DUSE_TYPE_CHECKING_STRICT -fno-optimize-sibling-calls -fpic  -g -O2 -Wall -pedantic -flto -c wrappers.cpp -o wrappers.o

/usr/local/gcc-13.2.0/bin/g++-13.2 -std=gnu++11 -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/Library/Frameworks/R.framework/Resources/lib -L/usr/local/lib -o rexpokit.so lapack/blas_mod.o lapack/lapack.o lapack/mataid.o lapack/my_expokit.o my_matexp.o itscale5.o coo.o wrappers.o -L/Library/Frameworks/R.framework/Resources/lib -lRlapack -L/Library/Frameworks/R.framework/Resources/lib -lRblas -L/usr/local/gfortran/lib/gcc/x86_64-apple-darwin15/6.1.0 -L/usr/local/gfortran/lib -lgfortran -lquadmath -lm -L/usr/local/gfortran/lib/gcc/x86_64-apple-darwin15/6.1.0 -L/usr/local/gfortran/lib -lgfortran -lquadmath -lm -F/Library/Frameworks/R.framework/.. -framework R -Wl,-framework -Wl,CoreFoundation -fno-optimize-sibling-calls -flto -fno-strict-aliasing -Wlto-type-mismatch

[not all of the above may be needed, I was just copying the default compilation commands and then splicing in by 13.2.0 gcc/gfortran)

===========================



2023-11-22: this reproduced these errors:

ld: warning: directory not found for option '-L/usr/local/gfortran/lib/gcc/x86_64-apple-darwin15/6.1.0'
ld: warning: directory not found for option '-L/usr/local/gfortran/lib/gcc/x86_64-apple-darwin15/6.1.0'
ld: warning: -undefined dynamic_lookup may not work with chained fixups
lapack/lapack.f:1261:72: warning: type of ‘zswapy’ does not match original declaration [-Wlto-type-mismatch]
 1261 |               call zswapy(tempkm1,tempx,tempzx,1,b(1),1)
      |                                                                        ^
lapack/blas_mod.f:961:24: note: ‘zswapy’ was previously declared here
  961 |       subroutine  zswapy (n,m,zx,incx,zy,incy)
      |                        ^
lapack/blas_mod.f:961:24: note: code may be misoptimized unless ‘-fno-strict-aliasing’ is used
lto-wrapper: warning: using serial compilation of 2 LTRANS jobs
lto-wrapper: note: see the ‘-flto’ option documentation for more information
ld: warning: directory not found for option '-L/usr/local/gfortran/lib/gcc/x86_64-apple-darwin15/6.1.0'
ld: warning: directory not found for option '-L/usr/local/gfortran/lib/gcc/x86_64-apple-darwin15/6.1.0'
ld: warning: -undefined dynamic_lookup may not work with chained fixups




This produced the errors above on the last command.



2. Warnings like 

"warning: type of "zswapx" does not match original declaration [-Wlto-type-mismatch]"

...are very unhelpful.  To get insight, I had to run the last step with -fdump-tree-all:

/Users/nmat471/GCC-13.2.0/bin/g++ -std=gnu++11 -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/Library/Frameworks/R.framework/Resources/lib -L/usr/local/lib -o rexpokit.so lapack/blas_mod.o lapack/lapack.o mataid.o my_expokit.o my_matexp.o itscale5.o coo.o wrappers.o -L/Library/Frameworks/R.framework/Resources/lib -lRlapack -L/Library/Frameworks/R.framework/Resources/lib -lRblas -L/usr/local/gfortran/lib/gcc/x86_64-apple-darwin15/6.1.0 -L/usr/local/gfortran/lib -lgfortran -lquadmath -lm -L/usr/local/gfortran/lib/gcc/x86_64-apple-darwin15/6.1.0 -L/usr/local/gfortran/lib -lgfortran -lquadmath -lm -F/Library/Frameworks/R.framework/.. -framework R -Wl,-framework -Wl,CoreFoundation -fno-optimize-sibling-calls -flto -fno-strict-aliasing -Wlto-type-mismatch -fdump-tree-all


This spits a massive number of files into rexpokit/src.  To get the useful information, do something like this:

more *.optimized > optimized.txt

...and then open in a text file and look for the functions causing problems.  I saw these:

==========================
;; Function zswapx (zswapx_, funcdef_no=7, decl_uid=4353, cgraph_uid=8, symbol_order=11)
[...]
zswapx (int & restrict n, complex double[1] * restrict zx, int & restrict incx, complex double[1] * restrict zy, int & restrict incy)


;; Function zswapy (zswapy_, funcdef_no=6, decl_uid=4352, cgraph_uid=7, symbol_order=12)
[...]
zswapy (int & restrict n, int & restrict m, complex double[1] * restrict zx, int & restrict incx, complex double[1] * restrict zy, int & restrict incy)

;; Function zaxpx (zaxpx_, funcdef_no=15, decl_uid=4361, cgraph_uid=16, symbol_order=3)
[...]
zaxpx (int & restrict n, complex double & restrict za, complex double[1] * restrict zx, int & restrict incx, complex double[1] * restrict zy, int & restrict incy)
==========================

...which gives the types of the input variables.

The problems in blas_mod.f, lapack.f, and my_expokit.f seem to be where the FORTRAN code is assuming a switch of type, often when a calculation is input into "n", "m", or "za".

The solution was to do the calculation on a separate line, making sure the result is input into a "tempn", "tempx" etc. variable that is forced to be the correct type.

I noted all of these changes with "2019-07-02_NJM:" in the .f files in rexpokit/src.



POSTSCRIPT

Now it compiles without those errors. Hopefully this is it. It took only 3 work days to figure out. This seems like a lot in order to fix an issue that seems like it might be fixed in the future anyway by the FORTRAN folks (who themselves seem to be arguing about it: , ), and that is not causing problems now.  But apparently I've signed up, forever, to burning several days every year or two when CRAN or gfortran updates something in order to keep rexpokit on CRAN.  Unfortunately I kind of have to keep rexpokit on CRAN as CRAN produces compiled binaries of the package for all different operating systems.  Without those binaries, all BioGeoBEARS users would have to install their own gcc and gfortran compilers, including on Windows, which would be somewhere between difficult and impossible for many R users.













