# Options:
# -L DIRECTORY search for C# libraries also in DIRECTORY
+# func_tmpdir
+# creates a temporary directory.
+# Sets variable
+# - tmp pathname of freshly created temporary directory
+func_tmpdir ()
+{
+ # Use the environment variable TMPDIR, falling back to /tmp. This allows
+ # users to specify a different temporary directory, for example, if their
+ # /tmp is filled up or too small.
+ : "${TMPDIR=/tmp}"
+ {
+ # Use the mktemp program if available. If not available, hide the error
+ # message.
+ tmp=`(umask 077 && mktemp -d -q "$TMPDIR/gtXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+ } ||
+ {
+ # Use a simple mkdir command. It is guaranteed to fail if the directory
+ # already exists. $RANDOM is bash specific and expands to empty in shells
+ # other than bash, ksh and zsh. Its use does not increase security;
+ # rather, it minimizes the probability of failure in a very cluttered /tmp
+ # directory.
+ tmp=$TMPDIR/gt$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+ } ||
+ {
+ echo "$0: cannot create a temporary directory in $TMPDIR" >&2
+ { (exit 1); exit 1; }
+ }
+}
+
sed_quote_subst='s/\([|&;<>()$`"'"'"'*?[#~=% \\]\)/\\\1/g'
libdirs_mono=
+libdirs_dotnet=
prog=
while test $# != 0; do
case "$1" in
-L)
libdirs_mono="${libdirs_mono:+$libdirs_mono@MONO_PATH_SEPARATOR@}$2"
+ libdirs_dotnet="${libdirs_dotnet:+$libdirs_dotnet|}$2"
shift
;;
-*)
test -z "$CSHARP_VERBOSE" || echo mono "$@"
exec mono "$@"
else
- if test -n "@HAVE_CLIX@"; then
- CONF_CLIX_PATH='@CLIX_PATH@'
- if test -n "$libdirs_mono"; then
- @CLIX_PATH_VAR@="$libdirs_mono${CONF_CLIX_PATH:+@MONO_PATH_SEPARATOR@$CONF_CLIX_PATH}"
- else
- @CLIX_PATH_VAR@="$CONF_CLIX_PATH"
- fi
- export @CLIX_PATH_VAR@
+ if test -n "@HAVE_DOTNET@"; then
+ # Invoke 'dotnet $prog ...'.
+ # Documentation:
+ # <https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet#options-for-running-an-application>
+ # This could be optimized on Windows platforms, because C# .exe files are
+ # directly executable there. But there's no point in optimizing specifically
+ # a non-free platform, especially since it would increase the test matrix.
shift
- # On Windows, assume that 'clix' is a native Windows program,
- # not a Cygwin program.
+ # On Windows, assume that 'dotnet' is a native Windows program, not a Cygwin program.
+ prog_arg="$prog"
case "@build_os@" in
cygwin*)
- prog=`cygpath -w "$prog"`
+ prog_arg=`cygpath -w "$prog"`
;;
esac
- test -z "$CSHARP_VERBOSE" || echo clix "$prog" "$@"
- exec clix "$prog" "$@"
+ # Handle the -L options.
+ # The way this works is that we have to copy (or symlink) the DLLs into the
+ # directory where FOO.exe resides.
+ # Maybe there is another way to do this, but I haven't found it, trying
+ # - the --additionalprobingpath command-line option,
+ # - the additionalProbingPaths property in runtimeconfig.json,
+ # - adding a --deps deps.json option,
+ # cf. <https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet#options-for-running-an-application>
+ # and <https://github.com/dotnet/runtime/blob/main/docs/design/features/host-probing.md>.
+ tmpfiles=
+ if test -n "$libdirs_dotnet"; then
+ # Make sure the added DLLs are removed when this script terminates.
+ func_cleanup_tmpfiles()
+ {
+ saved_IFS="$IFS"
+ IFS='|'
+ for file in $tmpfiles; do
+ IFS="$saved_IFS"
+ rm -f "$file"
+ done
+ IFS="$saved_IFS"
+ }
+ trap func_cleanup_tmpfiles HUP INT QUIT PIPE TERM
+ trap 'exit_status=$?; func_cleanup_tmpfiles; exit $exit_status' EXIT
+ # Copy the DLLs.
+ prog_dir=`dirname "$prog"`
+ saved_IFS="$IFS"
+ IFS='|'
+ for dir in $libdirs_dotnet; do
+ IFS="$saved_IFS"
+ for file in `cd "$dir" && echo *.dll`; do
+ if test -f "$prog_dir/$file"; then
+ # A DLL of this name is already at the expected location.
+ :
+ else
+ tmpfiles="${tmpfiles:+$tmpfiles|}$prog_dir/$file"
+ cp "$dir/$file" "$prog_dir/$file" || exit 1
+ fi
+ done
+ done
+ IFS="$saved_IFS"
+ fi
+ if test -f "${prog%.exe}.runtimeconfig.json"; then
+ # There is already a FOO.runtimeconfig.json alongside FOO.exe.
+ dotnet exec "$prog_arg" "$@"
+ result=$?
+ else
+ # dotnet needs a FOO.runtimeconfig.json alongside FOO.exe in order to
+ # execute FOO.exe. Create a dummy one in a temporary directory
+ # (because the directory where FOO.exe sits is not necessarily writable).
+ # Documentation of this file format:
+ # <https://learn.microsoft.com/en-us/dotnet/core/runtime-config/>
+ func_tmpdir
+ runtimeconfig="$tmp"/runtimeconfig.json
+ dotnet --list-runtimes | sed -n -e 's/Microsoft.NETCore.App \([^ ]*\) .*/{ "runtimeOptions": { "framework": { "name": "Microsoft.NETCore.App", "version": "\1" } } }/p' > "$runtimeconfig"
+ runtimeconfig_arg="$runtimeconfig"
+ case "@build_os@" in
+ cygwin*)
+ runtimeconfig_arg=`cygpath -w "$runtimeconfig"`
+ ;;
+ esac
+ test -z "$CSHARP_VERBOSE" || echo dotnet exec --runtimeconfig "$runtimeconfig_arg" "$prog_arg" "$@"
+ dotnet exec --runtimeconfig "$runtimeconfig_arg" "$prog_arg" "$@"
+ result=$?
+ rm -f "$runtimeconfig"
+ rmdir "$tmp"
+ fi
+ exit $result
else
- echo 'C# virtual machine not found, try installing mono, then reconfigure' 1>&2
- exit 1
+ if test -n "@HAVE_CLIX@"; then
+ CONF_CLIX_PATH='@CLIX_PATH@'
+ if test -n "$libdirs_mono"; then
+ @CLIX_PATH_VAR@="$libdirs_mono${CONF_CLIX_PATH:+@MONO_PATH_SEPARATOR@$CONF_CLIX_PATH}"
+ else
+ @CLIX_PATH_VAR@="$CONF_CLIX_PATH"
+ fi
+ export @CLIX_PATH_VAR@
+ shift
+ # On Windows, assume that 'clix' is a native Windows program,
+ # not a Cygwin program.
+ case "@build_os@" in
+ cygwin*)
+ prog=`cygpath -w "$prog"`
+ ;;
+ esac
+ test -z "$CSHARP_VERBOSE" || echo clix "$prog" "$@"
+ exec clix "$prog" "$@"
+ else
+ echo 'C# virtual machine not found, try installing mono or dotnet, then reconfigure' 1>&2
+ exit 1
+ fi
fi
fi
-# csharpexec.m4 serial 9
+# csharpexec.m4 serial 10
dnl Copyright (C) 2003-2005, 2009-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
# Prerequisites of csharpexec.sh.
# Checks for a C# execution engine.
# gt_CSHARPEXEC or gt_CSHARPEXEC(testexecutable, its-directory)
-# Sets at most one of HAVE_MONO, HAVE_CLIX.
+# Sets at most one of HAVE_MONO, HAVE_DOTNET, HAVE_CLIX.
# Sets HAVE_CSHARPEXEC to nonempty if csharpexec.sh will work.
AC_DEFUN([gt_CSHARPEXEC],
[
pushdef([AC_CHECKING],[:])dnl
pushdef([AC_MSG_RESULT],[:])dnl
AC_CHECK_PROG([HAVE_MONO_IN_PATH], [mono], [yes])
+ AC_CHECK_PROG([HAVE_DOTNET_IN_PATH], [dotnet], [yes])
AC_CHECK_PROG([HAVE_CLIX_IN_PATH], [clix], [yes])
popdef([AC_MSG_RESULT])dnl
popdef([AC_CHECKING])dnl
popdef([AC_MSG_CHECKING])dnl
- for impl in "$CSHARP_CHOICE" mono no; do
+ for impl in "$CSHARP_CHOICE" mono dotnet no; do
case "$impl" in
mono)
if test -n "$HAVE_MONO_IN_PATH" \
break
fi
;;
+ dotnet)
+ if test -n "$HAVE_DOTNET_IN_PATH" \
+ && dotnet --list-runtimes >/dev/null 2>/dev/null; then
+ HAVE_DOTNET=1
+ ac_result="dotnet"
+ break
+ fi
+ ;;
sscli)
if test -n "$HAVE_CLIX_IN_PATH" \
m4_if([$1], , , [&& clix $2/$1 >/dev/null 2>/dev/null]); then
AC_SUBST([CLIX_PATH_VAR])
AC_SUBST([CLIX_PATH])
AC_SUBST([HAVE_MONO])
+ AC_SUBST([HAVE_DOTNET])
AC_SUBST([HAVE_CLIX])
])