easuter
easuter

Reputation: 1197

C++/CLI - .obj file generated from .cpp source file contains no symbols (LNK2020)

At the moment I'm working on implementing a managed wrapper in C++/CLI, for a native C library.

I have no hard experience with the language, and this week has been a sort of crash course while trying to complete my project. Although it has a few surprising and frustrating quirks, there are plenty of good articles floating around.

Background:

Common.h:

#pragma once

namespace LibavDotNet {

    template<class T>
    public ref class WrappedAvType abstract
    {
    public:
        property bool IsDirty;
        WrappedAvType();
        WrappedAvType(T avObject);
        ~WrappedAvType();
        virtual T Unwrap();

    private:
        T _avObject;

    protected:
        virtual void SetAvObject(T avObject);
    };
}

Common.cpp:

#include "Common.h"

namespace LibavDotNet {

    template<class T>
    WrappedAvType<T>::WrappedAvType()
    {
        IsDirty = false;
    }

    template<class T>
    WrappedAvType<T>::WrappedAvType(T avObject)
    {
        _avObject = avObject;
    }

    template<class T>
    WrappedAvType<T>::~WrappedAvType()
    { }

    template<class T>
    T WrappedAvType<T>::Unwrap()
    {
        return _avObject;
    }

    template<class T>
    void WrappedAvType<T>::SetAvObject(T avObject)
    {
        _avObject = avObject;
    }
}

However I'm currently stumped (maybe blinded from staring at the code for too damn long...) with a peculiar problem: whenever I compile the project in its described state, I receive error LNK2020 indicating that it no token can be found for WrappedAvType.

To confirm that the symbols were available in the generated binary, I used dumpbin /symbols Common.obj and in fact there don't appear to be any:

Microsoft (R) COFF/PE Dumper Version 11.00.61030.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file Common.obj

File Type: COFF OBJECT

COFF SYMBOL TABLE
000 00CFEE66 ABS    notype       Static       | @comp.id
001 80000191 ABS    notype       Static       | @feat.00
002 00000000 SECT1  notype       Static       | .drectve
    Section length   78, #relocs    0, #linenums    0, checksum        0
004 00000000 SECT2  notype       Static       | .debug$S
    Section length  35C, #relocs    0, #linenums    0, checksum        0
006 00000000 SECT3  notype       Static       | .debug$T
    Section length   7C, #relocs    0, #linenums    0, checksum        0
008 00000000 SECT4  notype       Static       | .cormeta
    Section length  45C, #relocs    0, #linenums    0, checksum        0

String Table Size = 0x0 bytes

  Summary

         45C .cormeta
         35C .debug$S
          7C .debug$T
          78 .drectve

If I include the class implementation directly with #include "..\Common.cpp" in the other source files that need it (only one other so far), then the project compiles as expected. At this point I have no idea what else to try and have searched for a solution for hours. I'd very much like to keep my headers with class declarations and source files with class implementations separate.

I fully expect this to be something minor that I've overlooked or that I'm just too green to notice. What am I missing?

Upvotes: 0

Views: 332

Answers (1)

Hans Passant
Hans Passant

Reputation: 941455

template<class T>

This is a standard C++ problem, it doesn't have anything to do with C++/CLI. Templates do not have external linkage. The entire implementation of the template class must be present in the .h file. Which is why the #include worked.

Do keep the strong code smell in mind, templates are a pure C++ feature. Your wrapper isn't actually usable by any other .NET language, they don't support templates of course. Only ref classes that are declared with the generic keyword are usable.

Upvotes: 2

Related Questions