Xcode 6 Beta 6을 사용하고 있습니다.
이것은 지금 당장 나를 괴롭힌 적이 있지만 지금은 거의 사용할 수없는 시점에 도달하고 있습니다.
내 프로젝트는 적당한 크기의 65 Swift 파일과 몇 개의 브리지 된 Objective-C 파일 (실제로 문제의 원인이 아님) 을 갖기 시작했습니다 .
응용 프로그램에서 거의 사용되지 않는 클래스에 간단한 공백을 추가하는 것과 같이 Swift 파일을 약간 수정 한 것처럼 지정된 대상의 전체 Swift 파일이 다시 컴파일됩니다.
더 깊이 조사한 결과, 컴파일러 시간의 거의 100 %를 차지하는 것은 CompileSwift
Xcode가 swiftc
대상의 모든 Swift 파일 에서 명령을 실행하는 단계 라는 것을 알았습니다 .
추가 조사를 수행했으며 기본 컨트롤러로 앱 대리자를 유지하면 컴파일 속도가 매우 빨라지지만 점점 더 많은 프로젝트 파일을 추가할수록 컴파일 시간이 느려지기 시작했습니다.
이제 65 개의 소스 파일 만 있으면 매번 컴파일하는 데 약 8/10 초가 걸립니다. 전혀 빠르지 는 않습니다.
나는 제외하고는이 문제에 대해 이야기 사후 보지 못했지만 이 일을 하지만 그 경우에 하나의이야 만약 내가 궁금하네요 그래서 엑스 코드 (6)의 이전 버전을했다.
최신 정보
Alamofire , Euler 및 CryptoSwift 와 같은 GitHub 에서 몇 가지 Swift 프로젝트를 확인 했지만 실제로 비교할 충분한 Swift 파일이 없었습니다. 내가 적당한 크기의 프로젝트를 시작한 것으로 밝혀진 유일한 프로젝트 는 SwiftHN 이며, 소스 파일이 수십 개인데도 여전히 동일한 것을 확인할 수 있었고, 간단한 공간 하나와 전체 프로젝트를 다시 컴파일해야했습니다. 작은 시간 (2/3 초).
분석기와 컴파일이 빠르게 진행되는 Objective-C 코드와 비교할 때, 이것은 스위프트가 큰 프로젝트를 처리 할 수 없을 것 같지만, 내가 틀렸다고 말해주십시오.
Xcode 6 베타 7로 업데이트
여전히 개선이 없습니다. 이 말이 터지기 시작했습니다. #import
스위프트 (Swift) 가 없기 때문에 애플이 어떻게 이것을 최적화 할 수 있을지 모르겠다.
Xcode 6.3 및 Swift 1.2로 업데이트
Apple은 증분 빌드 (및 기타 많은 컴파일러 최적화)를 추가했습니다. 이러한 이점을 보려면 코드를 Swift 1.2로 마이그레이션해야하지만 Apple은 Xcode 6.3에 도구를 추가하여 다음과 같은 이점을 제공합니다.
하나
내가 한 것처럼 너무 빨리 기뻐하지 마십시오. 빌드 증분을 만드는 데 사용하는 그래프 솔버는 아직 잘 최적화되지 않았습니다.
실제로 함수 서명 변경 사항을 보지 않으므로 한 방법의 블록에 공백을 추가하면 해당 클래스에 따른 모든 파일이 다시 컴파일됩니다.
둘째, 변경 사항이 영향을 미치지 않더라도 다시 컴파일 된 파일을 기반으로 트리를 만드는 것 같습니다. 예를 들어,이 세 클래스를 다른 파일로 옮길 경우
class FileA: NSObject {
var foo:String?
}
class FileB: NSObject {
var bar:FileA?
}
class FileC: NSObject {
var baz:FileB?
}
이제 수정 FileA
하면 컴파일러가 FileA
다시 컴파일되도록 표시 됩니다. 또한 재 컴파일합니다 FileB
(즉의 변경에 따라 확인 될 것이다 FileA
), 그러나 또한 FileC
있기 때문에 FileB
다시 컴파일하고 있기 때문에 그것은 아주 나쁜는 FileC
절대 사용하지 않습니다 FileA
여기.
의존성 트리 솔버가 개선되기를 바랍니다 .이 샘플 코드 로 레이더 를 열었습니다 .
Xcode 7 베타 5 및 Swift 2.0으로 업데이트
어제 Apple은 베타 5를 출시했으며 릴리스 노트에서 다음과 같이 볼 수 있습니다.
Swift Language & Compiler • 증분 빌드 : 함수 본문 만 변경해도 더 이상 종속 파일이 다시 작성되지 않아야합니다. (15352929)
나는 그것을 시도했고 그것이 실제로 (정말!) 잘 작동한다고 말해야합니다. 그들은 증분 빌드를 신속하게 최적화했습니다.
swift2.0
XCode 7 베타 5를 사용하여 브랜치 를 만들고 코드를 최신 상태로 유지 하는 것이 좋습니다 . 컴파일러의 향상된 기능에 만족할 것입니다 (그러나 XCode 7의 글로벌 상태는 여전히 느리고 버그가 있습니다)
Xcode 8.2로 업데이트
이 문제에 대한 마지막 업데이트 이후 오랜 시간이 지났습니다.
우리의 응용 프로그램은 이제 거의 독점적으로 Swift 코드의 약 20k 줄입니다. 스위프트 2와 스위프트 3 마이그레이션보다 빠릅니다. 2014 년 중반 Macbook Pro (2.5GHz Intel Core i7)에서 컴파일하는 데 약 5 / 6m가 소요되며 이는 깔끔한 빌드에서는 괜찮습니다.
그러나 애플이 다음과 같이 주장하지만 증분 빌드는 여전히 농담입니다.
Xcode는 작은 변경 사항이 발생한 경우 전체 대상을 다시 작성하지 않습니다. (28892475)
분명히 나는 우리 중 많은 사람들 이이 넌센스를 확인한 후 웃었다 고 생각합니다 (프로젝트의 파일에 하나의 개인 (개인!) 속성을 추가하면 전체가 다시 컴파일됩니다 …)
Apple 개발자 포럼 에서이 문제에 대해 더 많은 정보를 제공하는 스레드 를 지적하고 싶습니다 (이 문제에 대한 Apple 개발자의 커뮤니케이션에 감사드립니다)
기본적으로 사람들은 증분 빌드를 개선하기 위해 몇 가지를 생각해 냈습니다.
- 로
HEADER_MAP_USES_VFS
설정된 프로젝트 설정 추가true
Find implicit dependencies
당신의 계획에서 비활성화- 새 프로젝트를 작성하고 파일 계층을 새 프로젝트로 이동하십시오.
솔루션 3을 시도하지만 솔루션 1/2은 우리에게 효과가 없었습니다.
이 전체 상황에서 아이러니하게도 재미있는 것은 우리가 Xcode 6을 사용하고있는이 문제에 대한 첫 번째 게시물을 살펴보면 첫 번째 컴파일 부진에 도달했을 때 swift 1 또는 swift 1.1 코드를 믿으며 약 2 년 후에 Apple의 실제 개선에도 불구하고 상황은 Xcode 6에서와 마찬가지로 나빴습니다.
사실은 정말 그것 때문에 포함 매일 좌절의 우리의 프로젝트의 Obj / C를 통해 스위프트을 선택 후회. (나는 심지어 AppCode로 전환하지만 다른 이야기입니다)
어쨌든 나는이 SO 게시물 이이 글을 쓰는 시점에서 32k + 조회수와 143 업을 가지고 있으므로 내가 유일한 사람이 아니라고 생각합니다. 이 상황에 비관적이지만 터널 끝 부분에 약간의 빛이있을 수 있습니다.
시간이 있고 용기가 있다면, 애플이 이것에 대해 레이더를 환영한다고 생각합니다.
다음 시간까지! 건배
Xcode 9로 업데이트
오늘 이것을 우연히 발견 하십시오 . Xcode는 현재 끔찍한 성능을 향상시키기 위해 새로운 빌드 시스템을 조용히 도입했습니다. 작업 공간 설정을 통해 활성화해야합니다.
아직 시도했지만이 게시물이 완료되면 업데이트됩니다. 그래도 유망 해 보인다.
답변
롭 네이피어가 옳다는 것이 밝혀졌습니다. 컴파일러가 berzek으로 이동하게하는 것은 하나의 단일 파일 (실제로 하나의 방법)이었습니다.
이제 내가 틀리지 마 Swift는 매번 모든 파일을 다시 컴파일하지만, 이제는 Apple이 컴파일하는 파일에 실시간 컴파일 피드백을 추가하여 Xcode 6 GM이 컴파일중인 Swift 파일과 컴파일 상태를 실시간으로 보여줍니다. 이 스크린 샷에서 볼 수 있듯이
따라서 어느 파일이 오래 걸리는지 아는 것이 매우 편리합니다. 제 경우에는 다음과 같은 코드였습니다.
var dic = super.json().mutableCopy() as NSMutableDictionary
dic.addEntriesFromDictionary([
"url" : self.url?.absoluteString ?? "",
"title" : self.title ?? ""
])
return dic.copy() as NSDictionary
속성이 있기 때문에 title
유형이었다 var title:String?
하지 NSString
. 에 추가 할 때 컴파일러가 열광했습니다 NSMutableDictionary
.
로 변경 :
var dic = super.json().mutableCopy() as NSMutableDictionary
dic.addEntriesFromDictionary([
"url" : self.url?.absoluteString ?? "",
"title" : NSString(string: self.title ?? "")
])
return dic.copy() as NSDictionary
컴파일이 10/15 초 (아마도 더 많음)에서 1 초까지 … 놀랍습니다.
답변
우리는 약 100k 라인의 Swift 코드와 300k 라인의 ObjC 코드를 가지고 있기 때문에 이것을 극복하기 위해 몇 가지 노력을 기울였습니다.
첫 번째 단계는 함수 컴파일 시간 출력에 따라 모든 함수를 최적화하는 것입니다 (예 : https://thatthinginswift.com/debug-long-compile-times-swift/에 설명 된대로 )
다음으로 모든 신속한 파일을 하나의 파일로 병합하는 스크립트를 작성했습니다. 이로 인해 액세스 수준이 떨어지지 만 컴파일 시간이 5-6 분에서 ~ 1 분으로 단축되었습니다.
Apple에 문의하여 다음과 같은 조치를 취해야한다고 권고했기 때문에 이는 현재 소멸되었습니다.
- ‘Swift Compiler-Code Generation’빌드 설정에서 ‘전체 모듈 최적화’를 켜십시오. 고르다
'Fast, Whole Module Optimization'
- 개발 빌드를 위해 ‘Swift Compiler-Custom Flags’에서
'-Onone'
이 플래그가 설정되면 컴파일러는 모든 Swift 파일을 한 단계로 컴파일합니다. 병합 스크립트를 사용하면 파일을 개별적으로 컴파일하는 것보다 훨씬 빠릅니다. 그러나 ‘ -Onone'
재정의가 없으면 전체 모듈도 최적화되므로 속도가 느려집니다. '-Onone'
다른 Swift 플래그에 플래그를 설정하면 최적화가 중지되지만 한 번에 모든 Swift 파일 컴파일이 중지되지는 않습니다.
전체 모듈 최적화에 대한 자세한 내용은 Apple 블로그 게시물 ( https://swift.org/blog/whole-module-optimizations/)을 참조하십시오.
이러한 설정을 통해 Swift 코드가 30 초 안에 컴파일 될 수 있다는 것을 알았습니다 .-) 다른 프로젝트에서 어떻게 작동하는지에 대한 증거는 없지만 Swift 컴파일 시간이 여전히 문제가되는 경우 시도해 보는 것이 좋습니다.
App Store 빌드의 경우 '-Onone'
프로덕션 빌드에 최적화가 권장 되므로 플래그를 남겨 두어야 합니다.
답변
프로젝트 크기와 거의 관련이 없습니다. 아마도 특정 코드 조각 일 수도 있고 아마도 한 줄일 수도 있습니다. 전체 프로젝트가 아닌 한 번에 하나의 파일을 컴파일하여이를 테스트 할 수 있습니다. 또는 빌드 로그를보고 어떤 파일이 오래 걸리는지 확인하십시오.
문제를 일으킬 수있는 코드 종류의 예로, 이 38 줄 짜리 요점 은 베타 7에서 컴파일하는 데 1 분 이상 걸립니다. 이 모든 것은이 하나의 블록으로 인해 발생합니다 :
let pipeResult =
seq |> filter~~ { $0 % 2 == 0 }
|> sorted~~ { $1 < $0 }
|> map~~ { $0.description }
|> joinedWithCommas
한두 줄만으로 단순화하면 거의 즉시 컴파일됩니다. 문제는 컴파일러에서 지수 성장 (아마도 계승 성장)을 일으키는 것입니다. 분명히 이상적이지는 않으며 그러한 상황을 격리 할 수 있다면 레이더를 열어서 문제를 해결하는 데 도움이됩니다.
답변
컴파일 시간을 늦추는 특정 파일을 식별하려는 경우 xctool 을 통해 명령 줄에서 파일을 컴파일하면 파일별로 컴파일 시간을 줄 수 있습니다.
주목할 것은 기본적으로 각 CPU 코어 당 2 개의 파일을 동시에 빌드하며 “net”경과 시간이 아니라 절대 “user”시간을 제공한다는 것입니다. 이렇게하면 병렬화 된 파일 사이의 모든 타이밍이 매우 유사 해 보이고 매우 유사 해 보입니다.
이를 극복하려면 파일 빌드를 병렬화하지 않도록 플래그를 1로 설정하십시오-jobs
. 시간이 더 걸리지 만 결국에는 파일별로 파일을 비교할 수있는 “net”컴파일 시간이 있습니다.
다음은 트릭을 수행해야하는 명령 예입니다.
xctool -workspace <your_workspace> -scheme <your_scheme> -jobs 1 build
“Swift 파일 컴파일”단계의 결과는 다음과 같습니다.
...
✓ Compile EntityObserver.swift (1623 ms)
✓ Compile Session.swift (1526 ms)
✓ Compile SearchComposer.swift (1556 ms)
...
이 출력에서 컴파일하는 데 다른 파일보다 시간이 오래 걸리는 파일을 빠르게 식별 할 수 있습니다. 또한 리팩토링 (명시 적 캐스트, 유형 힌트 등)이 특정 파일의 컴파일 시간을 단축시키는 지 여부를 정확하게 결정할 수 있습니다.
참고 : 기술적으로도 가능 xcodebuild
하지만 출력은 매우 장황하고 소비하기가 어렵습니다.
답변
필자의 경우 Xcode 7은 전혀 차이가 없었습니다. 컴파일하는 데 몇 초가 걸리는 여러 함수가 있습니다.
예
// Build time: 5238.3ms
return CGSize(width: size.width + (rightView?.bounds.width ?? 0) + (leftView?.bounds.width ?? 0) + 22, height: bounds.height)
옵션을 풀고 나면 빌드 시간이 99.4 % 감소했습니다 .
// Build time: 32.4ms
var padding: CGFloat = 22
if let rightView = rightView {
padding += rightView.bounds.width
}
if let leftView = leftView {
padding += leftView.bounds.width
}
return CGSizeMake(size.width + padding, bounds.height)
에서 더 많은 예제를 참조하십시오 이 게시물 과 이 게시물을 .
Xcode 용 빌드 시간 분석기
나는 엑스 코드 플러그에서 개발 된 이러한 문제가 발생하는 누군가를 위해 유용하게 사용할 수 있습니다.
Swift 3에는 개선이있을 것으로 보이므로 Swift 코드가 더 빨리 컴파일되는 것을 보게 될 것입니다.
답변
아마도 우리는 Swift 컴파일러를 고칠 수 없지만 고칠 수있는 것은 코드입니다!
Swift 컴파일러에는 숨겨진 모든 옵션이 있습니다.이 옵션은 컴파일러가 모든 단일 함수를 컴파일하는 데 걸리는 정확한 시간 간격을 인쇄합니다 -Xfrontend -debug-time-function-bodies
. 이를 통해 코드에서 병목 현상을 발견하고 컴파일 시간을 크게 개선 할 수 있습니다.
터미널에서 다음을 간단히 실행하고 결과를 분석하십시오.
xcodebuild -workspace App.xcworkspace -scheme App clean build OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" | grep [1-9].[0-9]ms | sort -nr > culprits.txt
멋진 Brian Irace는 Swift 컴파일 시간 프로파일 링 에 대한 훌륭한 기사를 썼습니다 .
답변
해결책은 캐스팅 중입니다.
나는 다음과 같이 엄청난 양의 사전을 가지고있었습니다.
["title" : "someTitle", "textFile" : "someTextFile"],
["title" : "someTitle", "textFile" : "someTextFile"],
["title" : "someTitle", "textFile" : "someTextFile"],
["title" : "someTitle", "textFile" : "someTextFile"],
.....
컴파일하는 데 약 40 분이 걸렸습니다. 내가 이런 식으로 사전을 캐스팅 할 때까지 :
["title" : "someTitle", "textFile" : "someTextFile"] as [String : String],
["title" : "someTitle", "textFile" : "someTextFile"] as [String : String],
["title" : "someTitle", "textFile" : "someTextFile"] as [String : String],
....
이것은 내 응용 프로그램에 하드 코딩 된 데이터 유형과 관련하여 거의 모든 다른 문제에 효과적이었습니다.