티스토리 뷰
[Xcode] StaticLinker 의 release, debug 빌드 차이 (-export_dynamic, -no_deduplicate)
eungding 2024. 4. 20. 02:01[1] Linker Option > release vs debug
다음과 같이 프로젝트를 세팅했을 때
debug랑 release 의 빌드로그 차이점 몇가지를 살펴 보자.
1) debug 빌드일때만 링커에 -export_dynamic, -no_deduplicate 옵션을 넘긴다
우선 해당 옵션을 하나씩 보자
# -no_depulicate
중복 제거 최적화 (사이즈 최적화) 를 하지 말라는 옵션이다.
debug 빌드는 빠른 속도가 중요하기 때문에
사이즈 최적화 단계를 거치지 않도록 해당 옵션을 넘긴다.
# -export_dynamic
공유 라이브러리의 symbol을 외부로 노출시키고, 다른 모듈에서 해당 기호를 사용할 수 있도록 하는 옵션이다.
(출처 GPT)
debug 에서는 중복제거를 안하므로 duplicated symbol 이 발생할 수 있다.
그래서 -no_depulicate 와 짝궁으로 쓰는 옵션으로 보인다.
# -dead_strip
-dead_strip 을 검색해보면
Release 는 두번, Debug 는 한번 나온다.
위의 -export_dynamic 과 관련이 깊어보이는데,
릴리즈빌드에서는 두개의 framework 에 각각 데드스트리핑을 실행하는 것 같고
디버그빌드에서는 공유 라이브러리 하나에 데드스트리핑을 실행하는 것 같다.
For statically-linked executables, dead-code stripping is the process of removing unreferenced code from the executable file. The idea behind dead-stripping is that if the code is unreferenced, it must not be used and therefore is not needed in the executable file. Removing dead code reduces the size of your executable and can help reduce paging.
2) debug 빌드일때만 SwiftEmitModule 명령어를 실행한다.
뒤의
-emit-module -experimental-skip-non-inlinable-function-bodies-without-types 플래그도 눈에 띈다.
모듈을 만드는 로그 같은데 정확히 잘모르겠다.
[2] Linking > release vs debug
즉 중복된 dependecy 를 가지는 상황에서
release, debug 모두 duplicated symbol 이 발생하지 않는다.
app executable 파일에 nm 명령어 실행해보면
s _symbolic _____ 3Toy0A5View1V 가 한개 인 것을 확인할 수 있다.
하지만 링커 옵션의 차이로 내부 동작이 다르므로
아래와 같이 다른 결과가 나온다.
# release 빌드
- 앱 실행 파일 사이즈 211KB
- release 빌드에서 아카이빙한 ipa 사이즈 21KB
# debug 빌드
- 앱 실행 파일 사이즈 140KB
- debug 빌드에서 아카이빙한 ipa 사이즈 35KB
[3] 결론
컴퓨터 프로그래밍에서 일반적으로 말하는 Static Linking과 Dynmaic Linking 의 차이 (+ static 의 중복 복사 이슈) 가
iOS 에서 발생한다고 보기에 무리가 있다.
우리의 StaticLinker 는 강력하다.
[4] 의문점 > dead stripping
아래 WWDC 를 보고 dead stripping 은 중복 복사는 되지만
duplicated symbol 관련 워닝 또는 에러가 나지 않게 해주는 기술이라고 이해했다.
앱 실행파일에 dependency 가 중복 복사는 되어서 사이즈 증가는 그대로이고
위의 상황에서 에러만 발생하지 않도록
링커가 중복된 심볼 중 첫번째 것을 선택해주는 옵션이라고 생각했음..
하지만 문서도, 실험결과도 중복복사가 아니라고 말한다.
아래의 WWDC 23 > Meet Mergeable libraries 의 스크립트를 보고
이렇게 받아들였다.
1. Woody Framework 에서 ToyView 1 API 를 복사
2. Buzz Framework 에서도 ToyView 1 API 를 복사
3. 중복! (같은 해쉬값) 첫번째 ToyView 1 API 를 선택하고 두번째 ToyView 1 API 를 지움.
아니면 2번 단계에서 복사를 아예 진행하지 않았을 수 도 있음
빌드 때 정적 링커가 라이브러리에서 어떤 API를 사용할지 찾아서 코드를 앱 바이너리에 복사하죠
복사했기 때문에 빌드 후에는 라이브러리가 필요 없어요
정적 라이브러리 코드가 바뀌거나 더 많은 라이브러리가 사용되면 빌드 시간이 느려지죠
앱에 아카이브되거나 링크된 방식 때문인데 반복적 빌드와 디버깅을 느리게 하죠
동적 라이브러리를 사용하면 이를 방지할 수 있어요
동적 라이브러리는 통상 dylib이라고 부르죠 Xcode 프레임워크 타겟을 위한 바이너리 파일 타입이에요
프레임워크의 코드를 실행 파일에 복사하지 않죠
대신 정적 링커가 라이브러리의 설치 경로를 나중을 위해 앱 바이너리에 기록해요
Apple SDK에 없는 모든 프레임워크는 앱 번들에 임베딩해야 하죠
큰 차이점은 동적 라이브러리가 추가되거나 업데이트될 때 정적 링커가 코드를 복사하지 않아도 된다는 거예요
이를 통해 빌드가 빨라져요
하지만 앱이 런타임 때 사용되면 복잡도가 증가하죠
이때 동적 링커가 필요해요 앱을 실행했을 때 dyld라는 동적 링커가 프레임워크 의존성을 찾아서 로딩해야 하죠
해당 프레임워크가 의존하는 라이브러리도 포함해요
더 많이 사용될수록 메모리 사용량과 앱 실행 시간이 점차 증가하게 되죠
Apple SDK의 의존성까지 고려할 경우 앱이 수백 개의 프레임워크를 로딩할 수도 있어요
우리 플랫폼은 이를 수용하기 위해 시스템 라이브러리를 최적화했죠
하지만 앱에 임베딩되는 프레임워크에는 적용되지 않아요
다시 정리해 보면 정적, 동적 라이브러리를 선택하는 것에 있어 각각의 단점이 있죠
동적 라이브러리는 빌드 시간에 영향을 적게 주지만 실행 시간이 길어질 수 있고
정적 라이브러리는 실행 시간에 영향을 적게 주지만 빌드 시간이 길어질 수 있어요
[ 추천글 ]
https://liam777.tistory.com/18
'🍏 > iOS' 카테고리의 다른 글
[iOS] 웹뷰 인스펙터, 웹뷰 디버깅 (0) | 2024.06.28 |
---|---|
[Xcode] Swift Package Plugin (3) | 2024.04.30 |
[Xcode] Instruments - Swift Concurrency (1) | 2024.03.11 |
[Xcode] Instruments 로 Hang 개선하기 (8) | 2024.03.08 |
[iOS] iOS 17 Text Selection 의 변화 (1) | 2023.11.10 |
- Total
- Today
- Yesterday
- flutter dynamic link
- Flutter 로딩
- Flutter getter setter
- 구글 Geocoding API
- 장고 URL querystring
- Flutter Spacer
- 플러터 얼럿
- Django Firebase Cloud Messaging
- flutter 앱 출시
- flutter deep link
- Watch App for iOS App vs Watch App
- ribs
- DRF APIException
- SerializerMethodField
- ipad multitasking
- github actions
- PencilKit
- drf custom error
- Dart Factory
- cocoapod
- Django FCM
- Flutter Clipboard
- Django Heroku Scheduler
- Python Type Hint
- 장고 Custom Management Command
- METAL
- 플러터 싱글톤
- Flutter Text Gradient
- Sketch 누끼
- flutter build mode
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |