Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

/MD vs /MT

7 views
Skip to first unread message

mathieu

unread,
May 27, 2008, 6:06:34 PM5/27/08
to
Hi there,

I would like to know what are the subtle differences in between an
app+libs compiled with /MD versus an app+libs compiled with /MT.
Summary of issue:
I am getting a segfault when building my pet project 'gdcm' using /MT
while nothing seems to be going on wrong using /MD (linux+gcc seems to
be fine too).

I searched through the svn history and found the latest working rev
to be 2848, what I did at rev 2849 is simply move one main C++ class
from a shared lib to another:

http://gdcm.svn.sourceforge.net/viewvc/gdcm?view=rev&revision=2849

Thanks for pointers/suggestions

-Mathieu

Joseph M. Newcomer

unread,
May 27, 2008, 8:04:57 PM5/27/08
to
This question presumes that the reader of the question has the vaguest idea about what /MD
and /MT do, as if this is something we care about in the slightest. I'm sure these
switches exist, but I handle them by selecting options in the "Project Properties". So
why not express the question in terms the rest of us use?

Note that /MD is very carefully stated as creating a DLL, and you would use this if you
were created a .dll file. /MT is used to create a multithreaded executable, and therefore
would be used only if you were created a .exe file. So the answer is, they are
incompatible choices and which one you choose depends on whether you are created a .exe or
a .dll, a parameter you seem to have omitted; you say something like "app+libs" which as
far as I can tell is content-free. A .lib file is something else entirely. Had you said
"exe+dll" it might have made sense, in which case you would use the /MT option for the
.exe and /MD for the .dlls. So please ask this question again, explaining EXACTLY what
you are doing, and, for example, why you are thinking about command line switches when
most of us think of project options.
joe

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Doug Harrison [MVP]

unread,
May 27, 2008, 8:50:21 PM5/27/08
to
On Tue, 27 May 2008 15:06:34 -0700 (PDT), mathieu
<mathieu....@gmail.com> wrote:

>Hi there,
>
> I would like to know what are the subtle differences in between an
>app+libs compiled with /MD versus an app+libs compiled with /MT.
> Summary of issue:
>I am getting a segfault when building my pet project 'gdcm' using /MT
>while nothing seems to be going on wrong using /MD (linux+gcc seems to
>be fine too).

The /MD option causes you to use the multithreaded CRT in DLL form, while
/MT causes you to use the multithreaded CRT in static library form. If your
"app+libs" means EXE plus static libraries, then of course all must use the
same CRT flavor and be compiled with the same compiler version. If your
"app+libs" means EXE plus DLLs, and you expect them to share CRT state such
as the heap, C-level file descriptors, and so forth, you must consider it
equivalent to static linking WRT compilation dependencies, plus you must
link everyone to the same CRT DLL. Call this "Case 1". Only a DLL that is
treated as a black box, which shares no state with anyone, and which only
exposes a C-like API, may choose its CRT independently of its clients. Call
this "Case 2".

> I searched through the svn history and found the latest working rev
>to be 2848, what I did at rev 2849 is simply move one main C++ class
>from a shared lib to another:
>
>http://gdcm.svn.sourceforge.net/viewvc/gdcm?view=rev&revision=2849

If the C++ class is shared between modules (EXE and DLLs), you almost
certainly have the "Case 1" scenario described above. Given that /MD works
while /MT doesn't, I'd suspect that the other modules you link to are using
/MD. Thus, when you use /MT, and you try to delete an object that was
created in a /MD module, you end up trying to return it to the wrong heap,
or when you use a file descriptor that was created in a /MD module, you end
up using an empy IO block, etc etc etc.


--
Doug Harrison
Visual C++ MVP

mathieu

unread,
May 28, 2008, 3:54:03 AM5/28/08
to
Hi Joseph,

On May 28, 2:04 am, Joseph M. Newcomer <newco...@flounder.com> wrote:
> This question presumes that the reader of the question has the vaguest idea about what /MD
> and /MT do, as if this is something we care about in the slightest. I'm sure these
> switches exist, but I handle them by selecting options in the "Project Properties". So
> why not express the question in terms the rest of us use?

Sorry, I use cmake which is basically an abstraction layer above
Makefiles on *NIX and Visual Studio dsw/sln on Win32/Win64 system. I
have never used the Visual Studio interface directly.

> Note that /MD is very carefully stated as creating a DLL, and you would use this if you
> were created a .dll file. /MT is used to create a multithreaded executable, and therefore
> would be used only if you were created a .exe file. So the answer is, they are
> incompatible choices and which one you choose depends on whether you are created a .exe or
> a .dll, a parameter you seem to have omitted; you say something like "app+libs" which as
> far as I can tell is content-free. A .lib file is something else entirely. Had you said
> "exe+dll" it might have made sense, in which case you would use the /MT option for the
> .exe and /MD for the .dlls.
> So please ask this question again, explaining EXACTLY what
> you are doing, and, for example, why you are thinking about command line switches when
> most of us think of project options.

Again CMake is doing this for me. I do not need to know I am using
VCExpress/Visual Studio or NMake, I only work at the abstraction
level.
I had actually to dig into the generated file to compare what was done
in what case that was different from the other.

Just for reference, the free VCToolkit 2003 can only be used to
compile C++ using /MT, while VS2005 & VS2008 handle both switch: /MT
& /MD (that how I noticed the issue).

Thanks anyway,
-Mathieu

mathieu

unread,
May 28, 2008, 3:57:57 AM5/28/08
to
Hi Doug,

On May 28, 2:50 am, "Doug Harrison [MVP]" <d...@mvps.org> wrote:
> On Tue, 27 May 2008 15:06:34 -0700 (PDT), mathieu
>

> <mathieu.malate...@gmail.com> wrote:
> >Hi there,
>
> > I would like to know what are the subtle differences in between an
> >app+libs compiled with /MD versus an app+libs compiled with /MT.
> > Summary of issue:
> >I am getting a segfault when building my pet project 'gdcm' using /MT
> >while nothing seems to be going on wrong using /MD (linux+gcc seems to
> >be fine too).
>
> The /MD option causes you to use the multithreaded CRT in DLL form, while
> /MT causes you to use the multithreaded CRT in static library form.

ok

> If your
> "app+libs" means EXE plus static libraries, then of course all must use the
> same CRT flavor and be compiled with the same compiler version. If your
> "app+libs" means EXE plus DLLs, and you expect them to share CRT state such
> as the heap, C-level file descriptors, and so forth, you must consider it
> equivalent to static linking WRT compilation dependencies, plus you must
> link everyone to the same CRT DLL. Call this "Case 1". Only a DLL that is
> treated as a black box, which shares no state with anyone, and which only
> exposes a C-like API, may choose its CRT independently of its clients. Call
> this "Case 2".
>
> > I searched through the svn history and found the latest working rev
> >to be 2848, what I did at rev 2849 is simply move one main C++ class
> >from a shared lib to another:
>
> >http://gdcm.svn.sourceforge.net/viewvc/gdcm?view=rev&revision=2849
>
> If the C++ class is shared between modules (EXE and DLLs), you almost
> certainly have the "Case 1" scenario described above.

Do you mean inline member function being both in the DLL and the EXE,
for example ?

> Given that /MD works
> while /MT doesn't, I'd suspect that the other modules you link to are using
> /MD. Thus, when you use /MT, and you try to delete an object that was
> created in a /MD module, you end up trying to return it to the wrong heap,
> or when you use a file descriptor

Exactly ! the debugger would seg fault in _file_getc :)


> that was created in a /MD module, you end
> up using an empy IO block, etc etc etc.

I guess I do not have the knowledge to work toward your Case 2, I'll
stick to the simple /MD compilation and make sure to package the
proper dlls. I need to figure out if they are redistruable and how.

Thanks for your time !

-Mathieu

Giovanni Dicanio

unread,
May 28, 2008, 5:39:55 AM5/28/08
to

"mathieu" <mathieu....@gmail.com> ha scritto nel messaggio
news:b6e9a3bf-7c8a-4c9c...@f63g2000hsf.googlegroups.com...

>> If the C++ class is shared between modules (EXE and DLLs), you almost
>> certainly have the "Case 1" scenario described above.
>
> Do you mean inline member function being both in the DLL and the EXE,
> for example ?

I think this is one of the cases.


> I guess I do not have the knowledge to work toward your Case 2,

Doug's post was very clear and correct, as usual.
I just try to elaborate a bit on Doug's Case 2, to try to make it more clear
for you.

Suppose you have a DLL called MyClassCPP.dll, which defines and exports a
C++ class like this:

class MyClass
{
public:
MyClass();
~MyClass();

void DoSomething( const std::string & s );
};

So, this MyClassCPP.dll has a C++ interface.

In that case, you are in "Doug's Case 1".

But suppose that you want to make that DLL a "Doug's Case 2" DLL.

The first thing you should do, is to wrap this C++ class interface into a
C-like interface, and only use C-like interface as DLL interface.
(You can use C++ *inside* the DLL, but the interface must be pure C.)

Moreover, every instance of the class must be built inside the DLL, and must
be freed inside the DLL, too.

i.e. the DLL should be like a "monad", which only communicates with the
external world using a C-like interface, and every heap allocation ('new')
must be done inside the DLL, and that heap memory must be freed ('delete')
in the same DLL.

Call this "Doug's Case 2" DLL MyClassC.dll.

This DLL may export the following functions (C-like interface):

MyClass_New /* kind of corresponds to 'new MyClass' */
MyClass_Delete /* kind of corresponds to 'delete MyClass' */
MyClass_DoSomething /* corresponds to MyClass::DoSomething */

The problem is that you must refer to a particular MyClass class instance
when you call this C functions
i.e. you need the C++ "this" pointer.
You can wrap that C++ "this" pointer in a void * pointer, or an unsigned
int, etc.

So, in your DLL header file you may have:

<code>

typedef void * MYCLASS;

MYCLASS MyClass_New( void );
void MyClass_Delete( MYCLASS c );
void MyClass_DoSomething( MYCLASS c, const char * s );

// void MyClass_DoSomethingElse( MYCLASS c, ... other parameters ... );

</code>

The above is the interface that the DLL client uses: as you can see, it is
just a C-like interface (you should wrap that using the classic #ifdef
__cplusplus extern "C" { ... stuff).

Let's see how you could implement that in your DLL.
You can still use *C++* in your DLL for class main implementation, you just
need to wrap that into a C interface.
So, you can have code like this:

<code>

MYCLASS MyClass_New( void )
{
// Create a new instance of MyClass class in the DLL's heap
MyClass * c = new MyClass();

// [See note after code]

// Return the "opaque" pointer
return (MYCLASS)c;
}

void MyClass_Delete( MYCLASS c )
{
// Check that the pointer is valid
ASSERT( c != NULL );

// Get our MyClass back
MyClass * p = (MyClass *)c;

// Delete from DLL's heap
delete p;
}

void MyClass_DoSomething( MYCLASS c, const char * s )
{
// Check that the pointer is valid
ASSERT( c != NULL );

// Get our MyClass back
MyClass * p = (MyClass *)c;

// Call method
p->DoSomething( s );
// Note that there is an implicit conversion
// from const char * and std::string;
// std::string const reference was in MyClass::DoSomething
// prototype
}

</code>

So, you can still use C++ in your DLL. You just need to wrap C++ stuff into
a thin C-interface.

An important note:

In C++, "everyone" (e.g. standard library class methods, custom class
methods...) can throw exceptions. You must make sure that those exceptions
do not cross your DLL boundaries.
So, you may consider putting a try/catch guard inside every C-interface
function body, to capture exceptions and convert them to something that C
language likes, like return error codes.

For example, in case of 'new', if there is a problem in allocating object, a
std::bad_alloc exception is thrown by 'new'.
You don't want this exception to cross your C-interface DLL.
So, you should catch that exception, and return NULL to the caller.

In general, you can use code like this in your C wrappers:

try
{
// Do C++ stuff...
}
catch ( std::exception & )
{
// Catch standard exceptions and return error codes
// using the C-like interface
}


HTH,
Giovanni


Doug Harrison [MVP]

unread,
May 28, 2008, 11:58:50 AM5/28/08
to
On Wed, 28 May 2008 00:57:57 -0700 (PDT), mathieu
<mathieu....@gmail.com> wrote:

>> If the C++ class is shared between modules (EXE and DLLs), you almost
>> certainly have the "Case 1" scenario described above.
>
>Do you mean inline member function being both in the DLL and the EXE,
>for example ?

Yes, but I also include classes shared through exporting. If you want a
program composed of EXE and DLLs to act like a real C++ program, as opposed
to a collection of independent modules, you have to link everyone to the
same CRT DLL. As you seem to be coming from a Unix background, you should
be aware that the Unix and Windows dynamic linking models are very
different. There used to be a manuscript for Levine's book "Linkers &
Loaders" available at iecc.com, but I'm getting "Forbidden" errors now;
this book talks about it in some detail. In a nutshell, Unix maintains
enough state to perform something close to a static link when it
dynamically links two modules, while Windows relies on a more formal
import/export model. Each approach has its advantages; for example, Unix
comes closer to traditional linking without imposing new burdens, while
Windows helps with data hiding and order of initialization of globals in
different modules. For disadvantages, exchange Unix/Windows and negate the
statements of the previous sentence.

mathieu

unread,
May 28, 2008, 1:10:28 PM5/28/08
to
On May 28, 5:58 pm, "Doug Harrison [MVP]" <d...@mvps.org> wrote:
> On Wed, 28 May 2008 00:57:57 -0700 (PDT), mathieu
>

Indeed I have seen some pretty nasty things going on, on *NIX :

http://mail.python.org/pipermail/python-dev/2002-May/023923.html
and
http://gcc.gnu.org/faq.html#dso

Anyway thanks again for your help, I think I can in fact work around
the issue if I build my entire project using static lib (and thus
static linking for the exe). there is only one single lib that need to
be shared: the python module. But AFAIK the c++ code generated by SWIG
might fall in your 'Case 2' scenario.

I'll try that tonight.

-Mathieu

mathieu

unread,
May 28, 2008, 4:50:56 PM5/28/08
to
> andhttp://gcc.gnu.org/faq.html#dso

>
> Anyway thanks again for your help, I think I can in fact work around
> the issue if I build my entire project using static lib (and thus
> static linking for the exe). there is only one single lib that need to
> be shared: the python module. But AFAIK the c++ code generated by SWIG
> might fall in your 'Case 2' scenario.
>
> I'll try that tonight.

Done. That works :) The trick is to simply rebuild all libs as static
libs.

Thanks everyone for your help. I'll stick to that solution as the M$
linker is pretty good dealing with static lib (size is very
resonable). SWIG generated code is doing the 'right' thing AFAIK.

-Mathieu

0 new messages