External libraries#
Linking to external libraries is a nightmare using autotools, and this has been a major deterrent for Octopus to be able to make use of external packages. This is greatly simplified in CMake, and we can more easily develop integrations with any libraries
Let’s take netCDF as an example. Things get a lot more complicated for other packages on the Autotools side, while on the CMake side, things remain the same.
/m4/netcdf.m4
AC_DEFUN([ACX_NETCDF], [
acx_netcdf_ok=no
dnl Check if the library was given in the command line
AC_ARG_WITH(netcdf-prefix, [AS_HELP_STRING([--with-netcdf-prefix=DIR], [Directory where netcdf was installed.])])
case $with_netcdf_prefix in
no ) acx_netcdf_ok=disabled ;;
"") if test "x$FCFLAGS_NETCDF" == x; then
FCFLAGS_NETCDF="$ax_cv_f90_modflag/usr/include"
fi;;
*) LIBS_NETCDF="-L$with_netcdf_prefix/lib"; FCFLAGS_NETCDF="$ax_cv_f90_modflag$with_netcdf_prefix/include" ;;
esac
AC_ARG_WITH(netcdf-include, [AS_HELP_STRING([--with-netcdf-include=DIR], [Directory where netcdf Fortran headers were installed.])])
case $with_netcdf_include in
"") ;;
*) FCFLAGS_NETCDF="$ax_cv_f90_modflag$with_netcdf_include" ;;
esac
dnl Backup LIBS and FCFLAGS
acx_netcdf_save_LIBS="$LIBS"
acx_netcdf_save_FCFLAGS="$FCFLAGS"
dnl The tests
AC_MSG_CHECKING([for netcdf])
if test "$acx_netcdf_ok" != disabled; then
netcdf_fcflags="$FCFLAGS_NETCDF"
FCFLAGS="$netcdf_fcflags $acx_netcdf_save_FCFLAGS"
for netcdf_libsl in "" -lnetcdf "-lnetcdff -lnetcdf"; do
netcdf_libs="$LIBS_NETCDF $netcdf_libsl"
LIBS="$netcdf_libs $acx_netcdf_save_LIBS"
AC_LINK_IFELSE(AC_LANG_PROGRAM([],[
use netcdf
integer :: ncid
integer :: status
status = nf90_close(ncid)
]), [acx_netcdf_ok=yes; FCFLAGS_NETCDF="$netcdf_fcflags"; LIBS_NETCDF="$netcdf_libs"], [])
if test "$acx_netcdf_ok" == yes; then
LIBS_NETCDF=$netcdf_libs
break
fi
done
fi
AC_MSG_RESULT([$acx_netcdf_ok ($FCFLAGS_NETCDF $LIBS_NETCDF)])
dnl Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$acx_netcdf_ok" = xyes; then
AC_DEFINE(HAVE_NETCDF,1,[Defined if you have NETCDF library.])
else
AC_MSG_WARN([Could not find NetCDF library.
*** Will compile without NetCDF and ETSF I/O support])
FCFLAGS_NETCDF=""
LIBS_NETCDF=""
fi
AC_SUBST(FCFLAGS_NETCDF)
AC_SUBST(LIBS_NETCDF)
FCFLAGS="$acx_netcdf_save_FCFLAGS"
LIBS="$acx_netcdf_save_LIBS"
])dnl ACX_NETCDF
In the CMakeLists.txt files you will find:
option(OCTOPUS_netCDF "Octopus: Build with netCDF support" OFF)
...
if (OCTOPUS_netCDF)
find_package(netCDF-Fortran REQUIRED MODULE)
set(HAVE_NETCDF 1)
endif ()
...
if (TARGET netCDF::Fortran)
target_link_libraries(Octopus_lib PRIVATE netCDF::Fortran)
endif ()
This takes advantage of the built-in support for CMake packages. But sometimes the package might not be correctly installed and this support might be missing.
Not to worry, this was already considered, see /cmake/FindnetCDF-Fortran.cmake
include(Octopus)
Octopus_FindPackage(${CMAKE_FIND_PACKAGE_NAME}
# Try to import via native CMake support
NAMES netCDF-Fortran
# Otherwise use `pkg-config` to find the necessary files
PKG_MODULE_NAMES netcdf-fortran)
# Create appropriate aliases
if (${CMAKE_FIND_PACKAGE_NAME}_PKGCONFIG)
add_library(netCDF::Fortran ALIAS PkgConfig::${CMAKE_FIND_PACKAGE_NAME})
elseif (NOT TARGET netCDF::Fortran)
if (TARGET netCDF::netcdff)
add_library(netCDF::Fortran ALIAS netCDF::netcdff)
else ()
add_library(netCDF::Fortran ALIAS netcdff)
endif ()
endif ()
One aspect that is only present in CMake is the ability to link to git
repositories directly so that you can more easily prototype. For example,
see the Spglib integration.
FetchContent_Declare(Spglib
GIT_REPOSITORY https://github.com/spglib/spglib
GIT_TAG v2.1.0-rc2
FIND_PACKAGE_ARGS MODULE REQUIRED COMPONENTS Fortran
)
FetchContent_MakeAvailable(Spglib)
...
target_link_libraries(Octopus_lib PRIVATE Spglib::Fortran)