Fortran“对[函数]的未定义引用”直接编译 .f90 文件即可消除错误

发布于 2025-01-15 13:11:09 字数 5980 浏览 1 评论 0原文

在有人结束问题之前,是的,有很多问题看起来很相似,但到目前为止,我还没有找到一个具有这种奇怪问题的问题,这种问题似乎只是有时会消失。

我在尝试制作线性回归模块时遇到了一个奇怪的 Fortran 错误。

该模块名为“LSQregression”,主程序名为“LSQAdvertising”。使用以下 gfortran 命令编译它是可行的:

gfortran ../LSQregression.f90 LinearAdvertising.f90 -llapack -o LinAd

但是,我希望能够将我的模块转换为 .o 文件并将其与我可能需要的任何程序链接,而不是每次都重新编译。所以我尝试这样做:

gfortran -c ../LSQregression.f90

然后将其与我的程序文件链接起来,如下所示:

gfortran ../LSQregression.o LinearAdvertising.f90 -llapack -o LinAd

我还尝试将程序转换为 .o 文件。两者都不起作用,它们都返回以下错误:

/usr/bin/ld: /tmp/ccf7T1aj.o: in function `MAIN__':
LinearAdvertising.f90:(.text+0x1f8b): undefined reference to `__lsqregression_MOD_lsqestimate_simple'
collect2: error: ld returned 1 exit status

它指的是程序内部正在调用的模块中的以下函数:

print *, LSQestimate(test,LSQbeta(inputs,sales,(/1,2/)) )

函数本身被定义为接口的一部分:

interface LSQestimate
     procedure LSQestimate_simple, LSQestimate_using
  end interface LSQestimate

 real(8) function LSQestimate_simple(X, beta)
    implicit none
    real(8), dimension(:,:) :: X, beta
    real(8)                 :: boundary, Y
    integer                 :: i, Xlen, betalen

    Xlen    = size(X, 1)
    betalen = size(beta, 1)

    if (Xlen + 1 .ne. betalen) stop "incompatible beta and X"

    Y = beta(1,1)

    do i = 1, Xlen
       Y = Y + beta(i+1, 1)*X(i,1)
    end do

    LSQestimate_simple = Y
    
  end function LSQestimate_simple

这很奇怪,因为我做了同样的事情使用另一个函数,它似乎工作正常,并且只有当我首先将模块转换为 .o 文件时才会出现问题,如果我尝试直接编译 .f90 文件,问题就会消失......我不明白为什么一个有效,另一个无效。

编辑:有人告诉我做nm ../LSQregression.o | grep -i 回归 。我不知道那是做什么的,但我这样做了,所以如果它有帮助的话,结果如下:

0000000000002768 T __lsqregression_MOD_inv
0000000000000b85 T __lsqregression_MOD_lsqbeta_simple
000000000000035c T __lsqregression_MOD_lsqbeta_using
0000000000000000 T __lsqregression_MOD_lsqdecision

奇怪的是,有问题的函数的名称甚至没有出现在这里。

编辑2:决定发布模块的完整代码:

module LSQregression
  implicit none

  public  :: LSQbeta, LSQestimate

  interface LSQbeta
     procedure LSQbeta_simple, LSQbeta_using
  end interface LSQbeta

  interface LSQestimate
     procedure LSQestimate_simple, LSQestimate_using
  end interface LSQestimate
  
  
  
  
contains
  
  function inv(A) result(Ainv)
    implicit none
    real(8), dimension(:,:), intent(in)     :: A
    real(8), dimension(size(A,1),size(A,2)) :: Ainv

    real(8), dimension(size(A,1)) :: work  ! work array for LAPACK
    integer, dimension(size(A,1)) :: ipiv   ! pivot indices
    integer :: n, info

    ! External procedures defined in LAPACK
    external DGETRF
    external DGETRI

    ! Store A in Ainv to prevent it from being overwritten by LAPACK
    Ainv = A
    n = size(A,1)

    ! DGETRF computes an LU factorization of a general M-by-N matrix A
    ! using partial pivoting with row interchanges.
    call DGETRF(n, n, Ainv, n, ipiv, info)

    if (info /= 0) then
       stop 'Matrix is numerically singular!'
    end if

    ! DGETRI computes the inverse of a matrix using the LU factorization
    ! computed by DGETRF.
    call DGETRI(n, Ainv, n, ipiv, work, n, info)
    
    if (info /= 0) then
       stop 'Matrix inversion failed!'
    end if
  end function inv
  
  !----------------------------------------------------------------------
  
  function LSQbeta_simple(Xold, Y) result(beta)
    real(8), dimension(:,:)                          :: Xold, Y
    real(8), dimension(size(Xold,1), size(Xold,2)+1) :: X
    real(8), dimension(:,:), allocatable             :: beta, XTX, IXTX, pinv
    integer                                          :: rowsX, colsX, rowsY, colsY,i


    rowsX = size(X(:,1))
    colsX = size(X(1,:))
    rowsY = size(Y(:,1))
    colsY = size(Y(1,:))

    if (colsY .ne. 1)     stop 'Inappropriate y'
    if (rowsY .ne. rowsX) stop "Y and X rows don't match"
    
    !---X-ify-----------
    X(:,1) = 1.0     !includes 1 in the first column
    
    do i = 2, colsX
       X(:,i) = Xold(:,i-1)
    end do
    !--------------------

   
    allocate(XTX(colsX,colsX))
    allocate(IXTX(colsX,colsX))
    allocate(pinv(colsX,rowsY))
    allocate(beta(colsX,1))

    XTX   = matmul(transpose(X),X)
    IXTX  = inv(XTX)
    pinv  = matmul(IXTX, transpose(X))
    beta  = matmul(pinv, Y)

    deallocate(pinv)
    deallocate(XTX)
    deallocate(IXTX)

    return
    
    deallocate(beta)
    
  end function LSQbeta_simple
  !--------------------------------------------
  
  function LSQbeta_using(Xold, Y, indexes) result(beta)
    implicit none
    real(8), dimension(:,:)                        :: Xold, Y
    integer, dimension(:)                          :: indexes
    real(8), dimension(size(indexes)+1,1)          :: beta
    real(8), dimension(size(Xold,1),size(indexes)) :: X
    integer                                        :: indLen,i

    indLen = size(indexes) 
    
    do i = 1, indLen
       X(:,i) = Xold(:,indexes(i))
    end do

    beta = LSQbeta_simple(X,Y)
    
  end function LSQbeta_using

  real(8) function LSQestimate_simple(X, beta)
    implicit none
    real(8), dimension(:,:) :: X, beta
    real(8)                 :: boundary, Y
    integer                 :: i, Xlen, betalen

    Xlen    = size(X, 1)
    betalen = size(beta, 1)

    if (Xlen + 1 .ne. betalen) stop "incompatible beta and X"

    Y = beta(1,1)

    do i = 1, Xlen
       Y = Y + beta(i+1, 1)*X(i,1)
    end do

    LSQestimate_simple = Y
    
  end function LSQestimate_simple

  real(8) function LSQestimate_using()
    LSQestimate_using = 1.0D0
  end function LSQestimate_using
  
  

  logical function LSQdecision(X, beta, boundary)
    implicit none
    real(8), dimension(:,:) :: X, beta
    real(8)                 :: boundary
    
    LSQdecision = LSQestimate(X, beta) > boundary
    
  end function LSQdecision
  


  
end module LSQregression

Before someone closes the question, yes, there are many questions that seem similar, but so far I haven't found one with this exact weird problem that seems to go away only sometimes.

I had an odd Fortran error while trying to make a module for linear regression.

The module is named "LSQregression" and the main program "LSQAdvertising". Compiling it using the following gfortran command works:

gfortran ../LSQregression.f90 LinearAdvertising.f90 -llapack -o LinAd

However, I'd like to be able to turn my module into a .o file and link it with whatever program I may need instead of compiling again every time. So I tried to do that:

gfortran -c ../LSQregression.f90

And then link it with my program file like that:

gfortran ../LSQregression.o LinearAdvertising.f90 -llapack -o LinAd

I also tried also turning the program into a .o file. Neither works, they both return the following error:

/usr/bin/ld: /tmp/ccf7T1aj.o: in function `MAIN__':
LinearAdvertising.f90:(.text+0x1f8b): undefined reference to `__lsqregression_MOD_lsqestimate_simple'
collect2: error: ld returned 1 exit status

It refers to the following function in the module that is being called here inside the program:

print *, LSQestimate(test,LSQbeta(inputs,sales,(/1,2/)) )

The function itself is defined as part of an interface:

interface LSQestimate
     procedure LSQestimate_simple, LSQestimate_using
  end interface LSQestimate

 real(8) function LSQestimate_simple(X, beta)
    implicit none
    real(8), dimension(:,:) :: X, beta
    real(8)                 :: boundary, Y
    integer                 :: i, Xlen, betalen

    Xlen    = size(X, 1)
    betalen = size(beta, 1)

    if (Xlen + 1 .ne. betalen) stop "incompatible beta and X"

    Y = beta(1,1)

    do i = 1, Xlen
       Y = Y + beta(i+1, 1)*X(i,1)
    end do

    LSQestimate_simple = Y
    
  end function LSQestimate_simple

It's very odd because I've done the same thing with another function and it seems to work fine, and the problem only happens when I turn the module into a .o file first, and goes away if I try to directly compile the .f90 file... I can't figure out why one works and the other doesn't.

EDIT: Someone told me to do nm ../LSQregression.o | grep -i regression . I have no idea what that does but I did it so here are the results if it helps at all:

0000000000002768 T __lsqregression_MOD_inv
0000000000000b85 T __lsqregression_MOD_lsqbeta_simple
000000000000035c T __lsqregression_MOD_lsqbeta_using
0000000000000000 T __lsqregression_MOD_lsqdecision

Oddly enough the name of the function in question doesn't even appear here.

EDIT 2: Decided to post the entire code of the module:

module LSQregression
  implicit none

  public  :: LSQbeta, LSQestimate

  interface LSQbeta
     procedure LSQbeta_simple, LSQbeta_using
  end interface LSQbeta

  interface LSQestimate
     procedure LSQestimate_simple, LSQestimate_using
  end interface LSQestimate
  
  
  
  
contains
  
  function inv(A) result(Ainv)
    implicit none
    real(8), dimension(:,:), intent(in)     :: A
    real(8), dimension(size(A,1),size(A,2)) :: Ainv

    real(8), dimension(size(A,1)) :: work  ! work array for LAPACK
    integer, dimension(size(A,1)) :: ipiv   ! pivot indices
    integer :: n, info

    ! External procedures defined in LAPACK
    external DGETRF
    external DGETRI

    ! Store A in Ainv to prevent it from being overwritten by LAPACK
    Ainv = A
    n = size(A,1)

    ! DGETRF computes an LU factorization of a general M-by-N matrix A
    ! using partial pivoting with row interchanges.
    call DGETRF(n, n, Ainv, n, ipiv, info)

    if (info /= 0) then
       stop 'Matrix is numerically singular!'
    end if

    ! DGETRI computes the inverse of a matrix using the LU factorization
    ! computed by DGETRF.
    call DGETRI(n, Ainv, n, ipiv, work, n, info)
    
    if (info /= 0) then
       stop 'Matrix inversion failed!'
    end if
  end function inv
  
  !----------------------------------------------------------------------
  
  function LSQbeta_simple(Xold, Y) result(beta)
    real(8), dimension(:,:)                          :: Xold, Y
    real(8), dimension(size(Xold,1), size(Xold,2)+1) :: X
    real(8), dimension(:,:), allocatable             :: beta, XTX, IXTX, pinv
    integer                                          :: rowsX, colsX, rowsY, colsY,i


    rowsX = size(X(:,1))
    colsX = size(X(1,:))
    rowsY = size(Y(:,1))
    colsY = size(Y(1,:))

    if (colsY .ne. 1)     stop 'Inappropriate y'
    if (rowsY .ne. rowsX) stop "Y and X rows don't match"
    
    !---X-ify-----------
    X(:,1) = 1.0     !includes 1 in the first column
    
    do i = 2, colsX
       X(:,i) = Xold(:,i-1)
    end do
    !--------------------

   
    allocate(XTX(colsX,colsX))
    allocate(IXTX(colsX,colsX))
    allocate(pinv(colsX,rowsY))
    allocate(beta(colsX,1))

    XTX   = matmul(transpose(X),X)
    IXTX  = inv(XTX)
    pinv  = matmul(IXTX, transpose(X))
    beta  = matmul(pinv, Y)

    deallocate(pinv)
    deallocate(XTX)
    deallocate(IXTX)

    return
    
    deallocate(beta)
    
  end function LSQbeta_simple
  !--------------------------------------------
  
  function LSQbeta_using(Xold, Y, indexes) result(beta)
    implicit none
    real(8), dimension(:,:)                        :: Xold, Y
    integer, dimension(:)                          :: indexes
    real(8), dimension(size(indexes)+1,1)          :: beta
    real(8), dimension(size(Xold,1),size(indexes)) :: X
    integer                                        :: indLen,i

    indLen = size(indexes) 
    
    do i = 1, indLen
       X(:,i) = Xold(:,indexes(i))
    end do

    beta = LSQbeta_simple(X,Y)
    
  end function LSQbeta_using

  real(8) function LSQestimate_simple(X, beta)
    implicit none
    real(8), dimension(:,:) :: X, beta
    real(8)                 :: boundary, Y
    integer                 :: i, Xlen, betalen

    Xlen    = size(X, 1)
    betalen = size(beta, 1)

    if (Xlen + 1 .ne. betalen) stop "incompatible beta and X"

    Y = beta(1,1)

    do i = 1, Xlen
       Y = Y + beta(i+1, 1)*X(i,1)
    end do

    LSQestimate_simple = Y
    
  end function LSQestimate_simple

  real(8) function LSQestimate_using()
    LSQestimate_using = 1.0D0
  end function LSQestimate_using
  
  

  logical function LSQdecision(X, beta, boundary)
    implicit none
    real(8), dimension(:,:) :: X, beta
    real(8)                 :: boundary
    
    LSQdecision = LSQestimate(X, beta) > boundary
    
  end function LSQdecision
  


  
end module LSQregression

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文