我的项目最近表现得很好 - 我解决了一大堆错误,然后它引发了一个神秘的ld: symbol(s) not found
错误。但是,很明显符号确实存在:
Undefined symbols:
"Solid::~Solid()", referenced from:
void std::_Destroy<Solid>(Solid*)in ui.o
"Log::operator+=(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)", referenced from:
runUI() in ui.o
"Log::getLog(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)", referenced from:
runUI() in ui.o
"Log::Log()", referenced from:
__static_initialization_and_destruction_0(int, int)in ui.o
"Building::Building(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)", referenced from:
runUI() in ui.o
"Log::~Log()", referenced from:
___tcf_1 in ui.o
以下是它引用的文件:
/*
* log.cpp
*
* Created on: Apr 30, 2011
* Author: wjc
*/
#include <string>
#include <vector>
#include <sstream> // for converting count to string
#include "consts.h"
using namespace std;
struct logResult {
vector <string> result;
int status;
};
struct parsedLog {
string result;
int status;
};
class Log {
private:
bool initialized;
vector <string> * actionLog;
static int count;
string countString(){
stringstream ss;
ss<<count;
return ss.str();
}
public:
int initialize(){
if (initialized) return ALREADY_INIT;
actionLog->push_back("*** Log initialized ***");
actionLog->push_back("This is log#" + countString() +". If this is greater than one, there is a problem.");
initialized = true;
return SUCCESS;
}
int initialize(string text){
int initResult = initialize();
if (initResult == ALREADY_INIT) return ALREADY_INIT;
actionLog->push_back("Initialization message: "+text);
return SUCCESS;
}
Log (){
initialize();
count++;
}
Log (string text){
initialize(text);
count++;
}
~Log (){
count--;
}
bool isInitialized(){
return initialized;
}
int add(string text){
if (!initialized) return NOT_INIT;
actionLog->push_back(text);
return SUCCESS;
}
int operator+= (string text){
return add(text);
}
int clearLog(bool init = true){
if (!initialized) return NOT_INIT;
delete actionLog;
int initResult = SUCCESS;
if (init) initResult = initialize();
if (initResult == ALREADY_INIT) return ALREADY_INIT;
// Otherwise
// (no other possibilities because initialize()
// only returns either a SUCCESS or
// ALREADY_INIT value)
return SUCCESS;
}
logResult getLog(){
if (!initialized){
logResult final;
final.status = NOT_INIT;
return final;
} else {
logResult final;
final.result = *actionLog;
final.status = SUCCESS;
return final;
}
}
parsedLog getLog(string delim){
if (!initialized){
parsedLog final;
final.status = NOT_INIT;
return final;
} else {
parsedLog final;
string logString;
for (unsigned int i; i<actionLog->size()-1; i++){
logString += (*actionLog)[i];
logString += delim;
}
logString += actionLog->back();
final.result = logString;
final.status = SUCCESS;
return final;
}
}
};
/*
* log.h
*
* Created on: Apr 30, 2011
* Author: wjc
*/
#ifndef LOG_H_
#define LOG_H_
#include <string>
using namespace std;
struct logResult {
vector <string> result;
int status;
};
struct parsedLog {
string result;
int status;
};
class Log {
public:
int initialize();
int initialize(string text);
Log ();
Log (string text);
~Log();
bool isInitialized;
int add(string text);
int operator+= (string text);
int clearLog (bool init = true);
vector <string> getLog();
parsedLog getLog(string delim);
private:
bool initialized;
vector <string> actionLog;
static int count;
string countString();
};
#endif /* LOG_H_ */
/*
* Created on: Apr 26, 2011
* ui.cpp
* Author: wjc
*/
#include <iostream>
#include <vector>
#include <sstream>
#include "filedaemon.h"
#include "vsystem.h"
#include "customio.h"
#include "building.h"
#include "log.h"
using namespace std;
bool shouldexit = false;
bool back = false;
int selection;
void addShape();
void modifyVars();
struct getVarResult {
var result;
int status;
};
Log actionLog;
var novar = {"ERROR", -1, Reserved};
getVarResult getVar(int type);
void viewBuilding();
int runUI(){
while (!shouldexit){
cout<<"Please select an item from the list below and press Enter:"<<endl;
const int mmenuLength = 2;
string mmenuOptions[2] = {"Create a new document","Quit"};
for (int i=0; i<2; i++){
cout<<i+1<<": "<<mmenuOptions[i]<<endl;
} cout<<endl;
selection = getMenuItem(1,mmenuLength);
if (selection == mmenuLength) return 0; // Quit if it's the last one
cout<<"Enter a name for your building:"<<endl;
string buildingTitle;
getline(cin, buildingTitle);
Building b(buildingTitle);
actionLog += "New building " + buildingTitle + " created.";
const int bmenuLength = 5;
string bmenuOptions[5] = {"Add shape","Modify variables","View building","View log","Quit"};
for (int i=0; i<bmenuLength; i++){
cout<<i+1<<": "<<bmenuOptions[i]<<endl;
} cout<<endl;
selection = getMenuItem(1,bmenuLength);
switch (selection){
case 1:
// Add a shape
break;
case 2:
modifyVars();
break;
case 3:
// View building
break;
case 4:
{
parsedLog parsed = actionLog.getLog("\n");
if (parsed.status == SUCCESS) {
cout<<"The following contains the contents of your action log."<<endl;
cout<<parsed.result<<endl<<endl;
} else {
cout<<"Somehow your log is not initialized."<<endl<<endl;
}
}
break;
case 5:
shouldexit = true;
break;
default:
cout<<"You entered a number greater than "<<bmenuLength<<" or less than 1. How you did this is a mystery."<<endl<<"[ Press Enter to exit ]"<<endl;
string temp;
getline(cin, temp);
return 0;
}
// The following commented-out block is a
// test of the variable storing system.
// It will not be used in any final products.
/*cout << " Variable Systems Test "<<endl;
cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~"<<endl;
cout << endl;
cout<<"Enter a variable name:"<<endl;
string varname;
cin>>varname;
cout<<"Enter a value (A FLOAT!):"<<endl;
float value;
cin>>value;
cout<<"Checking to see if "<<varname<<" exists."<<endl;
bool alreadythere = checkVar(varname);
alreadythere ? cout<<"It exists!"<<endl : cout<<"It doesn't exist."<<endl;
if (alreadythere){
cout<<"Changing variable. Function returned "<<changeVar(varname, value)<<endl;
} else {
cout<<"Setting variable. Function returned "<<addVar(varname, value)<<endl;
}
cout<<"Enter a variable to check:"<<endl;
string varcheck;
cin>>varcheck;
fetchResult result = fetchVar(varcheck);
if(! result.good){
cout<<"Variable \""<<varcheck<<"\" doesn't exist!"<<endl;
} else {
cout<<"Variable \""<<varcheck<<"\" is equal to "<<result.result<<endl;
}
cout<<getVarList("\n","\t")<<endl;
string exitstr;
getch;*/
}
return 0;
}
void modifyVars(){
while (! back){
cout<<"These are your defined variables."<<endl;
cout<<"Reserved variables have an asterisk preceding them."<<endl;
vector <var> vars = getVarList();
for (unsigned int i = 0; i<vars.size(); i++){
cout<<endl;
vars[i].reserved ? cout<<" * " : cout<<" ";
cout << vars[i].name<<" = ";
cout<<fixed<<vars[i].value;
}cout<<endl;
cout<<"What would you like to do?"<<endl;
string varMenuOptions[4] = {"Add a variable","Change a variable","Remove a variable","Go back"};
for (int i = 0; i<4; i++){
cout<<i+1<<". "<<varMenuOptions[i]<<endl;
} cout<<endl;
selection = getMenuItem(1,3);
switch(selection){
case 1: // Add variable
{
getVarResult gvr = getVar(ADD);
if (gvr.status == SUCCESS)
addVar(gvr.result.name, gvr.result.value, UserDefined);
break;
}
case 2: // Change variable
{
getVarResult gvr = getVar(CHANGE);
if (gvr.status == SUCCESS)
changeVar(gvr.result.name, gvr.result.value);
break;
} // switch (selection)
} // while (!back)
}
}
getVarResult getVar(int type){
getVarResult finalResult;
getVarResult invalidType;
getVarResult cancelled;
invalidType.result = novar;
invalidType.status = INVALID_TYPE;
cancelled.result = novar;
cancelled.status = USER_CANCELLED;
if (type != ADD && type != CHANGE) return invalidType;
bool usercancelled = false;
bool nameOK = true;
bool varIsReserved = false;
string varName;
do {
switch(type){
case ADD:
if (!nameOK) cout<<"That variable already exists."<<endl;
break;
case CHANGE:
if (!nameOK) cout<<"That variable has not yet been created."<<endl;
if (varIsReserved) cout<<"That variable is used by the system and cannot be changed."<<endl;
break;
}
cout<<"Enter the variable's name, or \"BACK\": "; varName = getString(1,16);
if (varName == "BACK"){
usercancelled = true;
break;
}
fetchResult testExist = fetchVar(varName);
switch(type){
case ADD:
nameOK = !testExist.good;
break;
case CHANGE:
nameOK = testExist.good;
varIsReserved = testExist.reserved;
break;
default:
cout << "Function error - int type seems to have changed since user called getVar(int type)."<<endl;
cout << "[ Press Enter to exit]"<<endl;
string temp;
getline(cin, temp);
return invalidType;
}
} while (! nameOK || varIsReserved);
finalResult.result.name = varName;
if (usercancelled) return cancelled;
bool valueOK = true;
float numValue;
do {
if (! valueOK) cout<<"That doesn't seem to be a valid positive number.";
cout<<"Enter the new value, or \"COPY\" to copy a variable, or \"BACK\":"<<endl;
string value = getString();
/*
* If "BACK" then break do-while(! valueOK)
*/
if (value == "BACK"){
usercancelled = true;
break;
}
if(value == "COPY"){
string copyVar;
fetchResult varContents;
bool copyOK = true;
do {
if (!copyOK) cout<<"That variable does not exist. Note that names are case-sensitive."<<endl;
cout<<"Enter the variable to copy, \"VIEW\" to view all, or \"BACK\":"<<endl;
/*
* If "BACK" then break do-while(! valueOK)
*/
if (value == "BACK"){
usercancelled = true;
break;
}
copyVar = getString(1,8);
if (copyVar == "VIEW") {
cout<<"Your current variables are as follows:"<<endl;
vector <var> vars = getVarList();
for (unsigned int i = 0; i<vars.size(); i++){
cout<<endl;
vars[i].reserved ? cout<<" * " : cout<<" ";
cout << vars[i].name<<" = ";
cout<<fixed<<vars[i].value;
}cout<<endl;
} else {
varContents = fetchVar(copyVar);
copyOK = varContents.good;
numValue = varContents.result;
}
} while (copyVar == "VIEW" || ! copyOK);
} else {
// This code converts from string to number safely.
stringstream testStream(value);
if (! (testStream >> numValue))
valueOK = false;
}
if (! usercancelled) break;
} while (! valueOK);
finalResult.result.value = numValue;
if (usercancelled) return cancelled;
finalResult.status = SUCCESS;
return finalResult;
}
/*
* ui.h
*
* Created on: Apr 26, 2011
* Author: wjc
*/
#ifndef UI_H_
#define UI_H_
#include "vsystem.h"
int runUI();
void addShape();
void modifyVars();
struct getVarResult {
var result;
int status;
};
getVarResult getVar(int type);
void viewBuilding();
#endif /* UI_H_ */
/*
* building.h
*
* Created on: Apr 30, 2011
* Author: wjc
*/
#ifndef BUILDING_H_
#define BUILDING_H_
#include <string>
#include <vector>
#include "consts.h"
#include "solid_type.h"
using namespace std;
struct dimension {
bool exists;
float value;
};
class Solid {
public:
string name;
string comment;
solid_type type;
bool positive;
dimension dim1; // Radius, width, or side length
dimension dim2; // Height, number of sides, or fraction of sphere_over_n
dimension dim3; // Width - only for prism_rect, pyrm_rect and tprym_rect
Solid ();
Solid (bool pos);
Solid (string setName, string setComment, solid_type setType, bool setPos, dimension setDim1,
dimension setDim2, dimension setDim3);
~Solid();
int countShapes();
int howMany();
private:
static int count;
};
class Building {
private:
string name;
vector <Solid> components;
public:
Building(string text);
void setName(string text);
string getName();
vector <Solid> addComponent(Solid component);
};
#endif /* BUILDING_H_ */
/*
* building.cpp
*
* Created on: May 1, 2011
* Author: wjc
*/
#include <string>
#include <vector>
#include "consts.h"
#include "solid_type.h"
using namespace std;
struct dimension {
bool exists;
float value;
};
class Solid{
public:
string name; // So the user can look at the log
string comment; // Expanded version of name, again for the log
solid_type type; // Determines the type of Solid
bool positive; // Positive = addition; negative = subtraction
dimension dim1; // Radius, width, or side length
dimension dim2; // Height, number of sides, or fraction of sphere_over_n
dimension dim3; // Width - only for prism_rect, pyrm_rect and tprym_rect
Solid(){
count++;
}
Solid(bool setPos){
count++;
positive = setPos;
}
Solid (string setName, string setComment, solid_type setType, bool setPos, dimension setDim1,
dimension setDim2, dimension setDim3){
count++;
name = setName;
comment = setComment;
type = setType;
positive = setPos;
dim1 = setDim1;
dim2 = setDim2;
dim3 = setDim3;
}
~Solid(){
count--;
}
int howMany(){
return count;
}
int countSolids(){
return howMany();
}
private:
static int count; // Number of Solids in existence
};
class Building {
private:
string name;
vector <Solid> components;
public:
Building (string text){
setName(text);
}
void setName(string text) {
name = text;
}
string getName(){
return name;
}
vector <Solid> addComponent(Solid component){
components.push_back(component);
return components;
}
};
我的完整代码可以在FileDropper找到,虽然我知道大多数人都不想打开拉链,所以我把相关的代码放在上面。 任何帮助将不胜感激!
在Mac OS X Snow Leopard 10.6.7上使用G ++ 4.2.1运行Eclipse Helios。
完整的链接命令是:
g++ -o "BuildingGenerator" ./src/bgmath.o ./src/building.o ./src/customio.o \
./src/filedaemon.o ./src/log.o ./src/main.o ./src/ui.o ./src/vsystem.o
所以看起来它正在链接所有必要的文件。此外,(标题)文件在需要时都是#include
'。
答案 0 :(得分:2)
发现问题;大纲修复创建......
接收,解包和编译代码;链接器产生的错误基本上与您所看到的相同......
Osiris-8 JL: make bgmath.o building.o customio.o filedaemon.o log.o main.o ui.o vsystem.o
g++ -c -o bgmath.o bgmath.cpp
g++ -c -o building.o building.cpp
g++ -c -o customio.o customio.cpp
g++ -c -o filedaemon.o filedaemon.cpp
g++ -c -o log.o log.cpp
g++ -c -o main.o main.cpp
g++ -c -o ui.o ui.cpp
g++ -c -o vsystem.o vsystem.cpp
Osiris-8 JL: g++ -o cmd *.o
Undefined symbols for architecture x86_64:
"Building::Building(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)", referenced from:
runUI() in ui.o
"Log::operator+=(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)", referenced from:
runUI() in ui.o
"Log::getLog(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)", referenced from:
runUI() in ui.o
"Log::Log()", referenced from:
__static_initialization_and_destruction_0(int, int) in ui.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
Osiris-8 JL:
这是在带有GCC 4.6.0(我编译的)的MacOS X 10.6.7上。由于它与你得到的基本相同,G ++的版本基本上是无关紧要的(但并非完全相同; Apple与GCC 4.2.1一起分发的c ++过滤器不能识别你提供的'nm'输出,即使在清除文件中的BOM。)
好的 - 以后几个白发 - 我大致知道发生了什么。
当我运行nm log.o
时,它会说'nm: no name list
'。那是因为它实际上是一个空的目标文件。它是一个空目标文件,因为所有代码都在类声明中,但从未使用过,因此文件中没有目标代码,也没有函数。
我怀疑它与定义有关 - 我没有猜到它是完全'没有定义的功能'。
那么,我们该如何解决呢?
第一个问题是你有log.cpp但它不包括log.h.这是问题的有力指标。标头定义了源中定义的类的公共接口,并且确保它们一致的唯一(理智)方法是在源文件中包含标头。实际上,最好首先包含标题,以便确保它是自包含的(可以在任何源模块中使用)。
当我们这样做时,我们立即发现log.h不是自包含的 - 它也需要#include <vector>
。当修复后,我们发现你无法成功编译log.cpp:
g++ -c -o log.o log.cpp
log.cpp:12:8: error: redefinition of ‘struct logResult’
log.h:15:8: error: previous definition of ‘struct logResult’
log.cpp:17:8: error: redefinition of ‘struct parsedLog’
log.h:20:8: error: previous definition of ‘struct parsedLog’
log.cpp:22:7: error: redefinition of ‘class Log’
log.h:25:7: error: previous definition of ‘class Log’
make: *** [log.o] Error 1
这两个结构在标题中声明,因此不应在源代码中重新声明它们。函数定义必须以Log ::为前缀,并从“class Log {...}”括号中删除。然后例行清理编译错误,导致:
#ifndef LOG_H_
#define LOG_H_
#include <vector>
#include <string>
using namespace std;
struct logResult {
vector <string> result;
int status;
};
struct parsedLog {
string result;
int status;
};
class Log {
public:
int initialize();
int initialize(string text);
Log ();
Log (string text);
bool isInitialized();
int add(string text);
int operator+= (string text);
int clearLog (bool init = true);
logResult getLog();
parsedLog getLog(string delim);
private:
bool initialized;
vector <string> actionLog;
};
#endif /* LOG_H_ */
#include "log.h"
#include "consts.h"
using namespace std;
int Log::initialize(){
if (initialized) return ALREADY_INIT;
actionLog.push_back("*** Log initialized ***");
initialized = true;
return SUCCESS;
}
int Log::initialize(string text){
if (initialized) return ALREADY_INIT;
// otherwise...
initialize();
actionLog.push_back("Initialization message: "+text);
return SUCCESS;
}
Log::Log (){
initialize();
}
Log::Log (string text){
initialize(text);
}
bool Log::isInitialized(){
return initialized;
}
int Log::add(string text){
if (!initialized) return NOT_INIT;
actionLog.push_back(text);
return SUCCESS;
}
int Log::operator+= (string text){
return add(text);
}
int Log::clearLog(bool init){
if (!initialized) return NOT_INIT;
//delete actionLog;
initialized = false;
if (init) return initialize();
// Else
return SUCCESS;
}
logResult Log::getLog(){
if (!initialized){
logResult final;
final.status = NOT_INIT;
return final;
} else {
logResult final;
final.result = actionLog;
final.status = SUCCESS;
return final;
}
}
parsedLog Log::getLog(string delim){
if (!initialized){
parsedLog final;
final.status = NOT_INIT;
return final;
} else {
parsedLog final;
string logString;
for (unsigned int i; i<actionLog.size()-1; i++){
logString += actionLog[i];
logString += delim;
}
logString += actionLog.back();
final.result = logString;
final.status = SUCCESS;
return final;
}
}
这些文件干净地编译以生成包含一些有用功能的log.o.之后的链接失败是:
Undefined symbols for architecture x86_64:
"Building::Building(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)", referenced from:
runUI() in ui.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
修复这个问题留给你 - 但我相信在building.h和building.cpp中需要进行类似的修改。
仍有一些问题需要解决。特别是,标题通常不应该using namespace std;
,因为这是对其他程序员对其使用的名称空间的控制的无理侵入。有关此问题的最新讨论,请参阅Using namespace in C++ headers。