Skip to content

Use LFortran to compile eCLM #98

@Leon-Degel-Koehn

Description

@Leon-Degel-Koehn

LFortran Support for eCLM

This issue tracks the investigation of using LFortran to compile eCLM.
This was investigated as part of the Research Software Engineering Winter of Code.
It provides guidance for future developers who may want to attempt migrating eCLM to LFortran and documents the current limitations and workarounds discovered during the investigation.

Current Status

  • eCLM cannot currently be compiled using LFortran.

  • Critical limitations include:

    • No official OpenMPI / MPI support in LFortran.
    • No support for Fortran namelists.
  • Minor issues also exist, including:

    • Some unsupported statements such as call abort (upstream fix merged but not in conda release yet as of writing this report: #9595).
    • Some unsupported statements such as call flush_ would still have to be implemented upstream.
    • Compiler crashes due to unexpected memory errors even after fixes are applied.
    • As the compiler becomes capable of progressing futher into the project during compilation, more issues may be discovered.

Despite these limitations, it has become clear that CMake infrastructure changes for LFortran would be minimal once the compiler matures.
LFortran should eventually be close to a drop-in replacement for gfortran.

MPI Workaround

To partially address MPI-related compilation issues:

  • An extended MPI wrapper is available for LFortran: fortran_mpi.
  • This provides implementations of MPI functions that LFortran currently lacks.
  • Some non-trivial MPI interfaces remain to be implemented. (See logical BCast for example)
  • If LFortran gains official MPI support, this wrapper may no longer be required.

Namelist Support

  • LFortran currently does not support Fortran namelists.

  • Full compilation is blocked until namelist support is implemented.

  • Once available, further issues may be revealed during testing and compilation.

Compilation of External Projects

  • eCLM depends on several external projects, which require careful handling:

    • Some projects (e.g., GPTL) break if the --cpp flag is enabled.
    • Other projects require --cpp for compilation.
    • Solution: Configure --cpp on a per-external-project basis in CMake.
  • Minor fixes required for unsupported statements or functions in these external projects. (Diff is provided)

CMake Integration

  • Minimal changes are required to integrate LFortran into eCLM’s CMake workflow. (Documented in diff)
  • LFortran is already recognized by CMake as a compiler.
  • Once LFortran is functional, only a new conditional branch is needed alongside the existing gfortran and Intel compiler options.
  • No additional compiler flags are needed other than --cpp where required.

Summary of Findings

Issue Status / Workaround
MPI support Partial workaround via fortran_mpi
Namelist support Not supported; blocks compilation
External projects & --cpp Needs per-project CMake configuration
Compiler crashes Still present after fixes; blocks compilation

Recommendations for Future Work

  1. Monitor LFortran releases for:
    • Namelist support
    • Stable MPI integration
  2. Test compilation of external projects individually to handle --cpp inconsistencies.
  3. Once LFortran reaches a usable state, update CMake with a branch for LFortran and test full eCLM compilation.

To execute compilation to the stage where we got it to work so far, apply the provided diff and
run the script.

Usage

Applying the following diff enables partial compilation using the script below.

diff --git a/cmake/SetBuildOptions.cmake b/cmake/SetBuildOptions.cmake
index c6b9323..e70ec04 100644
--- a/cmake/SetBuildOptions.cmake
+++ b/cmake/SetBuildOptions.cmake
@@ -12,12 +12,12 @@ endif()
 
 # Check if MPI is present. This should succeed if
 # the compilers were set to mpifort and mpicc.
-find_package(MPI REQUIRED)
 
 # Set default compiler = GNU if none was specified. 
 if(NOT COMPILER)
     set(COMPILER "${CMAKE_Fortran_COMPILER_ID}" CACHE STRING "Choose compiler toolchain." FORCE)
     set_property(CACHE COMPILER PROPERTY STRINGS "GNU" "Intel")
+    set_property(CACHE COMPILER PROPERTY STRINGS "GNU" "Intel" "LFortran")
 endif()
 
 # Set compiler specific flags.
@@ -44,6 +44,11 @@ elseif(COMPILER STREQUAL "Intel" OR COMPILER STREQUAL "IntelLLVM")
       set(CMAKE_Fortran_FLAGS_DEBUG "-O0 -g -fpe0 -check all")
     endif()
     set(CMAKE_Fortran_FLAGS_RELEASE "-O2 -debug minimal")
+elseif(COMPILER STREQUAL "LFortran")
+    add_compile_definitions(CPRLFORTRAN)
+    # There is an issue, some modules require --cpp as a flag in their compilation
+    # some flat out break, if we put --cpp
+    # set(CMAKE_Fortran_FLAGS "--cpp")
 else()
     message(FATAL_ERROR "COMPILER='${COMPILER}' is not supported.")
 endif()
diff --git a/src/externals/gptl/CMakeLists.txt b/src/externals/gptl/CMakeLists.txt
index f882ded..f9dbd7c 100644
--- a/src/externals/gptl/CMakeLists.txt
+++ b/src/externals/gptl/CMakeLists.txt
@@ -9,7 +9,7 @@ SET(TIMING_INCLUDE_DIRS   ${CMAKE_CURRENT_SOURCE_DIR}
     CACHE STRING "")
 INCLUDE_DIRECTORIES(${TIMING_INCLUDE_DIRS})
 
-ADD_DEFINITIONS(-DINCLUDE_CMAKE_FCI -DHAVE_MPI)
+ADD_DEFINITIONS(-DINCLUDE_CMAKE_FCI)
 
 SET(SRCS_C  GPTLget_memusage.c
             GPTLprint_memusage.c
diff --git a/src/externals/gptl/Makefile b/src/externals/gptl/Makefile
index 69372ae..8ea75c0 100644
--- a/src/externals/gptl/Makefile
+++ b/src/externals/gptl/Makefile
@@ -32,7 +32,6 @@ ifeq ($(strip $(MPILIB)), mpi-serial)
 else
   CC := $(MPICC)
   FC := $(MPIFC)
-  CPPDEFS += -DHAVE_MPI
 endif
 ifdef CPRE
   FPPDEFS := $(patsubst -D%,$(CPRE)%,$(CPPDEFS))
diff --git a/src/externals/gptl/perf_utils.F90 b/src/externals/gptl/perf_utils.F90
index 3aa29e8..d0430de 100644
--- a/src/externals/gptl/perf_utils.F90
+++ b/src/externals/gptl/perf_utils.F90
@@ -164,9 +164,6 @@ SUBROUTINE shr_sys_flush(unit)
    call flush(unit)
 #endif
 #endif
-#if (defined AIX)
-   call flush_(unit)
-#endif
 
 END SUBROUTINE shr_sys_flush

And the corresponding compilation script

#!/bin/bash
# Run from root directory of eCLM.
# The build is expected to fail.
# If you see it fail at the `call abort` line, you may build a
# newer version of lfortran from source which should fix that.

BUILD_DIR="bld"
INSTALL_DIR="install"
CC="gcc"
MPICC="gcc"
FC="lfortran"
MPIFC="lfortran"

# Set this to the path where mpi.h is located
# if you have installed open-mpi via conda:
MPI_C_INCLUDE_PATH="$CONDA_PREFIX/include"
# Otherwise, an installation might be at
# MPI_C_INCLUDE_PATH="/usr/lib/x86_64-linux-gnu/openmpi/include"


# Set this to the path to where you have cloned the fortran_mpi repo
# For example:
MPI_FORTRAN="../fortran_mpi"
 
# For lfortran mpi mock
$CC -I$MPI_C_INCLUDE_PATH -c $MPI_FORTRAN/src/mpi_constants.c
$FC --cpp -c $MPI_FORTRAN/src/mpi_c_bindings.f90
$FC --cpp -c $MPI_FORTRAN/src/mpi.f90
cp mpi* src/externals/gptl
cp mpi* src/externals/pio1

# Cleanup
rm -rf $BUILD_DIR
rm -rf $INSTALL_DIR

cmake -S src -B $BUILD_DIR                                \
	-DCMAKE_INSTALL_PREFIX=$INSTALL_DIR                 \
	-DCMAKE_C_COMPILER=$CC                              \
	-DCMAKE_Fortran_COMPILER=$FC \
	-DCOMPILER=LFortran

cmake --build $BUILD_DIR
cmake --install $BUILD_DIR

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    build-issueBuild errors and other compiler-related issues.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions