Skip to content
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

"multiple definition" linking error when compiling netCDF v4.9.0 with GCC 11.3.0 #2419

Open
boegel opened this issue Jun 22, 2022 · 5 comments
Assignees
Labels
area/nczarr nczarr related topics.
Milestone

Comments

@boegel
Copy link

boegel commented Jun 22, 2022

When trying to compile netCDF v4.9.0 with GCC 11.3.0 + binutils 2.38 + CMake 3.23.1 on RHEL 8.4, we're hitting the following linker error:

/software/OpenMPI/4.1.4-GCC-11.3.0/bin/mpicc -fPIC -O2 -ftree-vectorize -march=native -fno-math-errno -fPIC -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -L/software/zstd/1.5.2-GCCcore-11.3.0/lib64 -L/software/zstd/1.5.2-GCCcore-11.3.0/lib -L/software/Szip/2.1.1-GCCcore-11.3.0/lib64 -L/software/Szip/2.1.1-GCCcore-11.3.0/lib -L/software/cURL/7.83.0-GCCcore-11.3.0/lib64 -L/software/cURL/7.83.0-GCCcore-11.3.0/lib -L/software/HDF5/1.13.1-gompi-2022.05/lib64 -L/software/HDF5/1.13.1-gompi-2022.05/lib -L/software/GCCcore/11.3.0/lib64 -L/software/GCCcore/11.3.0/lib -shared  -o lib__nczhdf5filters.so CMakeFiles/nczhdf5filters.dir/NCZhdf5filters.c.o  /software/HDF5/1.13.1-gompi-2022.05/lib/libhdf5_hl.so /software/HDF5/1.13.1-gompi-2022.05/lib/libhdf5.so -lm /software/zlib/1.2.12-GCCcore-11.3.0/lib/libz.so /software/zstd/1.5.2-GCCcore-11.3.0/lib/libzstd.so /software/bzip2/1.0.8-GCCcore-11.3.0/lib/libbz2.so /software/Szip/2.1.1-GCCcore-11.3.0/lib/libsz.so /software/cURL/7.83.0-GCCcore-11.3.0/lib/libcurl.so /software/libxml2/2.9.13-GCCcore-11.3.0/lib/libxml2.so ../liblib/libnetcdf.a -ldl /software/HDF5/1.13.1-gompi-2022.05/lib/libhdf5_hl.so /software/HDF5/1.13.1-gompi-2022.05/lib/libhdf5.so -lm /software/zlib/1.2.12-GCCcore-11.3.0/lib/libz.so /software/zstd/1.5.2-GCCcore-11.3.0/lib/libzstd.so /software/bzip2/1.0.8-GCCcore-11.3.0/lib/libbz2.so /software/Szip/2.1.1-GCCcore-11.3.0/lib/libsz.so /software/cURL/7.83.0-GCCcore-11.3.0/lib/libcurl.so /software/libxml2/2.9.13-GCCcore-11.3.0/lib/libxml2.so
/software/binutils/2.38-GCCcore-11.3.0/bin/ld: error: ../liblib/libnetcdf.a(ncjson.c.o): multiple definition of 'NCJreclaim'
/software/binutils/2.38-GCCcore-11.3.0/bin/ld: CMakeFiles/nczhdf5filters.dir/NCZhdf5filters.c.o: previous definition here
/software/binutils/2.38-GCCcore-11.3.0/bin/ld: error: ../liblib/libnetcdf.a(ncjson.c.o): multiple definition of 'NCJnew'
/software/binutils/2.38-GCCcore-11.3.0/bin/ld: CMakeFiles/nczhdf5filters.dir/NCZhdf5filters.c.o: previous definition here
/software/binutils/2.38-GCCcore-11.3.0/bin/ld: error: ../liblib/libnetcdf.a(ncjson.c.o): multiple definition of 'NCJnewstringn'
/software/binutils/2.38-GCCcore-11.3.0/bin/ld: CMakeFiles/nczhdf5filters.dir/NCZhdf5filters.c.o: previous definition here
/software/binutils/2.38-GCCcore-11.3.0/bin/ld: error: ../liblib/libnetcdf.a(ncjson.c.o): multiple definition of 'NCJnewstring'
/software/binutils/2.38-GCCcore-11.3.0/bin/ld: CMakeFiles/nczhdf5filters.dir/NCZhdf5filters.c.o: previous definition here
/software/binutils/2.38-GCCcore-11.3.0/bin/ld: error: ../liblib/libnetcdf.a(ncjson.c.o): multiple definition of 'NCJparse'
/software/binutils/2.38-GCCcore-11.3.0/bin/ld: CMakeFiles/nczhdf5filters.dir/NCZhdf5filters.c.o: previous definition here
/software/binutils/2.38-GCCcore-11.3.0/bin/ld: error: ../liblib/libnetcdf.a(ncjson.c.o): multiple definition of 'NCJdictget'
/software/binutils/2.38-GCCcore-11.3.0/bin/ld: CMakeFiles/nczhdf5filters.dir/NCZhdf5filters.c.o: previous definition here
/software/binutils/2.38-GCCcore-11.3.0/bin/ld: error: ../liblib/libnetcdf.a(ncjson.c.o): multiple definition of 'NCJcvt'
/software/binutils/2.38-GCCcore-11.3.0/bin/ld: CMakeFiles/nczhdf5filters.dir/NCZhdf5filters.c.o: previous definition here
collect2: error: ld returned 1 exit status
make[2]: *** [plugins/CMakeFiles/nczhdf5filters.dir/build.make:119: plugins/lib__nczhdf5filters.so] Error 1

To reproduce:

cmake -DCMAKE_INSTALL_PREFIX=/software/netCDF/4.9.0-gompi-2022.05 -DCMAKE_BUILD_TYPE=Release 
  -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_C_COMPILER='mpicc'
  -DCMAKE_C_FLAGS='-O2 -ftree-vectorize -march=native -fno-math-errno -fPIC' -DCMAKE_CXX_COMPILER='mpicxx' 
  -DCMAKE_CXX_FLAGS='-O2 -ftree-vectorize -march=native -fno-math-errno -fPIC'
  -DCMAKE_Fortran_COMPILER='mpifort' -DCMAKE_Fortran_FLAGS='-O2 -ftree-vectorize -march=native -fno-math-errno -fPIC'
  -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_FIND_USE_PACKAGE_REGISTRY=FALSE -DBUILD_SHARED_LIBS=OFF 
  -DCURL_INCLUDE_DIR=/software/cURL/7.83.0-GCCcore-11.3.0/include   -DCURL_LIBRARY=/software/cURL/7.83.0-GCCcore-11.3.0/lib/libcurl.so
  -DHDF5_INCLUDE_DIR=/software/HDF5/1.13.1-gompi-2022.05/include   -DUSE_HDF5=ON
  -DHDF5_C_LIBRARY=/software/HDF5/1.13.1-gompi-2022.05/lib/libhdf5.so   -DHDF5_HL_LIBRARY=/software/HDF5/1.13.1-gompi-2022.05/lib/libhdf5_hl.so
  -DSZIP_INCLUDE_DIR=/software/Szip/2.1.1-GCCcore-11.3.0/include   -DSZIP_LIBRARY=/software/Szip/2.1.1-GCCcore-11.3.0/lib/libsz.so
  -DZLIB_INCLUDE_DIR=/software/zlib/1.2.12-GCCcore-11.3.0/include   -DZLIB_LIBRARY=/software/zlib/1.2.12-GCCcore-11.3.0/lib/libz.so
  /tmp/easybuild_build/netCDF/4.9.0/gompi-2022.05/netcdf-c-4.9.0/

make

We are not seeing this problem with netCDF v4.8.1 using the exact same compiler toolchain (GCC 11.3.0 + binutils 2.38) and CMake (3.23.1) on RHEL 8.4...

@zao
Copy link

zao commented Jun 22, 2022

There seems to be two distinct implementations of the JSON bits in the codebase, one in pair of separate libdispatch/ncjson.c and include/ncjson.h; and one mechanically combined into a header with definitions directly in the header without any inlining at all in include/netcdf_json.h.

The purpose of netcdf_json.h seems to be to have a decoupled implementation of the JSON functionality for use in plugins, while the separated core bits goes into libdispatch which ends up in the netcdf library.

Here nczhdf5filters and nczstdfilters plugins include the standalone implementation header, but they also link netcdf which due to how static linking works is treating the symbols from the static netcdf library with the same importance as any other object file in the plugin.

This linking problem is masked when linking against shared libraries as the single-header implementation in the object files is preferred over the implementation in the shared library. Amusingly enough, depending on executable/library load order, the shared library may end up using a symbol defined in the executable or a previously loaded library rather than its own symbol.

One workaround that seems to do the trick for my non-netcdf test case is to mark the function declarations and definitions in the single-file implementation netcdf_json.h as static, giving them internal linkage to each source file it's included in.

@DennisHeimbigner
Copy link
Collaborator

Your json analysis is correct. I wanted it to be possible to build
the nczarr adjunct wrapper code so that it did not need access to
libnetcdf. Also, I wanted to keep only one core json code base
so I would not have to apply fixes twice.
Not surprisingly, I tried to be too clever by half, and it does not work right.
Using "static" works, but make the construction of the netcdf_json.h file
more difficult. I suppose I could just give up and require that nczarr
wrappers must use libnetcdf.
Let me think about this a bit.

@WardF WardF self-assigned this Jun 22, 2022
@WardF WardF added the area/nczarr nczarr related topics. label Jun 22, 2022
@WardF WardF added this to the 4.9.1 milestone Jun 22, 2022
@boegel
Copy link
Author

boegel commented Jun 23, 2022

We puzzled together a patch that allows us to bypass this problem, by adding static in netcdf_json.h; see https://github.com/easybuilders/easybuild-easyconfigs/blob/develop/easybuild/easyconfigs/n/netCDF/netCDF-4.9.0_fix-linking-errors.patch

@DennisHeimbigner
Copy link
Collaborator

Yes,I am following a similar path by using a macro that gets
redefined depending on the context.
Hope to have a PR up soon.

DennisHeimbigner added a commit to DennisHeimbigner/netcdf-c that referenced this issue Jul 6, 2022
re: Issue Unidata#2419

There are effectively two json subsystems in netcdf-c.
1. ncjson.[ch] in libnetcdf
2. netcdf_json.h for use by plugins so they can be built without need
   for libnetcdf.

The netcdf_json.h file is constructed from the concatenation of
ncjson.h plus ncjson.c. It turned out that in doing this, I was
leaving some symbols externally visible so that if, for some
reason, a plugin was built and needed libnetcdf, then symbol
conflicts arose.

The solution is to prefix the declarations in ncjson.[ch] with a
macro (OPTSTATIC) that can be resolved to either nothing or to
"static". Then in netcdf_json.h, it resolves to "static" and
prevents the symbol conflicts.

Note that netcdf_json.h is constructed once in
netcdf-c/include/Makefile.am with the rule named
"makepluginjson". This means that it is included in the
distribution. However, this also means that if ncjson.[ch] is
changed, then it is necessary to invoke makepluginjson
explicitly to rebuild netcdf_json.h
@DennisHeimbigner
Copy link
Collaborator

See PR #2448

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/nczarr nczarr related topics.
Projects
None yet
Development

No branches or pull requests

4 participants