Подтвердить что ты не робот

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

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

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

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

/Users/Developer/iOS/TestProj/libpresage.a

Основываясь на этом вопросе, я попытался превратить Build Active Architecture только в NO, и я получаю ту же ошибку. Это заставляет меня подозревать, что я собрал библиотеку для неправильной архитектуры.

Запуск lipo -info в файле .a дает:

входной файл libpresage.a не является жирным файлом Нежирный файл: libpresage.a

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

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

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: warning: ld: warning: игнорирование файла /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libSystem.dylib, отсутствует требуемая архитектура arm64 в файле /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libSystem.dylib(2 среза) игнорирование файла /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libstdc++.dylib, отсутствует требуемая архитектура arm64 в файле /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libstdc++.dylib(2 среза)

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

Есть ли что-то очевидное, что мне не хватает?

EDIT:

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

Мои шаги отсюда:

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

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

  • Моя объектная С++-оболочка (связывание внешнего содержимого библиотеки С++ presage.h):

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

Ключевыми моментами script являются:

  • Получение последнего SDK
  • Создание каждого фрагмента
  • Затем запуск липо

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

Также помните, что вы несете ответственность за правильную ссылку в универсальной 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/$1.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=$1
    hosttarget=$1
    platform=$2

    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

Ответ 2

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

Однако я попытаюсь описать некоторые шаги, которые вам необходимо принять во внимание:

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

Существует несколько способов решения этих проблем.

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

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

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

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

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

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

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

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

Надеюсь, это поможет:).

Ответ 3

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

Ответ 4

Установите для своей архитектуры значение по умолчанию, а затем попробуйте следующее. 1. В Build Phases- > Link Binary With Libraries добавьте библиотеки libz.dylib и libxml2.dylib в ваш проект. 2. В BuildSettings- > Пути поиска установите Always Search User Paths в Yes, а в Path Path Paths укажите правильный путь к вашей структуре. Используйте терминал, чтобы получить правильный путь к вашей структуре. 3. Попробуйте установить свой "источник компилятора как" на С++ или используйте "хит" и "пробный" и проверьте все параметры. Источник Complier Source также находится в разделе BuildSettings. Используйте cmd + f для поиска.

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

Ответ 5

script от Mobile Ben отличен, кроме финальных строк hardcodes, имя файла библиотеки в script. Ниже приводится замена последней команды 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

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

Ответ 6

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

2) В проекте Xcode, где используется dylib/linked:
a) "Путь поиска пути":
   @Executable_path/Каркасы
b) В "Build Phase- > Embed Libraries" убедитесь, что вы выбрали "Destination" как "Executables" и Subpath как "Frameworks", "Code sign on copy" отмечен:
Настройка приложения для подключения iOS

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

Дэвид