سؤال

I recently decided to try to run some of my graphics code on an iOS device, but I use FreeImage to load textures. As a result I need to build it for iOS 5.0.

I'm currently getting link errors when I try to use the FreeImage library. The link errors are all standard C++ library related. For instance...

Undefined symbols for architecture i386:
  "std::basic_string<char, std::char_traits<char>, std::allocator<char>>::~basic_string()", referenced from:
  _FreeImage_GetMetadata in libfreeimage-iphonesimulator.a(BitmapAccess.o-i386)
  _FreeImage_SetMetadata in libfreeimage-iphonesimulator.a(BitmapAccess.o-i386)
  _FreeImage_CloneMetadata in libfreeimage-iphonesimulator.a(BitmapAccess.o-i386)
  _FreeImage_Clone in libfreeimage-iphonesimulator.a(BitmapAccess.o-i386)
  std::pair<std::string const, FITAG*>::~pair() in libfreeimage-iphonesimulator.a(BitmapAccess.o-i386)
  Load(FreeImageIO*, void*, int, int, void*) in libfreeimage-iphonesimulator.a(PluginEXR.o-i386)
  C_OStream::write(char const*, int) in libfreeimage-iphonesimulator.a(PluginEXR.o-i386)
  ...

Unfortunately the supplied makefile for building FreeImage for iOS was a bit dated so I was forced to update it. Additionally in my XCode project I switched the compiler to support C++11 features and use libc++ (As described here Can I use C++11 with Xcode?)

So I attempted to mirror these changes in the makefile for FreeImage, yet I'm still getting these errors.

My makefile looks like this (I found this post somewhat helpful http://sourceforge.net/p/freeimage/discussion/36110/thread/51445acc)

# Configuration for iPhone OS, making static libs
# this will generate both iPhone (arm) and iPhoneSimulator (i686) libs

include Makefile.srcs

CFLAGS =  -g -O2 -Wall -Wmissing-prototypes -std=c99 -ffast-math -fno-strict-aliasing
CXXFLAGS = -g -O2 -Wall -fno-strict-aliasing -std=c++0x -stdlib=libc++

GCC_VERSION = 4.2
IPHONEOS_DEPLOYMENT_TARGET = 5.0
MACOSX_DEPLOYMENT_TARGET = 10.6

PLATFORM_SIM = iPhoneSimulator
PLATFORM_PHONE = iPhoneOS

ARCH_SIM = i386
ARCH_PHONE = armv7

PLATFORM_SIM_DEVELOPER_BIN_DIR = /Developer/Platforms/$(PLATFORM_SIM).platform/Developer/usr/bin
PLATFORM_PHONE_DEVELOPER_BIN_DIR = /Developer/Platforms/$(PLATFORM_PHONE).platform/Developer/usr/bin

SDKROOT_SIM = /Developer/Platforms/$(PLATFORM_SIM).platform/Developer/SDKs/$(PLATFORM_SIM)$(IPHONEOS_DEPLOYMENT_TARGET).sdk
SDKROOT_PHONE = /Developer/Platforms/$(PLATFORM_PHONE).platform/Developer/SDKs/$(PLATFORM_PHONE)$(IPHONEOS_DEPLOYMENT_TARGET).sdk

EXTRA_CFLAGS_SIM += -arch $(ARCH_SIM) -pipe -mdynamic-no-pic -fvisibility=hidden $(INCLUDE) -isysroot $(SDKROOT_SIM)
EXTRA_LDFLAGS_SIM += -arch $(ARCH_SIM) -isysroot $(SDKROOT_SIM) -Wl,-dead_strip
EXTRA_CFLAGS_SIM += -D__IPHONE_OS_VERSION_MIN_REQUIRED=20000 -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET)
EXTRA_LDFLAGS_SIM += -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET)

EXTRA_CFLAGS_PHONE += -arch $(ARCH_PHONE) -pipe -mdynamic-no-pic -fvisibility=hidden $(INCLUDE) -isysroot $(SDKROOT_PHONE)
EXTRA_LDFLAGS_PHONE += -arch $(ARCH_PHONE) -isysroot $(SDKROOT_PHONE) -Wl,-dead_strip
EXTRA_CFLAGS_PHONE += -miphoneos-version-min=$(IPHONEOS_DEPLOYMENT_TARGET)
EXTRA_LDFLAGS_PHONE += -miphoneos-version-min=$(IPHONEOS_DEPLOYMENT_TARGET)

AR_SIM = $(PLATFORM_SIM_DEVELOPER_BIN_DIR)/ar
AR_PHONE = $(PLATFORM_PHONE_DEVELOPER_BIN_DIR)/ar

CC_SIM = $(PLATFORM_SIM_DEVELOPER_BIN_DIR)/llvm-gcc-$(GCC_VERSION)
CC_PHONE = $(PLATFORM_PHONE_DEVELOPER_BIN_DIR)/llvm-gcc-$(GCC_VERSION)

CFLAGS_SIM = $(CFLAGS) $(EXTRA_CFLAGS_SIM)
LDFLAGS_SIM = $(EXTRA_LDFLAGS_SIM)
CXX_SIM = $(PLATFORM_SIM_DEVELOPER_BIN_DIR)/clang++
CXXFLAGS_SIM += $(EXTRA_CFLAGS_SIM) -fvisibility-inlines-hidden 
LIBTOOL_SIM = /Developer/Platforms/$(PLATFORM_SIM).platform/Developer/usr/bin/libtool

CFLAGS_PHONE = $(CFLAGS) $(EXTRA_CFLAGS_PHONE)
LDFLAGS_PHONE += $(EXTRA_LDFLAGS_PHONE)
CXX_PHONE = $(PLATFORM_PHONE_DEVELOPER_BIN_DIR)/clang++
CXXFLAGS_PHONE += $(EXTRA_CFLAGS_PHONE) -fvisibility-inlines-hidden
LIBTOOL_PHONE = /Developer/Platforms/$(PLATFORM_PHONE).platform/Developer/usr/bin/libtool

TARGET = freeimage
STATICLIB_SIM = lib$(TARGET)-iphonesimulator.a
STATICLIB_PHONE = lib$(TARGET)-iphone.a
HEADER = Source/FreeImage.h

.SUFFIXES: .o-i386 .o-arm
MODULES_ARM = $(SRCS:.c=.o-arm)
MODULES_ARM := $(MODULES_ARM:.cpp=.o-arm)
MODULES_i386 = $(SRCS:.c=.o-i386)
MODULES_i386 := $(MODULES_i386:.cpp=.o-i386)

default: all

all: dist

dist: FreeImage
    cp *.a Dist
    cp Source/FreeImage.h Dist

FreeImage: $(STATICLIB_SIM) $(STATICLIB_PHONE)

$(STATICLIB_SIM): $(MODULES_i386)
    $(LIBTOOL_SIM) -arch_only $(ARCH_SIM) -o $@ $(MODULES_i386)

.c.o-i386:
    $(CC_SIM) $(CFLAGS_SIM) -c $< -o $@

.cpp.o-i386:
    $(CXX_SIM) $(CXXFLAGS_SIM) -c $< -o $@

$(STATICLIB_PHONE): $(MODULES_ARM)
    $(LIBTOOL_PHONE) -arch_only $(ARCH_PHONE) -o $@ $(MODULES_ARM)

.c.o-arm:
    $(CC_PHONE) $(CFLAGS_PHONE) -c $< -o $@

.cpp.o-arm:
    $(CXX_PHONE) $(CXXFLAGS_PHONE) -c $< -o $@

clean:
    rm -f core Dist/*.* u2dtmp* $(MODULES_i386) $(MODULES_ARM) $(STATICLIB_SIM) $(STATICLIB_PHONE)

Perhaps someone could point out where I'm going wrong

Edit: I fixed a problem where it was not rebuilding the i386 object files hoping for that to be the solution, however it still has the same link errors.

Edit: I adjusted my makefile to use clang++

I also added libc++ to the linked frameworks

enter image description here

And here are my settings for the XCode project in regards to C++

enter image description here

I also have .cpp files in my XCode project. The errors however, still persists.

Edit3:

Results for requested query:

nm libfreeimage-iphonesimulator.a | c++filt | grep '~basic_string()' | sort -u
nm: no name list
nm: no name list
         U std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()

The full linker error output can be found here: http://pastebin.com/wjbWgE4S

هل كانت مفيدة؟

المحلول

Objective C projects use the clang compiler (you may still be using gcc), which is a (technically speaking) C compiler, not a C++ compiler. It's smart enough to use file extensions to determine whether to compile code as C, Objective C or C++.

When you link an Objective C project it links using clang, which doesn't link in the C++ runtime. You need to link in the runtime.

If you're building your library using the libc++ library, then you will need to add libc++ to the list of libraries that are linked into the project in the Build Phases -> Link Binary With Libraries. If you're building with the libstdc++ library, then you will need to add libstdc++ to the list of libraries that are linked in.

Xcode is smart enough to link using clang++ if there is even one C++ file in the project, eliminating your need to explicitly link in the C++ runtime in that situation.

tl;dr - it looks like you're not compiling the C++ code for the simulator with the same flags as you're building your main app. The line:

CXXFLAGS_SIM += $(EXTRA_CFLAGS_SIM) -fvisibility-inlines-hidden

is actually missing the base $(CXXFLAGS) item and should read:

CXXFLAGS_SIM += $(CXXFLAGS) $(EXTRA_CFLAGS_SIM) -fvisibility-inlines-hidden

similarly for the CXXFLAGS_PHONE line

as a result you're mixing libc++ and libstdc++ compiled code which leads to the link error. It should have been a hint that the CXXFLAGS line was not being used as it has c++ at the start of the compile line, which would have triggered a compile error if it was used in any of the code.

There are other issues, e.g. to use libc++ your iPhone deployment target must be iOS 5 or later (so __IPHONE_OS_VERSION_MIN_REQUIRED=50000 is needed for the simulator compilation), and you'll need to fix up some of the files because of sign-extension issues e.g.

Source/LibRawLite/./internal/dcraw_common.cpp:3926:19: error: constant expression evaluates to 128 which cannot be narrowed to type 'signed char' [-Wc++11-narrowing]

If you want to check whether C++ code has been compiled with -stdlib=libc++ or -stdlib=libstdc++, you can do an nm of any of the resultant compiled code, passing it through c++filt. If you see a namespace of std::__1::, then the code was compiled with -stdlib=libc++, otherwise it was compiled with -stdlib=libstdc++

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top