This is a proposed patch to libiberty, with an accompanying patch to GCC.
The purpose of this patch is to make it possible for Windows-hosted toolchains to have the ability to control whether Canonicalized filenames are converted to all lower-case.
Most Windows users are not affected by this behavior.
However, we have at least one customer who does use Windows systems where their hard drives are case-sensitive.  Thus, they desire this ability.

The first implementation of Windows support in libiberty/lrealpath.c was added back in 2004.  The new code included a call to GetFullPathName(), to Canonicalize the filename.  Next,  if there was sufficient room in the buffer, the following code was run:

        /* The file system is case-preserving but case-insensitive,
           Canonicalize to lowercase, using the codepage associated
           with the process locale.  */
        CharLowerBuff (buf, len);
        return strdup (buf);

In effect, the assumption of the code is that all Windows file systems will be case-preserving but case-insensitive, so converting a filename to lowercase is not a problem.  And tools would always find the resulting file on the file system.  That turns out not to be true, but lrealpath() was mostly used just for system header files, so no one noticed.

However, in April 2014, libcpp was patched, to cause even non-system headers on Windows systems to be Canonicalized.  This patch has caused problems for users that have case-sensitive file systems on their Windows systems.  A patch to libcpp was proposed to do additional Canonicalize non-system headers on Windows systems. The discussion on the patch starts at https://gcc.gnu.org/ml/gcc-patches/2014-04/msg00009.html
As is noted in the comments:
      For DOS based file system, we always try to shorten non-system headers, as DOS has a tighter constraint on max path length. The okay to add the patch was given May 9, 2014 at https://gcc.gnu.org/ml/gcc-patches/2014-05/msg00557.html , with the note:       I've spoke with Kai a bit about this and he thinks it's appropriate and desirable to shorten paths on these kinds of filesystems.

The libcpp change meant that lrealpath() began to get called for non-system header files.  There is other code in both bfd and libiberty that can reach the lrealpath() function, but apparently those functions are not as much of a problem, as in not really being used in most tools (obviously since our customer had no complaints before 2014).

What I am proposing is to modify lrealpath() to only call CharLowerBuff when the user has a filesystem where changing the case of the filename is not an issue.
That is actually most users, so the default should be to call CharLowerBuff.
But I want to give the user the ability to control that behavior.

My proposal is to change that section of code in libiberty/lrealpath.c as follows:

     else
       {
-       /* The file system is case-preserving but case-insensitive,
-          Canonicalize to lowercase, using the codepage associated
+       /* The file system is normally case-preserving but case-insensitive,
+          Canonicalize to lowercase if desired, using the codepage associated
           with the process locale.  */
-        CharLowerBuff (buf, len);
+       if (libiberty_lowerpath)
+          CharLowerBuff (buf, len);
         return strdup (buf);
       }

In effect, this just adds a control to let the user decide whether or not a pathname is converted to lowercase on Windows systems.

I also added a global definition for that control at the start of the libiberty/lrealpath.c source, setting it so the default behavior on Windows is to convert pathnames to lowercase:

+/* External option to control whether a pathname is converted
+   to all lower-case on Windows systems.  The default behavior
+   is to convert.
+*/
+#if defined (_WIN32)
+#ifdef __cplusplus
+extern "C" {
+#endif
+unsigned char libiberty_lowerpath = 1;
+#ifdef __cplusplus
+}
+#endif
+#endif

And, for use by tools that link to libiberty.a, I added an external reference to that control in include/libiberty.h:

+#if defined (_WIN32)
+/* Determine if filenames should be converted to lower case */
+extern unsigned char libiberty_lowerpath;
+#endif


Adding the above code to include/libiberty.h and libiberty/lrealpath.c results in a libiberty.a that behaves exactly the same as it does today for most users. It also makes available a method of affecting whether or not a given tool affects canonicalized pathnames on Windows by also converting those pathnames to lowercase.

The questions to discuss:
1.    Is this a reasonable solution to this problem, by adding such a controlling symbol? 2.    Is it reasonable to use ‘libiberty_lowerpath’ as the symbol’s name?  There are other global symbols defined in libiberty that use a similar name, so this seems reasonable. 3.    Should the symbol be called ‘libiberty_lowerpath’ or something else, such as ‘libiberty_lowerfilename’?  Does that matter? 4.    While the ‘CharLowerBuff()’ code is within a _WIN32 section of code, should the global symbol also be defined so it only exists in libiberty.a for Windows hosts?  Or should that global symbol always be defined in libiberty.a, regardless of whether it is for Windows or Linux?  Obviously that symbol is only meaningful for Windows hosts.  But the existence (or non-existence)  of the symbol obviously affects how tools write their code to modify that symbol.  As presently written, tools would only modify this symbol when being built for running on Windows.

Depending on the answers to the above, a followup can show the proposed changes to tools, to add options to allow control of changing filenames to lower case on Windows.

If the above change (or something similar) is done to libiberty, then GCC should also be changed to add an option for accessing this variable.  I would propose adding the '-flowerpath' option, which would be the default.  That also adds '-fno-lowerpath', which is what users would use to keep their filenames from being converted to lower-case.  Most users, of course, could just ignore this option.  And it would only be meaningful for Windows-hosted tools.

Here are the patches that would implement the above:

diff -raup a/include/libiberty.h b/include/libiberty.h
--- a/include/libiberty.h    2019-08-07 08:16:05.269694038 -0700
+++ b/include/libiberty.h    2019-08-07 09:02:05.771381502 -0700
@@ -750,6 +750,11 @@ extern unsigned long libiberty_len;
    (char *) memcpy (libiberty_nptr, libiberty_optr, libiberty_len))
 #endif

+#if defined (_WIN32)
+/* Determine if filenames should be converted to lower case */
+extern unsigned char libiberty_lowerpath;
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff -raup a/libiberty/lrealpath.c b/libiberty/lrealpath.c
--- a/libiberty/lrealpath.c    2019-08-07 08:16:05.957694774 -0700
+++ b/libiberty/lrealpath.c    2019-08-07 09:03:03.271408306 -0700
@@ -72,6 +72,20 @@ extern char *canonicalize_file_name (con
 # endif
 #endif

+/* External option to control whether a pathname is converted
+   to all lower-case on Windows systems.  The default behavior
+   is to convert.
+*/
+#if defined (_WIN32)
+#ifdef __cplusplus
+extern "C" {
+#endif
+unsigned char libiberty_lowerpath = 1;
+#ifdef __cplusplus
+}
+#endif
+#endif
+
 char *
 lrealpath (const char *filename)
 {
@@ -159,10 +173,11 @@ lrealpath (const char *filename)
       return strdup (filename);
     else
       {
-    /* The file system is case-preserving but case-insensitive,
-       Canonicalize to lowercase, using the codepage associated
+    /* The file system is normally case-preserving but case-insensitive,
+       Canonicalize to lowercase if desired, using the codepage associated
        with the process locale.  */
-        CharLowerBuff (buf, len);
+    if (libiberty_lowerpath)
+          CharLowerBuff (buf, len);
         return strdup (buf);
       }
   }
diff -raup a/gcc/common.opt b/gcc/common.opt
--- a/gcc/common.opt    2019-08-05 09:42:54.889054582 -0700
+++ b/gcc/common.opt    2019-08-05 10:09:01.708902089 -0700
@@ -1543,6 +1543,10 @@ floop-nest-optimize
 Common Report Var(flag_loop_nest_optimize) Optimization
 Enable the loop nest optimizer.

+flowerpath
+Common Report
+Convert pathnames to all lowercase on Windows (ignore elsewhere).
+
 fstrict-volatile-bitfields
 Common Report Var(flag_strict_volatile_bitfields) Init(-1) Optimization
 Force bitfield accesses to match their type width.
diff -raup a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
--- a/gcc/doc/invoke.texi    2019-08-05 09:42:55.213053535 -0700
+++ b/gcc/doc/invoke.texi    2019-08-05 10:27:53.749415626 -0700
@@ -174,7 +174,8 @@ in the following sections.
 -pass-exit-codes  -pipe  -specs=@var{file}  -wrapper  @gol
 @@@var{file}  -ffile-prefix-map=@var{old}=@var{new}  @gol
 -fplugin=@var{file}  -fplugin-arg-@var{name}=@var{arg}  @gol
--fdump-ada-spec@r{[}-slim@r{]}  -fada-spec-parent=@var{unit} -fdump-go-spec=@var{file}}
+-fdump-ada-spec@r{[}-slim@r{]}  -fada-spec-parent=@var{unit} @gol
+-fdump-go-spec=@var{file} -fno-lowerpath}

 @item C Language Options
 @xref{C Dialect Options,,Options Controlling C Dialect}.
diff -raup a/gcc/opts.c b/gcc/opts.c
--- a/gcc/opts.c    2019-08-05 09:42:55.385052980 -0700
+++ b/gcc/opts.c    2019-08-05 10:09:01.724902054 -0700
@@ -2412,6 +2412,12 @@ common_handle_option (struct gcc_options
       opts->x_flag_stack_usage_info = value != 0;
       break;

+    case OPT_flowerpath:
+#ifdef __WIN32
+      libiberty_lowerpath = value;
+#endif
+      break;
+
     case OPT_g:
       set_debug_level (NO_DEBUG, DEFAULT_GDB_EXTENSIONS, arg, opts, opts_set,
                        loc);




Reply via email to