2016-07-08 18 views
7

Mam Swift Framework, który kompilujemy i rozpowszechniamy na rzecz zewnętrznych programistów. Chcę dołączyć do projektu kod C, ale jedyny sposób, w jaki udało mi się go uruchomić, to importowanie nagłówka C do nagłówka mojego framework'a i ustawienie nagłówka C jako publicznego. To ujawnia cały kod C deweloperom zewnętrznym, co nie jest tym, czego chcemy.Jak skompilować kod C do Swift Framework

Wszystko mogę znaleźć online, jak to zrobić jest odmianą tej metody: https://spin.atomicobject.com/2015/02/23/c-libraries-swift/

Ale zastrzeżenie tej metody jest „Zauważ, że konsumenci wszelkich ram Ci zbudować używając tej techniki są również będzie mieć aby dodać moduł do ich ścieżek wyszukiwania Swift. " Próbowaliśmy tego i na pewno nasi zewnętrzni programiści dostali błąd Missing required module 'CGeodesic', który jest zdefiniowanym przez nas modułem wskazującym na nagłówek C.

W jaki sposób możemy po prostu skompilować kod C bezpośrednio do naszego systemu, zachowując kod prywatny i nie wymagając od zewnętrznych programistów zmiany ustawień kompilacji, aby działał? Nie mam nic przeciwko konieczności konfigurowania tych submodułów w naszym projekcie, ale na koniec tego dnia chcę, aby był on skompilowany bezpośrednio w jedno płaskie binarne ramy, bez dynamicznego łączenia lub ścieżek wyszukiwania lub czegoś podobnego.

Edycja


Projekt kod C side-by-side z kodem szybka. Mam podkatalog w moim projekcie, który wygląda tak:

  • geodezyjnych/
    • Geodesic.h
    • Geodesic.c
    • Geodesic.swift

Plik Swift zawija kod C, aby ułatwić pracę. Miałem również plik module.modulemap w tym katalogu, ale jak już powiedziałem wcześniej, to nie działało. Wolałbym trzymać kod C równolegle z moim kodem Swift, ale jestem gotów dać to w celu rozwiązania tego problemu.

+0

Jaka jest Twoja obecna konfiguracja? Kod C obok kodu Swift? – zneak

+0

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html. czy to pomaga? Kod C to Objective-C i wygląda na to, że można napisać framework w mieszance C i Swift, i będzie wyglądał dla użytkowników tak, jakby był napisany w jednym języku. Jeszcze tego nie próbowałem. – OmniProg

+0

@OmniProg, więc to właśnie robimy obecnie. Problem z tą metodą polega na tym, że z konieczności ujawnia ona wszystkie te nagłówki publicznie, czego właśnie próbujemy uniknąć. – user1084447

Odpowiedz

14

Tylko w celu ponownego sformułowania problemu: Zasadniczo chcesz zawinąć kod C w Swift i uniemożliwić bezpośredni dostęp do enkapsulowanego kodu C. Oznacza to, aby uniemożliwić dostęp zarówno z Swift, jak i Objective-C.

Jest to możliwe, ale wymaga pewnych korekt w procesie kompilacji i niektórych procesów przetwarzania.

C i Swift Interop w Ram

Każdy kod C, które chcesz zawinąć w Swift musi być publiczne podczas kompilacji albo poprzez nagłówku parasol lub za pomocą mapy modułu. Ważna część tutaj: podczas kompilacji. Ramy nie mają kontroli integralności, co oznacza, że ​​możesz zastosować do nich przetwarzanie końcowe (np. Stworzyć grubą strukturę binarną z lipo). I to właśnie tutaj musimy zrobić.

Przygotowanie kompilacji

Zamiast umieszczać wszystkie zależności C nagłówka w nagłówku parasol można również umieścić je w pliku module.modulemap. Ma to jedną zaletę: możesz utworzyć nagłówki prywatne w fazie budowania Headers.

Dlatego utworzyć plik w projekcie module.modulemap i ustawić ścieżkę do niego w Module Map File produkcji zachodzącego w sekcji Packaging (MODULEMAP_FILE w plikach xcconfig), np $(SRCROOT)/MyFramework/module.modulemap.

Plik module.modulemap powinien mieć następującą treść:

# module.modulemap 

framework module MyFramework { 

    umbrella header "MyFramework.h" 

    export * 
    module * {export *} 

    # All C Files you want to wrap in your Swift code 

    header "A.h" 
    header "B.h" 
} 

tej pory tak dobrze. Teraz powinieneś być w stanie zbudować swój kod i uzyskać do niego dostęp zarówno z Swift, jak i z Objective-C. Jedyny problem: nadal możesz uzyskać dostęp do swoich plików nagłówkowych C w Swift i Objective-C.

Postprocessing

Jeśli spojrzeć na końcowym ram pakiet można zauważyć, że wszystkie swoje prywatne pliki nagłówkowe zostały skopiowane do folderu MyFramework.framework/PrivateHeaders. Oznacza to, że nadal możesz uzyskać do nich dostęp poprzez #import <MyFramework/A.h> w Objective-C.

W Swift nadal można uzyskać dostęp do kodu C, ponieważ umieszczamy pliki nagłówkowe w pliku module.modulemap, który został skopiowany do MyFramework.framework/Modules/module.modulemap.

Na szczęście, możemy po prostu pozbyć się tych dwóch problemów z odrobiną obróbki:

  1. Usuń folder PrivateHeaders z wiązki ramowej.
  2. Utwórz oddzielną mapę modulacji i usuń wszystkie instrukcje header "XYZ.h", np. Nadaj jej nazwę public.modulemap.
  3. Put wszystko to w Fazie Run Script budowy

Oto modulemap publiczny:

# public.modulemap 

framework module MyFramework { 

    umbrella header "MyFramework.h" 

    export * 
    module * {export *} 

    # No more C Headers here 
} 

i skrypt run, które należy dodać do końca fazy budować swój ramowego:

# Delete PrivateHeaders folder 
rm -rf ${TARGET_BUILD_DIR}/${PRODUCT_NAME}${WRAPPER_SUFFIX}/PrivateHeaders 

# Remove module.modulemap file 
rm ${TARGET_BUILD_DIR}/${PRODUCT_NAME}${WRAPPER_SUFFIX}/Modules/module.modulemap 

# Copy public.modulemap file and rename it to module.modulemap 
cp ${SRCROOT}/test/public.modulemap ${TARGET_BUILD_DIR}/${PRODUCT_NAME}${WRAPPER_SUFFIX}/Modules/module.modulemap 

# Append the Swift module so you can access you Swift code in Objective-C via @import MyFramework.Swift 
echo "module ${PRODUCT_NAME}.Swift { header \"${PRODUCT_NAME}-Swift.h\" }" >> ${TARGET_BUILD_DIR}/${PRODUCT_NAME}${WRAPPER_SUFFIX}/Modules/module.modulemap 

Nadzieję, że pomaga!

+0

Działa idealnie! Dziękuję Ci! – user1084447

+3

To jest doskonała odpowiedź na złożony problem, dziękuję. –

+0

ta odpowiedź jest oczywiście niewiarygodna, @JensMeder, dzięki.jedno - być może mógłbyś dodać krótki dodatek * prostszego przypadku *, w którym * nie ma potrzeby *, aby uniemożliwić bezpośredni dostęp. To może wyjaśnić odpowiedź. Założę się, że byłoby to pomocne dla wielu. (Wszystkie starsze artykuły na ten temat na www zniknęły z czasem! :)) – Fattie

1

Istnieje rozwiązanie, chociaż nie jest to zalecane. Możesz use @_silgen_name w swoim pliku .Swift zamiast używać nagłówka C.

Powiązane problemy