Solved 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
Link to the full project: https://www.dropbox.com/s/coz48htffj1kbg3/pluralsight-vfp-app.zip?dl=0I'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); } }
-
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.
-
~~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.