Visual Studio, MSBuild: первая сборка после сбоя очистки, последующие сборки успешны - PullRequest
3 голосов
/ 25 июля 2011

Что-то не так с моей сборкой, но я не могу понять это.Я сузил это до одного из моих проектов: первая сборка после сбоя очистки, все последующие сборки успешны.

Я получаю ошибки связывания, которые говорят, что некоторые символы уже определены:

>------ Build started: Project: Problem, Configuration: Debug Win32 ------
> Blah blah blah...
23>     Creating library D:\SVN.DRA.WorkingCopy\Debug\Problem.lib and object D:\SVN.DRA.WorkingCopy\Debug\Problem.exp
23>ProblemDependency1.lib(PD1.obj) : error LNK2005: "public: unsigned short __thiscall PD2Class::getFoo(void)const " (?getFoo@PD2Class@@QBEGXZ) already defined in ProblemDependecy2.lib(ProblemDependency2.dll)
23>ProblemDependency1.lib(PD1.obj) : error LNK2005: "public: void __thiscall PD2Class2::`default constructor closure'(void)" (??_FPD2Class2@Image@DRA@@QAEXXZ) already defined in ProblemDependency2.lib(ProblemDependency2.dll)
23>D:\SVN.DRA.WorkingCopy\Debug\Problem.dll : fatal error LNK1169: one or more multiply defined symbols found
  • Problem - это проект C ++ / CLI, созданный с ключом / clr, который ссылается на неуправляемые проекты C ++ ProblemDependency1, статическая библиотека, и ProblemDependency2, dll.
  • ProblemDependency1 ссылается на ProblemDependency2.
  • getFoo () объявлен как встроенный и определен вне объявления класса, в .h
  • PD2Class2 не имеет явно определенного конструктора по умолчанию, но у него есть конструктор, который имеет все аргументы по умолчанию, так что выМожно сказать, что он включает в себя конструктор по умолчанию в качестве особого случая
  • .h, где они определены, имеют #pragma один раз в качестве первой строки.

Есть какие-нибудь подсказки по устранению неполадок?При необходимости я могу опубликовать дополнительную информацию

Обновление : первую ошибку я исправил благодаря предложению Андерса Абеля, но до сих пор не могу решить вторую (ту, что касается конструктора по умолчанию)

Обновление : если я компилирую с использованием MSBuild вне Visual Studio, он всегда завершается с ошибкой

Редактировать : Вот некоторый код.Сначала немного о декларации PD2Class2.Настоящее имя PD2Class2 - CImage (лень анонимизировать), CImage.h:

#pragma once
#pragma warning( disable: 4251 )    //TODO: Disable and solve

#include "ImageProperties.h"
#include "../CommonCppLibrary/CriticalSection.h"
#include <windows.h>
#include <stdexcept>
#include <string>

class CSharedMemory;
class EmptyImageException;
struct IShape;

struct SImageStatics {
    unsigned short low3Percentile;
    unsigned short high97Percentile;
    unsigned short medianPixelValue;
    unsigned short meanPixelValue;
    unsigned short minPixelValue;
    unsigned short maxPixelValue;
};

namespace DRA{
namespace Image{
class __declspec(dllexport) CImage {
    friend class CImageLock;

//Attributes
    int m_iPitch;
protected:
    mutable CImageProperties                    m_cProperties;
    CSharedMemory *                             m_pSharedMemmory;
    mutable DRA::CommonCpp::CCriticalSection    m_csData;
    static const float                          PIXEL_FREQUENCY_COVERAGE;
    static const float                          PIXEL_CUTOFF_PERCENTAGE;
    static const int                            MINIMUM_PIXEL_FREQUENCY;    //Pixels with a frequency lower than this are ignored
    static const int                            MINIMUM_WINDOW_WIDTH_FOR_16_BITS;

//Methods
    //Some private methods

public:

    CImage( DWORD dwWidth = 0, DWORD dwHeight = 0, ULONG uBytesPerPixel = 0,
            bool isSigned = false, EPhotometricInterpretation ePI = PI_UNKNOWN,
            UINT bitsStored = 0, float pw = -1.0f, float ph = -1.0f, BYTE * pData = NULL );
    CImage( const CImageProperties& cProperties, int iPitch = 0 );
    CImage( const CImage& rImage );
    virtual ~CImage();
    virtual CImage& operator=( const CImage& );
    bool operator==( const CImage& rImage );

//Alter State
    //More methods
//Query State
    //More methods
};
}
}

Далее определение конструктора из CImage.cpp:

CImage::CImage( DWORD dwWidth, DWORD dwHeight, ULONG uBytesPerPixel, bool isSigned,
                EPhotometricInterpretation ePI, UINT bitsStored, float pw, float ph,
                BYTE * pData ) :
        m_iPitch( dwWidth * uBytesPerPixel ),
        m_cProperties( dwWidth, dwHeight, uBytesPerPixel, bitsStored, ePI, isSigned, pw, ph ),
        m_pSharedMemmory( NULL ),
        m_csData(){
    m_pSharedMemmory = new CSharedMemory( pData ? pData : new BYTE[getSize()] );
}

Ответы [ 3 ]

3 голосов
/ 25 июля 2011

Просто то, с чем я недавно столкнулся, чтобы проверить:

Вы строите сетевой том?У меня были проблемы с невозможностью отладки моих приложений, потому что файл .pdb не был "там" после сборки и перед запуском отладки из-за задержки в SAN, над которой я работал как каталог сборки.

Как только я переместил сборку проекта на локальный том, все было в порядке.

Не знаю, происходит ли это с тобой, или нет, но кое-что я изучу.

3 голосов
/ 01 августа 2011

У меня нет большого опыта работы с c ++, но подобные проблемы в других языках .NET часто возникают из-за того, что DLL ссылается на другой проект в том же решении (на DLL в папке "obj" или "bin" вдругой проект, вместо ссылки на проект. Это лишает Visual Studio возможности определить порядок сборки и, следовательно, в первый раз после «очистки» у вас не будет DLL, от которой вы зависите.во второй сборке эта DLL уже будет собрана, и сборка будет успешной.

3 голосов
/ 25 июля 2011

getFoo() помечен как __declspec(dllexport)? Если это встроенная функция, она создается / используется везде, где она вызывается через включенный заголовок. Он не должен быть частью функций, которые экспортирует dll, и не должен иметь директивы dllexport.

__declspec(dllexport) может обрабатываться с помощью макроса, который расширяется до dllexport или dllimport в зависимости от того, является ли это dll или код, использующий dll, который скомпилирован. Если в объявлении функции есть какой-либо макрос, вам, возможно, придется покопаться в нем, чтобы узнать, существует ли директива экспорта.

Обновление

Я думаю, что если файл заголовка используется как при сборке библиотеки DLL, так и при использовании библиотеки DLL, неправильно указывать __declspec(dllexport) в файле заголовка. Вместо этого используйте систему макросов:

#ifdef PROBLEMDEPENDENCY2
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT __declspec(dllimport)
#endif

class DLLEXPORT CImage
{
    //...
}

Затем определите символ препроцессора PROBLEMDEPENDENCY2 при построении библиотеки DLL, но не при ее использовании. Проблема с жестким кодированием __declspec(dllexport) в заголовочном файле заключается в том, что компилятор попытается экспортировать класс как из ProblemDependency2 (что правильно), так и из ProblemDependency1 (что неверно).

...