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

conda spawn gfortran should call bash on a bash script, not shell #221

Open
Tracked by #185
certik opened this issue Feb 3, 2025 · 0 comments
Open
Tracked by #185

conda spawn gfortran should call bash on a bash script, not shell #221

certik opened this issue Feb 3, 2025 · 0 comments

Comments

@certik
Copy link
Collaborator

certik commented Feb 3, 2025

The error is:

$ conda spawn gfortran
Filename: "/Users/ondrej/miniforge3/envs/gfortran/etc/conda/activate.d/activate-gfortran_osx-arm64.sh"
Syntax error:   × Failed to parse input
  ╰─▶ Failure to parse at Pos((5, 31))
   ╭────
 1 │ function _get_sourced_filename() {
   ·                               ┬
   ·                               ╰── expected EOI, TILDE_PREFIX, AND_IF, OR_IF, Stdout, StdoutStderr, io_redirect, or separator_op
   ╰────
  help: expected EOI, TILDE_PREFIX, AND_IF, OR_IF, Stdout, StdoutStderr,
        io_redirect, or separator_op

The bash file it is trying to "source" is:

$ cat /Users/ondrej/miniforge3/envs/gfortran/etc/conda/activate.d/activate-gfortran_osx-arm64.sh
#!/bin/bash

# This function takes no arguments
# It tries to determine the name of this file in a programatic way.
function _get_sourced_filename() {
    if [ -n "${BASH_SOURCE[0]}" ]; then
        basename "${BASH_SOURCE[0]}"
    elif [ -n "${(%):-%x}" ]; then
        # in zsh use prompt-style expansion to introspect the same information
        # see http://stackoverflow.com/questions/9901210/bash-source0-equivalent-in-zsh
        basename "${(%):-%x}"
    else
        echo "UNKNOWN FILE"
    fi
}

# The arguments to this are:
# 1. activation nature {activate|deactivate}
# 2. toolchain nature {build|host|ccc}
# 3. machine (should match -dumpmachine)
# 4. prefix (including any final -)
# 5+ program (or environment var comma value)
# The format for 5+ is name{,,value}. If value is specified
#  then name taken to be an environment variable, otherwise
#  it is taken to be a program. In this case, which is used
#  to find the full filename during activation. The original
#  value is stored in environment variable CONDA_BACKUP_NAME
#  For deactivation, the distinction is irrelevant as in all
#  cases NAME simply gets reset to CONDA_BACKUP_NAME.  It is
#  a fatal error if a program is identified but not present.
function _tc_activation() {
  local act_nature=$1; shift
  local tc_prefix=$1; shift
  local thing
  local newval
  local from
  local to
  local pass

  if [ "${act_nature}" = "activate" ]; then
    from=""
    to="CONDA_BACKUP_"
  else
    from="CONDA_BACKUP_"
    to=""
  fi

  for pass in check apply; do
    for thing in "$@"; do
      case "${thing}" in
        *,*)
          newval=$(echo "${thing}" | sed "s,^[^\,]*\,\(.*\),\1,")
          thing=$(echo "${thing}" | sed "s,^\([^\,]*\)\,.*,\1,")
          ;;
        *)
          newval="${CONDA_PREFIX}/bin/${tc_prefix}${thing}"
          thing=$(echo ${thing} | tr 'a-z+-' 'A-ZX_')
          if [ ! -x "${newval}" -a "${pass}" = "check" ]; then
            echo "ERROR: This cross-compiler package contains no program ${newval}"
            return 1
          fi
          ;;
      esac
      if [ "${pass}" = "apply" ]; then
        eval oldval="\$${from}$thing"
        if [ -n "${oldval}" ]; then
          eval export "${to}'${thing}'=\"${oldval}\""
        else
          eval unset '${to}${thing}'
        fi
        if [ -n "${newval}" ]; then
          eval export "'${from}${thing}=${newval}'"
        else
          eval unset '${from}${thing}'
        fi
      fi
    done
  done
  return 0
}

# When people are using conda-build, assume that adding rpath during build, and pointing at
#    the host env's includes and libs is helpful default behavior
if [ "${CONDA_BUILD:-0}" = "1" ]; then
  FFLAGS_USED="-march=armv8.3-a -ftree-vectorize -fPIC -fno-stack-protector -O2 -pipe -isystem ${PREFIX}/include -fdebug-prefix-map=${SRC_DIR}=/usr/local/src/conda/${PKG_NAME}-${PKG_VERSION} -fdebug-prefix-map=${PREFIX}=/usr/local/src/conda-prefix"
else
  FFLAGS_USED="-march=armv8.3-a -ftree-vectorize -fPIC -fno-stack-protector -O2 -pipe -isystem ${CONDA_PREFIX}/include"
fi

if [ "${CONDA_BUILD:-0}" = "1" ]; then
  if [ -f /tmp/old-env-$$.txt ]; then
    rm -f /tmp/old-env-$$.txt || true
  fi
  env > /tmp/old-env-$$.txt
fi

_tc_activation \
  activate arm64-apple-darwin20.0.0- \
  gfortran \
  "FC_FOR_BUILD,${CONDA_PREFIX}/bin/arm64-apple-darwin20.0.0-gfortran" \
  "FFLAGS,${FFLAGS:-${FFLAGS_USED}}" \
  "FORTRANFLAGS,${FORTRANFLAGS:-${FFLAGS_USED}}" \
  "DEBUG_FFLAGS,${FFLAGS:-${FFLAGS_USED} -march=armv8.3-a -ftree-vectorize -fPIC -fno-stack-protector -O2 -pipe -Og -g -Wall -Wextra -fcheck=all -fbacktrace -fimplicit-none -fvar-tracking-assignments}" \
  "DEBUG_FORTRANFLAGS,${FORTRANFLAGS:-${FFLAGS_USED} -march=armv8.3-a -ftree-vectorize -fPIC -fno-stack-protector -O2 -pipe -Og -g -Wall -Wextra -fcheck=all -fbacktrace -fimplicit-none -fvar-tracking-assignments}"

# extra ones - have a dependency on the previous ones, so done after.
_tc_activation \
  activate arm64-apple-darwin20.0.0- \
  "FC,${FC:-${GFORTRAN}}" \
  "F77,${F77:-${GFORTRAN}}" \
  "F90,${F90:-${GFORTRAN}}" \
  "F95,${F95:-${GFORTRAN}}"

if [ $? -ne 0 ]; then
  echo "ERROR: $(_get_sourced_filename) failed, see above for details"
else
  if [ "${CONDA_BUILD:-0}" = "1" ]; then
    if [ -f /tmp/new-env-$$.txt ]; then
      rm -f /tmp/new-env-$$.txt || true
    fi
    env > /tmp/new-env-$$.txt

    echo "INFO: $(_get_sourced_filename) made the following environmental changes:"
    diff -U 0 -rN /tmp/old-env-$$.txt /tmp/new-env-$$.txt | tail -n +4 | grep "^-.*\|^+.*" | grep -v "CONDA_BACKUP_" | sort
    rm -f /tmp/old-env-$$.txt /tmp/new-env-$$.txt || true
  fi
fi

We might eventually support all this syntax, but I think the robust approach here is to imply call bash since the above file is written for bash.

It looks like the above script is doing a lot of hackish logic, but in the end it just sets some environment variables.

I think we need a mechanism to "extract" the environment changes that this script does, and apply them in our current shell.

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

No branches or pull requests

1 participant