Zbuduj statyczną bibliotekę fat (urządzenie + symulator) przy użyciu Xcode i SDK 4+

Wygląda na to, że możemy-teoretycznie-zbudować jedną statyczną bibliotekę, która zawiera zarówno symulator, jak i iPhone ' a i iPada.

Jednak Apple nie ma dokumentacji na ten temat, które można znaleźć, i domyślne szablony Xcode nie są skonfigurowane do tego celu.

Szukam prostej, przenośnej, wielokrotnego użytku techniki, która może być wykonana wewnątrz Xcode.

Trochę historii:

  • w 2008 roku, byliśmy w stanie zrobić pojedyncze static-libs, które obejmowały zarówno sim i urządzenie. Apple wyłączyło to.
  • przez cały 2009 rok tworzyliśmy pary statycznych libów - jeden dla Karty sim, Jeden dla urządzenia. Apple wyłączyło teraz również to.

Bibliografia:

  1. To świetny pomysł, świetne podejście, ale nie działa: http://www.drobnik.com/touch/2010/04/universal-static-libraries/

    • jest kilka błędów w jego skrypcie, co oznacza, że działa tylko na jego komputerze-powinien używać BUILT_PRODUCTS_DIR i/lub BUILD_DIR zamiast "zgadywać" je)
    • [9]}najnowszy Xcode firmy Apple uniemożliwia Ci robienie tego, co zrobił - po prostu nie będzie działać, ze względu na (udokumentowaną) zmianę w sposobie przetwarzania celów Xcode)
  2. Inny więc pytający zapytał, Jak to zrobić bez xcode, a z odpowiedziami, które skupiały się na arm6 vs arm7 część - ale zignorował część i386: Jak skompilować statyczną bibliotekę (fat) dla armv6, armv7 i i386

    • Od najnowszego Apple ' a zmiany, część symulatora nie jest już taka sama jak różnica arm6/arm7 - to inny problem, patrz wyżej)
 286
Author: natevw, 2010-08-19

10 answers

Alternatywy:

Łatwe kopiowanie / wklejanie najnowszej wersji (ale instrukcje instalacji mogą się zmienić-patrz poniżej!)

Biblioteka Karla wymaga znacznie więcej wysiłku w konfiguracji, ale znacznie ładniejsze rozwiązanie długoterminowe (przekształca bibliotekę w Framework).

Użyj tego, a następnie dostosuj go, aby dodać wsparcie dla Archive builds - C.f. komentarz @Frederik poniżej na temat zmian, których używa, aby to działało dobrze z trybem Archiwum.


OSTATNIE ZMIANY: 1. Dodano obsługę systemu iOS 10.x (przy zachowaniu wsparcia dla starszych platform)

  1. Informacje o tym, jak korzystać z tego skryptu z projektu-embedded-in-another-project (chociaż Gorąco polecam nie robić, ever-Apple ma kilka błędów show-stopper w Xcode jeśli osadzać projekty wewnątrz siebie, z Xcode 3.x do Xcode 4.6.x)

  2. Skrypt bonusowy pozwalający na automatyczne dołączanie pakietów (np. dołączanie plików PNG, PLIST itp. z biblioteki!)- patrz niżej (przewiń do dołu)

  3. Teraz obsługuje iPhone5 (używając obejścia błędu Apple w lipo). Uwaga: instrukcje instalacji zostały zmienione (prawdopodobnie mogę to uprościć zmieniając skrypt w przyszłości, ale nie chcę ryzykować teraz)

  4. "Sekcja Kopiuj nagłówki" respektuje teraz ustawienie budowania dla lokalizacji nagłówków publicznych (dzięki uprzejmości Frederika Wallnera)

  5. Dodano jawne ustawienie SYMROOT (może trzeba też ustawić OBJROOT?), dzięki Doug Dickinson


SCRIPT (to jest to co musisz skopiować/wkleić)

Instrukcje użytkowania / instalacji znajdują się poniżej

##########################################
#
# c.f. https://stackoverflow.com/questions/3520977/build-fat-static-library-device-simulator-using-xcode-and-sdk-4
#
# Version 2.82
#
# Latest Change:
# - MORE tweaks to get the iOS 10+ and 9- working
# - Support iOS 10+
# - Corrected typo for iOS 1-10+ (thanks @stuikomma)
# 
# Purpose:
#   Automatically create a Universal static library for iPhone + iPad + iPhone Simulator from within XCode
#
# Author: Adam Martin - http://twitter.com/redglassesapps
# Based on: original script from Eonil (main changes: Eonil's script WILL NOT WORK in Xcode GUI - it WILL CRASH YOUR COMPUTER)
#

set -e
set -o pipefail

#################[ Tests: helps workaround any future bugs in Xcode ]########
#
DEBUG_THIS_SCRIPT="false"

if [ $DEBUG_THIS_SCRIPT = "true" ]
then
echo "########### TESTS #############"
echo "Use the following variables when debugging this script; note that they may change on recursions"
echo "BUILD_DIR = $BUILD_DIR"
echo "BUILD_ROOT = $BUILD_ROOT"
echo "CONFIGURATION_BUILD_DIR = $CONFIGURATION_BUILD_DIR"
echo "BUILT_PRODUCTS_DIR = $BUILT_PRODUCTS_DIR"
echo "CONFIGURATION_TEMP_DIR = $CONFIGURATION_TEMP_DIR"
echo "TARGET_BUILD_DIR = $TARGET_BUILD_DIR"
fi

#####################[ part 1 ]##################
# First, work out the BASESDK version number (NB: Apple ought to report this, but they hide it)
#    (incidental: searching for substrings in sh is a nightmare! Sob)

SDK_VERSION=$(echo ${SDK_NAME} | grep -o '\d\{1,2\}\.\d\{1,2\}$')

# Next, work out if we're in SIM or DEVICE

if [ ${PLATFORM_NAME} = "iphonesimulator" ]
then
OTHER_SDK_TO_BUILD=iphoneos${SDK_VERSION}
else
OTHER_SDK_TO_BUILD=iphonesimulator${SDK_VERSION}
fi

echo "XCode has selected SDK: ${PLATFORM_NAME} with version: ${SDK_VERSION} (although back-targetting: ${IPHONEOS_DEPLOYMENT_TARGET})"
echo "...therefore, OTHER_SDK_TO_BUILD = ${OTHER_SDK_TO_BUILD}"
#
#####################[ end of part 1 ]##################

#####################[ part 2 ]##################
#
# IF this is the original invocation, invoke WHATEVER other builds are required
#
# Xcode is already building ONE target...
#
# ...but this is a LIBRARY, so Apple is wrong to set it to build just one.
# ...we need to build ALL targets
# ...we MUST NOT re-build the target that is ALREADY being built: Xcode WILL CRASH YOUR COMPUTER if you try this (infinite recursion!)
#
#
# So: build ONLY the missing platforms/configurations.

if [ "true" == ${ALREADYINVOKED:-false} ]
then
echo "RECURSION: I am NOT the root invocation, so I'm NOT going to recurse"
else
# CRITICAL:
# Prevent infinite recursion (Xcode sucks)
export ALREADYINVOKED="true"

echo "RECURSION: I am the root ... recursing all missing build targets NOW..."
echo "RECURSION: ...about to invoke: xcodebuild -configuration \"${CONFIGURATION}\" -project \"${PROJECT_NAME}.xcodeproj\" -target \"${TARGET_NAME}\" -sdk \"${OTHER_SDK_TO_BUILD}\" ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO" BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" SYMROOT=\"${SYMROOT}\"

xcodebuild -configuration "${CONFIGURATION}" -project "${PROJECT_NAME}.xcodeproj" -target "${TARGET_NAME}" -sdk "${OTHER_SDK_TO_BUILD}" ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" SYMROOT="${SYMROOT}"

ACTION="build"

#Merge all platform binaries as a fat binary for each configurations.

# Calculate where the (multiple) built files are coming from:
CURRENTCONFIG_DEVICE_DIR=${SYMROOT}/${CONFIGURATION}-iphoneos
CURRENTCONFIG_SIMULATOR_DIR=${SYMROOT}/${CONFIGURATION}-iphonesimulator

echo "Taking device build from: ${CURRENTCONFIG_DEVICE_DIR}"
echo "Taking simulator build from: ${CURRENTCONFIG_SIMULATOR_DIR}"

CREATING_UNIVERSAL_DIR=${SYMROOT}/${CONFIGURATION}-universal
echo "...I will output a universal build to: ${CREATING_UNIVERSAL_DIR}"

# ... remove the products of previous runs of this script
#      NB: this directory is ONLY created by this script - it should be safe to delete!

rm -rf "${CREATING_UNIVERSAL_DIR}"
mkdir "${CREATING_UNIVERSAL_DIR}"

#
echo "lipo: for current configuration (${CONFIGURATION}) creating output file: ${CREATING_UNIVERSAL_DIR}/${EXECUTABLE_NAME}"
xcrun -sdk iphoneos lipo -create -output "${CREATING_UNIVERSAL_DIR}/${EXECUTABLE_NAME}" "${CURRENTCONFIG_DEVICE_DIR}/${EXECUTABLE_NAME}" "${CURRENTCONFIG_SIMULATOR_DIR}/${EXECUTABLE_NAME}"

#########
#
# Added: StackOverflow suggestion to also copy "include" files
#    (untested, but should work OK)
#
echo "Fetching headers from ${PUBLIC_HEADERS_FOLDER_PATH}"
echo "  (if you embed your library project in another project, you will need to add"
echo "   a "User Search Headers" build setting of: (NB INCLUDE THE DOUBLE QUOTES BELOW!)"
echo '        "$(TARGET_BUILD_DIR)/usr/local/include/"'
if [ -d "${CURRENTCONFIG_DEVICE_DIR}${PUBLIC_HEADERS_FOLDER_PATH}" ]
then
mkdir -p "${CREATING_UNIVERSAL_DIR}${PUBLIC_HEADERS_FOLDER_PATH}"
# * needs to be outside the double quotes?
cp -r "${CURRENTCONFIG_DEVICE_DIR}${PUBLIC_HEADERS_FOLDER_PATH}"* "${CREATING_UNIVERSAL_DIR}${PUBLIC_HEADERS_FOLDER_PATH}"
fi
fi

INSTRUKCJA INSTALACJI

  1. Utwórz statyczny projekt lib
  2. wybierz cel
  3. W zakładce "Build Settings" Ustaw "Build Active Architecture Only" NA " NO " (dla wszystkich elementów)
  4. w zakładce "fazy budowania" wybierz "Dodaj ... Nowy Etap Budowy ... Nowy Run Script Build Faza "
  5. skopiuj / wklej skrypt (powyżej) do pola

...BONUS opcjonalne użycie:

  1. opcjonalne: jeśli masz nagłówki w bibliotece, dodaj je do fazy" Kopiuj nagłówki "
  2. opcjonalnie: ...i przeciągnij / upuść je z sekcji "projekt" do sekcji" publiczne "
  3. opcjonalnie: ...i będą automatycznie eksportowane za każdym razem, gdy zbudujesz aplikację, do podkatalogu katalogu "debug-universal" (będą w usr / local / include)
  4. opcjonalne: UWAGA: jeśli również spróbuj przeciągnąć / upuścić swój projekt do innego projektu Xcode, to ujawnia błąd w Xcode 4, gdzie nie można utworzyć .Plik IPA jeśli masz nagłówki publiczne w projekcie przeciągnij/upuść. Obejście: nie osadzaj projektów xcode (zbyt wiele błędów w kodzie Apple!)

Jeśli nie możesz znaleźć pliku wyjściowego, oto obejście:

  1. Dodaj poniższy kod na samym końcu skryptu (dzięki uprzejmości Frederik Wallner): open " ${CREATING_UNIVERSAL_DIR}"

  2. Apple usuwa wszystkie wyjścia po 200 liniach. Wybierz swój cel, a w fazie Run Script należy odznaczyć: "Pokaż zmienne środowiskowe w dzienniku budowy"

  3. Jeśli używasz niestandardowego katalogu" build output "dla XCode4, XCode umieszcza wszystkie "nieoczekiwane" pliki w niewłaściwym miejscu.

    1. Zbuduj projekt
    2. kliknij ostatnią ikonę po prawej stronie, w lewym górnym rogu Xcode4
    3. wybierz górną pozycję (jest to "najnowsza kompilacja". Apple powinno go automatycznie wybrać, ale nie pomyśleli o tym)
    4. w głównym oknie przewiń do dołu. Ostatnia linia powinna brzmieć: lipo: dla bieżącej konfiguracji (Debug) tworzenie pliku wyjściowego: /Users/blah/Library/Developer/Xcode/DerivedData/AppName-ashwnbutvodmoleijzlncudsekyf/Build/Products/Debug-universal/libTargetName.a

    ...to jest miejsce Twojego uniwersalnego Buduj.


Jak dołączyć pliki "non sourcecode" do projektu (PNG, PLIST, XML itp.)

  1. zrób wszystko powyżej, sprawdź czy działa
  2. Utwórz nową fazę Run Script, która nastąpi po pierwszej (skopiuj / wklej poniższy kod)
  3. Utwórz nowy cel w Xcode, typu "bundle"
  4. W głównym projekcie, w "fazach budowania", Dodaj nowy pakiet jako coś, od czego "zależy" (górna sekcja, naciśnij przycisk plus, przewiń do dołu, znajdź ".pakiet " plik w twoich produktach)
  5. W Nowym docelowym pakiecie, w" fazach budowania", dodaj sekcję "Kopiuj zasoby pakietu" i przeciągnij/upuść wszystkie pliki PNG itp.]}

Skrypt do automatycznego kopiowania wbudowanych pakietów do tego samego folderu co biblioteka statyczna FAT:

echo "RunScript2:"
echo "Autocopying any bundles into the 'universal' output folder created by RunScript1"
CREATING_UNIVERSAL_DIR=${SYMROOT}/${CONFIGURATION}-universal
cp -r "${BUILT_PRODUCTS_DIR}/"*.bundle "${CREATING_UNIVERSAL_DIR}"
 274
Author: Adam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-19 23:09:11

Spędziłem wiele godzin próbując zbudować statyczną bibliotekę fat, która będzie działać na armv7, armv7s i symulatorze. W końcu znalazłem rozwiązanie .

Gist polega na zbudowaniu dwóch bibliotek (jednej dla urządzenia, a następnie dla symulatora) oddzielnie, zmianie ich nazw, aby odróżnić je od siebie, a następnie stworzeniu ich lipo w jedną bibliotekę.

lipo -create libPhone.a libSimulator.a -output libUniversal.a
Próbowałem i działa!
 87
Author: g_low,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-27 22:36:42

Zrobiłem Szablon projektu Xcode 4, który pozwala stworzyć uniwersalny framework tak łatwo, jak zwykła biblioteka.

 74
Author: Karl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-02 11:30:11

Istnieje narzędzie wiersza poleceń xcodebuild i możesz uruchomić polecenie powłoki w xcode. Tak więc, jeśli nie masz nic przeciwko użyciu niestandardowego skryptu, ten skrypt może Ci pomóc.

#Configurations.
#This script designed for Mac OS X command-line, so does not use Xcode build variables.
#But you can use it freely if you want.

TARGET=sns
ACTION="clean build"
FILE_NAME=libsns.a

DEVICE=iphoneos3.2
SIMULATOR=iphonesimulator3.2






#Build for all platforms/configurations.

xcodebuild -configuration Debug -target ${TARGET} -sdk ${DEVICE} ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO
xcodebuild -configuration Debug -target ${TARGET} -sdk ${SIMULATOR} ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO
xcodebuild -configuration Release -target ${TARGET} -sdk ${DEVICE} ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO
xcodebuild -configuration Release -target ${TARGET} -sdk ${SIMULATOR} ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO







#Merge all platform binaries as a fat binary for each configurations.

DEBUG_DEVICE_DIR=${SYMROOT}/Debug-iphoneos
DEBUG_SIMULATOR_DIR=${SYMROOT}/Debug-iphonesimulator
DEBUG_UNIVERSAL_DIR=${SYMROOT}/Debug-universal

RELEASE_DEVICE_DIR=${SYMROOT}/Release-iphoneos
RELEASE_SIMULATOR_DIR=${SYMROOT}/Release-iphonesimulator
RELEASE_UNIVERSAL_DIR=${SYMROOT}/Release-universal

rm -rf "${DEBUG_UNIVERSAL_DIR}"
rm -rf "${RELEASE_UNIVERSAL_DIR}"
mkdir "${DEBUG_UNIVERSAL_DIR}"
mkdir "${RELEASE_UNIVERSAL_DIR}"

lipo -create -output "${DEBUG_UNIVERSAL_DIR}/${FILE_NAME}" "${DEBUG_DEVICE_DIR}/${FILE_NAME}" "${DEBUG_SIMULATOR_DIR}/${FILE_NAME}"
lipo -create -output "${RELEASE_UNIVERSAL_DIR}/${FILE_NAME}" "${RELEASE_DEVICE_DIR}/${FILE_NAME}" "${RELEASE_SIMULATOR_DIR}/${FILE_NAME}"

Może wygląda nieefektywnie (nie jestem dobry w skrypcie powłoki), ale łatwo zrozumieć. Skonfigurowałem nowy cel uruchamiający tylko ten skrypt. Skrypt jest przeznaczony do wiersza poleceń, ale nie testowany w :)

Podstawowe pojęcia to xcodebuild i lipo.

Próbowałem wielu konfiguracji w Xcode UI, ale nic nie działało. Ponieważ jest to rodzaj przetwarzania wsadowego, więc projekt wiersza poleceń jest bardziej odpowiedni, więc Apple usunął funkcję budowania partii z Xcode stopniowo. Nie spodziewam się więc, że w przyszłości będą oferować funkcję budowania wsadowego opartą na interfejsie użytkownika.

 30
Author: eonil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-01 09:43:24

Potrzebowałem fat static lib dla JsonKit, więc stworzyłem statyczny projekt lib w Xcode, a następnie uruchomiłem skrypt bash w katalogu projektu. Tak długo, jak skonfigurowałeś projekt xcode z wyłączonym "Build active configuration only" , powinieneś uzyskać wszystkie architektury w jednym lib.

#!/bin/bash
xcodebuild -sdk iphoneos
xcodebuild -sdk iphonesimulator
lipo -create -output libJsonKit.a build/Release-iphoneos/libJsonKit.a build/Release-iphonesimulator/libJsonKit.a
 11
Author: Brad Robinson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-21 02:22:33

Aktualizacja IOS 10:

Miałem problem z zbudowaniem fatlib z iphoneos10. 0 ponieważ wyrażenie regularne w skrypcie oczekuje tylko 9.x i lower oraz zwraca 0.0 dla ios 10.0

Aby to naprawić wystarczy wymienić

SDK_VERSION=$(echo ${SDK_NAME} | grep -o '.\{3\}$')

Z

SDK_VERSION=$(echo ${SDK_NAME} | grep -o '[\\.0-9]\{3,4\}$')
 7
Author: ben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-19 12:18:16

Zrobiłem z tego Xcode 4 szablon, w tym samym duchu co statyczny szablon ramowy Karla.

Odkryłem, że budowanie statycznych frameworków (zamiast zwykłych bibliotek statycznych) powodowało losowe awarie z LLVM, z powodu widocznego błędu linkera - więc, myślę, że biblioteki statyczne są nadal użyteczne!

 4
Author: Michael Tyson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-29 15:54:18

Świetna robota! Zhakowałem coś podobnego, ale musiałem to uruchomić osobno. Posiadanie go po prostu częścią procesu budowania sprawia, że jest to o wiele prostsze.

Jedna uwaga. Zauważyłem, że nie kopiuje żadnego z plików nagłówkowych, które oznaczasz jako publiczne. Dostosowałem to, co miałem w swoim skrypcie do twojego i działa dość dobrze. Wklej poniższy tekst na koniec skryptu.
if [ -d "${CURRENTCONFIG_DEVICE_DIR}/usr/local/include" ]
then
  mkdir -p "${CURRENTCONFIG_UNIVERSAL_DIR}/usr/local/include"
  cp "${CURRENTCONFIG_DEVICE_DIR}"/usr/local/include/* "${CURRENTCONFIG_UNIVERSAL_DIR}/usr/local/include"
fi
 2
Author: user503821,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-01 12:48:16

Xcode 12 update:

Jeśli uruchomisz xcodebuild Bez -arch param, XCode 12 zbuduje bibliotekę symulatora z architekturą "arm64 x86_64" jako domyślną.

Następnie uruchom {[2] } spowoduje konflikt, ponieważ architektura arm64 istnieje w symulatorze, a także w bibliotece urządzeń.

I fork script from Adam git and fix it.

 2
Author: ShaoJen Chen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-30 11:38:18

Właśnie napisałem w tym celu własny skrypt. Nie używa Xcode. (Jest oparty na podobnym skrypcie w projekcie Gambit Scheme.)

W zasadzie działa ./ configure and make three times (for i386, armv7, and armv7s), and combines each of the result libraries into a fat lib.

 1
Author: whooops,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-02 11:17:38