2013-01-04 39 views
3

我最近決定嘗試在iOS設備上運行一些圖形代碼,但我使用FreeImage來加載紋理。因此我需要爲iOS 5.0構建它。編譯/鏈接FreeImage for 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) 
    ... 

不幸的是,建築的FreeImage爲iOS提供的makefile文件是有點過時了,所以我被迫更新。此外,在我的XCode項目中,我將編譯器切換爲支持C++ 11功能並使用libC++(如此處所述Can I use C++11 with 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 [email protected] $(MODULES_i386) 

.c.o-i386: 
    $(CC_SIM) $(CFLAGS_SIM) -c $< -o [email protected] 

.cpp.o-i386: 
    $(CXX_SIM) $(CXXFLAGS_SIM) -c $< -o [email protected] 

$(STATICLIB_PHONE): $(MODULES_ARM) 
    $(LIBTOOL_PHONE) -arch_only $(ARCH_PHONE) -o [email protected] $(MODULES_ARM) 

.c.o-arm: 
    $(CC_PHONE) $(CFLAGS_PHONE) -c $< -o [email protected] 

.cpp.o-arm: 
    $(CXX_PHONE) $(CXXFLAGS_PHONE) -c $< -o [email protected] 

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

也許有人能指出我要去哪裏錯了

編輯: 我固定一個問題,即它是不重建希望成爲解決方案的i386目標文件,但它仍然具有相同的鏈接錯誤。

編輯: 我調整好自己的Makefile使用鐺++

我還添加了的libC++到鏈接的框架

enter image description here

這裏是關於C++

我的XCode項目設置

enter image description here

我也有.cpp文件在我的XCode項目中。然而,錯誤仍然存​​在。

EDIT3:

結果請查詢:

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

+0

兩個庫和二進制編譯正在使用相同版本的libC++編譯(即要麼的libC++或stdlibC++,但不是混合) - 這可能會導致鏈接錯誤。另外,如果你只用clang進行編譯,那麼默認情況下它不會鏈接到C++庫中。鏗鏘++將鏈接在C++庫中默認。這是一個典型的c/C++編譯gotcha – Petesh

+0

不要忘記明確地將libC++/libstdC++添加到框架/庫來鏈接。默認情況下,它們在Objective-C項目中沒有鏈接 – Petesh

+0

所有我不知道的東西,謝謝你的幫助。 – Tocs

回答

4

目標C項目使用clang編譯器(你可能仍然在使用gcc),這是一個(技術上講)C編譯器,而不是一個C++編譯器。它足夠聰明,可以使用文件擴展名來確定是否將代碼編譯爲C,Objective CC++

鏈接目標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++

+0

您先生,最好的。你發現了MIN_REQUIRED的事情。兩分鐘後,我絆倒了我。對不起,我打印出我的代碼,並將它製作成一個可怕的錯字的帽子。 – Tocs