-
-
Notifications
You must be signed in to change notification settings - Fork 59
Open
Description
Kiwi Swift 바인딩 구현 계획
개요
Kiwi 한국어 형태소 분석기에 Swift 바인딩을 추가하여 iOS/macOS에서 사용 가능하게 합니다.
핵심 결정사항:
- 배포 방식: XCFramework (바이너리)
- 최소 iOS: 12.0 / macOS: 10.14
- Async/await: 미지원 (동기 API만 제공)
접근 방식: C API 직접 연동
Swift의 C interop 기능을 활용하여 기존 C API(capi.h)를 직접 import합니다.
┌─────────────────┐
│ Swift API │ ← 사용자 친화적 Swift 인터페이스
│ (Kiwi.swift) │
└────────┬────────┘
│
┌────────┴────────┐
│ CKiwi Module │ ← module.modulemap으로 C API import
└────────┬────────┘
│
┌────────┴────────┐
│ libkiwi_static │ ← XCFramework로 배포
└─────────────────┘
디렉토리 구조
bindings/swift/
├── Package.swift
├── README.md
├── Sources/
│ ├── CKiwi/
│ │ ├── module.modulemap
│ │ └── include/ # capi.h 심볼릭 링크
│ └── Kiwi/
│ ├── Kiwi.swift # 메인 클래스
│ ├── KiwiBuilder.swift # 빌더 패턴
│ ├── Token.swift # 토큰 구조체
│ ├── POSTag.swift # 품사 태그 enum
│ ├── MatchOptions.swift # 분석 옵션 (OptionSet)
│ ├── Dialect.swift # 방언 플래그
│ ├── Joiner.swift # 형태소 결합
│ ├── MorphemeSet.swift # 블랙리스트
│ ├── TypoTransformer.swift
│ ├── Errors.swift # KiwiError
│ └── Internal/
│ └── HandleWrapper.swift # C 핸들 RAII 래퍼
├── Tests/
│ └── KiwiTests/
├── CMakeLists.txt # iOS/macOS 빌드 설정
└── scripts/
└── build-xcframework.sh # XCFramework 빌드 스크립트
핵심 타입 매핑
| C API | Swift |
|---|---|
kiwi_h |
Kiwi (class) |
kiwi_builder_h |
KiwiBuilder (class) |
kiwi_res_h |
내부 처리 후 [TokenResult]로 변환 |
kiwi_joiner_h |
Joiner (class) |
kiwi_token_info_t |
Token (struct) |
KIWI_MATCH_* |
MatchOptions (OptionSet) |
KIWI_TAG_* |
POSTag (enum) |
주요 API 설계
// KiwiBuilder
public final class KiwiBuilder {
public init(modelPath: String, numThreads: Int = -1, options: BuildOptions = .default) throws
public init(bundle: Bundle, modelDirectory: String = "KiwiModels") throws
public func addWord(_ word: String, tag: POSTag, score: Float = 0) throws -> Bool
public func build(typoTransformer: TypoTransformer? = nil) throws -> Kiwi
}
// Kiwi
public final class Kiwi {
public static var version: String { get }
public func analyze(_ text: String, topN: Int = 1, options: MatchOptions = .all) throws -> [TokenResult]
public func tokenize(_ text: String, options: MatchOptions = .all) throws -> [Token]
public func splitIntoSentences(_ text: String) throws -> [Sentence]
public func createJoiner(useLMSearch: Bool = true) -> Joiner
}
// Token
public struct Token {
public let form: String
public let tag: POSTag
public let position: Int
public let length: Int
public let score: Float
}메모리 관리
모든 C 핸들을 Swift class로 래핑하고 deinit에서 정리:
internal final class HandleWrapper<H> {
let handle: H
private let cleanup: (H) -> Void
init(_ handle: H, cleanup: @escaping (H) -> Void) {
self.handle = handle
self.cleanup = cleanup
}
deinit { cleanup(handle) }
}빌드 시스템
CMakeLists.txt 주요 설정
# iOS Device (arm64)
set(CMAKE_SYSTEM_NAME iOS)
set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0")
set(CMAKE_OSX_ARCHITECTURES "arm64")
# iOS Simulator (arm64 + x86_64)
set(CMAKE_OSX_SYSROOT iphonesimulator)
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64")
# macOS (Universal)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14")
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64")XCFramework 빌드
scripts/build-xcframework.sh:
- iOS device용 arm64 빌드
- iOS simulator용 arm64+x86_64 빌드
- macOS용 arm64+x86_64 빌드
xcodebuild -create-xcframework로 통합
구현 단계
1단계: 기반 구조
-
bindings/swift/디렉토리 생성 -
Package.swift작성 -
Sources/CKiwi/module.modulemap작성 -
HandleWrapper.swift구현
2단계: 핵심 타입
-
POSTag.swift- 61개 품사 태그 -
MatchOptions.swift- 분석 옵션 플래그 -
Dialect.swift- 방언 플래그 -
Token.swift- 토큰 구조체 -
Errors.swift- KiwiError enum
3단계: 메인 API
-
KiwiBuilder.swift- 빌더 클래스 -
Kiwi.swift- 메인 분석 클래스 -
Joiner.swift- 형태소 결합
4단계: 고급 기능
-
MorphemeSet.swift- 블랙리스트 -
TypoTransformer.swift- 오타 교정 - Bundle에서 모델 로딩 지원
5단계: 빌드 및 배포
-
CMakeLists.txt작성 -
build-xcframework.sh작성 - GitHub Actions 워크플로우 추가
- README.md 문서화
6단계: 테스트
- 단위 테스트 작성
- 예제 iOS 앱 (선택)
수정할 파일
새로 생성:
bindings/swift/전체 디렉토리
수정:
CMakeLists.txt- iOS 타겟 추가 (선택적).github/workflows/- iOS 빌드 워크플로우 추가
검증 방법
- XCFramework 빌드 성공 확인
- 새 iOS 프로젝트에서 SPM으로 추가
- 기본 분석 테스트:
let kiwi = try KiwiBuilder(modelPath: path).build() let tokens = try kiwi.tokenize("안녕하세요") assert(!tokens.isEmpty)
- 메모리 누수 테스트 (Instruments)
참고 파일
include/kiwi/capi.h- C API 전체 정의bindings/java/src/kr/pe/bab2min/Kiwi.java- Java API 참고bindings/java/csrc/kiwi_java.cpp- 바인딩 구현 참고
Copilot