diff mbox series

lto: Don't assume a posix shell is usable on windows [PR110710]

Message ID 20240326223601.32541-1-peter0x44@disroot.org
State New
Headers show
Series lto: Don't assume a posix shell is usable on windows [PR110710] | expand

Commit Message

Peter0x44 March 26, 2024, 10:36 p.m. UTC
lto-wrapper generates Makefiles that use the following:
touch -r file file.tmp && mv file.tmp file
to truncate files.
If there is no suitable "touch" or "mv" available, then this errors with
"The system cannot find the file specified".

The solution here is to check if sh -c true works, before trying to use it in
the Makefile. If it doesn't, then fall back to "copy /y nul file" instead.
The fallback doesn't work exactly the same (the modified time of the file gets
updated), but this doesn't seem to matter in practice.

I tested this both in environments both with and without sh present, and
observed no issues.

Signed-off-by: Peter Damianov <peter0x44@disroot.org>
---
 gcc/lto-wrapper.cc | 35 ++++++++++++++++++++++++++++++++---
 1 file changed, 32 insertions(+), 3 deletions(-)

Comments

Peter0x44 March 26, 2024, 10:43 p.m. UTC | #1
26 Mar 2024 10:36:45 pm Peter Damianov <peter0x44@disroot.org>:

> lto-wrapper generates Makefiles that use the following:
> touch -r file file.tmp && mv file.tmp file
> to truncate files.
> If there is no suitable "touch" or "mv" available, then this errors 
> with
> "The system cannot find the file specified".
>
> The solution here is to check if sh -c true works, before trying to use 
> it in
> the Makefile. If it doesn't, then fall back to "copy /y nul file" 
> instead.
> The fallback doesn't work exactly the same (the modified time of the 
> file gets
> updated), but this doesn't seem to matter in practice.
>
> I tested this both in environments both with and without sh present, 
> and
> observed no issues.
>
> Signed-off-by: Peter Damianov <peter0x44@disroot.org>
> ---
> gcc/lto-wrapper.cc | 35 ++++++++++++++++++++++++++++++++---
> 1 file changed, 32 insertions(+), 3 deletions(-)
>
> diff --git a/gcc/lto-wrapper.cc b/gcc/lto-wrapper.cc
> index 5186d040ce0..8dee0aaa2d8 100644
> --- a/gcc/lto-wrapper.cc
> +++ b/gcc/lto-wrapper.cc
> @@ -1389,6 +1389,27 @@ make_exists (void)
>    return errmsg == NULL && exit_status == 0 && err == 0;
> }
>
> +/* Test that an sh command is present and working, return true if so.
> +   This is only relevant for windows hosts, where a /bin/sh shell 
> cannot
> +   be assumed to exist. */
> +
> +static bool
> +sh_exists (void)
> +{
> +  const char *sh = "sh";
> +  const char *sh_args[] = {sh, "-c", "true", NULL};
> +#ifdef _WIN32
> +  int exit_status = 0;
> +  int err = 0;
> +  const char *errmsg
> +    = pex_one (PEX_SEARCH, sh_args[0], CONST_CAST (char **, sh_args),
> +          "sh", NULL, NULL, &exit_status, &err);
> +  return errmsg == NULL && exit_status == 0 && err == 0;
> +#else
> +  return true;
> +#endif
> +}
> +
> /* Execute gcc. ARGC is the number of arguments. ARGV contains the 
> arguments. */
>
> static void
> @@ -1402,6 +1423,7 @@ run_gcc (unsigned argc, char *argv[])
>    const char *collect_gcc;
>    char *collect_gcc_options;
>    int parallel = 0;
> +  bool have_sh = sh_exists ();
>    int jobserver = 0;
>    bool jobserver_requested = false;
>    int auto_parallel = 0;
> @@ -2016,6 +2038,7 @@ cont:
>       argv_ptr[5] = NULL;
>       if (parallel)
>         {
> +         fprintf (mstream, "SHELL=%s\n", have_sh ? "sh" : "cmd");
>           fprintf (mstream, "%s:\n\t@%s ", output_name, new_argv[0]);
>           for (j = 1; new_argv[j] != NULL; ++j)
>         fprintf (mstream, " '%s'", new_argv[j]);
> @@ -2024,9 +2047,15 @@ cont:
>              truncate them as soon as we have processed it.  This
>          reduces temporary disk-space usage.  */
>           if (! save_temps)
> -       fprintf (mstream, "\t@-touch -r \"%s\" \"%s.tem\" > /dev/null "
> -            "2>&1 && mv \"%s.tem\" \"%s\"\n",
> -            input_name, input_name, input_name, input_name);
> +       {
> +         fprintf (mstream,
> +              have_sh
> +              ? "\t@-touch -r \"%s\" \"%s.tem\" > /dev/null "
> +                "2>&1 && mv \"%s.tem\" \"%s\"\n"
> +              : "\t@-copy /y nul \"%s\" > NUL "
> +                "2>&1\n",
> +              input_name, input_name, input_name, input_name);
> +       }
>         }
>       else
>         {
> --
> 2.39.2
I made this patch against gcc 13.2, because I couldn't get gcc 14 to 
build.
I got the following errors:

In file included from ../../../../gcc/libgcc/config/i386/cpuinfo.c:30:
../../../../gcc/libgcc/../gcc/common/config/i386/cpuinfo.h: In function 
'get_available_features':
../../../../gcc/libgcc/../gcc/common/config/i386/cpuinfo.h:938:21: error: 
'bit_USER_MSR' undeclared (first use in this function)
  938 | if (edx & bit_USER_MSR)
      | ^~~~~~~~~~~~
../../../../gcc/libgcc/../gcc/common/config/i386/cpuinfo.h:938:21: note: 
each undeclared identifier is reported only once for each function it 
appears in
../../../../gcc/libgcc/../gcc/common/config/i386/cpuinfo.h:950:25: error: 
'bit_AVXVNNIINT16' undeclared (first use in this function); did you mean 
'bit_AVXVNNIINT8'?
  950 | if (edx & bit_AVXVNNIINT16)
      | ^~~~~~~~~~~~~~~~
      | bit_AVXVNNIINT8

Hopefully it's still okay.
Richard Biener March 27, 2024, 7:51 a.m. UTC | #2
On Tue, Mar 26, 2024 at 11:37 PM Peter Damianov <peter0x44@disroot.org> wrote:
>
> lto-wrapper generates Makefiles that use the following:
> touch -r file file.tmp && mv file.tmp file
> to truncate files.
> If there is no suitable "touch" or "mv" available, then this errors with
> "The system cannot find the file specified".
>
> The solution here is to check if sh -c true works, before trying to use it in
> the Makefile. If it doesn't, then fall back to "copy /y nul file" instead.
> The fallback doesn't work exactly the same (the modified time of the file gets
> updated), but this doesn't seem to matter in practice.

I suppose it doesn't matter as we (no longer?) have the input as dependency
on the rule so make doesn't get confused to re-build it.  I guess we
only truncate
the file because it's going to be deleted by another process.

Instead of doing sth like sh_exists I would suggest to simply use #ifdef __WIN
or something like that?  Not sure if we have suitable macros to identify the
host operating system though and whether mingw, cygwin, etc. behave the same
here.

As a stop-gap solution doing

  ( @-touch -r ... ) || true

might also work?  Or another way to note to make the command can fail
without causing a problem.

Another way would be to have a portable solution to truncate a file
(maybe even removing it would work).  I don't think we should override
SHELL.

Richard.

> I tested this both in environments both with and without sh present, and
> observed no issues.
>
> Signed-off-by: Peter Damianov <peter0x44@disroot.org>
> ---
>  gcc/lto-wrapper.cc | 35 ++++++++++++++++++++++++++++++++---
>  1 file changed, 32 insertions(+), 3 deletions(-)
>
> diff --git a/gcc/lto-wrapper.cc b/gcc/lto-wrapper.cc
> index 5186d040ce0..8dee0aaa2d8 100644
> --- a/gcc/lto-wrapper.cc
> +++ b/gcc/lto-wrapper.cc
> @@ -1389,6 +1389,27 @@ make_exists (void)
>    return errmsg == NULL && exit_status == 0 && err == 0;
>  }
>
> +/* Test that an sh command is present and working, return true if so.
> +   This is only relevant for windows hosts, where a /bin/sh shell cannot
> +   be assumed to exist. */
> +
> +static bool
> +sh_exists (void)
> +{
> +  const char *sh = "sh";
> +  const char *sh_args[] = {sh, "-c", "true", NULL};
> +#ifdef _WIN32
> +  int exit_status = 0;
> +  int err = 0;
> +  const char *errmsg
> +    = pex_one (PEX_SEARCH, sh_args[0], CONST_CAST (char **, sh_args),
> +              "sh", NULL, NULL, &exit_status, &err);
> +  return errmsg == NULL && exit_status == 0 && err == 0;
> +#else
> +  return true;
> +#endif
> +}
> +
>  /* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */
>
>  static void
> @@ -1402,6 +1423,7 @@ run_gcc (unsigned argc, char *argv[])
>    const char *collect_gcc;
>    char *collect_gcc_options;
>    int parallel = 0;
> +  bool have_sh = sh_exists ();
>    int jobserver = 0;
>    bool jobserver_requested = false;
>    int auto_parallel = 0;
> @@ -2016,6 +2038,7 @@ cont:
>           argv_ptr[5] = NULL;
>           if (parallel)
>             {
> +             fprintf (mstream, "SHELL=%s\n", have_sh ? "sh" : "cmd");
>               fprintf (mstream, "%s:\n\t@%s ", output_name, new_argv[0]);
>               for (j = 1; new_argv[j] != NULL; ++j)
>                 fprintf (mstream, " '%s'", new_argv[j]);
> @@ -2024,9 +2047,15 @@ cont:
>                  truncate them as soon as we have processed it.  This
>                  reduces temporary disk-space usage.  */
>               if (! save_temps)
> -               fprintf (mstream, "\t@-touch -r \"%s\" \"%s.tem\" > /dev/null "
> -                        "2>&1 && mv \"%s.tem\" \"%s\"\n",
> -                        input_name, input_name, input_name, input_name);
> +               {
> +                 fprintf (mstream,
> +                          have_sh
> +                          ? "\t@-touch -r \"%s\" \"%s.tem\" > /dev/null "
> +                            "2>&1 && mv \"%s.tem\" \"%s\"\n"
> +                          : "\t@-copy /y nul \"%s\" > NUL "
> +                            "2>&1\n",
> +                          input_name, input_name, input_name, input_name);
> +               }
>             }
>           else
>             {
> --
> 2.39.2
>
diff mbox series

Patch

diff --git a/gcc/lto-wrapper.cc b/gcc/lto-wrapper.cc
index 5186d040ce0..8dee0aaa2d8 100644
--- a/gcc/lto-wrapper.cc
+++ b/gcc/lto-wrapper.cc
@@ -1389,6 +1389,27 @@  make_exists (void)
   return errmsg == NULL && exit_status == 0 && err == 0;
 }
 
+/* Test that an sh command is present and working, return true if so.
+   This is only relevant for windows hosts, where a /bin/sh shell cannot
+   be assumed to exist. */
+
+static bool
+sh_exists (void)
+{
+  const char *sh = "sh";
+  const char *sh_args[] = {sh, "-c", "true", NULL};
+#ifdef _WIN32
+  int exit_status = 0;
+  int err = 0;
+  const char *errmsg
+    = pex_one (PEX_SEARCH, sh_args[0], CONST_CAST (char **, sh_args),
+	       "sh", NULL, NULL, &exit_status, &err);
+  return errmsg == NULL && exit_status == 0 && err == 0;
+#else
+  return true;
+#endif
+}
+
 /* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */
 
 static void
@@ -1402,6 +1423,7 @@  run_gcc (unsigned argc, char *argv[])
   const char *collect_gcc;
   char *collect_gcc_options;
   int parallel = 0;
+  bool have_sh = sh_exists ();
   int jobserver = 0;
   bool jobserver_requested = false;
   int auto_parallel = 0;
@@ -2016,6 +2038,7 @@  cont:
 	  argv_ptr[5] = NULL;
 	  if (parallel)
 	    {
+	      fprintf (mstream, "SHELL=%s\n", have_sh ? "sh" : "cmd");
 	      fprintf (mstream, "%s:\n\t@%s ", output_name, new_argv[0]);
 	      for (j = 1; new_argv[j] != NULL; ++j)
 		fprintf (mstream, " '%s'", new_argv[j]);
@@ -2024,9 +2047,15 @@  cont:
 	         truncate them as soon as we have processed it.  This
 		 reduces temporary disk-space usage.  */
 	      if (! save_temps)
-		fprintf (mstream, "\t@-touch -r \"%s\" \"%s.tem\" > /dev/null "
-			 "2>&1 && mv \"%s.tem\" \"%s\"\n",
-			 input_name, input_name, input_name, input_name); 
+		{
+		  fprintf (mstream,
+			   have_sh
+			   ? "\t@-touch -r \"%s\" \"%s.tem\" > /dev/null "
+			     "2>&1 && mv \"%s.tem\" \"%s\"\n"
+			   : "\t@-copy /y nul \"%s\" > NUL "
+			     "2>&1\n",
+			   input_name, input_name, input_name, input_name);
+		}
 	    }
 	  else
 	    {