]> Savannah Git Hosting - gnulib.git/commitdiff
csharpexec-script: Add support for dotnet.
authorBruno Haible <bruno@clisp.org>
Wed, 9 Oct 2024 01:12:42 +0000 (03:12 +0200)
committerBruno Haible <bruno@clisp.org>
Wed, 16 Oct 2024 12:06:28 +0000 (14:06 +0200)
* m4/csharpexec.m4 (gt_CSHARPEXEC): Support 'dotnet' as implementation.
Set HAVE_DOTNET.
* build-aux/csharpexec.sh.in (func_tmpdir): New function, copied from
build-aux/csharpcomp.sh.in.
Add implementation for the case $HAVE_DOTNET = 1.

ChangeLog
build-aux/csharpexec.sh.in
m4/csharpexec.m4

index b1c83c199e4be1ff350c241433e6dbac5d7d4cc4..a1e92dd25713d4b7c0fc6d8a228c3db0c7197f52 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2024-10-08  Bruno Haible  <bruno@clisp.org>
+
+       csharpexec-script: Add support for dotnet.
+       * m4/csharpexec.m4 (gt_CSHARPEXEC): Support 'dotnet' as implementation.
+       Set HAVE_DOTNET.
+       * build-aux/csharpexec.sh.in (func_tmpdir): New function, copied from
+       build-aux/csharpcomp.sh.in.
+       Add implementation for the case $HAVE_DOTNET = 1.
+
 2024-10-08  Bruno Haible  <bruno@clisp.org>
 
        csharpexec-script, csharpcomp-script: Prepare support for dotnet.
index 83d60ca870ebb07a7be50ab993ba5741db4a5670..45c95b4b5fe84f6a6c4ecfbf315aa7f6295d0ca6 100644 (file)
 # 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
       ;;
     -*)
@@ -71,26 +104,111 @@ if test -n "@HAVE_MONO@"; then
   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
index 079c5723fd61cb2049872f0f02c7276d5113019a..5d7a0e889922b45698e353001941cb24480ff3bd 100644 (file)
@@ -1,4 +1,4 @@
-# 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,
@@ -7,7 +7,7 @@ dnl with or without modifications, as long as this notice is preserved.
 # 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],
 [
@@ -24,11 +24,12 @@ 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" \
@@ -39,6 +40,14 @@ AC_DEFUN([gt_CSHARPEXEC],
           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
@@ -72,5 +81,6 @@ AC_DEFUN([gt_CSHARPEXEC],
   AC_SUBST([CLIX_PATH_VAR])
   AC_SUBST([CLIX_PATH])
   AC_SUBST([HAVE_MONO])
+  AC_SUBST([HAVE_DOTNET])
   AC_SUBST([HAVE_CLIX])
 ])