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
distribution.

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.
#define __USE_MINGW_ANSI_STDIO 1
#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
#endif
#ifndef _ISOC99_SOURCE
#define _ISOC99_SOURCE
#endif
#ifndef _GLIBCXX_HAVE_WCSTOF
#define _GLIBCXX_HAVE_WCSTOF 1
#endif

#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
{
public:
  /* 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;

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

int
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
MinGW-users@xxxxxxxxxxxxxxxxxxxxx

This list observes the Etiquette found at 
http://www.mingw.org/Mailing_Lists.
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:
https://lists.sourceforge.net/lists/listinfo/mingw-users
Also: mailto:mingw-users-request@xxxxxxxxxxxxxxxxxxxxx?subject=unsubscribe