Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symbols not found for architecture i386 - But works for iOS device

I am facing a strange problem here, I am trying to integrate the libkml C++ project sources into my iOS project. The project compiles independently fine, but when it comes to linking through this line of code:

kmldom::PointPtr appPoint = kmlconvenience::CreatePointLatLon(appLocation.coordinate.latitude, appLocation.coordinate.longitude);

I get linker errors Only when I am building it for simulator. It works fine when I build it for iOS device, but for simulator I get the following 3 linker errors:

(null): "kmldom::GxTimeSpan::GxTimeSpan()", referenced from:

(null): Kmldom::KmlFactory::CreateGxTimeSpan() const in libLibKML.a(kml_factory.o)

(null): "kmldom::GxTimeStamp::GxTimeStamp()", referenced from:

(null): Kmldom::KmlFactory::CreateGxTimeStamp() const in libLibKML.a(kml_factory.o)

(null): Symbol(s) not found for architecture i386

(null): Linker command failed with exit code 1 (use -v to see invocation)

These errors occur only when I try to build for simulator

I could be fine with developing for device alone but I am looking to fix this problem for 2 reasons:

  1. Would be easy for team to use simulator at times for development purposes.
  2. I really want to get to the bottom of it and understand why this is happening in first case. Why it builds for device and fails for simulator though the target is same and the source files included in the target would be the same across simulator as well as device?.

The definition of GXTimeStamp and GXTimeSpan classes are in the header file gx_timeprimitive.h and this is the contents:

#ifndef KML_DOM_GX_TIMEPRIMITIVE_H__
#define KML_DOM_GX_TIMEPRIMITIVE_H__

#include <string>
#include "kml/base/xml_namespaces.h"
#include "kml/dom/kml22.h"
#include "kml/dom/object.h"
#include "kml/dom/timeprimitive.h"

namespace kmldom {

class Serializer;
class Visitor;

// <gx:TimeSpan>
class GxTimeSpan : public TimeSpan {
 public:
  virtual ~GxTimeSpan();
  static KmlDomType ElementType() {
    return Type_GxTimeSpan;
  }
  virtual KmlDomType Type() const { return Type_GxTimeSpan; }
  virtual bool IsA(KmlDomType type) const {
    return type == Type_GxTimeSpan || TimeSpan::IsA(type);
  }

  // Visitor API methods, see visitor.h.
  virtual void Accept(Visitor* visitor);

 private:
  friend class KmlFactory;
  GxTimeSpan();
  LIBKML_DISALLOW_EVIL_CONSTRUCTORS(GxTimeSpan);
};

// <gx:TimeStamp>
class GxTimeStamp : public TimeStamp {
 public:
  virtual ~GxTimeStamp();
  static KmlDomType ElementType() {
    return Type_GxTimeStamp;
  }
  virtual KmlDomType Type() const { return Type_GxTimeStamp; }
  virtual bool IsA(KmlDomType type) const {
    return type == Type_GxTimeStamp || TimeStamp::IsA(type);
  }

  // Visitor API methods, see visitor.h.
  virtual void Accept(Visitor* visitor);

 private:
  friend class KmlFactory;
  GxTimeStamp();
  LIBKML_DISALLOW_EVIL_CONSTRUCTORS(GxTimeStamp);
};

}  // end namespace kmldom

#endif  // KML_DOM_GX_TIMEPRIMITIVE_H__

I have read many posts that linker errors occur coz the source files are not compiled. I was thinking in the same lines to solve this problem too, but I cannot include this header file into compile sources because it is a .h file.

Also, I double checked - kml_factory.cc file is included in the compile sources of the inner project:

kml_factory.cc file included in compile phase

Looking forward for suggestions and help. Thanks.

like image 593
Raj Pawan Gumdal Avatar asked May 19 '13 17:05

Raj Pawan Gumdal


2 Answers

Makes me feel stupid to say this, but, I don't know how the gx_timeprimitive.cc file was missing. I was in an impression that gx_timeprimitive.h file was complete by itself as it has virtual classes and I tried to define the GXTimeSpan and GXTimeStamp classes by providing the empty implementation of constructors in Private scope, like this:

class GxTimeSpan : public TimeSpan {
 public:
  virtual ~GxTimeSpan();
  static KmlDomType ElementType() {
    return Type_GxTimeSpan;
  }
  virtual KmlDomType Type() const { return Type_GxTimeSpan; }
  virtual bool IsA(KmlDomType type) const {
    return type == Type_GxTimeSpan || TimeSpan::IsA(type);
  }

  // Visitor API methods, see visitor.h.
  virtual void Accept(Visitor* visitor);

 private:
  friend class KmlFactory;
  GxTimeSpan()
  {

  }
  LIBKML_DISALLOW_EVIL_CONSTRUCTORS(GxTimeSpan);
};

But still, the compiler would not create object file out of interface files (.h files are excluded from compile sources, they just contain all declarations), hence the linker cannot find the constructors it needed. This made me to search gx_timeprimitive.cc file in internet and it indeed was available.

Thinking with cool head would have saved me 100 bounty points, but I have a lesson to carry!

Also, to answer why it was giving error in simulator mode alone: Actually the line I mentioned above - kmldom::PointPtr appPoint = kmlconvenience::CreatePointLatLon(appLocation.coordinate.latitude, appLocation.coordinate.longitude); when built for ARMv7, I think, that unless the variable appPoint is used elsewhere in the code the linker skips linking it with the sources of libkml's object file. Whereas, i386 would perform linking irrespective of whether the variable is used in code or not. I guess this is some sort of compiler optimisation due to which the behaviour is different in the respective architectures. It was this puzzle which made me miss the crucial clue of looking into the missing file!

Apologies for those who took time to solve this silly problem of mine, thank you all.

like image 83
Raj Pawan Gumdal Avatar answered Nov 12 '22 14:11

Raj Pawan Gumdal


This may be something similar to iOS symbols not found for architecture i386.

Here are the most relevant points:

When building libraries, frameworks or applications for iOS, XCode will only compile object code for the architectures specified in the build settings for the target. XCode will also only link to binaries that have the specified architecture built in.

When running code in the iOS simulator you are running your code on your desktop which is the i386 architecture.

If you get the missing i386 architecture error running an iOS application in the simluator you need to make sure that your application and all its dependent libraries have been built for i386 architecture.

like image 2
Nick Fishman Avatar answered Nov 12 '22 15:11

Nick Fishman