gpt4 book ai didi

c++ - extern "C"拆解导致奇怪的链接器错误

转载 作者:行者123 更新时间:2023-12-02 10:06:48 43 4
gpt4 key购买 nike

我有以下头文件

possion_surface_reconstructor.h

#ifndef POISSON_SURFACE_RECONSTRUCTOR_H
#define POISSON_SURFACE_RECONSTRUCTOR_H

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <iostream>
#include <boost/format.hpp>

#include "../core/PreProcessor.h"
#include "../core/MyMiscellany.h"
#include "../core/CmdLineParser.h"
#include "../core/PPolynomial.h"
#include "../core/FEMTree.h"
#include "../core/Ply.h"
#include "../core/PointStreamData.h"
#include "../core/Image.h"

#include "callbacks.h"

namespace MeshingAdapter
{

#undef USE_DOUBLE // If enabled, double-precesion is used
#define DATA_DEGREE 0 // The order of the B-Spline used to splat in data for color interpolation
#define WEIGHT_DEGREE 2 // The order of the B-Spline used to splat in the weights for density estimation
#define NORMAL_DEGREE 2 // The order of the B-Spline used to splat in the normals for constructing the Laplacian constraints
#define DEFAULT_FEM_DEGREE 1 // The default finite-element degree
#define DEFAULT_FEM_BOUNDARY BOUNDARY_NEUMANN // The default finite-element boundary type
#define DIMENSION 3

cmdLineParameter< char* >
In("in"),
Out("out"),
TempDir("tempDir"),
Grid("grid"),
Tree("tree"),
Transform("xForm");

cmdLineReadable
Performance("performance"),
ShowResidual("showResidual"),
NoComments("noComments"),
PolygonMesh("polygonMesh"),
NonManifold("nonManifold"),
ASCII("ascii"),
Density("density"),
LinearFit("linearFit"),
PrimalGrid("primalGrid"),
ExactInterpolation("exact"),
Normals("normals"),
Colors("colors"),
InCore("inCore"),
Verbose("verbose");

cmdLineParameter< int >
#ifndef FAST_COMPILE
Degree("degree", DEFAULT_FEM_DEGREE),
#endif // !FAST_COMPILE
Depth("depth", 8),
KernelDepth("kernelDepth"),
Iters("iters", 8),
FullDepth("fullDepth", 5),
BaseDepth("baseDepth", 0),
BaseVCycles("baseVCycles", 1),
#ifndef FAST_COMPILE
BType("bType", DEFAULT_FEM_BOUNDARY + 1),
#endif // !FAST_COMPILE
MaxMemoryGB("maxMemory", 0),
#ifdef _OPENMP
ParallelType("parallel", (int)ThreadPool::OPEN_MP),
#else // !_OPENMP
ParallelType("parallel", (int)ThreadPool::THREAD_POOL),
#endif // _OPENMP
ScheduleType("schedule", (int)ThreadPool::DefaultSchedule),
ThreadChunkSize("chunkSize", (int)ThreadPool::DefaultChunkSize),
Threads("threads", (int)std::thread::hardware_concurrency());

cmdLineParameter< float >
DataX("data", 32.f),
SamplesPerNode("samplesPerNode", 1.5f),
Scale("scale", 1.1f),
Width("width", 0.f),
Confidence("confidence", 0.f),
ConfidenceBias("confidenceBias", 0.f),
CGSolverAccuracy("cgAccuracy", 1e-3f),
PointWeight("pointWeight");

cmdLineReadable* params[] =
{
#ifndef FAST_COMPILE
&Degree,
&BType,
#endif // !FAST_COMPILE
&In,
&Depth,
&Out,
&Transform,
&Width,
&Scale,
&Verbose,
&CGSolverAccuracy,
&NoComments,
&KernelDepth,
&SamplesPerNode,
&Confidence,
&NonManifold,
&PolygonMesh,
&ASCII,
&ShowResidual,
&ConfidenceBias,
&BaseDepth,
&BaseVCycles,
&PointWeight,
&Grid,
&Threads,
&Tree,
&Density,
&FullDepth,
&Iters,
&DataX,
&Colors,
&Normals,
&LinearFit,
&PrimalGrid,
&TempDir,
&ExactInterpolation,
&Performance,
&MaxMemoryGB,
&InCore,
&ParallelType,
&ScheduleType,
&ThreadChunkSize,
NULL
};

class PoissonSurfaceReconstructor
{
public:
PoissonSurfaceReconstructor(
ProgressCallback& progressCallback,
WarningCallback& warningCallback,
ErrorCallback& errorCallback);

bool ExecuteSurfaceReconstruction(int argc, char* argv[]);

private:
template< unsigned int Dim, class Real >
struct FEMTreeProfiler;

template< unsigned int Dim, typename Real >
struct ConstraintDual;

template< unsigned int Dim, typename Real >
struct SystemDual;

template< unsigned int Dim >
struct SystemDual< Dim, double >;

template< class Real, typename ... SampleData, unsigned int ... FEMSigs >
int Execute(int argc, char* argv[], UIntPack< FEMSigs ... >);

template< unsigned int Dim, class Real, typename ... SampleData >
int Execute(int argc, char* argv[]);

template< typename Real, unsigned int Dim >
int WriteGrid(ConstPointer(Real) values, int res, const char* fileName);

template< typename Vertex, typename Real, typename SetVertexFunction, unsigned int ... FEMSigs, typename ... SampleData >
int ExtractMesh(
UIntPack< FEMSigs ... >,
std::tuple< SampleData ... >,
FEMTree< sizeof ... (FEMSigs), Real >& tree,
const DenseNodeData< Real, UIntPack< FEMSigs ... > >& solution,
Real isoValue,
const std::vector< typename FEMTree< sizeof ... (FEMSigs),
Real >::PointSample >* samples,
std::vector< MultiPointStreamData< Real, PointStreamNormal< Real, DIMENSION >,
MultiPointStreamData< Real, SampleData ... > > >* sampleData,
const typename FEMTree< sizeof ... (FEMSigs), Real >::template DensityEstimator< WEIGHT_DEGREE >* density,
const SetVertexFunction& SetVertex,
std::vector< std::string >& comments,
XForm< Real, sizeof...(FEMSigs) + 1 > iXForm);

template< class Real, unsigned int Dim >
XForm< Real, Dim + 1 > GetBoundingBoxXForm(Point< Real, Dim > min, Point< Real, Dim > max, Real scaleFactor);

template< class Real, unsigned int Dim >
XForm< Real, Dim + 1 > GetBoundingBoxXForm(
Point< Real, Dim > min,
Point< Real, Dim > max,
Real width,
Real scaleFactor,
int& depth);

template< class Real, unsigned int Dim >
XForm< Real, Dim + 1 > GetPointXForm(InputPointStream< Real, Dim >& stream, Real width, Real scaleFactor, int& depth);

template< class Real, unsigned int Dim >
XForm< Real, Dim + 1 > GetPointXForm(InputPointStream< Real, Dim >& stream, Real scaleFactor);

template<typename... Arguments>
std::string FormatString(const std::string& fmt, const Arguments&... args);

double Weight(double v, double start, double end);

const float DefaultPointWeightMultiplier = 2.f;

ProgressCallback _progressCallback;
WarningCallback _warningCallback;
ErrorCallback _errorCallback;
};
}
#endif // POISSON_SURFACE_RECONSTRUCTOR_H

支持此类的 .cpp 文件可以正常编译。我可以将此代码编译为 .exe 并进行一些调整,这就是我想要的。但是,我需要从 C# 调用此代码,因此我创建了一个可从 C# 调用的包装类

配置.h
#ifndef MESHING_DLL_CONFIG_H
#define MESHING_DLL_CONFIG_H

#if defined(_MSC_VER)
# define LIBRARY_EXPORT __declspec(dllexport)
# define LIBRARY_IMPORT __declspec(dllimport)
#elif defined(__GNUC__) && __GNUC__ > 3
# define LIBRARY_EXPORT __attribute__((visibility("default")))
# define LIBRARY_IMPORT __attribute__((visibility("default")))
#else
# define LIBRARY_EXPORT
# define LIBRARY_IMPORT
#endif

#ifdef LIBRARY_API_EXPORTS
# define LIBRARY_API LIBRARY_EXPORT
#elif LIBRARY_API_IMPORTS
# define LIBRARY_API LIBRARY_IMPORT
#else
# define LIBRARY_API
#endif
#endif /* MESHING_DLL_CONFIG_H */

包装器.h
#ifndef MESHING_WRAPPERS_H
#define MESHING_WRAPPERS_H

#include <exception>
#include "configuration.h"
#include "callbacks.h"
#include "poisson_surface_reconstructor.h"

typedef intptr_t ArrayHandle;

extern "C"
{
LIBRARY_EXPORT bool ExecutePoissonSurfaceReconstruction(
int argc,
char* argv[],
ProgressCallback progressCallback,
WarningCallback warningCallback,
ErrorCallback errorCallback);

LIBRARY_EXPORT bool Release(ArrayHandle arrayHandle);
}
#endif // MESHING_WRAPPERS_H

包装器.cpp
#include "wrappers.h"

using namespace MeshingAdapter;

LIBRARY_EXPORT bool ExecutePoissonSurfaceReconstruction(
int argc,
char* argv[],
ProgressCallback progressCallback,
WarningCallback warningCallback,
ErrorCallback errorCallback)
{
try
{
PoissonSurfaceReconstructor* poissonSurfaceRecon =
new PoissonSurfaceReconstructor(
progressCallback,
warningCallback,
errorCallback);
bool success = poissonSurfaceRecon->ExecuteSurfaceReconstruction(argc, argv);
delete poissonSurfaceRecon;
return success;
}
catch (const std::exception& ex)
{
errorCallback(ex.what());
return false;
}
}

LIBRARY_EXPORT bool Release(ArrayHandle arrayHandle)
{
// #TODO can we do this smarter?
return true;
}

但是,包含 possion_surface_reconstructor.h原因 114 LNK2005错误,主要来自我从不同项目中引用的类。一个例子是

2>wrappers.obj : error LNK2005: "private: static bool ThreadPool::_Close" (?_Close@ThreadPool@@0_NA) already defined in poisson_surface_reconstructor.obj
2>wrappers.obj : error LNK2005: "public: static unsigned __int64 ThreadPool::DefaultChunkSize" (?DefaultChunkSize@ThreadPool@@2_KA) already defined in poisson_surface_reconstructor.obj
2>wrappers.obj : error LNK2005: "private: static class std::vector<class std::thread,class std::allocator<class std::thread> > ThreadPool::_Threads" (?_Threads@ThreadPool@@0V?$vector@Vthread@std@@V?$allocator@Vthread@std@@@2@@std@@A) already defined in poisson_surface_reconstructor.obj
2>wrappers.obj : error LNK2005: "private: static class std::condition_variable ThreadPool::_DoneWithWork" (?_DoneWithWork@ThreadPool@@0Vcondition_variable@std@@A) already defined in poisson_surface_reconstructor.obj
2>wrappers.obj : error LNK2005: "public: static int const (* HyperCube::MarchingSquares::edges)[5]" (?edges@MarchingSquares@HyperCube@@2QAY04$$CBHA) already defined in poisson_surface_reconstructor.obj
2>wrappers.obj : error LNK2005: "char const * * type_names" (?type_names@@3PAPEBDA) already defined in poisson_surface_reconstructor.obj
2>wrappers.obj : error LNK2005: "char const * * BoundaryNames" (?BoundaryNames@@3PAPEBDA) already defined in poisson_surface_reconstructor.obj
2>wrappers.obj : error LNK2005: "char const * * ShowGlobalResidualNames" (?ShowGlobalResidualNames@@3PAPEBDA) already defined in poisson_surface_reconstructor.obj
2>wrappers.obj : error LNK2005: "private: static unsigned int volatile ThreadPool::_RemainingTasks" (?_RemainingTasks@ThreadPool@@0IC) already defined in poisson_surface_reconstructor.obj
2>wrappers.obj : error LNK2005: "public: static char const * const StackTracer::exec" (?exec@StackTracer@@2PEBDEB) already defined in poisson_surface_reconstructor.obj
2>wrappers.obj : error LNK2005: "public: static char const * const ImageWriterParams::DefaultTileExtension" (?DefaultTileExtension@ImageWriterParams@@2PEBDEB) already defined in poisson_surface_reconstructor.obj
2>wrappers.obj : error LNK2005: "public: static enum ThreadPool::ScheduleType ThreadPool::DefaultSchedule" (?DefaultSchedule@ThreadPool@@2W4ScheduleType@1@A) already defined in poisson_surface_reconstructor.obj

和更多。从上面的错误列表中举一个例子 ThreadPool::DefaultSchedule这是在我引用的一个包含文件中定义的,并且是我的代码库的一部分。这个 struct定义为
struct ThreadPool
{
enum ParallelType
{
#ifdef _OPENMP
OPEN_MP ,
#endif // _OPENMP
THREAD_POOL ,
ASYNC ,
NONE
};
static const std::vector< std::string > ParallelNames;

enum ScheduleType
{
STATIC ,
DYNAMIC
};
static const std::vector< std::string > ScheduleNames;

static size_t DefaultChunkSize;
static ScheduleType DefaultSchedule;

template< typename ... Functions >
static void ParallelSections( const Functions & ... functions )
{
std::vector< std::future< void > > futures( sizeof...(Functions) );
_ParallelSections( &futures[0] , functions ... );
for( size_t t=0 ; t<futures.size() ; t++ ) futures[t].get();
}

static void Parallel_for( size_t begin , size_t end , const std::function< void ( unsigned int , size_t ) > &iterationFunction , ScheduleType schedule=DefaultSchedule , size_t chunkSize=DefaultChunkSize )
{
if( begin>=end ) return;
size_t range = end - begin;
size_t chunks = ( range + chunkSize - 1 ) / chunkSize;
unsigned int threads = (unsigned int)NumThreads();
std::atomic< size_t > index;
index.store( 0 );


if( range<chunkSize || _ParallelType==NONE || threads==1 )
{
for( size_t i=begin ; i<end ; i++ ) iterationFunction( 0 , i );
return;
}

auto _ChunkFunction = [ &iterationFunction , begin , end , chunkSize ]( unsigned int thread , size_t chunk )
{
const size_t _begin = begin + chunkSize*chunk;
const size_t _end = std::min< size_t >( end , _begin+chunkSize );
for( size_t i=_begin ; i<_end ; i++ ) iterationFunction( thread , i );
};
auto _StaticThreadFunction = [ &_ChunkFunction , chunks , threads ]( unsigned int thread )
{
for( size_t chunk=thread ; chunk<chunks ; chunk+=threads ) _ChunkFunction( thread , chunk );
};
auto _DynamicThreadFunction = [ &_ChunkFunction , chunks , &index ]( unsigned int thread )
{
size_t chunk;
while( ( chunk=index.fetch_add(1) )<chunks ) _ChunkFunction( thread , chunk );
};

if ( schedule==STATIC ) _ThreadFunction = _StaticThreadFunction;
else if( schedule==DYNAMIC ) _ThreadFunction = _DynamicThreadFunction;

if( false ){}
#ifdef _OPENMP
else if( _ParallelType==OPEN_MP )
{
if( schedule==STATIC )
#pragma omp parallel for num_threads( threads ) schedule( static , 1 )
for( int c=0 ; c<chunks ; c++ ) _ChunkFunction( omp_get_thread_num() , c );
else if( schedule==DYNAMIC )
#pragma omp parallel for num_threads( threads ) schedule( dynamic , 1 )
for( int c=0 ; c<chunks ; c++ ) _ChunkFunction( omp_get_thread_num() , c );
}
#endif // _OPENMP
else if( _ParallelType==ASYNC )
{
static std::vector< std::future< void > > futures;
futures.resize( threads-1 );
for( unsigned int t=1 ; t<threads ; t++ ) futures[t-1] = std::async( std::launch::async , _ThreadFunction , t );
_ThreadFunction( 0 );
for( unsigned int t=1 ; t<threads ; t++ ) futures[t-1].get();
}
else if( _ParallelType==THREAD_POOL )
{
unsigned int targetTasks = 0;
if( !SetAtomic( &_RemainingTasks , threads-1 , targetTasks ) )
{
WARN( "nested for loop, reverting to serial" );
for( size_t i=begin ; i<end ; i++ ) iterationFunction( 0 , i );
}
else
{
_WaitingForWorkOrClose.notify_all();
{
std::unique_lock< std::mutex > lock( _Mutex );
_DoneWithWork.wait( lock , [&]( void ){ return _RemainingTasks==0; } );
}
}
}
}

static unsigned int NumThreads( void ){ return (unsigned int)_Threads.size()+1; }

static void Init( ParallelType parallelType , unsigned int numThreads=std::thread::hardware_concurrency() )
{
_ParallelType = parallelType;
if( _Threads.size() && !_Close )
{
_Close = true;
_WaitingForWorkOrClose.notify_all();
for( unsigned int t=0 ; t<_Threads.size() ; t++ ) _Threads[t].join();
}
_Close = true;
numThreads--;
_Threads.resize( numThreads );
if( _ParallelType==THREAD_POOL )
{
_RemainingTasks = 0;
_Close = false;
for( unsigned int t=0 ; t<numThreads ; t++ ) _Threads[t] = std::thread( _ThreadInitFunction , t );
}
}
static void Terminate( void )
{
if( _Threads.size() && !_Close )
{
_Close = true;
_WaitingForWorkOrClose.notify_all();
for( unsigned int t=0 ; t<_Threads.size() ; t++ ) _Threads[t].join();
_Threads.resize( 0 );
}
}
private:
ThreadPool( const ThreadPool & ){}
ThreadPool &operator = ( const ThreadPool & ){ return *this; }

template< typename Function >
static void _ParallelSections( std::future< void > *futures , const Function &function ){ *futures = std::async( std::launch::async , function ); }
template< typename Function , typename ... Functions >
static void _ParallelSections( std::future< void > *futures , const Function &function , const Functions& ... functions )
{
*futures = std::async( std::launch::async , function );
_ParallelSections( futures+1 , functions ... );
}
static void _ThreadInitFunction( unsigned int thread )
{
// Wait for the first job to come in
std::unique_lock< std::mutex > lock( _Mutex );
_WaitingForWorkOrClose.wait( lock );
while( !_Close )
{
lock.unlock();
// do the job
_ThreadFunction( thread );

// Notify and wait for the next job
lock.lock();
_RemainingTasks--;
if( !_RemainingTasks ) _DoneWithWork.notify_all();
_WaitingForWorkOrClose.wait( lock );
}
}

static bool _Close;
static volatile unsigned int _RemainingTasks;
static std::mutex _Mutex;
static std::condition_variable _WaitingForWorkOrClose , _DoneWithWork;
static std::vector< std::thread > _Threads;
static std::function< void ( unsigned int ) > _ThreadFunction;
static ParallelType _ParallelType;
};

显然 static ScheduleType DefaultSchedule;作为静态变量会导致问题,而其他错误可能是由相同的问题引起的(这最初不是我的代码,我需要将其包装以暴露给 C#)。
  • 对于 ThreadPool 的情况为什么值类型struct ThreadPool那是我的 PossionSurfaceReconstructor 的成员导致这个问题的类?
  • 解决此问题的最简单方法是什么(不将每个错误实例的 struct 更改为 class

  • 提前致谢。

    最佳答案

    #include指令本质上是在 #include 的位置处执行指定文件内容的文本级复制和粘贴。出现。您的标题 MyMiscellany.h包含一堆静态成员变量的定义:

    size_t ThreadPool::DefaultChunkSize = 128;
    ThreadPool::ScheduleType ThreadPool::DefaultSchedule = ThreadPool::DYNAMIC;
    bool ThreadPool::_Close;
    volatile unsigned int ThreadPool::_RemainingTasks;
    std::mutex ThreadPool::_Mutex;
    std::condition_variable ThreadPool::_WaitingForWorkOrClose;
    std::condition_variable ThreadPool::_DoneWithWork;
    std::vector< std::thread > ThreadPool::_Threads;
    std::function< void ( unsigned int ) > ThreadPool::_ThreadFunction;
    ThreadPool::ParallelType ThreadPool::_ParallelType;

    当此 header 包含在多个 .cpp 文件中时,这些变量将有多个定义。程序中只能有一个非内联函数或变量的定义 [basic.def.odr]/4 ,这正是链接器所提示的:

    2>wrappers.obj : error LNK2005: "private: static bool ThreadPool::_Close" (?_Close@ThreadPool@@0_NA) already defined in poisson_surface_reconstructor.obj
    […]



    此错误消息只是告诉您 ThreadPool::_Close等,在 wrappers.obj 中有一个定义。 , 在 poisson_surface_reconstructor.obj 中已有定义.两者, poisson_surface_reconstructor.cpp以及 wrappers.cpp (间接)包括 MyMiscellany.h ,因此,编译这两个 .cpp 文件产生的两个目标文件中的每一个都包含所有这些变量的定义。当定义包含 MyMiscellany.h 时,它们被粘贴到每个 .cpp 文件中。 .

    要解决这个问题,您可以将有问题的变量内联(需要 C++17),在这种情况下,您也可以将定义保留在类内,而不必在类外定义变量

    class ThreadPool
    {

    inline static bool Close = true;

    };

    或将定义移动到单独的 .cpp 文件中(参见 this question 了解更多信息)。

    注: extern "C"与消除任何东西无关。它所做的只是声明所讨论的实体应具有 C 语言链接,无论这在目标平台上意味着什么。例如,在 Windows 上, even C linkage may still involve name mangling

    此外,我建议更换您的 volatile变量 _RemainingTasks和定制 SetAtomic使用 std::atomic 实现.

    最后,请注意包含双下划线的标识符以及以下划线开头后跟大写字母的标识符,例如 _Close , 保留 [lex.name]/3 .实际上,您不允许在代码中使用类似的标识符。

    关于c++ - extern "C"拆解导致奇怪的链接器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59832270/

    43 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com