4

我最近决定尝试在 iOS 设备上运行我的一些图形代码,但我使用 FreeImage 来加载纹理。因此,我需要为 iOS 5.0 构建它。

我目前在尝试使用 FreeImage 库时遇到链接错误。链接错误都与标准 C++ 库相关。例如...

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)
  ...

不幸的是,为 iOS 构建 FreeImage 提供的 makefile 有点过时,所以我被迫更新它。此外,在我的 XCode 项目中,我切换了编译器以支持 C++11 功能并使用 libc++(如此处所述我可以将 C++11 与 Xcode 一起使用吗?

所以我试图在 FreeImage 的 makefile 中镜像这些更改,但我仍然收到这些错误。

我的 makefile 看起来像这样(我发现这篇文章有些帮助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)

也许有人可以指出我哪里出错了

编辑:我修复了一个问题,它没有重建 i386 目标文件,希望这是解决方案,但是它仍然有相同的链接错误。

编辑:我调整了我的makefile以使用clang++

我还在链接的框架中添加了 libc++

在此处输入图像描述

这是我对 XCode 项目的 C++ 设置

在此处输入图像描述

我的 XCode 项目中也有 .cpp 文件。然而,错误仍然存​​在。

编辑3:

请求查询的结果:

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()

完整的链接器错误输出可以在这里找到:http: //pastebin.com/wjbWgE4S

4

1 回答 1

5

Objective C 项目使用clang编译器(您可能仍在使用 gcc),它是(从技术上讲)C编译器,而不是C++编译器。使用文件扩展名来确定是将代码编译为C,Objective C还是C++.

当您链接一个 Objective C 项目时,它使用 链接clang,它不会在C++运行时链接。您需要在运行时链接。

如果您正在使用该库构建您的libc++库,那么您将需要添加libc++到链接到Build Phases -> Link Binary With Libraries. 如果您正在使用libstdc++库进行构建,那么您将需要添加libstdc++到链接的库列表中。

Xcode 足够智能,clang++即使C++项目中只有一个文件也可以使用链接,在这种情况下无需在C++运行时显式链接。

tl; dr - 看起来您没有C++使用与构建主应用程序相同的标志来编译模拟器的代码。该行:

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

实际上缺少基本$(CXXFLAGS)项目,应阅读:

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

同样的CXXFLAGS_PHONE线

结果,您正在混合libc++libstdc++编译导致链接错误的代码。它应该暗示该CXXFLAGS行没有像c++在编译行开头那样被使用,如果在任何代码中使用它都会触发编译错误。

还有其他问题,例如要使用libc++您的 iPhone 部署目标必须是 iOS 5 或更高版本(__IPHONE_OS_VERSION_MIN_REQUIRED=50000模拟器编译需要如此),并且由于符号扩展问题,您需要修复一些文件,例如

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]

如果您想检查C++代码是否已使用-stdlib=libc++或编译-stdlib=libstdc++,您可以执行nm任何生成的编译代码,将其传递给c++filt. 如果您看到命名空间std::__1::,则代码是用 编译的-stdlib=libc++,否则它是用 编译的-stdlib=libstdc++

于 2013-01-04T17:34:50.753 回答