Autoconf, Automake, and Libtool: Separators and Drive Letters

  | #### 25.3.2.2 Separators and Drive Letters As discussed earlier (see section 15.3.5.6 Windows Separators and Drive Letters), the Windows file systems use different delimiters for separating directories and path elements than their Unix cousins. There are three places where this has an effect: the shell command line Up until Cygwin b20.1, it was possible to refer to drive letter prefixed paths from the shell using the ``//c/path/to/file'` syntax to refer to the directory root at ``C:\path\to\file'`. Unfortunately, the Windows kernel confused this with the its own network share notation, causing the shell to pause for a short while to look for a machine named ``c'` in its network neighbourhood. Since release 1.0 of Cygwin, the ``//c/path/to/file'` notation now really does refer to a machine named ``c'` from Cygwin as well as from Windows. To refer to drive letter rooted paths on the local machine from Cygwin there is a new hybrid ``c:/path/to/file'` notation. This notation also works in Cygwin b20, and is probably the system you should use. On the other hand, using the new hybrid notation in shell scripts means that they won't run on old Cygwin releases. Shell code embedded In ``configure.in'` scripts, should test whether the hybrid notation works, and use an alternate macro to translate hybrid notation to the old style if necessary. I must confess that from the command line I now use the longer ``/cygdrive/c/path/to/file'` notation, since `TAB` completion doesn't yet work for the newer hybrid notation. It is important to use the new notation in shell scripts however, or they will fail on the latest releases of Cygwin. shell scripts For a shell script to work correctly on non-Cygwin development environments, it needs to be aware of and handle Windows path and directory separator and drive letters. The Libtool scripts use the following idiom:
      case "$path" in
      # Accept absolute paths.
      [\\/]* | [A-Za-\]:[\\/]*)
        # take care of absolute paths
        insert some code here
        ;;
      *)
        # what is left must be a relative path
        insert some code here
        ;;
      esac
source code When porting Unix software to Cygwin, this is much less of an issue because these differences are hidden beneath the emulation layer, and by the `mount` command respectively; although I have found that GCC, for example, returns a mixed mode ``/'` and ``\'` delimitted include path which upsets Automake's dependency tracking on occasion. Cygwin provides convenience functions to convert back and forth between the different notations, which we call POSIX paths or path lists, and WIN32 paths or path lists: Function: int posix_path_list_p (const char *path) Return ``0'`, unless path is a ``/'` and ``:'` separated path list. The determination is rather simplistic, in that a string which contains a ``;'` or begins with a single letter followed by a ``:'` causes the ``0'` return. Function: void cygwin_win32_to_posix_path_list (const char *win32, char *posix) Converts the ``\'` and ``;'` delimiters in win32, into the equivalent ``/'` and ``:'` delimiters while copying into the buffer at address posix. This buffer must be preallocated before calling the function. Function: void cygwin_conv_to_posix_path (const char *path, char *posix_path) If path is a ``\'` delimitted path, the equivalent, ``/'` delimitted path is written to the buffer at address posix_path. This buffer must be preallocated before calling the function. Function: void cygwin_conv_to_full_posix_path (const char *path, char *posix_path) If path is a, possibly relative, ``\'` delimitted path, the equivalent, absolute, ``/'` delimitted path is written to the buffer at address posix_path. This buffer must be preallocated before calling the function. Function: void cygwin_posix_to_win32_path_list (const char *posix, char *win32) Converts the ``/'` and ``:'` delimiters in posix, into the equivalent ``\'` and ``;'` delimiters while copying into the buffer at address win32. This buffer must be preallocated before calling the function. Function: void cygwin_conv_to_win32_path (const char *path, char *win32_path) If path is a ``/'` delimitted path, the equivalent, ``\'` delimitted path is written to the buffer at address win32_path. This buffer must be preallocated before calling the function. Function: void cygwin_conv_to_full_win32_path (const char *path, char *win32_path) If path is a, possibly relative, ``/'` delimitted path, the equivalent, absolute, ``\'` delimitted path is written to the buffer at address win32_path. This buffer must be preallocated before calling the function. You can use these functions something like this:
    void
    display_canonical_path(const char *maybe_relative_or_win32)
    {
        char buffer[MAX_PATH];
        cygwin_conv_to_full_posix_path(maybe_relative_or_win32,
                                       buffer);
        printf("canonical path for %s:  %s\n",
               maybe_relative_or_win32, buffer);
    }
For your code to be fully portable however, you cannot rely on these Cygwin functions as they are not implemented on Unix, or even mingw or DJGPP. Instead you should add the following to a shared header, and be careful to use it when processing and building paths and path lists:
    #if defined __CYGWIN32__ && !defined __CYGWIN__
       /* For backwards compatibility with Cygwin b19 and
          earlier, we define __CYGWIN__ here, so that
          we can rely on checking just for that macro. */
    #  define __CYGWIN__  __CYGWIN32__
    #endif

    #if defined _WIN32 && !defined __CYGWIN__
       /* Use Windows separators on all _WIN32 defining
          environments, except Cygwin. */
    #  define DIR_SEPARATOR_CHAR		'\\'
    #  define DIR_SEPARATOR_STR		"\\"
    #  define PATH_SEPARATOR_CHAR		';'
    #  define PATH_SEPARATOR_STR		";"
    #endif
    #ifndef DIR_SEPARATOR_CHAR
       /* Assume that not having this is an indicator that all
          are missing. */
    #  define DIR_SEPARATOR_CHAR		'/'
    #  define DIR_SEPARATOR_STR		"/"
    #  define PATH_SEPARATOR_CHAR		':'
    #  define PATH_SEPARATOR_STR		":"
    #endif /* !DIR_SEPARATOR_CHAR */
With this in place we can use the macros defined above to write code which will compile and work just about anywhere:
    char path[MAXBUFLEN];
    snprintf(path, MAXBUFLEN, "%ctmp%c%s\n",
             DIR_SEPARATOR_CHAR, DIR_SEPARATOR_CHAR, foo);
    file = fopen(path, "tw+");

This document was generated by Gary V. Vaughan on May, 24 2001 using texi2html