-
Notifications
You must be signed in to change notification settings - Fork 14
Description
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.
- Some unsupported statements such as
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
--cppflag is enabled. - Other projects require
--cppfor compilation. - Solution: Configure
--cppon a per-external-project basis in CMake.
- Some projects (e.g., GPTL) break if the
-
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
gfortranandIntelcompiler options. - No additional compiler flags are needed other than
--cppwhere 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
- Monitor LFortran releases for:
- Namelist support
- Stable MPI integration
- Test compilation of external projects individually to handle
--cppinconsistencies. - 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_flushAnd 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