尽管编译了库的通用版本和 i386 版本,但未找到体系结构 i386 的符号

Symbol(s) not found for architecture i386 despite compiling universal and i386 versions of library

我一直在用C++开发一个动态库,在xcode命令行界面项目和gtest项目中测试时编译运行。

然而,当我尝试在 openframeworks 项目中 link 它时,linker 抱怨无法为我的 [=51= 之一的某些功能找到 i386 符号]是的。这特别奇怪,因为它可以看到 21 个函数、构造函数和析构函数中的 16 个的符号……我知道这一点是因为我可以调用所有 16 个函数而不会出现任何 linker 问题并获得预期结果。

这是 Xcode 吐出的内容:

Undefined symbols for architecture i386:
  "Cicada::Message::load(std::string const&)", referenced from:
      ofApp::setup() in ofApp.o
  "Cicada::Message::save(std::string const&)", referenced from:
      ofApp::setup() in ofApp.o
  "Cicada::Message::setContent(std::string)", referenced from:
      ofApp::setup() in ofApp.o
  "Cicada::Message::parse(std::string, bool)", referenced from:
      ofApp::setup() in ofApp.o
  "Cicada::Message::Message(std::string, Cicada::CALL_TO_ACTION, bool)", referenced from:
  ofApp::setup() in ofApp.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)

作为完整性检查,我在我的图书馆中调用了 lipo:

> lipo -info bin/libcicada.0.0.1.dylib
> Architectures in the fat file: bin/libcicada.0.0.1.dylib are: x86_64 i386

然后我打电话给 nm 看看我是否可以 "find" 它一直在苦苦挣扎的符号:

> nm -gj -arch i386 bin/libcicada.0.0.1.dylib
...
__ZN6Cicada7Message10setContentENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE
__ZN6Cicada7Message11generateUIDEv
__ZN6Cicada7Message13header_lengthE
__ZN6Cicada7Message13hexifyContentEv
__ZN6Cicada7Message14generateHeaderEv
__ZN6Cicada7Message15dehexifyContentEv
__ZN6Cicada7Message4loadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE
__ZN6Cicada7Message4saveERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE
__ZN6Cicada7Message5parseENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEb
__ZN6Cicada7Message5printEv
__ZN6Cicada7Message6setCTAENS_14CALL_TO_ACTIONE
__ZN6Cicada7Message8toStringEv
__ZN6Cicada7MessageC1ENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS_14CALL_TO_ACTIONEb
__ZN6Cicada7MessageC1Ev
__ZN6Cicada7MessageC2ENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS_14CALL_TO_ACTIONEb
__ZN6Cicada7MessageC2Ev
__ZN6Cicada7MessageD0Ev
__ZN6Cicada7MessageD1Ev
__ZN6Cicada7MessageD2Ev
...

link人看不到的符号是:

__ZN6Cicada7Message10setContentENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE
__ZN6Cicada7Message4loadERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE
__ZN6Cicada7Message4saveERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE
__ZN6Cicada7Message5parseENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEb
__ZN6Cicada7MessageC1ENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS_14CALL_TO_ACTIONEb

即主要构造函数,setContent,解析,保存和加载。

我知道 64 位功能仅在版本 9 中出现在 openframeworks 中,因此编译为通用二进制文件。我什至尝试过专门为 i386 编译,但没有成功...

我已经为 openframeworks 项目尝试了各种架构和 SDK,但除默认 $(NATIVE_ARCH) 之外的任何其他架构和 SDK 都会阻止 openframeworks 本身编译。库搜索路径指向正确的位置,我 link 在构建阶段指向正确的库,这很明显,当对有问题的函数的调用被注释掉时,它可以愉快地编译和运行。

我有一种挥之不去的感觉,这是一个 C++11 问题,因为它在我的整个库中使用,如果我没记错的话,openframeworks 在 C 方面有问题++11。如果有人认为它可能是其他东西,我将不胜感激!!!

这是有问题的副本 class...

//
//  Message.h
//  Cicada
//
//  Created by Pierre Chanquion on 06/09/2014.
//

#include "Definitions.h"
#include "Serialisable.h"

// ••••••••••••••••••••••••••••••••••••••••••••••••••••••
// • Message: Class for  parsing, loading, saving  
// ••••••••••••••••••••••••••••••••••••••••••••••••••••••
namespace Cicada {
    class Message : public Serialisable {
        private:
            // ----------------------------------------------->
            // content : Data (i.e. the message)
            // header  : Header
            // cta     : Call to Action
            // ishex   : Flag denoting content format
            std::string content, header;
            static const size_t header_length;
            size_t uid;
            CTA    cta;
            bool   ishex;
            ECL    ecl;
            // ----------------------------------------------->
            // Generates a header string
            void generateHeader();

            // ----------------------------------------------->
            // Generates a header string
            void generateUID();

        public:
            // ----------------------------------------------->
            // Constructors
            //  @con : content
            //  @cta : cta
            Message(std::string con, CTA cta, bool ishex = false);
            Message();

            // ----------------------------------------------->
            // Destructor
            ~Message();

            // ----------------------------------------------->
            // Print message
            void print();

            // ----------------------------------------------->
            // Stringify message
            std::string toString();

            // ----------------------------------------------->
            // Parse message
            //  @m   : stringified message to parse
            //  @hex : flag denoting payload format
            RC parse(std::string m, bool hex);

            // ----------------------------------------------->
            // Serialisation functions
            //  @fp : filepath
            virtual RC save(const std::string &fp);
            virtual RC load(const std::string &fp);

            // ----------------------------------------------->
            // Conversions between char and ascii no
            // representations
            void hexifyContent();
            void dehexifyContent();

            // ----------------------------------------------->
            // Accessors
            void setContent(std::string con);
            void setCTA(CTA cta);
            void setECL(ECL ecl) { this->ecl = ecl;}

            inline void setHex(bool b){ ishex = b;}
            inline std::string getContent() { return content; }
            inline std::string getHeader() { return header; }
            inline CTA    getCTA() { return cta; }
            inline size_t getUID() { return uid; }
            inline bool   isHex() { return ishex; }
    };
}

//
//  Message.cpp
//  Cicada
//
//  Created by Pierre Chanquion on 06/09/2014.
//

#include "Message.h"
#include "easylogging++.h"
#include "Utilities.h"
#include <iomanip>
#include <iostream>
#include <string>
using namespace std;
using namespace Cicada;
using namespace Cicada::Utilities;

const size_t Cicada::Message::header_length = 10;
// -----------------------------------------------
// Constructors
Cicada::Message::Message(string con, CTA cta, bool ishex){
    this->content = con;
    this->cta     = cta;
    this->ishex   = ishex;

    generateHeader();
    generateUID();
}
Cicada::Message::Message(){
    cta   = CTA::UNKNOWN;
    ishex = false;
}
Cicada::Message::~Message(){}

// -----------------------------------------------
// Print message to console
void Cicada::Message::print(){
    cout << "====> CICADA MESSAGE" << endl;
    cout << "\t===> CTA     : "   << cta             << endl;
    cout << "\t===> CONTENT : "   << content        << endl;
    cout << "\t===> SIZE    : "   << content.length() << " Bytes" <<endl;
}

// -----------------------------------------------
// Generate a header string for this message
void Cicada::Message::generateHeader(){
    ostringstream ss;
    ss << "SU"<< setfill('0') << setw(2) << cta << "N" << setfill('0') << setw(4) << content.length() << "T";
    header = ss.str();
}

// -----------------------------------------------
// Generate UID
void Cicada::Message::generateUID(){

    string s = toString();
    uid      = 0;
    for (char &c : s)
        uid = uid * 101 + c;
}

// -----------------------------------------------
// Parse message
RC Cicada::Message::parse(string m, bool hex){

    LOG(INFO) << "Parsing Message...";

    ostringstream ss;
    string        h, c;
    size_t        s;
    short         _0 = 48, _9 = 57;
    CTA           _cta;
    RC            r = RC::SUCCESS;

    // Compartor: check whether value is within a particular range
    auto in_range   = [] (int n, int mn, int mx) { return (n >= mn && n <= 57); };

    // Generate error codes
    auto error_code = [] (RC _r, RC _c) { return static_cast<RC>(_r == RC::SUCCESS ? _c : _r | _c); };

    // Check Header Length
    LOG(INFO) << "Check Header Length.";
    auto v = split(m, "T");

    if(v.size() == 1 || v[0].length() < header_length-1){
        LOG(ERROR) << "Corrupt Header: LENGTH INVALID!";
        r = error_code(r, RC::ERR_CORRUPT_HEADER);
        if(ecl == B_STRICT_PARSE) return r;
    }
    ss << v[0] << "T";
    h  =  ss.str(); // Header
    c  = v[1];      // Content

    LOG(INFO) << "Check Payload Length.";
    if((hex && (c.length()-1) % 2 != 0) || c.length() == 0){
        LOG(ERROR) << "Corrupt Payload: LENGTH INVALID!";
        r = error_code(r, RC::ERR_CORRUPT_PAYLOAD);
        if(ecl == B_STRICT_PARSE) return r;
    }
    LOG(INFO) << "Dehex String.";
    // Dehex string
    if(hex) c = hexStringToString(split(c, "Y")[0]);

    // Check CTA Chunk
    LOG(INFO) << "Check CTA Chunk.";
    string t = h.substr(1,3);
    if(t[0] != 'U' || !in_range(t[1], _0, _9) || !in_range(t[2], _0, _9)){
        LOG(ERROR) << "Corrupt Header: CTA CHUNK INVALID!";
        r = error_code(r, RC::ERR_CORRUPT_HEADER);
        if(ecl == B_STRICT_PARSE) return r;
    }
    _cta = (CTA) atoi(t.substr(1).c_str());

    // Check Length Chunk
    LOG(INFO) << "Check Length Chunk.";
    t = h.substr(4, 5);
    if(t[0] != 'N' || !in_range(t[1], _0, _9) || !in_range(t[2], _0, _9) || !in_range(t[3], _0, _9) || !in_range(t[4], _0, _9)){
        LOG(ERROR) << "Corrupt Header: SIZE CHUNK INVALID!";
        r = error_code(r, RC::ERR_CORRUPT_HEADER);
        if(ecl == B_STRICT_PARSE) return r;
    }
    s = atoi(t.substr(1).c_str());

    LOG(INFO) << "Check Content Chunk.";
    // Check content chunk
    if(s != c.length()){
        LOG(ERROR) << "Corrupt Payload: LENGTH DOES NOT MATCH HEADER SIZE CHUNK VALUE!";
        r = error_code(r, RC::ERR_CORRUPT_PAYLOAD);
        if(ecl == B_STRICT_PARSE) return r;
    }

    // Set content and cta.
    content = c;
    cta     = _cta;

    // Generate header string
    generateHeader();

    LOG(INFO) << "Message Parsed => content="<<content<<" cta="<<cta;

    return r;
}

// -----------------------------------------------
// Concatenates header and content
string Cicada::Message::toString(){
    ostringstream ss;
    ss << header << content;
    return ss.str();
}

// -----------------------------------------------
// Saves Message to file
RC Cicada::Message::save(const string &fp){

    ofstream outfile;
    ostringstream ss;

    // Append file type to fp
    ss << fp << ".bin";

    // Open File
    outfile.open(ss.str().c_str(), ios::binary);
    if (!outfile.is_open()) {
        LOG(ERROR) << "Unable to open file at filepath: " << ss.str();
        return RC::ERR_OPENING_FILE;
    }

    // Write to File
    outfile << "CTA: " << cta     << "\n";
    outfile << "CONTENT: " << content << "\n";

    outfile.close();

    return RC::SUCCESS;
}

// -----------------------------------------------
// Loads Message from file
RC Cicada::Message::load(const string &fp){

    ifstream  infile;
    ostringstream ss;

    // Append file type to fp
    ss << fp << ".bin";

    // Open File
    infile.open(ss.str().c_str(), ios::binary);
    if (!infile.is_open()) {
        LOG(ERROR) << "Unable to open file at filepath: " << ss.str().c_str();
        return RC::ERR_OPENING_FILE;
    }

    // Read From File
    while (infile.good()) {
        string row;
        if (getline(infile, row)) {
            auto s = Utilities::split(row, ": ");
            if(s.at(0) == "CTA")
                cta = (CTA) atoi(s.at(1).c_str());
            else if(s.at(0) == "CONTENT")
                content = s.at(1);
        }
    }

    return RC::SUCCESS;
}

// -----------------------------------------------
// Convert content to hex version
void Cicada::Message::hexifyContent(){
    ostringstream c;
    c << Utilities::stringToHexString(content) << "Y";
    content = c.str();
    ishex   = true;
}

// -----------------------------------------------
// Convert hex content to original version
void Cicada::Message::dehexifyContent(){
    content = Utilities::hexStringToString(split(content, "Y")[0]);
    ishex   = false;
}

// -----------------------------------------------
// Set content and generate header/UID
void Cicada::Message::setContent(string con) {
    content = con;
    generateHeader();
    generateUID();
}

// -----------------------------------------------
// Set content and generate header/UID
void Cicada::Message::setCTA(CTA cta) {
    this->cta = cta;
    generateHeader();
    generateUID();
}

编辑:这里是 ofApp:setup ...

void ofApp::setup(){

    try {
        buffer = new float[ws]();
        inwavebuf = new float[ws]();
    } catch (bad_alloc e) {
        cout << "Unable to allocate memory for " << e.what() << endl;
        exit();
    }

    message.hexifyContent();
    message.dehexifyContent();
    message.getContent();
    message.getCTA();
    message.getHeader();
    message.generateUID();
    message.generateHeader();
    message.getUID();
    message.isHex();
    message.load("");
    message.save("");
    message.toString();
    message.setHex(true);
    message.setECL(B_STRICT_PARSE);
    message.print();
    message.setContent("");
    message.setCTA(UNKNOWN);
    message.parse("010003414243", true);
    message = Message("", UNKNOWN);

    Message *msg = new Message("", UNKNOWN);

    ofBackground(0);
    setupGui();

}

事实证明 Openframeworks 不喜欢 C++11 二进制文件...我通过不对相关应用程序使用开放框架来解决此问题。