ld:找不到符号......但他们在那里......

时间:2011-05-03 01:51:56

标签: eclipse macos linker g++

我的项目最近表现得很好 - 我解决了一大堆错误,然后它引发了一个神秘的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

/*
 * 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

/*
 * 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_ */

ui.cppp

/*
 *  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

/*
 * 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

/*
 * 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

/*
 * 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'。

1 个答案:

答案 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 {...}”括号中删除。然后例行清理编译错误,导致:


log.h

#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_ */

log.cpp

#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