Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Need assistance with error: Symbols not found for architecture x86_64



  • Hi all,

    Fair warning, the majority of code here is exactly from an exercise on Pluralsight (I completed the prior chapter a week or two ago on a different machine and decided to download the files to pick back up where I left off). That being said, I do understand the majority of what is written and what the application is actually doing and will be happy to answer any questions as to thoughts behind why something may be written a particular way.

    From what I've found on Google, I believe the issue is that the Q_OBJECT macro is not being recognized any more. The issue seems to have cropped up after I did a bit refactoring of the Settings.h declarations but, I'm not seeing what specifically is causing the issue is or why the issue appeared. As far as I can tell, building / compiling was fine before I "intelligently" -insert a sarcastic snicker here- refactored the code.

    Thank you again in advance to you all for any assistance you can give.

    Screenshot of Error
    oh geez rick... what did I do?
    Link to the full project: https://www.dropbox.com/s/coz48htffj1kbg3/pluralsight-vfp-app.zip?dl=0

    I'll only provide the Settings.h and Settings.cpp files beneath since I believe the others are not a part of the issue, if it would be better to dump the entire contents of the project here (or if there a better location to put the project such as GitHub) please let me know.

    Settings.h

    #pragma once
    #include <QObject>
    
    class QString;
    class QStringListModel;
    struct QJsonParseError;
    class QJsonObject;
    class QFile;
    class QDir;
    
    
    namespace Ps{
    
        typedef std::pair<QJsonObject, QJsonParseError> JsonObjErrPair;
    
        class Settings : public QObject
        {
            Q_OBJECT
        public:
            explicit Settings(QObject *parent, QString filename);
            ~Settings();
            void ParseJsonData();
    
        signals:
            void NotifyStatusMessage(QString message);
    
        private:
            QString m_filename;
            QString m_applicationName;
            QString m_appShortName;
            QString m_hostName;
            quint16 m_portNumber;
            int m_waitMs;
            int m_readWaitMs;
            QStringListModel& m_modelCommands;
    
            QString ReadJsonFileFromInternalResource();
            JsonObjErrPair GetJsonObject(const QString& raw);
    
            QString ReadJsonFile();
            void SetupCommands(QJsonObject jsonObj);
            void SendErrorMessage(const QString& msg);
            void ShowJsonParseError(QJsonParseError jsonErr);
    
            explicit Settings(const Settings& rhs) = delete;
            Settings& operator= (const Settings& rhs) = delete;
        };
    }
    

    Settings.cpp

    #include "settings.h"
    #include <QDir>
    #include <QString>
    #include <QJsonObject>
    #include <QJsonParseError>
    #include <QJsonDocument>
    #include <QMessageBox>
    #include <QJsonArray>
    #include <QStringList>
    #include <QStringListModel>
    #include <utility>
    
    namespace Ps
    {
        //the default prefix used when opening the default config
        static auto RES_PREFIX = QString(":/json");
    
        Settings::Settings(QObject *parent, QString filename) :
            QObject(parent),
            m_filename(filename),
            m_modelCommands(*new QStringListModel(this))
        {
            //DEBUG:
            ReadJsonFile();
        }
    
        //Read settings from a json file
        QString Settings::ReadJsonFile()
        {
            //load default config first
            auto default_settings = ReadJsonFileFromInternalResource();
    
            //return default settings while testing
            return default_settings;
        }
    
        //Load the default config
        QString Settings::ReadJsonFileFromInternalResource()
        {
            //create a container to a directory
            QDir res_dir(RES_PREFIX);
    
            //check the prefix was valid / container exists
            if(!res_dir.exists())
            {
                //[ERR]: path does not exist error
                SendErrorMessage("Internal resource path is missing: " +
                                 res_dir.canonicalPath());
                return "";
            }
    
            //set a reference to the file
            auto path = res_dir.filePath(m_filename);
    
            //create a file resource using that file reference
            QFile res_file(path);
    
            //check that the file can be opened read only \
            //  as a plain text file
            if(!res_file.open(QFile::ReadOnly | QFile::Text))
            {
                //[ERR]: file was not opened properly
                SendErrorMessage("Could not open internal resource: " +
                                 path);
                return "";
            }
    
            //save content to string
            QString my_settings = res_file.readAll();
    
            //return the string to caller
            return my_settings;
    
        }
    
        //Parse the Json Data
        void Settings::ParseJsonData()
        {
            //read the config
            QString raw_json = ReadJsonFile();
    
            //is the config is empty, nothing to parse, exit
            if(raw_json.size() == 0) return;
    
            //transform settings into json object
            auto json_result = GetJsonObject(raw_json);
    
            //pull any errors returned from result
            auto json_err = json_result.second;
    
            //if an error was returned
            if(json_err.error != QJsonParseError::NoError)
            {
                //[ERR]: Json could not be parsed
                ShowJsonParseError(json_err);
            }
    
            //pull the object out for assignment
            auto json_obj = json_result.first;
    
            //set application variables
            m_applicationName = json_obj["applicationName"].toString();
            m_appShortName = json_obj["appShortName"].toString();
            m_hostName = json_obj["hostName"].toString();
            m_portNumber = json_obj["port"].toInt();
            m_waitMs = json_obj["tcpLongWaitMs"].toInt();
            m_readWaitMs = json_obj["tcpShortWaitMs"].toInt();
    
            //assign the cmd list within the json data
            //to our combobox
            SetupCommands(json_obj);
        }
    
        //Parse command list from json
        void Settings::SetupCommands(QJsonObject raw)
        {
            //create a new array to hold the list of strings
            QJsonArray cmd_array = raw["commands"].toArray();
    
            //create a list to temp hold the strings
            QStringList cmd_list;
    
            //iterate through each string in cmd_array
            //each value referenced as item
            for(auto item: cmd_array)
            {
                //append each value to the list
                cmd_list.append(item.toString());
            }
    
            //save the list to the app variable
            m_modelCommands.setStringList(cmd_list);
        }
    
        //Extract the json object from the data
        JsonObjErrPair Settings::GetJsonObject(const QString& raw)
        {
            //QJsonDoc needs a reference to a QJsonParseError for errors
            QJsonParseError json_parse_err;
    
            //load the json from the raw data
            QJsonDocument json_doc = QJsonDocument::fromJson(raw.toUtf8(),
                                                             &json_parse_err);
    
            //create an object from the JsonDocument
            QJsonObject json_obj = json_doc.object();
    
            //return the pair with data and any errors
            return std::make_pair(json_obj, json_parse_err);
        }
    
        //Show errors from parsing the settings file
        void Settings::ShowJsonParseError(QJsonParseError jsonErr)
        {
            //create a flavor string
            QString msg = tr("Error parsing JSON settings file.\n");
    
            //append the error using the errorString method to extract the details
            msg.append(jsonErr.errorString());
    
            //open a msg box to alert the user of the issue
            QMessageBox::critical(nullptr, tr("VFP"), msg);
        }
    
        //Show general errors
        void Settings::SendErrorMessage(const QString& msg)
        {
            emit NotifyStatusMessage(msg);
        }
    }
    

  • Lifetime Qt Champion

    @NoticeMeSenpai

    We need the full compile log, including linker command to give any hints.

    Hint: Use a version control system to archive your code. Once you have a working version, you can always go back there in case something breaks later. By diffing, it's also easier to see what changed and what could cause the problem.

    Regards

    Edit: The platform, compiler and Qt version would also be nice.



  • @aha_1980

    ~~Thanks for the prompt response. I hate to show my lack of knowledge but, would you be able to assist me with getting the compilation log?

    You are absolutely right, I've been playing around with git but admittedly I've not actually used it proper. I'll definitely make that a part of my regular workflow so I can sidestep these types of issues quicker.

    As for my QT version and environment; I'm running QT Creator 4.7.0 on Mac OS Sierra 10.12.6, using Clang 8.0.~~

    Actually, I found the issue thanks to your assistance. I had not realised that my compilation output was "empty" because the project was "already built". So I ended up cleaning the project and rebuilding. After which I found the following error in the output that then led me to realise that I added a definition for the destructor in the header but never defined a method for it in the class.

    Adding in the proper method for the destructor has solved the issue! I'll mark the issue as solved and +1 you for pointing me to the right location to look.

    OpenGL -framework AGL 
    Undefined symbols for architecture x86_64:
      "Ps::Settings::~Settings()", referenced from:
          vtable for Ps::Settings in moc_settings.o
      "Ps::Settings::~Settings()", referenced from:
          Ps::Startup::Startup() in startup.o
          vtable for Ps::Settings in moc_settings.o
    ld: symbol(s) not found for architecture x86_64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    make: *** [Vfp.app/Contents/MacOS/Vfp] Error 1
    03:30:05: The process "/usr/bin/make" exited with code 2.
    Error while building/deploying project Vfp (kit: Desktop Qt 5.11.1 clang 64bit)
    When executing step "Make"
    03:30:05: Elapsed time: 00:10.
    

Log in to reply