Undefined symbols for architecture x86_64 when compiling c++ - c++

I am continuously getting that error, and it's driving me crazy!
Undefined symbols for architecture x86_64:
"SSResourcesDepot::_sharedInstance", referenced from:
SSResourcesDepot::sharedInstance() in SSResourcesDepot.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
My code looks like:
#ifndef SolarSystem_SSResourcesDepot_h
#define SolarSystem_SSResourcesDepot_h
#include "SSResource.h"
/* SSResourcesDepot is implemented as a Singleton Depot that keeps track of all
* requested Resource objects, and avoid loading them twice in memory. */
class SSResourcesDepot {
SSResourcesDepot() {};
SSResourcesDepot(SSResourcesDepot const&){};
SSResourcesDepot& operator=(SSResourcesDepot const&){};
static SSResourcesDepot* _sharedInstance;
SSResource* _search(std::string resourceName);
SSResource* _load(std::string resourceName);
public:
static SSResourcesDepot* sharedInstance();
SSResource* requestResource(std::string resourceName);
};
#endif
and:
#include <iostream>
#include "SSResourcesDepot.h"
#pragma mark Public methods
SSResourcesDepot* SSResourcesDepot::sharedInstance() {
if (SSResourcesDepot::_sharedInstance == 0) {
SSResourcesDepot::_sharedInstance = new SSResourcesDepot();
}
return SSResourcesDepot::_sharedInstance;
}
SSResource* SSResourcesDepot::requestResource(std::string resourceName) {
SSResource *resource = this->_search(resourceName);
if (resource == NULL) resource = this->_load(resourceName);
return resource;
}
#pragma mark Private methods
SSResource* SSResourcesDepot::_search(std::string resourceName) {
return NULL;
}
SSResource* SSResourcesDepot::_load(std::string resourceName) {
return NULL;
}
It seems completely functional to me, but Apple-O-Matcher keeps complaining, and it doesn't let me compile ... :-S
Thanks in advance!

You didn't initialize your static member.
Add
SSResourcesDepot* SSResourcesDepot::_sharedInstance = NULL;
to your implementation file.

Related

Call main executable's functions from plugin compiled using Clang

I'm writing a program (macOS, clang++ compiler, only AppleSilicon at the moment) that I can extend later by providing custom plugins (dynamic library, loaded at runtime) which use main program's public interface.
test.hpp - public interface:
#if defined(MAGIC_PLUGIN)
# define MAGIC_EXPORT /* nothing */
#else
# define MAGIC_EXPORT __attribute__((visibility("default")))
#endif
MAGIC_EXPORT
void testCall();
test.cpp - main programm:
#include <stdio.h>
#include <dlfcn.h>
#include "test.hpp"
// Declare a function to call from a loaded plugin
typedef void (* plugin_call_func)(void);
int main(int argc, char** argv) {
// Load library
const char* libraryName = "plugin.dylib";
void* library = dlopen(libraryName, RTLD_NOW);
if (library == nullptr) {
printf("Cannot open library\n");
return 1;
}
// Get function from loaded library
plugin_call_func pluginCall = reinterpret_cast<plugin_call_func>(
dlsym(library, "pluginCall"));
if (pluginCall == nullptr) {
printf("Cannot find the pluginCall function\n");
return 2;
}
// Execute loaded function
pluginCall();
// Forget function and close library
pluginCall = nullptr;
auto libraryCloseResult = dlclose(library);
if (libraryCloseResult != 0) {
printf("Cannot close library\n");
return 3;
}
return 0;
}
// Public function, should be called from a plugin
void testCall() {
printf("Test call\n");
}
plugin.cpp - plugin's source:
#define MAGIC_PLUGIN
#include <stdio.h>
#include "test.hpp"
__attribute__((visibility("default")))
extern "C" void pluginCall(void) {
printf("Plugin call\n");
testCall();
}
First, I compile main app:
clang++ -std=c++20 -fvisibility=hidden -target arm64-apple-macos12 test.cpp -o test
The nm --defined-only test shows these symbols:
0000000100003ee4 T __Z8testCallv
0000000100000000 T __mh_execute_header
0000000100003dcc t _main
Mangled __Z8testCallv is what I need. Everything looks good so far. But then I try to compile the plugin as dynamic library...
clang++ -std=c++20 -fvisibility=hidden -dynamiclib -g -current_version 0.1 -target arm64-apple-macos12 plugin.cpp -o plugin.dylib
and get this error:
Undefined symbols for architecture arm64:
"testCall()", referenced from:
_pluginCall in plugin-38422c.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Well, it's kind of fair, I can understand this, because the dynamic library does not know that testCall is somewhere implemented. So I want to say it that it does not have to worry about testCall's existence.
I tried to research how to do this, looked up man pages, read tons of stack overflow answers, and what I only found that works is adding these flags to linker:
-Wl,-undefined,dynamic_lookup
It works, the library compiles and the app works as expected. But I don't really want to use dynamic_lookup because it will mark every undefined symbol in the library as resolved, which may lead to some bad consequences. I want to tell the linker only about existence of the main program's public symbols.
What am I missing? Is there any better solution than dynamic_lookup?
Your best bet is to manually do the work that's done by the library loader. That is: populating function pointers. After all, the plugin->main binding is already done manually, so doing the same thing the other way around makes sense.
You can make this process essentially transparent by carefully crafting the header shared by the plugin and main application. The only tricky part is handling ODR for plugins that are composed of multiple source files.
Since this is a C++ question, here's what it could look like with a RAII wrapper. The ODR conundrum is handled via the PLUGIN_MAIN macro that should only be defined in one of a plugin's sources.
test_plugin.hpp
using pluginCall_fn = void(*)();
using testCall_fn = void(*)();
#if !defined(MAIN_APPLICATION)
#if defined(PLUGIN_MAIN)
#define EXPORTED_FROM_MAIN __attribute__((visibility("default")))
#else
#define EXPORTED_FROM_MAIN __attribute__((visibility("default"))) extern
#endif
extern "C" {
// Declare symbols provided by the plugin
__attribute__((visibility("default"))) void pluginCall();
// etc...
// Declare/define pointers that will be populated by the main application
EXPORTED_FROM_MAIN testCall_fn testCall;
// etc...
}
#undef EXPORTED_FROM_MAIN
#else // In the main app.
#include <stdexcept>
// Declare "symbols" provided by the main application
void testCall();
// Utility class to load/unload a dynamic library.
// Probably belongs in its own header...
struct loaded_library final {
loaded_library(const char* libName)
: handle_(dlopen(libName, RTLD_NOW)) {
if(!handle_) {
throw std::runtime_error("failed to load plugin");
}
}
loaded_library(const loaded_library&) = delete;
loaded_library& operator=(const loaded_library&) = delete;
loaded_library(loaded_library&& rhs) : handle_(rhs.handle_) {
rhs.handle_ = nullptr;
}
loaded_library& operator=(loaded_library&& rhs) {
handle_ = rhs.handle_;
rhs.handle_ = nullptr;
return *this;
}
~loaded_library() {
if(handle_) {
dlclose(handle_);
}
}
template<typename T>
T get_symbol(const char* symbol) {
T result = reinterpret_cast<T>(dlsym(handle_, symbol));
if(!result) {
throw std::runtime_error("missing symbol");
}
return result;
}
private:
void* handle_;
};
// Plugin interface.
struct loaded_plugin final {
loaded_plugin(const char* libName)
: lib_(libName) {
// Load functions from plugin
pluginCall = lib_.get_symbol<pluginCall_fn>("pluginCall");
// ...
// Assign callbacks to plugin
*lib_.get_symbol<testCall_fn*>("testCall") = &testCall;
// ...
// Call the plugin's init function here if applicable.
}
pluginCall_fn pluginCall;
private:
loaded_library lib_;
};
#endif
plugin.cpp
#define PLUGIN_MAIN
#include "test_plugin.hpp"
#include <stdio.h>
void pluginCall() {
printf("Plugin call\n");
testCall();
}
test.cpp
#define MAIN_APPLICATION
#include "test_plugin.hpp"
int main(int argc, char** argv) {
const char* libraryName = "plugin.dylib";
loaded_plugin plugin(libraryName);
plugin.pluginCall();
}
// Public function, should be called from a plugin
void testCall() {
printf("Test call\n");
}
You may find that this code is a bit on the fragile side of things, since a few different portions of test_plugin.hpp need to be kept in sync.
This can be worked around with the use of X-Macros, at the cost of confusing IDEs and hurting code legibility. I wouldn't go down that road until the APIs in question become unwieldingly large.

Duplicate symbols only for iOS simulator build

I'm having a strange issue when compiling an open source library. When compiling for the device, Xcode compiles it just fine and deploys it no problem. However, when I compile for the simulator, I get duplicate symbol errors during the linking phase.
I've checked a few of these out, and it seems these symbols were all implemented in the .hh file as opposed to the .m file. Obviously this is bad code structure, and the errors make sense. However, what doesn't make sense is why there are no errors for the device build.
Each of these .hh files contains #pragma once at the top of the file. My initial thought was that this wasn't working as expected, but upon removal I get compile-time errors for both device and simulator builds stating I've redefined these symbols. Hmm, so I then tried replacing #pragma once with
#ifndef EXAMPLE_DEFINE
#define EXAMPLE_DEFINE
// code
#end if
But this yields identical results to the #pragma once.
Due to the sheer number of code changes that would be required, it isn't feasible for me to go through and fix every error manually, especially since I'll want to be able to update the codebase easily. So is there any reason this is not failing for the device, and how I could make simulator builds perform the same way?
EDIT: I've also tested using #import instead of #include, but it too yields the same results
EDIT 2: After more testing, I've found that if I define a Preprocessor macro in the target's build settings, the code inside the #ifndef never gets called, as is expected. For whatever reason, it looks like defining the new definition in the .hh file isn't being carried over into the next compilation of the file.
Also, as requested, here's an excerpt from the build log
duplicate symbol __ZZN12DelegateFuncIFvR16DualTextMenuItemRKN5Input5EventEEEC1IZN25MultiChoiceSelectMenuItem4initEPPKciiibSB_P12ResourceFaceEUlS1_S5_E_EERKT_PNSt3__19enable_ifIXntsr3std11is_functionISG_EE5valueEvE4typeEENKS8_ISF_EUlRKNS7_7StorageES1_S5_E_cvPFvSR_S1_S5_EEv in:
/Users/riley.testut/Library/Developer/Xcode/DerivedData/GBA4iOS-dqkflotukruucqbxjyslhtfuekse/Build/Intermediates/GBA4iOS.build/Debug-iphonesimulator/GBA4iOS.build/Objects-normal/i386/Main-FB93852047D42061.o
/Users/riley.testut/Library/Developer/Xcode/DerivedData/GBA4iOS-dqkflotukruucqbxjyslhtfuekse/Build/Intermediates/GBA4iOS.build/Debug-iphonesimulator/GBA4iOS.build/Objects-normal/i386/OptionView.o
duplicate symbol __ZZN12DelegateFuncIFbiRKN5Input5EventEEEC1IZN15MultiChoiceView4initER19MultiChoiceMenuItemb9_2DOriginEUliS3_E_EERKT_PNSt3__19enable_ifIXntsr3std11is_functionISC_EE5valueEvE4typeEENKS6_ISB_EUlRKNS5_7StorageEiS3_E_cvPFbSN_iS3_EEv in:
/Users/riley.testut/Library/Developer/Xcode/DerivedData/GBA4iOS-dqkflotukruucqbxjyslhtfuekse/Build/Intermediates/GBA4iOS.build/Debug-iphonesimulator/GBA4iOS.build/Objects-normal/i386/Main-FB93852047D42061.o
/Users/riley.testut/Library/Developer/Xcode/DerivedData/GBA4iOS-dqkflotukruucqbxjyslhtfuekse/Build/Intermediates/GBA4iOS.build/Debug-iphonesimulator/GBA4iOS.build/Objects-normal/i386/OptionView.o
duplicate symbol __ZZN12DelegateFuncIFvR12TextMenuItemRKN5Input5EventEEEC1IN14YesNoAlertView2noMUlS1_S5_E_EEERKT_PNSt3__19enable_ifIXntsr3std11is_functionISB_EE5valueEvE4typeEENKS8_ISA_EUlRKNS7_7StorageES1_S5_E_cvPFvSM_S1_S5_EEv in:
/Users/riley.testut/Library/Developer/Xcode/DerivedData/GBA4iOS-dqkflotukruucqbxjyslhtfuekse/Build/Intermediates/GBA4iOS.build/Debug-iphonesimulator/GBA4iOS.build/Objects-normal/i386/ButtonConfigView.o
/Users/riley.testut/Library/Developer/Xcode/DerivedData/GBA4iOS-dqkflotukruucqbxjyslhtfuekse/Build/Intermediates/GBA4iOS.build/Debug-iphonesimulator/GBA4iOS.build/Objects-normal/i386/MenuView.o
ld: 16 duplicate symbols for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
and here's one of the offending files (AlertView.hh):
#pragma once
#include <gui/View.hh>
#include <gui/MenuItem/MenuItem.hh>
#include <util/gui/BaseMenuView.hh>
#include <util/rectangle2.h>
#include <util/DelegateFunc.hh>
class AlertView : public View
{
public:
constexpr AlertView() { }
Rect2<GC> labelFrame;
Gfx::Text text;
BaseMenuView menu;
Rect2<int> rect;
Rect2<int> &viewRect() { return rect; }
void init(const char *label, MenuItem **menuItem, bool highlightFirst);
void deinit() override;
void place() override;
void inputEvent(const Input::Event &e) override;
void draw(Gfx::FrameTimeBase frameTime) override;
};
class YesNoAlertView : public AlertView
{
public:
YesNoAlertView() { }
typedef DelegateFunc<void (const Input::Event &e)> InputDelegate;
MenuItem *menuItem[2] = {nullptr};
// Optional delegates
InputDelegate &onYes() { return onYesD; }
InputDelegate &onNo() { return onNoD; }
void init(const char *label, bool highlightFirst, const char *choice1 = nullptr, const char *choice2 = nullptr)
{
yes.init(choice1 ? choice1 : "Yes"); menuItem[0] = &yes;
no.init(choice2 ? choice2 : "No"); menuItem[1] = &no;
assert(!onYesD);
assert(!onNoD);
AlertView::init(label, menuItem, highlightFirst);
}
void deinit() override
{
logMsg("deinit alert");
AlertView::deinit();
onYesD = {};
onNoD = {};
}
InputDelegate onYesD;
InputDelegate onNoD;
private:
TextMenuItem yes
{
[this](TextMenuItem &, const Input::Event &e)
{
auto callback = onYesD;
removeModalView();
if(callback) callback(e);
}
};
TextMenuItem no
{
[this](TextMenuItem &, const Input::Event &e)
{
auto callback = onNoD;
removeModalView();
if(callback) callback(e);
}
};
};
It shows you have tried the header guards but my suggestion is once you check for following
link.
http://en.wikipedia.org/wiki/Include_guard
http://c2.com/cgi/wiki?RedundantIncludeGuards
The update shows it is linker error for symbols and this is for the library you are using.

C++ Singleton fail to link on Mac OS

I am trying to create a very classic singleton on C++, Mac OS using Xcode
I create the Class MySingleton as follow:
class MySingleton{
private:
int val;
static MySingleton *instance;
MySingleton(){
val = 0;
}
public:
int getVal(){
return val;
}
void setVal(int iVal){
val = iVal;
}
static MySingleton* getInstance(){
if(instance == NULL)
instance = new MySingleton();
return instance;
}
};
Linker is complaining about static MySingleton* getInstance()
Follow the Linker message:
Undefined symbols for architecture x86_64: "MySingleton::instance",
referenced from:
MySingleton::getInstance() in main.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code
1 (use -v to see invocation)
Could somebody help on this? Perhaps I need to set something on Xcode, which by the way is version 4.2.1, and I am not able in doing this.
Thanks.
You need to define static variable in your cpp file, like this:
MySingleton *MySingleton::instance = 0;
The static member MySingleton needs to be defined in the cpp file. In the header you have have only declared it. See this for more information: Why do static variables need to be declared twice in C++
As far as I can see, you've declared static MySingleton *instance but haven't defined it anywhere.

Apple Mach-O Linker (Id) Error Issue

I've read a number of posts on this issue but I haven't found anything particularly helpful. I am trying to make a weldJoint when two sprites meet using a contact listener. I keep getting the following error:
Apple Mach-O Linker (Id) Error
"_touchingBodies", referenced from:
SubcContactListener::BeginContact(b2Contact*) in SubcContactListener.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Here is my contact listener.
SubcContactListener.h:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "Box2D.h"
#import <vector>
typedef std::pair<b2Body*, b2Body*> bodyPair;
typedef std::vector<bodyPair> thingsThatTouched;
extern thingsThatTouched touchingBodies;
class SubcContactListener : public b2ContactListener {
public:
void BeginContact(b2Contact* contact);
void EndContact(b2Contact* contact);
};
SubcContactListener.mm:
#import "SubcContactListener.h"
void SubcContactListener:: BeginContact(b2Contact *contact) {
touchingBodies.push_back( std::make_pair(contact->GetFixtureA()->GetBody(), contact->GetFixtureB()->GetBody()) );
}
I added:
thingsThatTouched touchingBodies;
to the HelloWorldLayer.h interface.
Finally, in the tick method of the HelloWorldLayer.mm (after the timestep):
b2WeldJointDef weldJointDef;
b2WeldJoint *weldJoint;
for (int i = 0; i < touchingBodies.size(); i++) {
b2Body* bodyA = touchingBodies[i].first;
b2Body* bodyB = touchingBodies[i].second;
weldJointDef.Initialize(bodyA, bodyB, bodyA->GetWorldCenter());
weldJointDef.collideConnected = false;
weldJoint = (b2WeldJoint*)world->CreateJoint(&weldJointDef);
}
touchingBodies.clear();
Please help, I've been at it for a while.
extern thingsThatTouched touchingBodies;
Such extern variables must be defined as static C variables elsewhere, not instance variables.
In light of a better design, I recommend to scrap the extern variable and instead access the touchingBodies through the HelloWorldLayer by adding a Singleton interface to it.
You'd then be able to access it from anywhere:
[HelloWorldLayer sharedWorldLayer].touchingBodies;

C++ Singleton in Xcode

I'm trying to make a Singleton class in C++ with Xcode. It's a really basic class and I get a linker error that I don't understand. Can any1 help please?
Here is the class header file :
#ifndef _NETWORK_H_
#define _NETWORK_H_
#include <iostream>
#include <list>
#include "Module.h"
using namespace std;
/*
* Assume only one network can run at a time
* in the program. So make the class a singleton.
*/
class Network {
private:
static Network* _instance;
list<Module*> _network;
public:
static Network* instance();
};
#endif
Here is the impl file :
#include "Network.h"
Network* Network::instance() {
if (!_instance)
_instance = new Network();
return _instance;
}
Here is the compiler error :
Undefined symbols for architecture x86_64:
"Network::_instance", referenced from:
Network::instance() in Network.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
You need to declare actual storage for Network::_instance somewhere. Likely the impl. file.
Try adding to your impl file:
Network *Network::_instance=0;
You need to define your instance in the implementation file:
#include "Network.h"
Network *Network::_instance;
The static Network *_instance; declaration just says that there exists a Network::_instance somewhere. You must provide a single definition somewhere for it to actually exist.