Exporting C++ Classes from a Static Library and from a DLL

V

Vijai Kalyan

I am not sure if this OT, but I will go ahead and post. If it has to be
posted elsewhere let me know.
-vijai.
------

I have a class declared as follows:

#pragma once

// a simple reference counter implementation

#ifndef __REF_COUNTER_H__
#define __REF_COUNTER_H__

#include <iosfwd>
#include "smlibdefs.h"

namespace SMLib
{

class SMLIBAPI_CLASS ReferenceCounter
{
unsigned long m_numrefs;
public:
ReferenceCounter();
ReferenceCounter(const ReferenceCounter&);
ReferenceCounter& operator = (const ReferenceCounter&);
virtual ~ReferenceCounter();

virtual void AcquireReference();
virtual void ReleaseReference();
virtual unsigned long CountReferences() const;
};

};

SMLIBAPI_FUNCTION std::eek:stream& operator << (std::eek:stream&, const
SMLib::ReferenceCounter&);
SMLIBAPI_FUNCTION std::wostream& operator << (std::wostream&, const
SMLib::ReferenceCounter&);

#endif

SMLIBAPI_FUNCTION is defined as __declspec(dllimport) or
__declspec(dllexport) depending on whether the class is being imported
or exported. (On Windows. On *nix I don't have to do anything to export
C++ classes I believe. All symbols are exported by default?)

I build a shared library and a static library. I test the class and
it's methods with the following separate test program.

#include <refcounter.h>
#include <windows.h>
#include <iostream>
#include <assert.h>

void Test_ReferenceCounter_Construction()
{
SMLib::ReferenceCounter ctr;
std::wcout<<L"Counter: "<<ctr<<std::endl;
}

void Test_ReferenceCounter_Initialization()
{
SMLib::ReferenceCounter ctr;
std::wcout<<L"Counter: "<<ctr<<std::endl;
assert(ctr.CountReferences() == 0);
}

void Test_ReferenceCounter_CopyConstruction()
{
SMLib::ReferenceCounter ctr;
std::wcout<<L"Counter 1: "<<ctr<<std::endl;
SMLib::ReferenceCounter ctr2 = ctr;
std::wcout<<L"Counter 2: "<<ctr2<<std::endl;
assert(ctr2.CountReferences() == 0);
}

void Test_ReferenceCounter_Assignment()
{
SMLib::ReferenceCounter ctr;
std::wcout<<L"Counter 1: "<<ctr<<std::endl;
ctr.AcquireReference();
ctr.AcquireReference();
SMLib::ReferenceCounter ctr2;
ctr2.AcquireReference();
std::wcout<<L"Counter 2: "<<ctr2<<std::endl;
ctr2 = ctr;
std::wcout<<L"Counter 2 (reassigned): "<<ctr2<<std::endl;
assert(ctr2.CountReferences() == ctr.CountReferences());
}

void Test_ReferenceCounter_ReferenceIncrement()
{
SMLib::ReferenceCounter ctr;
std::wcout<<L"Counter: "<<ctr<<std::endl;
ctr.AcquireReference();
assert(ctr.CountReferences() == 1);
}

void Test_ReferenceCounter_ReferenceDecrement()
{
SMLib::ReferenceCounter ctr;
std::wcout<<L"Counter: "<<ctr<<std::endl;
ctr.AcquireReference();
ctr.AcquireReference();
ctr.ReleaseReference();
assert(ctr.CountReferences() == 1);
}


int main()
{
LoadLibrary("smlib-1.0.0.0");

Test_ReferenceCounter_Construction();
Test_ReferenceCounter_Initialization();
Test_ReferenceCounter_Assignment();
Test_ReferenceCounter_ReferenceIncrement();
Test_ReferenceCounter_ReferenceDecrement();

return 0;
}

However, in the shared library:

I get an unresolved external error only for the overloaded left shift
operator. On the other hand for the static library I get unresolved
external symbols error for all the methods as well as the function. I
use the same makefile to compile both:


executableName = smlib
programName = smlib

version = 1.0.0.0

baseDir = .
incDir = $(baseDir)/
srcDir = $(baseDir)/

!if defined(DEBUG) || defined(_DEBUG)
buildSuffix = d
buildType = DEBUG
!else
buildSuffix =
buildType = RELEASE
!endif

ExtLibs = kernel32.lib \
msvcrt$(buildSuffix).lib \
libc$(buildSuffix).lib \
libcmt$(buildSuffix).lib

Includes = basedefs.h \
smlibdefs.h \
refcounter.h

OutPath = $(MAKEDIR)\$(buildType)

CCOpts = /c /Gd /MDd /EHa /D__SMLIB__BUILD /D$(buildType) /I$(incDir)
CC = cl.exe

LibOpts = /OUT:$(OutPath)\libsmlib-$(version).lib /NOLOGO
/SUBSYSTEM:NATIVE
LIB = lib.exe

LinkOpts = /$(buildType) /DLL /NOLOGO
/OUT:$(OutPath)\smlib-$(version).dll
/IMPLIB:$(OutPath)\smlib-$(version).lib
/PDB:$(OutPath)\smlib-$(version).pdb $(ExtLibs)
LINK = link.exe

refcounter: refcounter.cpp $(Includes)
$(CC) $(CCOpts) /Fo$(OutPath)/refcounter.obj refcounter.cpp

allObjs = $(OutPath)\refcounter.obj


lib: refcounter
$(LIB) $(LibOpts) $(allObjs)

dll: refcounter
$(LINK) $(LinkOpts) $(allObjs)

all: refcounter dll lib

clean:
del /Q $(OutPath)\*.obj
del /Q $(OutPath)\smlib-$(version).pdb
del /Q $(OutPath)\smlib-$(version).lib
del /Q $(OutPath)\smlib-$(version).exp
del /Q $(OutPath)\smlib-$(version).dll
del /Q $(OutPath)\smlib-$(version).ilk

Anyone have any ideas on what I am doing wrong?

thanks,

-vijai.
 
V

Victor Bazarov

Vijai said:
I am not sure if this OT, but I will go ahead and post. If it has to
be posted elsewhere let me know.

Letting you know: microsoft.public.vc.language.
[...]
Anyone have any ideas on what I am doing wrong?

Somebody in the VC++ newsgroup will tell you, no doubt. Your code
is so full of non-standard stuff that I don't think it is worth
picking apart here, in comp.lang.c++.

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top