views:

95

answers:

0

Hello I have problem with using std::locale::facets from DLL.

It seems that locale "id" is not shared between DLL and the source. has_facet reports that "facet exists" on different kind of facet. And facet ids reported incorrectly.

In the below example, foo::id and bar::id are seems to be the same and the has_facet reports true on uninstalled facet.

The question is: How to workaround this issue?

This is a simple example:

facet.h:

#include <locale>

#ifdef DLL_EXPORT
#       ifdef FOO_SOURCE
#               define API __declspec(dllexport)
#       else
#               define API __declspec(dllimport)
#       endif
#else
#       define API
#endif

class API bar : public std::locale::facet  {
public:
        bar(size_t refs=0) :
                std::locale::facet(refs)

        {
        }

        int test() const;

        static std::locale::id id;
        virtual ~bar() {}
};


class API foo : public std::locale::facet  {
public:
        foo(size_t refs=0) :
                std::locale::facet(refs)

        {
        }

        int test() const;

        static std::locale::id id;
        virtual ~foo() {}
};

std::locale API create();

Facet.cpp:

#define FOO_SOURCE
#include "facet.h"

std::locale::id foo::id;

int foo::test() const
{
        return id._M_id();
}

std::locale::id bar::id;

int bar::test() const
{
        return id._M_id();
}

std::locale API create()
{
        std::locale l(std::locale(),new foo());
        return l;
}

And simple test program:

#include <iostream>
#include "facet.h"
using namespace std;

int main()
{
        std::locale l=create();
        std::cout << has_facet<foo>(l) << std::endl;
        std::cout << has_facet<bar>(l) << std::endl;
        std::cout << foo::id._M_id() << std::endl;
        std::cout << bar::id._M_id() << std::endl;
        std::cout << use_facet<foo>(l).test() << std::endl;
        return 0;
}

If I compile it:

g++ -DDLL_EXPORT -shared facet.cpp -o facet.dll -Wl,--out-implib,libfacet.dll.a
g++ -DDLL_EXPORT test.cpp libfacet.dll.a

And run: I get true locale l having both foo and bar, when this is incorrect and when I compile statically:

g++ test.cpp facet.cpp

Everything works fine.

Form what I had found, the class std::locale::id defined as:

class locale::id {
...
   // Last id number assigned.
   static _Atomic_word         _S_refcount;
...
};

And it is not exported... So static member _S_refcount is not shared between DLL and the executable (damned dlls).

Is there any way to workaround this issue?

Solution for MinGW:

Use gcc 4.x, under MinGW + gcc-4.4 it works fine.

Still looking for solution for Cygwin, gcc-4.3 fails to compile and run this code... Some dll mess.