technorabble
technorabble

Reputation: 511

C++ / VS 2012 - Multi-project solution: Linker errors in one project but not another

I have an MFC DLL which is used by another project in the same solution. Everything works as it should when called from the consuming project, including the function I will be writing about below.

I have recently tried to put together a unit testing application for this DLL, which has been going well until the most recent addition to the DLL (which, as I said, I have proven to be working ok from the main project).

Note: I'm also showing the std::string one as it may be relevant (and is known working in my unit testing project).

The problem function is declared in the header file like this:

#pragma once

#include <string>
#include <afx.h>

#ifdef CALIBRATIONTOOL_EXPORTS
#define CALIBRATIONTOOL_API __declspec(dllexport)
#else
#define CALIBRATIONTOOL_API __declspec(dllimport)
#endif

namespace MyCompanyName
{
    namespace CalibrationTool
    {
        class FileUtils
        {
        public:
            CALIBRATIONTOOL_API static bool FileExists(std::string filename);

            CALIBRATIONTOOL_API static bool FileExists(CString filename);

        }; // end class FileUtils
    }; // end namespace CalibrationTool
}; // end namespace MyCompanyName

And implemented in the cpp:

#include "stdafx.h"
#include "FileUtils.h"
#include "StringUtils.h"
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>

#ifdef CALIBRATIONTOOL_EXPORTS
    #define CALIBRATIONTOOL_API __declspec(dllexport)
#else
    #define CALIBRATIONTOOL_API __declspec(dllimport)
#endif


namespace MyCompanyName
{
    namespace CalibrationTool
    {
        bool FileUtils::FileExists(std::string filename) 
        { 

            std::string filenameAsStdString(filename);
            std::string filenameWithDoubleBackslashes = MyCompanyName::CalibrationTool::StringUtils::SingleToDoubleBackslash(filenameAsStdString);
            std::ifstream ifile(filenameWithDoubleBackslashes);
            bool exists = (bool)ifile;
            ifile.close();
            return exists;
        } 

        bool FileUtils::FileExists(CString filename)
        {
            std::ifstream ifile(filename);
            bool exists = (bool)ifile;
            ifile.close();
            return exists;
        }

    }; // end namespace CalibrationTool
}; // end namespace MyCompanyName

So far so good. And like I said, it's testing ok when called from the main project. However, in my testing project, where it's called like this:

bool FileUtilsTest::FileExistsTestCString()
{
    bool passed = true;

    CString definitelyExists = _T("C:\\Windows\\system.ini");
    CString definitelyDoesntExist = _T("C:\\NotMuchChanceThatThisFileExists.zut");

    if (MyCompanyName::CalibrationTool::FileUtils::FileExists(definitelyExists))
        {
        // all is well
        CalibrationToolUnitTestsLogging::Write("Passed FileUtilsTest.FileExistsTestCString (files which exist). Successfully found C:\\Windows\\system.ini.");
    }
    else
    {
        // all is not well
        CalibrationToolUnitTestsLogging::Write("Failed FileUtilsTest.FileExistsTestCString (files which exist). Unable to find C:\\Windows\\system.ini.");
        passed = false;
    }
    // (and more testing, e.g. for files which don't exist)

return passed;
}

I get the error:

Error 4 error LNK2019: unresolved external symbol "__declspec(dllimport) public: static bool __cdecl MyCompanyName::CalibrationTool::FileUtils::FileExists(class ATL::CStringT<char,class StrTraitMFC_DLL<char,class ATL::ChTraitsCRT<char> > >)" (__imp_?FileExists@FileUtils@CalibrationTool@MyCompanyName@@SA_NV?$CStringT@DV?$StrTraitMFC_DLL@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@@Z) referenced in function "private: bool __thiscall FileUtilsTest::FileExistsTestCString(void)" (?FileExistsTestCString@FileUtilsTest@@AAE_NXZ) C:\_SVN\CalibrationToolUnitTests\FileUtilsTest.obj

Here's the working code in my main project, for completeness:

if ((MyCompanyName::CalibrationTool::FileUtils::FileExists(exists)) && (!MyCompanyName::CalibrationTool::FileUtils::FileExists(doesntExist)))
    {
        g_log.Write(log_debug, -1, _T("TEST"), _T("Seems fine."));
    }
    else
    {
        g_log.Write(log_debug, -1, _T("TEST"), _T("Something's up"));
    }

Can anyone suggest where I'm going wrong?

Upvotes: 0

Views: 300

Answers (1)

SHR
SHR

Reputation: 8313

In Visual studio 10 (and I guess vs 2012 is the same) There are 3 different ways to add dependency.

  1. Manual - add the include/library paths in the project setting, and add the library.
  2. New (prefer to do it like this...) - project -> properties. choose: Common properties-> Framework and References. Press "Add Reference". Now select the dependency.
  3. Old = add dependency - when you right click on project in the solution explorer and choose "Add dependency"

I think your problem is that you used one way on one project and other way for the second.

Other possibility is that one project is static lib. so it doesn't need to be linked.

Upvotes: 1

Related Questions