Mohammed Sayyari
Mohammed Sayyari

Reputation: 43

Fortran undefined reference when library is loaded and contains the sought after symbol

I have modules compiled on their own and then linked in an executible to form a program. I am calling symbols from the cgns library, but some of them throw an undefined reference error, even though the symbol exists in the library.

This code seems to compile fine in older gcc ~4 to 8 versions, but not my current version 13. I am also using the mpif90 compiler from mpich.

So I recreated the problem with a dummy code. Here is my setup with a dummy code that recreates the issue exactly:

The reference in question is cg_nbases_f, so doing

me@pc:dir$ objdump -T $MPI_LIB/libcgns.so | grep cg_nbases_t
00000000000a44b0 g    DF .text  0000000000000055  Base        cg_nbases_f

The dummy code consists of two files, a module cgnsreading.f90 and a program cgnsread.f90

cgnsreading.f90:

module cgnsreading
    implicit none

    private

    public talk_to_cgns

contains

    subroutine error_check()
        print *, 'hi I am the bane of arthropods'
    end subroutine error_check

    subroutine talk_To_cgns()
        character(100) :: errmsg
        integer :: i = 1
        integer :: nbases = 1
        integer :: ierr

        call cg_get_error_f(errmsg)
        print *, errmsg ! Should print that there is no error
        call error_check() ! Should print its guts

        call cg_nbases_f(i,nbases,ierr) ! Throws undefined reference error

    end subroutine talk_To_cgns

end module cgnsreading

cgnsread.f90:

program cgnsread
    use cgnsreading
    implicit none

    call talk_to_cgns()
    
end program cgnsread

Compiling it and linking in the following way produces the error:

me@pc:dir$ mpif90 cgnsreading.f90 -c
me@pc:dir$ mpif90 cgnsread.f90 -c
me@pc:dir$ mpif90 cgnsreading.o cgnsread.o -lcgns -o cgnsread
/usr/bin/ld: cgnsreading.o: in function `__cgnsreading_MOD_talk_to_cgns':
cgnsreading.f90:(.text+0x95): undefined reference to `cg_nbases_f_'
collect2: error: ld returned 1 exit status

My thought was that there were either some issues related to the module having private subroutines, but that is ruled out because the error occures by calling the public subroutine.

I was also suspecting that it's due to the compiler ignoring the linking flag (flags order), but when that happens, cg_get_error_f throws the same error. Hence, why I tested that as well.

I expected that the references would only be available in the devel versions of the cgns library, but that doesn't seem to be the case because I am using the devel version.

There was a suspicion that a different library was installed somewhere else, and indeed there is, but it also contains the missing reference.

I do not know if this is a specific problem to cgns or its installation, but I haven't tested this with something else.

Why would a library provide a symbol but not the other, even though both exist in the same library.

The same error occures on another pc with the same setup as mentioned above. So the problem can be replicated.

Upvotes: 1

Views: 134

Answers (1)

datawookie
datawookie

Reputation: 6554

Check the symbol names defined in the library:

nm -D /usr/lib/x86_64-linux-gnu/libcgns.so | grep nbases
0000000000047070 T cg_nbases
0000000000084900 T cg_nbases_f

The symbol that we are looking for is there, but the mpif90 compiler has appended an underscore to the name. In principle this is to prevent clashes between Fortran and C names.

Update cgnsreading.f90 and add use cgns:

module cgnsreading
    use cgns
    implicit none

    private

    public talk_to_cgns

contains

    subroutine error_check()
        print *, 'hi I am the bane of arthropods'
    end subroutine error_check

    subroutine talk_to_cgns()
        character(100) :: errmsg
        integer :: i = 1
        integer :: nbases = 1
        integer :: ierr

        call cg_get_error_f(errmsg)
        print *, errmsg ! Should print that there is no error
        call error_check() ! Should print its guts

        call cg_nbases_f(i,nbases,ierr) ! Throws undefined reference error

    end subroutine talk_to_cgns

end module cgnsreading

When you compile that you'll need to specify the include path for cgns.mod, which should be located at /usr/include/cgns.mod.

mpif90 cgnsreading.f90 -c -I/usr/include/
mpif90 cgnsread.f90 -c
mpif90 cgnsreading.o cgnsread.o -lcgns -o cgnsread

enter image description here

I don't have a Fedora 39 system but I can replicate with Docker. Follow these steps to get it set up.

FROM fedora:39

RUN dnf install -y wget gcc-gfortran hdf5-devel cgnslib openmpi openmpi-devel

RUN wget https://dl.fedoraproject.org/pub/fedora/linux/releases/39/Everything/x86_64/os/Packages/c/cgnslib-devel-4.4.0-2.fc39.x86_64.rpm && \
    rpm -i cgnslib-devel-4.4.0-2.fc39.x86_64.rpm && \
    rm -f cgnslib-devel-4.4.0-2.fc39.x86_64.rpm

ENV PATH=$PATH:/usr/lib64/openmpi/bin/

COPY *.f90 .

RUN mpif90 cgnsreading.f90 -c -I/usr/lib64/gfortran/modules/
RUN mpif90 cgnsread.f90 -c
RUN mpif90 cgnsreading.o cgnsread.o -lcgns -o cgnsread

Upvotes: 2

Related Questions