[v2,3/6] Move mkdir_recursive to common/filestuff.c

Message ID 20181018223100.20693-4-tom@tromey.com
State New
Headers show
Series
  • A different approach to startup-with-shell on macOS
Related show

Commit Message

Tom Tromey Oct. 18, 2018, 10:30 p.m.
This moves mkdir_recursive from dwarf-index-cache.c to
common/filestuff.c, and also changes it to return a boolean that says
whether or not it worked.

gdb/ChangeLog
2018-10-18  Tom Tromey  <tom@tromey.com>

	* unittests/mkdir-recursive-selftests.c: New file.
	* Makefile.in (SUBDIR_UNITTESTS_SRCS): Add
	unittests/mkdir-recursive-selftests.c.
	* dwarf-index-cache.c (mkdir_recursive): Move to
	common/filestuff.c.
	(index_cache::store): Check return value of mkdir_recursive.
	(create_dir_and_check, test_mkdir_recursive): Move to new file.
	(_initialize_index_cache): Don't register test.
	* common/filestuff.h (mkdir_recursive): Declare.
	* common/filestuff.c (mkdir_recursive): Move from
	dwarf-index-cache.c.  Return bool.
---
 gdb/ChangeLog                             |  14 +++
 gdb/Makefile.in                           |   1 +
 gdb/common/filestuff.c                    |  45 +++++++++
 gdb/common/filestuff.h                    |  10 ++
 gdb/dwarf-index-cache.c                   | 114 ++--------------------
 gdb/unittests/mkdir-recursive-selftests.c |  89 +++++++++++++++++
 6 files changed, 165 insertions(+), 108 deletions(-)
 create mode 100644 gdb/unittests/mkdir-recursive-selftests.c

-- 
2.17.1

Comments

Simon Marchi Oct. 29, 2018, 4 p.m. | #1
On 2018-10-18 6:30 p.m., Tom Tromey wrote:
> This moves mkdir_recursive from dwarf-index-cache.c to

> common/filestuff.c, and also changes it to return a boolean that says

> whether or not it worked.

> 

> gdb/ChangeLog

> 2018-10-18  Tom Tromey  <tom@tromey.com>

> 

> 	* unittests/mkdir-recursive-selftests.c: New file.

> 	* Makefile.in (SUBDIR_UNITTESTS_SRCS): Add

> 	unittests/mkdir-recursive-selftests.c.

> 	* dwarf-index-cache.c (mkdir_recursive): Move to

> 	common/filestuff.c.

> 	(index_cache::store): Check return value of mkdir_recursive.

> 	(create_dir_and_check, test_mkdir_recursive): Move to new file.

> 	(_initialize_index_cache): Don't register test.

> 	* common/filestuff.h (mkdir_recursive): Declare.

> 	* common/filestuff.c (mkdir_recursive): Move from

> 	dwarf-index-cache.c.  Return bool.


I just stumbled on a build failure caused by this patch, when building for mingw:

  CXX    unittests/mkdir-recursive-selftests.o
/home/emaisin/src/binutils-gdb/gdb/unittests/mkdir-recursive-selftests.c: In function ‘void selftests::mkdir_recursive::test()’:
/home/emaisin/src/binutils-gdb/gdb/unittests/mkdir-recursive-selftests.c:49:20: error: ‘mkdtemp’ was not declared in this scope
   if (mkdtemp (base) == NULL)
                    ^

The function in the original code was guarded by HAVE_MKDTEMP (the register_test
call still is).  So I guess the function should be put back in an ifdef, or we
should import the mkdtemp gnulib module (I don't remember why I chose not to do
that).

Simon
Simon Marchi Oct. 29, 2018, 10:16 p.m. | #2
On 2018-10-29 12:00 p.m., Simon Marchi wrote:
> On 2018-10-18 6:30 p.m., Tom Tromey wrote:

>> This moves mkdir_recursive from dwarf-index-cache.c to

>> common/filestuff.c, and also changes it to return a boolean that says

>> whether or not it worked.

>>

>> gdb/ChangeLog

>> 2018-10-18  Tom Tromey  <tom@tromey.com>

>>

>> 	* unittests/mkdir-recursive-selftests.c: New file.

>> 	* Makefile.in (SUBDIR_UNITTESTS_SRCS): Add

>> 	unittests/mkdir-recursive-selftests.c.

>> 	* dwarf-index-cache.c (mkdir_recursive): Move to

>> 	common/filestuff.c.

>> 	(index_cache::store): Check return value of mkdir_recursive.

>> 	(create_dir_and_check, test_mkdir_recursive): Move to new file.

>> 	(_initialize_index_cache): Don't register test.

>> 	* common/filestuff.h (mkdir_recursive): Declare.

>> 	* common/filestuff.c (mkdir_recursive): Move from

>> 	dwarf-index-cache.c.  Return bool.

> 

> I just stumbled on a build failure caused by this patch, when building for mingw:

> 

>   CXX    unittests/mkdir-recursive-selftests.o

> /home/emaisin/src/binutils-gdb/gdb/unittests/mkdir-recursive-selftests.c: In function ‘void selftests::mkdir_recursive::test()’:

> /home/emaisin/src/binutils-gdb/gdb/unittests/mkdir-recursive-selftests.c:49:20: error: ‘mkdtemp’ was not declared in this scope

>    if (mkdtemp (base) == NULL)

>                     ^

> 

> The function in the original code was guarded by HAVE_MKDTEMP (the register_test

> call still is).  So I guess the function should be put back in an ifdef, or we

> should import the mkdtemp gnulib module (I don't remember why I chose not to do

> that).

> 

> Simon

> 



What do you think about this?


From 4819c8481fe543df991c940137f80a238592c086 Mon Sep 17 00:00:00 2001
From: Simon Marchi <simon.marchi@ericsson.com>

Date: Mon, 29 Oct 2018 16:35:01 -0400
Subject: [PATCH] Import mkdtemp gnulib module, fix mingw build
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Building with mingw currently fails:

  CXX    unittests/mkdir-recursive-selftests.o
/home/emaisin/src/binutils-gdb/gdb/unittests/mkdir-recursive-selftests.c: In function ‘void selftests::mkdir_recursive::test()’:
/home/emaisin/src/binutils-gdb/gdb/unittests/mkdir-recursive-selftests.c:49:20: error: ‘mkdtemp’ was not declared in this scope
   if (mkdtemp (base) == NULL)
                    ^
Commit

    e418a61a67a ("Move mkdir_recursive to common/filestuff.c")

moved this code, but also removed the HAVE_MKDTEMP guard which prevented
the mkdtemp call to be compiled on mingw.

We can either put back the HAVE_MKDTEMP ifdef, or import the gnulib
mkdtemp module, which provides the function for mingw.  Since the
mkdir_recursive is susceptible to be used on mingw at some point, I
think it would be nice to have it tested on mingw, so I did the latter.

Once built, I tested it on Windows (copied the resulting gdb.exe on a
Windows machine, ran it, and ran "maint selftest mkdir_recursive").  It
failed, because the temporary directory is hardcoded to "/tmp/...".  I
therefore added and used a new get_standard_temp_dir function, which
returns an appropriate temporary directory for the host platform.

gdb/ChangeLog:

	* common/pathstuff.c (get_standard_temp_dir): New.
	* common/pathstuff.h (get_standard_temp_dir): New.
	* config.in: Re-generate.
	* configure: Re-generate.
	* configure.ac: Don't check for mkdtemp.
	* gnulib/aclocal-m4-deps.mk: Re-generate.
	* gnulib/aclocal.m4: Re-generate.
	* gnulib/config.in: Re-generate.
	* gnulib/configure: Re-generate.
	* gnulib/import/Makefile.am: Re-generate.
	* gnulib/import/Makefile.in: Re-generate.
	* gnulib/import/m4/gnulib-cache.m4: Re-generate.
	* gnulib/import/m4/gnulib-comp.m4: Re-generate.
	* gnulib/import/m4/mkdtemp.m4: New file.
	* gnulib/import/mkdtemp.c: New file.
	* gnulib/update-gnulib.sh (IMPORTED_GNULIB_MODULES):
	Add mkdtemp module.
	* unittests/mkdir-recursive-selftests.c (test): Use
	get_standard_temp_dir.
	(_initialize_mkdir_recursive_selftests): Remove HAVE_MKDTEMP
	ifdef.
	* compile/compile.c (get_compile_file_tempdir): Likewise.
---
 gdb/common/pathstuff.c                    | 21 ++++++++++
 gdb/common/pathstuff.h                    |  9 +++++
 gdb/compile/compile.c                     |  4 --
 gdb/config.in                             |  3 --
 gdb/configure                             |  2 +-
 gdb/configure.ac                          |  2 +-
 gdb/gnulib/aclocal-m4-deps.mk             |  1 +
 gdb/gnulib/aclocal.m4                     |  1 +
 gdb/gnulib/config.in                      |  6 +++
 gdb/gnulib/configure                      | 47 +++++++++++++++++++++++
 gdb/gnulib/import/Makefile.am             | 11 +++++-
 gdb/gnulib/import/Makefile.in             | 20 +++++-----
 gdb/gnulib/import/m4/gnulib-cache.m4      |  3 +-
 gdb/gnulib/import/m4/gnulib-comp.m4       |  9 +++++
 gdb/gnulib/import/m4/mkdtemp.m4           | 20 ++++++++++
 gdb/gnulib/import/mkdtemp.c               | 39 +++++++++++++++++++
 gdb/gnulib/update-gnulib.sh               |  1 +
 gdb/unittests/mkdir-recursive-selftests.c | 15 ++++----
 18 files changed, 187 insertions(+), 27 deletions(-)
 create mode 100644 gdb/gnulib/import/m4/mkdtemp.m4
 create mode 100644 gdb/gnulib/import/mkdtemp.c

diff --git a/gdb/common/pathstuff.c b/gdb/common/pathstuff.c
index 48ff861edae..c0c575f3fb4 100644
--- a/gdb/common/pathstuff.c
+++ b/gdb/common/pathstuff.c
@@ -193,6 +193,27 @@ get_standard_cache_dir ()

 /* See common/pathstuff.h.  */

+std::string
+get_standard_temp_dir ()
+{
+#ifdef WIN32
+  char *tmp = getenv ("TMP");
+  if (tmp != nullptr)
+    return tmp;
+
+  tmp = getenv ("TEMP");
+  if (tmp != nullptr)
+    return tmp;
+
+  error (_("Couldn't find temp dir path, both TMP and TEMP are unset."));
+
+#else
+  return "/tmp";
+#endif
+}
+
+/* See common/pathstuff.h.  */
+
 const char *
 get_shell ()
 {
diff --git a/gdb/common/pathstuff.h b/gdb/common/pathstuff.h
index d57aafff079..18af733ab98 100644
--- a/gdb/common/pathstuff.h
+++ b/gdb/common/pathstuff.h
@@ -66,6 +66,15 @@ extern bool contains_dir_separator (const char *path);

 extern std::string get_standard_cache_dir ();

+/* Get the usual temporary directory for the current platform.
+
+   On Windows, this is the TMP or TEMP environment variable.  On the rest,
+   it's /tmp.
+
+   Throw an exception on error.  */
+
+extern std::string get_standard_temp_dir ();
+
 /* Return the file name of the user's shell.  Normally this comes from
    the SHELL environment variable.  */

diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c
index ec644a7b5a8..f6f49e0833f 100644
--- a/gdb/compile/compile.c
+++ b/gdb/compile/compile.c
@@ -395,11 +395,7 @@ get_compile_file_tempdir (void)

   strcpy (tname, TEMPLATE);
 #undef TEMPLATE
-#ifdef HAVE_MKDTEMP
   tempdir_name = mkdtemp (tname);
-#else
-  error (_("Command not supported on this host."));
-#endif
   if (tempdir_name == NULL)
     perror_with_name (_("Could not make temporary directory"));

diff --git a/gdb/config.in b/gdb/config.in
index f0d14143520..deb9d4a996e 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -288,9 +288,6 @@
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H

-/* Define to 1 if you have the `mkdtemp' function. */
-#undef HAVE_MKDTEMP
-
 /* Define to 1 if you have a working `mmap' system call. */
 #undef HAVE_MMAP

diff --git a/gdb/configure b/gdb/configure
index 3652455322f..0f3ec4520aa 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -13320,7 +13320,7 @@ for ac_func in getauxval getrusage getuid getgid \
 		sigaction sigprocmask sigsetmask socketpair \
 		ttrace wborder wresize setlocale iconvlist libiconvlist btowc \
 		setrlimit getrlimit posix_madvise waitpid \
-		ptrace64 sigaltstack mkdtemp setns
+		ptrace64 sigaltstack setns
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/gdb/configure.ac b/gdb/configure.ac
index b2343a90e5f..e1ea60660b9 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1359,7 +1359,7 @@ AC_CHECK_FUNCS([getauxval getrusage getuid getgid \
 		sigaction sigprocmask sigsetmask socketpair \
 		ttrace wborder wresize setlocale iconvlist libiconvlist btowc \
 		setrlimit getrlimit posix_madvise waitpid \
-		ptrace64 sigaltstack mkdtemp setns])
+		ptrace64 sigaltstack setns])
 AM_LANGINFO_CODESET
 GDB_AC_COMMON

diff --git a/gdb/gnulib/aclocal-m4-deps.mk b/gdb/gnulib/aclocal-m4-deps.mk
index 5b2c6cc5ea3..ffa003d7613 100644
--- a/gdb/gnulib/aclocal-m4-deps.mk
+++ b/gdb/gnulib/aclocal-m4-deps.mk
@@ -80,6 +80,7 @@ aclocal_m4_deps = \
 	import/m4/mempcpy.m4 \
 	import/m4/memrchr.m4 \
 	import/m4/mkdir.m4 \
+	import/m4/mkdtemp.m4 \
 	import/m4/mkostemp.m4 \
 	import/m4/mmap-anon.m4 \
 	import/m4/mode_t.m4 \
diff --git a/gdb/gnulib/aclocal.m4 b/gdb/gnulib/aclocal.m4
index 861caf6692c..e480633394d 100644
--- a/gdb/gnulib/aclocal.m4
+++ b/gdb/gnulib/aclocal.m4
@@ -1353,6 +1353,7 @@ m4_include([import/m4/memmem.m4])
 m4_include([import/m4/mempcpy.m4])
 m4_include([import/m4/memrchr.m4])
 m4_include([import/m4/mkdir.m4])
+m4_include([import/m4/mkdtemp.m4])
 m4_include([import/m4/mkostemp.m4])
 m4_include([import/m4/mmap-anon.m4])
 m4_include([import/m4/mode_t.m4])
diff --git a/gdb/gnulib/config.in b/gdb/gnulib/config.in
index d23d208cb28..2f1a5405506 100644
--- a/gdb/gnulib/config.in
+++ b/gdb/gnulib/config.in
@@ -203,6 +203,9 @@
 /* Define to 1 when the gnulib module memrchr should be tested. */
 #undef GNULIB_TEST_MEMRCHR

+/* Define to 1 when the gnulib module mkdtemp should be tested. */
+#undef GNULIB_TEST_MKDTEMP
+
 /* Define to 1 when the gnulib module mkostemp should be tested. */
 #undef GNULIB_TEST_MKOSTEMP

@@ -548,6 +551,9 @@
    when it succeeds. */
 #undef HAVE_MINIMALLY_WORKING_GETCWD

+/* Define to 1 if you have the `mkdtemp' function. */
+#undef HAVE_MKDTEMP
+
 /* Define to 1 if you have the 'mkostemp' function. */
 #undef HAVE_MKOSTEMP

diff --git a/gdb/gnulib/configure b/gdb/gnulib/configure
index 5d7f8aa004f..340c622cb39 100644
--- a/gdb/gnulib/configure
+++ b/gdb/gnulib/configure
@@ -5841,6 +5841,7 @@ fi
   # Code from module mempcpy:
   # Code from module memrchr:
   # Code from module mkdir:
+  # Code from module mkdtemp:
   # Code from module mkostemp:
   # Code from module msvc-inval:
   # Code from module msvc-nothrow:
@@ -21891,6 +21892,52 @@ $as_echo "#define FUNC_MKDIR_DOT_BUG 1" >>confdefs.h
   fi


+  for ac_func in mkdtemp
+do :
+  ac_fn_c_check_func "$LINENO" "mkdtemp" "ac_cv_func_mkdtemp"
+if test "x$ac_cv_func_mkdtemp" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_MKDTEMP 1
+_ACEOF
+
+fi
+done
+
+  if test $ac_cv_func_mkdtemp = no; then
+    HAVE_MKDTEMP=0
+  fi
+
+  if test $HAVE_MKDTEMP = 0; then
+
+
+
+
+
+
+
+
+  gl_LIBOBJS="$gl_LIBOBJS mkdtemp.$ac_objext"
+
+    :
+
+  fi
+
+
+
+
+
+          GNULIB_MKDTEMP=1
+
+
+
+
+
+$as_echo "#define GNULIB_TEST_MKDTEMP 1" >>confdefs.h
+
+
+
+
+



diff --git a/gdb/gnulib/import/Makefile.am b/gdb/gnulib/import/Makefile.am
index 608c2c725cf..9dca489ee10 100644
--- a/gdb/gnulib/import/Makefile.am
+++ b/gdb/gnulib/import/Makefile.am
@@ -21,7 +21,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=import --m4-base=import/m4 --doc-base=doc --tests-base=tests --aux-dir=import/extra --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca canonicalize-lgpl dirent dirfd errno fnmatch-gnu frexpl getcwd glob inet_ntop inttypes limits-h lstat memchr memmem mkdir mkostemp pathmax rawmemchr readlink rename setenv signal-h strchrnul strstr strtok_r sys_stat unistd unsetenv update-copyright wchar wctype-h
+# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=import --m4-base=import/m4 --doc-base=doc --tests-base=tests --aux-dir=import/extra --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca canonicalize-lgpl dirent dirfd errno fnmatch-gnu frexpl getcwd glob inet_ntop inttypes limits-h lstat memchr memmem mkdir mkdtemp mkostemp pathmax rawmemchr readlink rename setenv signal-h strchrnul strstr strtok_r sys_stat unistd unsetenv update-copyright wchar wctype-h

 AUTOMAKE_OPTIONS = 1.9.6 gnits

@@ -1223,6 +1223,15 @@ EXTRA_libgnu_a_SOURCES += mkdir.c

 ## end   gnulib module mkdir

+## begin gnulib module mkdtemp
+
+
+EXTRA_DIST += mkdtemp.c
+
+EXTRA_libgnu_a_SOURCES += mkdtemp.c
+
+## end   gnulib module mkdtemp
+
 ## begin gnulib module mkostemp


diff --git a/gdb/gnulib/import/Makefile.in b/gdb/gnulib/import/Makefile.in
index 8b0487ccc75..f433c363485 100644
--- a/gdb/gnulib/import/Makefile.in
+++ b/gdb/gnulib/import/Makefile.in
@@ -35,7 +35,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=import --m4-base=import/m4 --doc-base=doc --tests-base=tests --aux-dir=import/extra --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca canonicalize-lgpl dirent dirfd errno fnmatch-gnu frexpl getcwd glob inet_ntop inttypes limits-h lstat memchr memmem mkdir mkostemp pathmax rawmemchr readlink rename setenv signal-h strchrnul strstr strtok_r sys_stat unistd unsetenv update-copyright wchar wctype-h
+# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=import --m4-base=import/m4 --doc-base=doc --tests-base=tests --aux-dir=import/extra --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca canonicalize-lgpl dirent dirfd errno fnmatch-gnu frexpl getcwd glob inet_ntop inttypes limits-h lstat memchr memmem mkdir mkdtemp mkostemp pathmax rawmemchr readlink rename setenv signal-h strchrnul strstr strtok_r sys_stat unistd unsetenv update-copyright wchar wctype-h



@@ -192,6 +192,7 @@ am__aclocal_m4_deps = $(top_srcdir)/import/m4/00gnulib.m4 \
 	$(top_srcdir)/import/m4/mempcpy.m4 \
 	$(top_srcdir)/import/m4/memrchr.m4 \
 	$(top_srcdir)/import/m4/mkdir.m4 \
+	$(top_srcdir)/import/m4/mkdtemp.m4 \
 	$(top_srcdir)/import/m4/mkostemp.m4 \
 	$(top_srcdir)/import/m4/mmap-anon.m4 \
 	$(top_srcdir)/import/m4/mode_t.m4 \
@@ -1515,9 +1516,9 @@ EXTRA_DIST = m4/gnulib-cache.m4 alloca.c alloca.in.h arpa_inet.in.h \
 	malloca.valgrind math.in.h mbrtowc.c mbsinit.c \
 	mbsrtowcs-impl.h mbsrtowcs-state.c mbsrtowcs.c memchr.c \
 	memchr.valgrind memmem.c str-two-way.h mempcpy.c memrchr.c \
-	mkdir.c mkostemp.c msvc-inval.c msvc-inval.h msvc-nothrow.c \
-	msvc-nothrow.h netinet_in.in.h open.c openat.c openat.h \
-	dirent-private.h opendir.c pathmax.h rawmemchr.c \
+	mkdir.c mkdtemp.c mkostemp.c msvc-inval.c msvc-inval.h \
+	msvc-nothrow.c msvc-nothrow.h netinet_in.in.h open.c openat.c \
+	openat.h dirent-private.h opendir.c pathmax.h rawmemchr.c \
 	rawmemchr.valgrind dirent-private.h readdir.c readlink.c \
 	realloc.c rename.c dirent-private.h rewinddir.c rmdir.c \
 	same-inode.h save-cwd.h secure_getenv.c setenv.c signal.in.h \
@@ -1587,11 +1588,11 @@ EXTRA_libgnu_a_SOURCES = alloca.c openat-proc.c canonicalize-lgpl.c \
 	gettimeofday.c glob.c inet_ntop.c isnan.c isnand.c isnan.c \
 	isnanl.c lstat.c malloc.c mbrtowc.c mbsinit.c \
 	mbsrtowcs-state.c mbsrtowcs.c memchr.c memmem.c mempcpy.c \
-	memrchr.c mkdir.c mkostemp.c msvc-inval.c msvc-nothrow.c \
-	open.c openat.c opendir.c rawmemchr.c readdir.c readlink.c \
-	realloc.c rename.c rewinddir.c rmdir.c secure_getenv.c \
-	setenv.c stat.c strchrnul.c strdup.c strerror.c \
-	strerror-override.c strstr.c strtok_r.c unsetenv.c
+	memrchr.c mkdir.c mkdtemp.c mkostemp.c msvc-inval.c \
+	msvc-nothrow.c open.c openat.c opendir.c rawmemchr.c readdir.c \
+	readlink.c realloc.c rename.c rewinddir.c rmdir.c \
+	secure_getenv.c setenv.c stat.c strchrnul.c strdup.c \
+	strerror.c strerror-override.c strstr.c strtok_r.c unsetenv.c

 # Use this preprocessor expression to decide whether #include_next works.
 # Do not rely on a 'configure'-time test for this, since the expression
@@ -1722,6 +1723,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mempcpy.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memrchr.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mkdir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mkdtemp.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mkostemp.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msvc-inval.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msvc-nothrow.Po@am__quote@
diff --git a/gdb/gnulib/import/m4/gnulib-cache.m4 b/gdb/gnulib/import/m4/gnulib-cache.m4
index 8cefb67be7c..4cbd1a76fa4 100644
--- a/gdb/gnulib/import/m4/gnulib-cache.m4
+++ b/gdb/gnulib/import/m4/gnulib-cache.m4
@@ -27,7 +27,7 @@


 # Specification in the form of a command-line invocation:
-#   gnulib-tool --import --lib=libgnu --source-base=import --m4-base=import/m4 --doc-base=doc --tests-base=tests --aux-dir=import/extra --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca canonicalize-lgpl dirent dirfd errno fnmatch-gnu frexpl getcwd glob inet_ntop inttypes limits-h lstat memchr memmem mkdir mkostemp pathmax rawmemchr readlink rename setenv signal-h strchrnul strstr strtok_r sys_stat unistd unsetenv update-copyright wchar wctype-h
+#   gnulib-tool --import --lib=libgnu --source-base=import --m4-base=import/m4 --doc-base=doc --tests-base=tests --aux-dir=import/extra --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca canonicalize-lgpl dirent dirfd errno fnmatch-gnu frexpl getcwd glob inet_ntop inttypes limits-h lstat memchr memmem mkdir mkdtemp mkostemp pathmax rawmemchr readlink rename setenv signal-h strchrnul strstr strtok_r sys_stat unistd unsetenv update-copyright wchar wctype-h

 # Specification in the form of a few gnulib-tool.m4 macro invocations:
 gl_LOCAL_DIR([])
@@ -48,6 +48,7 @@ gl_MODULES([
   memchr
   memmem
   mkdir
+  mkdtemp
   mkostemp
   pathmax
   rawmemchr
diff --git a/gdb/gnulib/import/m4/gnulib-comp.m4 b/gdb/gnulib/import/m4/gnulib-comp.m4
index 2c55958eb7e..1700bdd3cf0 100644
--- a/gdb/gnulib/import/m4/gnulib-comp.m4
+++ b/gdb/gnulib/import/m4/gnulib-comp.m4
@@ -121,6 +121,7 @@ AC_DEFUN([gl_EARLY],
   # Code from module mempcpy:
   # Code from module memrchr:
   # Code from module mkdir:
+  # Code from module mkdtemp:
   # Code from module mkostemp:
   # Code from module msvc-inval:
   # Code from module msvc-nothrow:
@@ -444,6 +445,12 @@ AC_DEFUN([gl_INIT],
   if test $REPLACE_MKDIR = 1; then
     AC_LIBOBJ([mkdir])
   fi
+  gl_FUNC_MKDTEMP
+  if test $HAVE_MKDTEMP = 0; then
+    AC_LIBOBJ([mkdtemp])
+    gl_PREREQ_MKDTEMP
+  fi
+  gl_STDLIB_MODULE_INDICATOR([mkdtemp])
   gl_FUNC_MKOSTEMP
   if test $HAVE_MKOSTEMP = 0; then
     AC_LIBOBJ([mkostemp])
@@ -845,6 +852,7 @@ AC_DEFUN([gl_FILE_LIST], [
   lib/mempcpy.c
   lib/memrchr.c
   lib/mkdir.c
+  lib/mkdtemp.c
   lib/mkostemp.c
   lib/msvc-inval.c
   lib/msvc-inval.h
@@ -992,6 +1000,7 @@ AC_DEFUN([gl_FILE_LIST], [
   m4/mempcpy.m4
   m4/memrchr.m4
   m4/mkdir.m4
+  m4/mkdtemp.m4
   m4/mkostemp.m4
   m4/mmap-anon.m4
   m4/mode_t.m4
diff --git a/gdb/gnulib/import/m4/mkdtemp.m4 b/gdb/gnulib/import/m4/mkdtemp.m4
new file mode 100644
index 00000000000..a2edd395005
--- /dev/null
+++ b/gdb/gnulib/import/m4/mkdtemp.m4
@@ -0,0 +1,20 @@
+# mkdtemp.m4 serial 8
+dnl Copyright (C) 2001-2003, 2006-2007, 2009-2016 Free Software Foundation,
+dnl Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_MKDTEMP],
+[
+  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+  AC_CHECK_FUNCS([mkdtemp])
+  if test $ac_cv_func_mkdtemp = no; then
+    HAVE_MKDTEMP=0
+  fi
+])
+
+# Prerequisites of lib/mkdtemp.c
+AC_DEFUN([gl_PREREQ_MKDTEMP],
+[:
+])
diff --git a/gdb/gnulib/import/mkdtemp.c b/gdb/gnulib/import/mkdtemp.c
new file mode 100644
index 00000000000..c1b05fd8ada
--- /dev/null
+++ b/gdb/gnulib/import/mkdtemp.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 1999, 2001-2003, 2006-2007, 2009-2016 Free Software
+   Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Extracted from misc/mkdtemp.c.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <stdlib.h>
+
+#include "tempname.h"
+
+/* Generate a unique temporary directory from XTEMPLATE.
+   The last six characters of XTEMPLATE must be "XXXXXX";
+   they are replaced with a string that makes the filename unique.
+   The directory is created, mode 700, and its name is returned.
+   (This function comes from OpenBSD.) */
+char *
+mkdtemp (char *xtemplate)
+{
+  if (gen_tempname (xtemplate, 0, 0, GT_DIR))
+    return NULL;
+  else
+    return xtemplate;
+}
diff --git a/gdb/gnulib/update-gnulib.sh b/gdb/gnulib/update-gnulib.sh
index 5129450577d..e67565a0e72 100755
--- a/gdb/gnulib/update-gnulib.sh
+++ b/gdb/gnulib/update-gnulib.sh
@@ -46,6 +46,7 @@ IMPORTED_GNULIB_MODULES="\
     memchr \
     memmem \
     mkdir \
+    mkdtemp \
     mkostemp \
     pathmax \
     rawmemchr \
diff --git a/gdb/unittests/mkdir-recursive-selftests.c b/gdb/unittests/mkdir-recursive-selftests.c
index d501f8e0817..5a5c453ad6a 100644
--- a/gdb/unittests/mkdir-recursive-selftests.c
+++ b/gdb/unittests/mkdir-recursive-selftests.c
@@ -21,6 +21,8 @@

 #include "common/filestuff.h"
 #include "selftest.h"
+#include "common/byte-vector.h"
+#include "common/pathstuff.h"

 namespace selftests {
 namespace mkdir_recursive {
@@ -44,9 +46,10 @@ create_dir_and_check (const char *dir)
 static void
 test ()
 {
-  char base[] = "/tmp/gdb-selftests-XXXXXX";
+  std::string tmp = get_standard_temp_dir () + "/gdb-selftests";
+  gdb::char_vector base = make_temp_filename (tmp);

-  if (mkdtemp (base) == NULL)
+  if (mkdtemp (base.data ()) == NULL)
     perror_with_name (("mkdtemp"));

   /* Try not to leave leftover directories.  */
@@ -66,12 +69,12 @@ test ()

   private:
     const char *m_base;
-  } cleanup_dirs (base);
+  } cleanup_dirs (base.data ());

-  std::string dir = string_printf ("%s/a/b", base);
+  std::string dir = string_printf ("%s/a/b", base.data ());
   SELF_CHECK (create_dir_and_check (dir.c_str ()));

-  dir = string_printf ("%s/a/b/c//d/e/", base);
+  dir = string_printf ("%s/a/b/c//d/e/", base.data ());
   SELF_CHECK (create_dir_and_check (dir.c_str ()));
 }

@@ -81,9 +84,7 @@ test ()
 void
 _initialize_mkdir_recursive_selftests ()
 {
-#if defined (HAVE_MKDTEMP)
   selftests::register_test ("mkdir_recursive",
 			    selftests::mkdir_recursive::test);
-#endif
 }

-- 
2.19.1
Tom Tromey Oct. 30, 2018, 8:55 p.m. | #3
>>>>> "Simon" == Simon Marchi <simon.marchi@ericsson.com> writes:


Simon> What do you think about this?

Thanks for doing this.

Simon>  /* See common/pathstuff.h.  */

Simon> +std::string
Simon> +get_standard_temp_dir ()
Simon> +{
Simon> +#ifdef WIN32
Simon> +  char *tmp = getenv ("TMP");
Simon> +  if (tmp != nullptr)
Simon> +    return tmp;
Simon> +
Simon> +  tmp = getenv ("TEMP");
Simon> +  if (tmp != nullptr)
Simon> +    return tmp;
Simon> +
Simon> +  error (_("Couldn't find temp dir path, both TMP and TEMP are unset."));
Simon> +
Simon> +#else
Simon> +  return "/tmp";

It would be normal to look at TMPDIR on unix systems.

Tom
Simon Marchi Oct. 30, 2018, 9:03 p.m. | #4
On 2018-10-30 4:55 p.m., Tom Tromey wrote:
>>>>>> "Simon" == Simon Marchi <simon.marchi@ericsson.com> writes:

> 

> Simon> What do you think about this?

> 

> Thanks for doing this.

> 

> Simon>  /* See common/pathstuff.h.  */

> 

> Simon> +std::string

> Simon> +get_standard_temp_dir ()

> Simon> +{

> Simon> +#ifdef WIN32

> Simon> +  char *tmp = getenv ("TMP");

> Simon> +  if (tmp != nullptr)

> Simon> +    return tmp;

> Simon> +

> Simon> +  tmp = getenv ("TEMP");

> Simon> +  if (tmp != nullptr)

> Simon> +    return tmp;

> Simon> +

> Simon> +  error (_("Couldn't find temp dir path, both TMP and TEMP are unset."));

> Simon> +

> Simon> +#else

> Simon> +  return "/tmp";

> 

> It would be normal to look at TMPDIR on unix systems.


Ah, indeed.  How is it with this little fixup on top of the patch?


From e8b9d0eabfb9bd85afcf42af9bdfb6a5bde66fc2 Mon Sep 17 00:00:00 2001
From: Simon Marchi <simon.marchi@ericsson.com>

Date: Tue, 30 Oct 2018 17:01:50 -0400
Subject: [PATCH] fixup

---
 gdb/common/pathstuff.c | 4 ++++
 gdb/common/pathstuff.h | 5 +++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/gdb/common/pathstuff.c b/gdb/common/pathstuff.c
index c0c575f3fb4..166a21593eb 100644
--- a/gdb/common/pathstuff.c
+++ b/gdb/common/pathstuff.c
@@ -208,6 +208,10 @@ get_standard_temp_dir ()
   error (_("Couldn't find temp dir path, both TMP and TEMP are unset."));

 #else
+  char *tmp = getenv ("TMPDIR");
+  if (tmp != nullptr)
+    return tmp;
+
   return "/tmp";
 #endif
 }
diff --git a/gdb/common/pathstuff.h b/gdb/common/pathstuff.h
index 18af733ab98..f29349e8b28 100644
--- a/gdb/common/pathstuff.h
+++ b/gdb/common/pathstuff.h
@@ -68,8 +68,9 @@ extern std::string get_standard_cache_dir ();

 /* Get the usual temporary directory for the current platform.

-   On Windows, this is the TMP or TEMP environment variable.  On the rest,
-   it's /tmp.
+   On Windows, this is the TMP or TEMP environment variable.
+
+   On the rest, this is the TMPDIR environment variable, if defined, else /tmp.

    Throw an exception on error.  */

-- 
2.19.1
Tom Tromey Oct. 31, 2018, 3:03 p.m. | #5
>>>>> "Simon" == Simon Marchi <simon.marchi@ericsson.com> writes:


>> It would be normal to look at TMPDIR on unix systems.


Simon> Ah, indeed.  How is it with this little fixup on top of the patch?

Seems reasonable, thanks!

Simon> +  char *tmp = getenv ("TMPDIR");

A tiny nit: you can use const char * here.

Tom
Simon Marchi Nov. 1, 2018, 7:44 p.m. | #6
On 2018-10-31 11:03, Tom Tromey wrote:
>>>>>> "Simon" == Simon Marchi <simon.marchi@ericsson.com> writes:

> 

>>> It would be normal to look at TMPDIR on unix systems.

> 

> Simon> Ah, indeed.  How is it with this little fixup on top of the 

> patch?

> 

> Seems reasonable, thanks!

> 

> Simon> +  char *tmp = getenv ("TMPDIR");

> 

> A tiny nit: you can use const char * here.

> 

> Tom


Pushed with that fixed, thanks!

Simon

Patch

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 0bb203f45f..4ab0da5c61 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -419,6 +419,7 @@  SUBDIR_UNITTESTS_SRCS = \
 	unittests/optional-selftests.c \
 	unittests/parse-connection-spec-selftests.c \
 	unittests/ptid-selftests.c \
+	unittests/mkdir-recursive-selftests.c \
 	unittests/rsp-low-selftests.c \
 	unittests/scoped_fd-selftests.c \
 	unittests/scoped_mmap-selftests.c \
diff --git a/gdb/common/filestuff.c b/gdb/common/filestuff.c
index dfd86f9fbb..d4bd1a8cb8 100644
--- a/gdb/common/filestuff.c
+++ b/gdb/common/filestuff.c
@@ -447,3 +447,48 @@  is_regular_file (const char *name, int *errno_ptr)
     *errno_ptr = EINVAL;
   return false;
 }
+
+/* See common/filestuff.h.  */
+
+bool
+mkdir_recursive (const char *dir)
+{
+  gdb::unique_xmalloc_ptr<char> holder (xstrdup (dir));
+  char * const start = holder.get ();
+  char *component_start = start;
+  char *component_end = start;
+
+  while (1)
+    {
+      /* Find the beginning of the next component.  */
+      while (*component_start == '/')
+	component_start++;
+
+      /* Are we done?  */
+      if (*component_start == '\0')
+	return true;
+
+      /* Find the slash or null-terminator after this component.  */
+      component_end = component_start;
+      while (*component_end != '/' && *component_end != '\0')
+	component_end++;
+
+      /* Temporarily replace the slash with a null terminator, so we can create
+         the directory up to this component.  */
+      char saved_char = *component_end;
+      *component_end = '\0';
+
+      /* If we get EEXIST and the existing path is a directory, then we're
+         happy.  If it exists, but it's a regular file and this is not the last
+         component, we'll fail at the next component.  If this is the last
+         component, the caller will fail with ENOTDIR when trying to
+         open/create a file under that path.  */
+      if (mkdir (start, 0700) != 0)
+	if (errno != EEXIST)
+	  return false;
+
+      /* Restore the overwritten char.  */
+      *component_end = saved_char;
+      component_start = component_end;
+    }
+}
diff --git a/gdb/common/filestuff.h b/gdb/common/filestuff.h
index e9328f5358..ecfc18d600 100644
--- a/gdb/common/filestuff.h
+++ b/gdb/common/filestuff.h
@@ -122,4 +122,14 @@  typedef std::unique_ptr<DIR, gdb_dir_deleter> gdb_dir_up;
    we're expecting a regular file.  */
 extern bool is_regular_file (const char *name, int *errno_ptr);
 
+
+/* A cheap (as in low-quality) recursive mkdir.  Try to create all the
+   parents directories up to DIR and DIR itself.  Stop if we hit an
+   error along the way.  There is no attempt to remove created
+   directories in case of failure.
+
+   Returns false on failure and sets errno.  */
+
+extern bool mkdir_recursive (const char *dir);
+
 #endif /* FILESTUFF_H */
diff --git a/gdb/dwarf-index-cache.c b/gdb/dwarf-index-cache.c
index 966630b60c..bac98f9db8 100644
--- a/gdb/dwarf-index-cache.c
+++ b/gdb/dwarf-index-cache.c
@@ -45,53 +45,6 @@  index_cache global_index_cache;
 static cmd_list_element *set_index_cache_prefix_list;
 static cmd_list_element *show_index_cache_prefix_list;
 
-/* A cheap (as in low-quality) recursive mkdir.  Try to create all the parents
-   directories up to DIR and DIR itself.  Stop if we hit an error along the way.
-   There is no attempt to remove created directories in case of failure.  */
-
-static void
-mkdir_recursive (const char *dir)
-{
-  gdb::unique_xmalloc_ptr<char> holder (xstrdup (dir));
-  char * const start = holder.get ();
-  char *component_start = start;
-  char *component_end = start;
-
-  while (1)
-    {
-      /* Find the beginning of the next component.  */
-      while (*component_start == '/')
-	component_start++;
-
-      /* Are we done?  */
-      if (*component_start == '\0')
-	return;
-
-      /* Find the slash or null-terminator after this component.  */
-      component_end = component_start;
-      while (*component_end != '/' && *component_end != '\0')
-	component_end++;
-
-      /* Temporarily replace the slash with a null terminator, so we can create
-         the directory up to this component.  */
-      char saved_char = *component_end;
-      *component_end = '\0';
-
-      /* If we get EEXIST and the existing path is a directory, then we're
-         happy.  If it exists, but it's a regular file and this is not the last
-         component, we'll fail at the next component.  If this is the last
-         component, the caller will fail with ENOTDIR when trying to
-         open/create a file under that path.  */
-      if (mkdir (start, 0700) != 0)
-	if (errno != EEXIST)
-	  return;
-
-      /* Restore the overwritten char.  */
-      *component_end = saved_char;
-      component_start = component_end;
-    }
-}
-
 /* Default destructor of index_cache_resource.  */
 index_cache_resource::~index_cache_resource () = default;
 
@@ -160,7 +113,12 @@  index_cache::store (struct dwarf2_per_objfile *dwarf2_per_objfile)
   TRY
     {
       /* Try to create the containing directory.  */
-      mkdir_recursive (m_dir.c_str ());
+      if (!mkdir_recursive (m_dir.c_str ()))
+	{
+	  warning (_("index cache: could not make cache directory: %s\n"),
+		   safe_strerror (errno));
+	  return;
+	}
 
       if (debug_index_cache)
         printf_unfiltered ("index cache: writing index cache for objfile %s\n",
@@ -346,62 +304,6 @@  show_index_cache_stats_command (const char *arg, int from_tty)
 		     indent, global_index_cache.n_misses ());
 }
 
-#if GDB_SELF_TEST && defined (HAVE_MKDTEMP)
-namespace selftests
-{
-
-/* Try to create DIR using mkdir_recursive and make sure it exists.  */
-
-static bool
-create_dir_and_check (const char *dir)
-{
-  mkdir_recursive (dir);
-
-  struct stat st;
-  if (stat (dir, &st) != 0)
-    perror_with_name (("stat"));
-
-  return (st.st_mode & S_IFDIR) != 0;
-}
-
-/* Test mkdir_recursive.  */
-
-static void
-test_mkdir_recursive ()
-{
-  char base[] = "/tmp/gdb-selftests-XXXXXX";
-
-  if (mkdtemp (base) == NULL)
-    perror_with_name (("mkdtemp"));
-
-  /* Try not to leave leftover directories.  */
-  struct cleanup_dirs {
-    cleanup_dirs (const char *base)
-      : m_base (base)
-    {}
-
-    ~cleanup_dirs () {
-      rmdir (string_printf ("%s/a/b/c/d/e", m_base).c_str ());
-      rmdir (string_printf ("%s/a/b/c/d", m_base).c_str ());
-      rmdir (string_printf ("%s/a/b/c", m_base).c_str ());
-      rmdir (string_printf ("%s/a/b", m_base).c_str ());
-      rmdir (string_printf ("%s/a", m_base).c_str ());
-      rmdir (m_base);
-    }
-
-  private:
-    const char *m_base;
-  } cleanup_dirs (base);
-
-  std::string dir = string_printf ("%s/a/b", base);
-  SELF_CHECK (create_dir_and_check (dir.c_str ()));
-
-  dir = string_printf ("%s/a/b/c//d/e/", base);
-  SELF_CHECK (create_dir_and_check (dir.c_str ()));
-}
-}
-#endif /*  GDB_SELF_TEST && defined (HAVE_MKDTEMP) */
-
 void
 _initialize_index_cache ()
 {
@@ -456,8 +358,4 @@  _initialize_index_cache ()
 When non-zero, debugging output for the index cache is displayed."),
 			    NULL, NULL,
 			    &setdebuglist, &showdebuglist);
-
-#if GDB_SELF_TEST && defined (HAVE_MKDTEMP)
-  selftests::register_test ("mkdir_recursive", selftests::test_mkdir_recursive);
-#endif
 }
diff --git a/gdb/unittests/mkdir-recursive-selftests.c b/gdb/unittests/mkdir-recursive-selftests.c
new file mode 100644
index 0000000000..d501f8e081
--- /dev/null
+++ b/gdb/unittests/mkdir-recursive-selftests.c
@@ -0,0 +1,89 @@ 
+/* Self tests for scoped_fd for GDB, the GNU debugger.
+
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+
+#include "common/filestuff.h"
+#include "selftest.h"
+
+namespace selftests {
+namespace mkdir_recursive {
+
+/* Try to create DIR using mkdir_recursive and make sure it exists.  */
+
+static bool
+create_dir_and_check (const char *dir)
+{
+  ::mkdir_recursive (dir);
+
+  struct stat st;
+  if (stat (dir, &st) != 0)
+    perror_with_name (("stat"));
+
+  return (st.st_mode & S_IFDIR) != 0;
+}
+
+/* Test mkdir_recursive.  */
+
+static void
+test ()
+{
+  char base[] = "/tmp/gdb-selftests-XXXXXX";
+
+  if (mkdtemp (base) == NULL)
+    perror_with_name (("mkdtemp"));
+
+  /* Try not to leave leftover directories.  */
+  struct cleanup_dirs {
+    cleanup_dirs (const char *base)
+      : m_base (base)
+    {}
+
+    ~cleanup_dirs () {
+      rmdir (string_printf ("%s/a/b/c/d/e", m_base).c_str ());
+      rmdir (string_printf ("%s/a/b/c/d", m_base).c_str ());
+      rmdir (string_printf ("%s/a/b/c", m_base).c_str ());
+      rmdir (string_printf ("%s/a/b", m_base).c_str ());
+      rmdir (string_printf ("%s/a", m_base).c_str ());
+      rmdir (m_base);
+    }
+
+  private:
+    const char *m_base;
+  } cleanup_dirs (base);
+
+  std::string dir = string_printf ("%s/a/b", base);
+  SELF_CHECK (create_dir_and_check (dir.c_str ()));
+
+  dir = string_printf ("%s/a/b/c//d/e/", base);
+  SELF_CHECK (create_dir_and_check (dir.c_str ()));
+}
+
+}
+}
+
+void
+_initialize_mkdir_recursive_selftests ()
+{
+#if defined (HAVE_MKDTEMP)
+  selftests::register_test ("mkdir_recursive",
+			    selftests::mkdir_recursive::test);
+#endif
+}
+