#!/usr/bin/env sh

# Copyright (c) 2012-2025. The SimGrid Team. All rights reserved.

# This program is free software; you can redistribute it and/or modify it
# under the terms of the license (GNU LGPL) which comes with this package.

SIMGRID_VERSION="SimGrid version 4.0"
SIMGRID_GITHASH="none, release version"

REAL_FORTRAN_COMPILER=/usr/bin/gfortran

#!/usr/bin/env sh

# Copyright (c) 2013-2025. The SimGrid Team. All rights reserved.

# This program is free software; you can redistribute it and/or modify it
# under the terms of the license (GNU LGPL) which comes with this package.

SAVEIFS="$IFS"
LISTSEP="$(printf '\b')"

# Create a temporary file, with its name of the form $1_XXX$2, where XXX is replaced by an unique string.
# $1: prefix, $2: suffix
mymktemp () {
    local_tmp=$(mktemp --suffix="$2" "$1_XXXXXXXXXX" 2> /dev/null)
    if [ -z "$local_tmp" ]; then
        # mktemp failed (unsupported --suffix ?), try unsafe mode
        local_tmp=$(mktemp -u "$1_XXXXXXXXXX" 2> /dev/null)
        if [ -z "$local_tmp" ]; then
            # mktemp failed again (doesn't exist ?), try very unsafe mode
            if [ -z "${mymktemp_seq}" ]; then
                mymktemp_seq=$(date +%d%H%M%S)
            fi
            local_tmp="$1_$$x${mymktemp_seq}"
            mymktemp_seq=$((mymktemp_seq + 1))
        fi
        local_tmp="${local_tmp}$2"
        # create temp file, and exit if it existed before
        sh -C -c "true > \"${local_tmp}\"" || exit 1
    fi
    echo "${local_tmp}"
}

# Add a word to the end of a list (words separated by LISTSEP)
# $1: list, $2...: words to add
list_add () {
    local_list="$1"
    shift
    if [ $# -gt 0 ]; then
        eval local_content=\"\${$local_list}\"
        IFS="$LISTSEP"
        local_newcontent="$*"
        IFS="$SAVEIFS"
        if [ -z "$local_content" ]; then
            local_content="$local_newcontent"
        else
            local_content="$local_content${LISTSEP}$local_newcontent"
        fi
        eval $local_list=\"\${local_content}\"
    fi
}

# Like list_add, but only if first word to add ($2) is not empty
list_add_not_empty () {
    if [ -n "$2" ]; then
        list_add "$@"
    fi
}

# Set contents of a list (words separated by LISTSEP)
# $1: list, $2...: words to set
list_set () {
    eval $1=""
    list_add "$@"
}

# Get the content of a list: positional parameters ($1, $2, ...) are set to the content of the list
# $1: list
# usage:  eval $(list_get list)
list_get () {
    printf 'IFS="'\$'LISTSEP"; eval set -- \$%s; IFS="'\$'SAVEIFS"\n' "$1"
}


list_set INCLUDEARGS "-I/usr/include" "-I/usr/include/smpi"
list_set CMAKE_LINKARGS "-L/usr/lib/aarch64-linux-gnu"

list_set FFLAGS "-fpic" "-ff2c" "-fno-second-underscore" 
list_set LINKARGS "-lsimgrid" "-lgfortran" "-lm"
if [ "x${SMPI_PRETEND_CC}" = "x" ]; then
   list_add LINKARGS "-shared"
   if [ "x${SMPI_NO_UNDEFINED_CHECK}" = "x" ]; then
     if [ "x" != "x1" ]; then
       list_add LINKARGS "-Wl,-z,defs"
     else
       list_add LINKARGS "-Wl,-undefined,error"
     fi
   fi
else
   echo "Warning: smpiff pretends to be a regular compiler (SMPI_PRETEND_CC is set). Produced binaries will not be usable in SimGrid."
fi
list_set TMPFILES

cleanup () {
    eval $(list_get TMPFILES)
    rm -f "$@"
}
trap 'cleanup' EXIT

filter_and_compile_f77() {
    if [ "x${SMPI_PRETEND_CC}" = "x" ] && [ "x${TMPFILE}" != "x" ]; then
      list_add TMPFILES "${TMPFILE}"
      #replace "program main_name by subroutine user_main (and the end clause as well)"
      if [ "$TRACE_CALL_LOCATION" -gt 0 ]; then
        echo "#include \"/usr/include/smpi/smpi_extended_traces_fortran.h\"" > "${TMPFILE}"
        echo "#line 1 \"${ARG}\"" >> "${TMPFILE}"
      fi
      sed 's/^[[:space:]]\{6\}[[:space:]]*\([eE][nN][dD] \)\{0,1\}[pP][rR][oO][gG][rR][aA][mM][^a-zA-Z0-9]*\([a-zA-Z0-9_]*\)/      \1subroutine user_main /g' "${ARG}" >> "${TMPFILE}"
      SRCFILE="${TMPFILE}"
    else
      SRCFILE="${ARG}"
    fi
    list_add CMDLINE "${SRCFILE}"
}
filter_and_compile_f90() {
    if [ "x${SMPI_PRETEND_CC}" = "x" ] && [ "x${TMPFILE}" != "x" ]; then
      list_add TMPFILES "${TMPFILE}"
      #replace "program main_name by subroutine user_main (and the end clause as well)"
      if [ "$TRACE_CALL_LOCATION" -gt 0 ]; then
        echo "#include \"/usr/include/smpi/smpi_extended_traces_fortran.h\"" > "${TMPFILE}"
        echo "#line 1 \"${ARG}\"" >> "${TMPFILE}"
      fi
      sed 's/^\([[:space:]]*\)\([eE][nN][dD] \)\{0,1\}[pP][rR][oO][gG][rR][aA][mM][^a-zA-Z0-9]*\([a-zA-Z0-9_]*\)/\1\2subroutine user_main /g' "${ARG}" >> "${TMPFILE}"
      SRCFILE="${TMPFILE}"
    else
      SRCFILE="${ARG}"
    fi
    list_add CMDLINE "${SRCFILE}"
}
TRACE_CALL_LOCATION=0
NEEDS_OUTPUT=1

list_set CMDLINE "${REAL_FORTRAN_COMPILER}"
list_add_not_empty CMDLINE "${FFLAGS}"
while [ $# -gt 0 ]; do
    ARG="$1"
    shift
    case "${ARG}" in
        -c)
            CMAKE_LINKARGS=""
            LINKARGS=""
            list_add CMDLINE "-c"
            ;;
        *.f)
            FILENAME=$(basename "${ARG}")
            if [ "$TRACE_CALL_LOCATION" -gt 0 ] || main=$(grep -q -i "program" "${ARG}"); then
              TMPFILE=$(mymktemp "${ARG}" ".f")
            fi
            ORIGFILE="${FILENAME%.f}"
            filter_and_compile_f77
            ;;
        *.F)
            FILENAME=$(basename "${ARG}")
            if [ "$TRACE_CALL_LOCATION" -gt 0 ] || main=$(grep -q -i "program" "${ARG}"); then
              TMPFILE=$(mymktemp "${ARG}" ".F")
            fi
            ORIGFILE="${FILENAME%.F}"
            filter_and_compile_f77
            ;;
        *.f90)
            FILENAME=$(basename "${ARG}")
            if [ "$TRACE_CALL_LOCATION" -gt 0 ] || main=$(grep -q -i "program" "${ARG}"); then
              TMPFILE=$(mymktemp "${ARG}" ".f90")
            fi
            ORIGFILE="${FILENAME%.f90}"
            filter_and_compile_f90
            ;;
        *.F90)
            FILENAME=$(basename "${ARG}")
            if [ "$TRACE_CALL_LOCATION" -gt 0 ] || main=$(grep -q -i "program" "${ARG}"); then
              TMPFILE=$(mymktemp "${ARG}" ".F90")
            fi
            ORIGFILE="${FILENAME%.F90}"
            filter_and_compile_f90
            ;;
        '-version' | '--version')
            printf '%b\n' "$SIMGRID_VERSION"
            exit 0
            ;;
        "-git-version" | "--git-version")
            printf '%b\n' "$SIMGRID_GITHASH"
            exit 0
            ;;
        '-compiler-version' | '--compiler-version')
            ${REAL_FORTRAN_COMPILER} --version
            ;;
        '-trace-call-location')
            TRACE_CALL_LOCATION=1
            # This should be list_add FFLAGS but it's not possible
            # anymore: FFLAGS was already moved into CMDLINE above.
            list_add CMDLINE "-ffixed-line-length-none" "-cpp"
            ;;
        -o)
            list_add CMDLINE "-o$1"
            NEEDS_OUTPUT=0
            shift
            ;;
	'-show'|'-compile-info'|'-link-info')
            # Dry run displaying commands instead of executing them. Useful to cmake
	    show=1
	    ;;
        *)
            list_add CMDLINE "${ARG}"
            ;;
    esac
done

if [ $NEEDS_OUTPUT -ne 0 ]; then
   list_add CMDLINE "-o${ORIGFILE}.o"
fi

list_add_not_empty CMDLINE "${INCLUDEARGS}"
list_add_not_empty CMDLINE "${CMAKE_LINKARGS}"
list_add_not_empty CMDLINE "${LINKARGS}"

eval $(list_get CMDLINE)
if [ "x$VERBOSE" = x1 ] || [ "x$show" = x1 ] ; then
  echo "$@"
  [ "x$show" = x1 ] && exit 0
fi
"$@"
