Web lists-archives.com

[Mingw-users] Multiple definition of `vsnprintf' when building C++ programs

As followup to the previous problem I reported when building GDB 8.0
pretest, I upgraded to mingwrt-5.0, which fixed the issue with
to_string, but introduced a new problem -- linking GDB failed thusly:

     d:/usr/lib/libmingwex.a(vsnprintf.o):(.text+0x0): multiple definition of `vsnprintf'
     cli-script.o:d:/usr/include/stdio.h:427: first defined here
     collect2.exe: error: ld returned 1 exit status

This happens because the GDB build defines __USE_MINGW_ANSI_STDIO in
its headers, and when a C++ program does that, including <stdio.h> and
<string> in a source file will (a) define vsnprintf as an inline
function, and (b) pull vsnprintf.o from libmingwex because it needs
__mingw_vsnprintf.  But vsnprintf.c from libmingwex also defines (a
non-inline version of) vsnprintf, and thus the above error.

(This doesn't happen in C programs because for C stdio.h defines
vsnprintf as a static inline function.)

I attach below a small nonsense program, which I concocted from bits
and pieces of GDB's cli-script.c; it can be used to reproduce this
problem.  It builds OK with mingwrt-3.22.2, but not with mingwrt-5.0,
using the same libstdc++ headers from the MinGW GCC 5.3.0

Any ideas for solutions are welcome.  (I assume that undefining
__USE_MINGW_ANSI_STDIO before including stdio.h is not a good idea,
since it will cause a non-compliant vsnprintf from msvcrt to be used,
which will subtly break the program.)

Here's the test program:

// ts.c
// Compile with 'g++ -std=gnu++11 -O2 -c ts.c -o ts.o',
// then examine the result with 'nm -A'.
// Or try building with 'g++ -std=gnu++11 -O2 ts.c -o ts.exe',
// and see it fail.
#include <stdio.h>

// The following 3 macros are for mingwrt-3.22, not needed for 5.0
#ifndef _GLIBCXX_USE_C99
#define _GLIBCXX_USE_C99 1
#ifndef _ISOC99_SOURCE
#define _ISOC99_SOURCE

#include <string>
#include <vector>

struct string_view
  string_view (const char *str_, size_t len_)
    : str (str_), len (len_)

  const char *str;
  size_t len;

class user_args
  /* Save the command line and store the locations of arguments passed
     to the user defined function.  */
  explicit user_args (const char *line);

  /* Insert the stored user defined arguments into the $arg arguments
     found in LINE.  */
  std::string insert_args (const char *line) const;

  /* The arguments.  Each element points inside M_COMMAND_LINE.  */
  std::vector<string_view> m_args;

static std::vector<user_args> user_args_stack;

user_args::insert_args (const char *line) const
  std::string new_line;
  new_line += std::to_string (m_args.size ());
  return new_line;

main (int argc, char *argv[])
  char line[80];
  const user_args &args = user_args_stack.back ();
  args.insert_args (line);
  return 0;

Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
MinGW-users mailing list

This list observes the Etiquette found at 
We ask that you be polite and do the same.  Disregard for the list etiquette may cause your account to be moderated.

You may change your MinGW Account Options or unsubscribe at:
Also: mailto:mingw-users-request@xxxxxxxxxxxxxxxxxxxxx?subject=unsubscribe