Компиляция внешней библиотеки C++ для использования с проектом iOS

Я совершенно новичок в использовании библиотек C++, поэтому ценю, что это может быть немного специфичным для моего случая (дайте мне знать, и я могу предоставить более подробную информацию).

у меня есть внешняя библиотека c++, которую я пытаюсь использовать с проектом iOS. Библиотека следует шаблону configure, make, make build для вывода a .файл библиотеки. Когда я пытаюсь добавить этот файл библиотеки в Xcode, я получаю следующую ошибку:

игнорируя файл / Пользователи / разработчик / iOS/TestProj / libpresage.ля, файл построенный для архива, который не является связанной архитектурой (i386):

/ пользователи / разработчик / iOS/TestProj / libpresage.а

на основе этот вопрос, я попытался превратить активную архитектуру сборки только в НЕТ, и я получаю ту же ошибку. Это заставляет меня подозревать, что я скомпилировал библиотеку за неправильной архитектуры.

запуск lipo-info на .файл дает:

входной файл libpresage.a не файл fat Non-fat file: libpresage.а

архитектура: x86_64 с

учитывая, что это не armv7s, armv7 или arm64, я снова пытаюсь скомпилировать библиотеку C++ со следующими параметрами:

1) попробовать

./configure CC="gcc -arch armv7s" 
                 CXX="g++ -arch armv7s" 
                 CPP="gcc -E" CXXCPP="g++ -E"

ошибка при компиляции, я получаю:

ld: library not found for -lcrt1.3.1.o
clang: error: linker command failed with exit code 1 (use -v to see invocation)

2) попробовать

./configure CC="gcc -arch arm64" 
                 CXX="g++ -arch arm64" 
                 CPP="gcc -E" CXXCPP="g++ -E"

ошибка при компиляции, я получаю:

ld: предупреждение: ld: предупреждение: игнорирование файл /Применения/Xcode.app / содержание / разработчик / платформы / MacOSX.платформа / разработчик / SDKs / MacOSX10.10.sdk / usr/lib / libSystem.dylib нужна, отсутствует необходимая архитектура arm64 в файле /Применения/Xcode.app / содержание / разработчик / платформы / MacOSX.платформа / разработчик / SDKs / MacOSX10.10.sdk / usr/lib / libSystem.dylib нужна (2 ломтика)игнорирование файла /Применения/Xcode.app / содержание / разработчик / платформы / MacOSX.платформа / разработчик / SDKs / MacOSX10.10.sdk / usr/lib / libstdc++.dylib нужна, отсутствует необходимая архитектура arm64 в файл /Применения/Xcode.app / содержание / разработчик / платформы / MacOSX.платформа / разработчик / SDKs / MacOSX10.10.sdk / usr/lib / libstdc++.dylib нужна (2 ломтика)

ld: динамические основные исполняемые файлы должны быть связаны с libSystem.dylib нужна для архитектура arm64 clang: ошибка: ошибка команды компоновщика с кодом выхода 1 (Используйте -V, чтобы увидеть вызов)

есть что-то очевидное, что я упускаю?

EDIT:

Спасибо за ответы, так я удалось получить библиотеку в Xcode как пользовательскую цель сборки, указав команду "make" на файл MakeFile библиотек. Этот билд отлично.

мои действия:

  • добавьте зависимость от моей цели приложения iOS Objective C в пользовательскую цель сборки.
  • ссылка на библиотеку и сделать объективную оболочку C++.
  • это кажется прекрасным, пока мне не нужно вызвать внешнюю библиотеку C++, тогда я получаю ошибку, когда компиляция:

неопределенные символы для архитектуры ARMv7: "Presage:: Presage (PresageCallback*)", ссылка из: - [PresageBridge init] в PresageBridge.о "Presage::~Presage ()", ссылка из: - [PresageBridge init] в PresageBridge.о ld: символ(ы) не найден для архитектуры armv7 clang: error: ошибка команды компоновщика с кодом выхода 1 (Используйте -v, чтобы увидеть вызов)

  • моя целевая оболочка C++ (связывание предустановки заголовка внешней библиотеки C++.h):

    #import "PresageBridge.h"
    #include "presage.h"
    
    @implementation PresageBridge
    
    - (instancetype)init
    {
        if(self = [super init])
        {
    
           Presage hello(&callback);
        }
    
        return self;
    }
    
  • основываясь на приведенном выше коде, не похоже, что мне не хватает заголовка, и интересно, что я также попытался создать экземпляр других классов во внешней библиотеке, и они, похоже, работают, что предполагает, что Xcode не может связать предустановку.h правильно по какой-то причине.

6 ответов


поэтому я использовал много сторонних библиотек C++ в своих проектах iOS. Для этого люди используют разные стратегии. Как уже упоминалось, вы можете напрямую включить код в проект, построить статический lib с помощью Xcode или построить его в командной строке. В случае кросс-платформенных библиотек C++, которые используют систему настройки и сборки GNU, я предпочитаю командную строку. Вам нужно только построить его один раз, и вам нужно только пересмотреть его, если вам нужно обновить версию или добавить новую архитектуру ломтик.

обобщенный подход, который вы хотите:

  • определите правильные аргументы настройки для построения каждого среза. Как правило, вам нужно сосредоточиться только на том, чтобы получить одну из рук, а также i386. Остальные легко вы это сделали. В некоторых случаях вам действительно нужно изменить файл configure, чтобы добавить хост или внести некоторые другие изменения.

  • Как только вы сможете построить все срезы, вы хотите запустить lipo для создания жирный двоичный.

лучший способ справиться с этим-создать скрипт сборки, который сделает всю работу за вас. Так легче переделать. Что еще более важно, вы можете повторно использовать скрипт или переставлять его для создания других внешних библиотек.

существует много способов создания сценария. Вот один. У меня есть несколько вариантов этого типа сценария. Этот скрипт использовался для сборки cURL. Он более или менее работал для presage с очень небольшим модом(т. е. измените curl на presage). Обратите внимание, что я не тестировал его в Xcode (т. е. связывание и запуск). Я обнаружил, что мне пришлось отключить sqlite, иначе он построил элементы инструментов, которые не строятся правильно. Если тебе это нужно, ты можешь это выяснить.

есть много способов сделать его более гладким. Например, использование массива для хранения всех архитектур. Это просто грубая сила.

ключевые моменты скрипта:

  1. получение последней SDK
  2. построение каждого куска
  3. затем работает lipo

обратите внимание, что он должен работать из коробки, но YMMV. Будьте готовы к необходимости отладки. Например, я не подтвердил тип хоста, но обычно это то, что я всегда использовал. Вы хотите поместить это в каталог для presage (тот же каталог, где настроить). Когда это сделано, все архитектуры находятся в выходном каталоге. Универсальный Либ в предвещать справочник.

также помните, что вы несете ответственность за правильную ссылку в универсальной lib, а также за правильное определение пути поиска файлов заголовков.

#!/bin/bash

PLATFORMPATH="/Applications/Xcode.app/Contents/Developer/Platforms"
TOOLSPATH="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin"
export IPHONEOS_DEPLOYMENT_TARGET="8.0"
pwd=`pwd`

findLatestSDKVersion()
{
    sdks=`ls $PLATFORMPATH/.platform/Developer/SDKs`
    arr=()
    for sdk in $sdks
    do
       arr[${#arr[@]}]=$sdk
    done

    # Last item will be the current SDK, since it is alpha ordered
    count=${#arr[@]}
    if [ $count -gt 0 ]; then
       sdk=${arr[$count-1]:${#1}}
       num=`expr ${#sdk}-4`
       SDKVERSION=${sdk:0:$num}
    else
       SDKVERSION="8.0"
    fi
}

buildit()
{
    target=
    hosttarget=
    platform=

    if [[ $hosttarget == "x86_64" ]]; then
        hostarget="i386"
    elif [[ $hosttarget == "arm64" ]]; then
        hosttarget="arm"
    fi

    export CC="$(xcrun -sdk iphoneos -find clang)"
    export CPP="$CC -E"
    export CFLAGS="-arch ${target} -isysroot $PLATFORMPATH/$platform.platform/Developer/SDKs/$platform$SDKVERSION.sdk -miphoneos-version-min=$SDKVERSION"
    export AR=$(xcrun -sdk iphoneos -find ar)
    export RANLIB=$(xcrun -sdk iphoneos -find ranlib)
    export CPPFLAGS="-arch ${target}  -isysroot $PLATFORMPATH/$platform.platform/Developer/SDKs/$platform$SDKVERSION.sdk -miphoneos-version-min=$SDKVERSION"
    export LDFLAGS="-arch ${target} -isysroot $PLATFORMPATH/$platform.platform/Developer/SDKs/$platform$SDKVERSION.sdk"

    mkdir -p $pwd/output/$target

     ./configure --prefix="$pwd/output/$target" --disable-shared --disable-sqlite --host=$hosttarget-apple-darwin

    make clean
    make
    make install
}

findLatestSDKVersion iPhoneOS

buildit armv7 iPhoneOS
buildit armv7s iPhoneOS
buildit arm64 iPhoneOS
buildit i386 iPhoneSimulator
buildit x86_64 iPhoneSimulator

LIPO=$(xcrun -sdk iphoneos -find lipo)
$LIPO -create $pwd/output/armv7/lib/libpresage.a  $pwd/output/armv7s/lib/libpresage.a $pwd/output/arm64/lib/libpresage.a $pwd/output/x86_64/lib/libpresage.a $pwd/output/i386/lib/libpresage.a -output libpresage.a

учитывая, что вы новичок в библиотеках c++, я думаю, вам нужно будет сделать немного больше исследований.

тем не менее, я попытаюсь изложить некоторые шаги, которые вам нужно принять во внимание :

  • вам нужно убедиться, что вы компилируете для одной и той же архитектуры как статическую библиотеку (.а) и проект
  • из вашей ошибки вам нужно скомпилировать статическую библиотеку для i386 или изменить свой проект на x86_64 ( разница между ними архитектуры немного сложнее, но пока предположим, что i386 означает рабочий стол 32 бит, а x86_64-рабочий стол 64 бит)
  • архитектуры arm предназначены для iPhone, а не для MacOS (вот почему он не может найти библиотеки с архитектурой arm внутри папки MacOSX) !

существует несколько способов подхода к этим вопросам .

для первого я бы предложил включить в ваше рабочее пространство статическую библиотеку и добавить ее в качестве зависимости от вашего целевой объект построения. Для этого вам нужно понять сборки XCode.

Я предполагаю, что вы на самом деле пытаетесь сделать приложение для телефона, поэтому для 3-го варианта вам нужно настроить сборку g++, чтобы заглянуть в iPhoneSDK из XCode при связывании целей arm (посмотрите за iPhoneOS.платформа) для этого.

создание сборки arm будет работать только на iPhones . Если вы хотите , чтобы он работал на симуляторе, вам нужно будет связать свою статическую библиотеку с библиотеками внутри iPhoneSimulator.платформа.

Если вы хотите, чтобы ваша статическая библиотека работала как для iPhone, так и для iPhone simulator, вам нужно будет сделать fat lib (в основном библиотеку, содержащую символы для обеих платформ)

Если вам не хватает этих платформ, вы можете скачать их с XCode (но я считаю, что они есть)

Как вы можете видеть, все будет становиться все более и более сложным на этом пути, поэтому я настоятельно рекомендую использовать XCode для компиляции статической библиотеки (это все еще выполнимо с g++ thou).

Я считаю, что следующие концепции, которые вы были бы полезны для исследования:

  • руку, на платформах x86 , x86_64 с
  • статическая библиотека
  • статическая линковка
  • fat lib (универсальная библиотека)
  • рабочее пространство XCode с несколькими проектами

надеюсь, что это помогает :).


вот что сработало для меня в Xcode 9 для устройств iOS (iPhone X):
1) скомпилируйте dylib с этими флагами, установленными следующим образом:
каталог установки": @executable_path/рамки b) " путь поиска Runpath": @executable_path/рамки
Смотрите картинку ниже:
настройки dylib в Xcode 9

2) в проекте Xcode, где используется dylib/linked:
a)"Runpath Search Path":
@executable_path/рамки
b) В разделе" фаза сборки->библиотеки встраивания "убедитесь, что вы выбрали" назначение "как" исполняемые файлы "и вложенный путь как" фреймворки"," кодовый знак на копии " проверено:
настройка связывающего приложения iOS

этот метод протестирован и используется с Xcode 9.2 и iPhone X.

Дэвид


C++ работает на iOS, вы можете просто добавить его в свой проект. Или, если вы действительно хотите иметь динамическую библиотеку, вы можете скомпилировать ее с помощью Xcode и указать целевую архитектуру.


установите архитектуру по умолчанию, затем попробуйте следующее. 1. В фазах сборки - > связать двоичный файл с библиотеками добавить libz.dylib и libxml2.библиотеки dylib для вашего проекта. 2. В BuildSettings - >Search Paths установите для поиска пользовательских путей значение Yes, а в разделе пути поиска фреймворка добавьте правильный путь фреймворка. Используйте terminal, чтобы получить правильный путь вашей структуры. 3. Попробуйте установить "источник компилятора как" на C++ или использовать hit и trial и проверить все параметры. Составителю источников, как это также в BuildSettings. Используйте cmd+f для поиска.

попробуйте и дайте мне знать, также расскажите мне о фреймворке или sdk, который вы пытаетесь использовать в своем проекте.


скрипт Mobile Ben великолепен, кроме последней строки, жестко кодирует имя файла библиотеки в скрипт. Ниже приводится замена последней команды lipo и динамически использует lipo объединяет каждый файл библиотеки, созданный после компиляции.

изменить линию мобильного Бена:

$LIPO -create $pwd/output/armv7/lib/libpresage.a  $pwd/output/armv7s/lib/libpresage.a $pwd/output/arm64/lib/libpresage.a $pwd/output/x86_64/lib/libpresage.a $pwd/output/i386/lib/libpresage.a -output libpresage.a

в:

for t in `ls $pwd/output/armv7/lib/*.a` ;
do
        export LIB=`basename $t`
        export ARCHSTRING=""
        for a in `ls $pwd/output`
        do
                export ARCSTRING="$ARCSTRING $pwd/output/$a/lib/$LIB "
        done
        $LIPO -create $ARCSTRING  -output $LIB
done

примечание: Я не хотел редактировать ответ мобильного Бена с новой функциональностью кода и добавлять это как потерянное форматирование комментария.