[MLton] mlnlffigen and filenames on Windows

Vesa Karvonen vesa.karvonen at cs.helsinki.fi
Wed Feb 21 05:04:37 PST 2007

Windows treats filenames case insensitively while mlnlffigen seems to
preserve the case of C identifiers in generated filenames.

I noticed this while using def-use mode.  I always edit on a Linux machine
(case sensitive), but compile also on Windows (case insensitive).  The
def-use info produced by MLton seems to contain only lowercase file names
on Windows (MinGW).  So, trying to jump to mlnlffigen generated files on
Linux fails unless the C identifier happened to be all lowercase.

While I haven't tested this, I think that given a C header with two things
whose names only differ in case, mlnlffigen will goof and use the same
filename for both.  I think that a reasonable way to fix this would be to
generate only lowercase names in mlnlffigen and ensure that they are
unique.  Below is a sketch of a patch to do this.  If this seems OK, I'll
test it on Windows (MinGW) and commit it.

-Vesa Karvonen

Index: mlnlffigen/gen.sml
--- mlnlffigen/gen.sml	(revision 5282)
+++ mlnlffigen/gen.sml	(working copy)
@@ -410,9 +410,21 @@
       fun smlFileAndExport (file,export,do_export) = 
-            (* we don't want apostrophes in file names -> turn them into minuses *)
-            val file = Vector.map (file, fn #"'" => #"-" | c => c)
-            val file = OS.Path.joinBaseExt {base = file, ext = SOME "sml"}
+            (* We don't want apostrophes in file names -> turn them into minuses.
+             * We also want to use only lowercase characters as some file systems
+             * are case insensitive.
+             *)
+            val base = Vector.map (file, fn #"'" => #"-" | c => Char.toLower c)
+            fun pick i = let
+               val file = OS.Path.joinBaseExt
+                             {base = if i=0 then base
+                                     else concat [base, "-", Int.toString i],
+                              ext = SOME "sml"}
+            in
+               if List.exists (!files, fn f => f = file) then pick (i+1)
+               else file
+            end
+            val file = pick 0
             val result = OS.Path.joinDirFile {dir = dir, file = file}
             checkDir ()

More information about the MLton mailing list