我能够从命名空间引用函数,但不能引用类。这是名称空间文件 SeqLib / FermiAssembler.h"
#ifndef SEQLIB_FERMI_H
#define SEQLIB_FERMI_H
#include <string>
#include <cstdlib>
#include <iostream>
namespace SeqLib
{
void print_my_name(){ std::cout << "It's Crt" }
class FermiAssembler {
public:
FermiAssembler();
~FermiAssembler();
void AddReads(const BamRecordVector& brv);
};
}
我可以致电print_my_name() via SeqLib::print_my_name()
,但无法通过SeqLib::FermiAssembler f
这是我/src
#include <iostream>
#include <Rcpp.h>
#include "SeqLib/FermiAssembler.h"
using namespace std;
// [[Rcpp::export]]
void whats_my_name(){
SeqLib::FermiAssembler f;
这是包的结构
temp
seqLib
SeqLib
src
FermiAssembler.cpp
SeqLib
FermiAssembler.h
headerFiles
SeqLibCommon.h
src
hello_world.cpp
Makevars which contains PKG_CXXFLAGS= -I../SeqLib
这是 FermiAssembler.cpp 定义的
#include "SeqLib/FermiAssembler.h"
#define MAG_MIN_NSR_COEF .1
namespace SeqLib {
FermiAssembler::~FermiAssembler() {
ClearReads();
ClearContigs();
}
}
错误消息为:Error in dyn.load(dllfile) :
unable to load shared object 'temp/seqLib/src/SeqLib.so':
temp/seqLib/src/SeqLib.so: undefined symbol: _ZN6SeqLib14FermiAssemblerD1Ev
更新我已将整个子模块移动到src文件夹中:
# temp
# |─── src
# |────SeqLib
# |──────SeqLib
# |────── FermiAssembler.h
# |──────src
# |────── FermiAssembler.cpp
答案 0 :(得分:3)
当您看到引用_ZN6SeqLib14FermiAssemblerD1Ev
之类的错误时,第一步是通过名称解析器c++filt
运行它,它应包含在任何Linux发行版中:
$ c++filt _ZN6SeqLib14FermiAssemblerD1Ev
# SeqLib::FermiAssembler::~FermiAssembler()
问题是,在您的标头文件中,声明了类FermiAssembler
的析构函数,但没有提供定义。你的选择是
~FermiAssembler() {}
(请注意大括号,将其与声明区分开来)。这相当于使用编译器生成的析构函数,如上所述。 FermiAssembler
类不需要非默认的析构函数,但是为了演示的目的我们将在下面探讨此选项。 这是我将要使用的文件布局;您需要相应地调整#include
路径等:
tree example/
# example/
# ├── DESCRIPTION
# ├── example.Rproj
# ├── NAMESPACE
# ├── R
# │ └── RcppExports.R
# └── src
# ├── demo.cpp
# ├── FermiAssembler.cpp
# ├── FermiAssembler.h
# └── RcppExports.cpp
标题FermiAssembler.h
现在变为:
#ifndef SEQLIB_FERMI_H
#define SEQLIB_FERMI_H
namespace SeqLib {
class BamRecordVector;
void print_my_name();
class FermiAssembler {
public:
FermiAssembler();
~FermiAssembler();
void AddReads(const BamRecordVector& brv);
};
} // SeqLib
#endif // SEQLIB_FERMI_H
请注意,我还将print_my_name
转换为函数原型,因此还需要在相应的源文件中定义它。此外,您可以将之前的#include
移动到源文件,因为此处不再需要它们:
// FermiAssembler.cpp
#include "FermiAssembler.h"
#include <iostream>
#include <Rcpp.h>
namespace SeqLib {
void print_my_name() {
std::cout << "It's Crt";
}
FermiAssembler::FermiAssembler()
{
Rcpp::Rcout << "FermiAssembler constructor\n";
}
FermiAssembler::~FermiAssembler()
{
Rcpp::Rcout << "FermiAssembler destructor\n";
}
} // SeqLib
最后,使用此类的文件:
// demo.cpp
#include "FermiAssembler.h"
// [[Rcpp::export]]
int whats_my_name() {
SeqLib::FermiAssembler f;
return 0;
}
在构建和安装软件包之后,它按预期工作:
library(example)
whats_my_name()
# FermiAssembler constructor
# FermiAssembler destructor
# [1] 0
更新关于“可以在顶级src/
目录以外的地方拥有源文件吗?”的问题,是的,你可以,但我会通常建议不要这样做,因为它需要一个非常重要的Makevars
文件。现在使用这种布局,
tree example
# example
# ├── DESCRIPTION
# ├── example.Rproj
# ├── man
# ├── NAMESPACE
# ├── R
# │ └── RcppExports.R
# ├── SeqLib
# │ ├── SeqLib
# │ │ └── FermiAssembler.h
# │ └── src
# │ └── FermiAssembler.cpp
# └── src
# ├── demo.cpp
# ├── Makevars
# └── RcppExports.cpp
我们位于顶级src/
目录(不 SeqLib/src
)此Makevars
:
PKG_CXXFLAGS= -I../SeqLib
SOURCES = $(wildcard ../SeqLib/*/*.cpp *.cpp)
OBJECTS = $(wildcard ../SeqLib/*/*.o *.o) $(SOURCES:.cpp=.o)
请注意,在上面的示例中,我们只是将所有目标文件编译到同一个共享库中。例如,如果您需要编译中间共享库或静态库并将它们链接到最终.so
,那么期望您的Makevars
变得更加混乱。
重建和安装,
library(example)
whats_my_name()
# FermiAssembler constructor
# FermiAssembler destructor
# [1] 0