February 10, 2004
Michael wrote:

>>> $ dmc -ND -DBUILD_DLL
>>> -I\dm\stlport\stlport -c Foo.cc
>>
>>This should also have "-WD -mn" in the compiler flags. Think of "-WD" as "-fpic -fPIC -DPIC" to generate position indep. code.
> 
> Thanks Scott. I've done some experimenting and learned a few things...
> 
> I left off "-mn" since it seems to be the default on Windows XP at least, and I found that "-WD" doesn't seem to have the semantics of -fPIC for GCC. I was able to leave off "-WD" when compiling the object files that would be used to build the DLL. This implies "-WD" doesn't generate position independent code, unless I was very lucky (or unlucky). :-)

'-mn' is the default memory model, so it's usually unnecessary on the 32-bit Win32 platforms (NT, 2K, XP). Doesn't hurt to be explicit.

'-WD' is for function prolog/epilog generation. It's not exactly PIC, which is why I said you can "think" of it as the Win32 equivalent of PIC. It's really more about some assumptions about segment register loading that need to be made to access the DLL's equivalent of Unix's ".data" and ".bss" segments; the DLL executes in its own address space. Under Unix and Unix-like OSes, shared objects are mmap-ed into the process's address space... not so under Win32. That's why the DllMain() function exists, so you can tell when someone attaches to your address space as a process or thread. This is generally useful if you have some per-thread or per-process state you want to allocate. But this means that the DS segment register has to be loaded with the DLL's data segment. IIRC, there's some funniness with the FS segment register as well.

Note also that for this reason, you also have to do the __dllexport(dllimport) funkiness to set up the correct cross address space invocation.

[Note: Others, like Jan and Walter, may refine this explanation considerably, but for an overview, it should suffice.]

While you may get away with not compiling your source with '-WD' (it looks like it works), you might want to do so anyway to CYA.

>>> $ dmc -oFoo.dll -ND -WD -mn -L/implib
>>> -I\dm\stlport\stlport Foo.obj
>>>  link Foo,Foo.dll,,,Foo/noi/implib;
>>> ..OPTLINK header/copyright elided...
>>
>>"-WD -mn" isn't needed here since you're linking.
> 
> Again, my experiments show just the opposite. When linking to build the DLL from object files I *had* to add "-WD" or I would get strange behavior at runtime (in my case, no output). Even when I added "-WD" to compile (which I found was unnecesary) I did need to use it for linking the DLL.

I usually go right for a '.DEF' file and invoke link when building my DLL; I don't invoke dmc. Thus, the '-WD' is superfluous. Really. :-)

[Note: dmc probably needs the '-WD' flag to generate the correct DEF file.]

Since you spent the $25 for the CD, use the IDDE to start a make file, then add to it as you go along. It'll create the DEF file (you might have one there already) and away you go...

> Thanks for helping out...it gave me enough insight to get through the initial quirks. I'm actually finding the control I have over exported symbols has a benefit. I don't need to export *all* of my classes, which helps with encapsulation. I can prevent clients from accessing internal classes. It's not as tedious as I had anticipated and forced me to consider what the public interface of my library should be. I still like developing on UNIX flavors better. ;-)

There's no doubt that Unix better architected in many respects (some Unices are better than others ;-). However, there's something to be said about the level of commoditization that Win32 has brought to software development. The usual comment about Unix that I've heard from is the lack of APIs that GTK+/Gnome and Qt supply for application-as-object interoperability, too many standards to choose from, no HTML browser object that can be invoked via X11R6, etc.

Sometimes it just hard to argue against success. As you point out, it does make you think a bit about your API and what you export, versus exporting everything in the Unix shared object world.


-scooter
February 10, 2004
>That's why the DllMain() function exists, so
>you can tell when someone attaches to your address space as a process or
>thread.

Yes, I just looked into that. I have already found some nice uses of that, such as initializing singletons. I started with just an empty DllMain() returning TRUE which seems to fulfill the minimum requirement.

>[Note: dmc probably needs the '-WD' flag to generate the correct DEF file.]

Yes, that looks like what's happening. I really wanted to avoid creating my own DEF, and so far have been getting by. It does feel like I'm going against the grain a little though.

>There's no doubt that Unix better architected in many respects (some Unices are better than others ;-). However, there's something to be said about the level of commoditization that Win32 has brought to software development. The usual comment about Unix that I've heard from is the lack of APIs that GTK+/Gnome and Qt supply for application-as-object interoperability, too many standards to choose from, no HTML browser object that can be invoked via X11R6, etc.

Well, you've got componentization across UNIX platforms now. I don't know any UNIX which doesn't support some implementation of CORBA at least. When I need off the shelf components I just go to Java though. I agree about all the standards though. So much to sift through.

By the way, I did run into a problem that I haven't solved. I continued my experimentation by changing my test class to a template class. Now my __declspec doesn't seem to work. The important bits look like this:

template <typename Type>
class EXPORT_DLL Foo
{
..elided...
};

I get undefined symbols when I try to link my DLL to the driver executable. I was afraid things were going too smoothly. Also, I'm concerned whether my inlined methods were really inlined. From the size of the DLL it looks like even the inlined member functions are built out of line.

Any special tricks I need to know about exporting/importing template classes? Don't tell me I have to instantiate them...please no. :-(

Thanks,
Michael


February 10, 2004
Michael wrote:

>>That's why the DllMain() function exists, so
>>you can tell when someone attaches to your address space as a process or
>>thread.
> 
> Yes, I just looked into that. I have already found some nice uses of that, such as initializing singletons. I started with just an empty DllMain() returning TRUE which seems to fulfill the minimum requirement.
> 
>>[Note: dmc probably needs the '-WD' flag to generate the correct DEF [file.]
> 
> Yes, that looks like what's happening. I really wanted to avoid creating my own DEF, and so far have been getting by. It does feel like I'm going against the grain a little though.

No worse than building up the libtool command line to build a shared object. It's just another file. :-)

Actually, you might try something like this in your make rule:

        link $(LFLAGS) @<<
$(OBJS) $(OBJS_2) $(EVEN_MORE_OBJS)
$(THE_DLLS_NAME)
$(LIBS_NEEDED_TO_LINK)
$(DEF_FILE)
<<

The DEF file is the one that starts with "LIBRARY". It's not where you put the object files, BTW. You'll still need to tell the linker what kind of target it's building.

> By the way, I did run into a problem that I haven't solved. I continued my experimentation by changing my test class to a template class. Now my __declspec doesn't seem to work. The important bits look like this:
> 
> template <typename Type>
> class EXPORT_DLL Foo
> {
> ..elided...
> };
> 
> I get undefined symbols when I try to link my DLL to the driver executable. I was afraid things were going too smoothly. Also, I'm concerned whether my inlined methods were really inlined. From the size of the DLL it looks like even the inlined member functions are built out of line.
> 
> Any special tricks I need to know about exporting/importing template classes? Don't tell me I have to instantiate them...please no. :-(

No, you don't need to instantiate them but you do need to give the compiler a clue:

template EXPPORT_DLL Foo<int>;


-scooter
1 2
Next ›   Last »