Skip to content

Commit d244f14

Browse files
Initial commit
0 parents  commit d244f14

File tree

32 files changed

+535
-0
lines changed

32 files changed

+535
-0
lines changed

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
xcuserdata/
5+
DerivedData/
6+
.swiftpm/configuration/registries.json
7+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8+
.netrc

Example/.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
xcuserdata/
5+
DerivedData/
6+
.swiftpm/configuration/registries.json
7+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8+
.netrc

Example/Package.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// swift-tools-version: 6.2
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "Example",
7+
dependencies: [
8+
.package(name: "swift-icudata-slim", path: "../"),
9+
],
10+
targets: [
11+
.executableTarget(
12+
name: "Example",
13+
dependencies: [
14+
.product(name: "ICUDataSlim", package: "swift-icudata-slim"),
15+
]
16+
),
17+
]
18+
)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// The Swift Programming Language
2+
// https://docs.swift.org/swift-book
3+
4+
import Foundation
5+
6+
@main
7+
struct Example {
8+
static func main() {
9+
print("Available locales: \(Locale.availableIdentifiers.joined(separator: ", "))")
10+
print("Available encodings: \(String.availableStringEncodings.map { "\($0)" }.joined(separator: ", "))")
11+
}
12+
}

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Goodnotes
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

NOTICE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
This project includes ICU (International Components for Unicode) data files under `./Sources/icudata/`.
2+
3+
- License: Unicode License V3
4+
- Source: https://github.com/unicode-org/icu
5+
- License URL: https://raw.githubusercontent.com/unicode-org/icu/refs/heads/main/LICENSE
6+
7+
The ICU data files are licensed under the Unicode License V3, which permits use, modification, and distribution for both commercial and non-commercial purposes. The license requires that copyright notices and permission notices be preserved in all copies or substantial portions of the data files.

Package.swift

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// swift-tools-version: 6.1
2+
3+
import PackageDescription
4+
5+
let swiftVersions = [
6+
"main",
7+
"6_2",
8+
"6_1",
9+
]
10+
11+
let currentSwiftVersion: String?
12+
#if compiler(>=6.2)
13+
currentSwiftVersion = "6_2"
14+
#elseif compiler(>=6.1)
15+
currentSwiftVersion = "6_1"
16+
#elseif compiler(>=6.0)
17+
currentSwiftVersion = "6_0"
18+
#else
19+
currentSwiftVersion = nil
20+
#endif
21+
22+
let package = Package(
23+
name: "swift-icudata-slim",
24+
products: (currentSwiftVersion.map { version in
25+
[
26+
.library(
27+
name: "ICUDataSlim",
28+
targets: [
29+
"ICUDataSlim_\(version)",
30+
]
31+
),
32+
.library(
33+
name: "ICUDataSlim_Minimal",
34+
targets: [
35+
"ICUDataSlim_Minimal_\(version)",
36+
]
37+
),
38+
]
39+
} ?? [])
40+
+ swiftVersions.flatMap { version in
41+
[
42+
.library(
43+
name: "ICUDataSlim_\(version)",
44+
targets: ["ICUDataSlim_\(version)"]
45+
),
46+
.library(
47+
name: "ICUDataSlim_Minimal_\(version)",
48+
targets: ["ICUDataSlim_Minimal_\(version)"]
49+
),
50+
]
51+
},
52+
targets: swiftVersions.flatMap { version in
53+
[
54+
.target(
55+
name: "ICUDataSlim_\(version)",
56+
path: "Sources/ICUDataSlim_\(version)/default"),
57+
.target(
58+
name: "ICUDataSlim_Minimal_\(version)",
59+
path: "Sources/ICUDataSlim_\(version)/minimal"),
60+
]
61+
}
62+
)

README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# swift-icudata-slim
2+
3+
A lightweight Swift package providing a slimmed-down version of ICU (International Components for Unicode) data. This package is designed to reduce the size of ICU data for use in Swift projects where full ICU data is unnecessary, improving build size and performance.
4+
5+
## Overview
6+
7+
This package is especially useful for platforms that only support static linking, such as WebAssembly, or when using `swift build --static-swift-stdlib` on Linux to produce statically linked executables.
8+
9+
10+
| ICU Data Variant | Data Size | Description |
11+
|:----------------------|----------:|---------------------------------------------|
12+
| Default | 29.3 MB | Full ICU data, all locales and features |
13+
| `ICUDataSlim` | 8.5 MB | Excludes some ICU features not used by Foundation; <br/> locale limited to `en_US` (see [default.json](./Scripts/filters/default.json)) |
14+
| `ICUDataSlim_Minimal` | 1.2 MB | Excludes even more features for a smaller footprint; <br/> locale limited to `en_US` (see [minimal.json](./Scripts/filters/minimal.json)) |
15+
16+
## When to use minimal
17+
18+
The `ICUDataSlim_Minimal` variant further reduces binary size by disabling additional ICU features. Use this variant **only if your application does not require** the following Foundation APIs or ICU features, which will not work due to the exclusions.
19+
20+
### Additional features excluded in `ICUDataSlim_Minimal`
21+
22+
Compared to the standard `ICUDataSlim`, the minimal variant also excludes:
23+
24+
| Excluded Feature | Affected Foundation APIs / Impact |
25+
|---------------------- |-----------------------------------|
26+
| `region_tree`, `locales_tree` | `Locale` |
27+
| `zone_*` | `TimeZone` |
28+
| `conversion_mappings` | `String.data(using:)`, `String.init(data:encoding:)` for non-unicode encodings may fail |
29+
| `curr_tree` | `NumberFormatter` with `.currency` style, `Locale.currencyCode`, `Locale.currencySymbol` |
30+
| `translit` | `NSMutableString.applyTransform(_:reverse:)` |
31+
| `coll_ucadata`, `coll_tree` | `NSString.compare(_:options:range:locale:)`, `String.localizedStandardCompare(_:)` |
32+
| `normalization` | `NSString.decomposedStringWithCanonicalMapping`, `NSString.precomposedStringWithCanonicalMapping`, `NSString.decomposedStringWithCompatibilityMapping`, `NSString.precomposedStringWithCompatibilityMapping` |
33+
34+
If you are unsure whether your app relies on any of these features or APIs, use the standard `ICUDataSlim` variant instead of `ICUDataSlim_Minimal`.
35+
36+
## Installation
37+
38+
Add `swift-icudata-slim` to your `Package.swift` dependencies:
39+
40+
```swift
41+
.package(url: "https://github.com/GoodNotes/swift-icudata-slim.git", from: "1.0.0")
42+
```
43+
44+
Then add it as a dependency to your **executable** target:
45+
46+
```swift
47+
.executableTarget(
48+
name: "YourTarget",
49+
dependencies: [
50+
.product(name: "ICUDataSlim", package: "swift-icudata-slim")
51+
]
52+
)
53+
```
54+
55+
See the [`Example`](./Example) directory for a complete setup.
56+
57+
> [!WARNING]
58+
> The pre-compiled ICU data included in this package assumes a little endian platform. Big endian platforms are not supported. (Swift does not officially support big endian platforms though)
59+
60+
## License
61+
62+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.

Scripts/build-all.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/usr/bin/env python3
2+
import json
3+
import os
4+
import subprocess
5+
from pathlib import Path
6+
7+
ICU_VERSIONS_FILE = Path(__file__).parent.parent / "icu-versions.json"
8+
PACKAGE_SCRIPT = Path(__file__).parent / "package-icudata.py"
9+
OUTPUT_BASE = Path(__file__).parent.parent / "Sources"
10+
11+
def build_with_filter(filter_json: Path, filter_name: str, versions: dict):
12+
print(f"Building with filter {filter_json}")
13+
icu_versions = set(versions["swift-icu-versions"].values())
14+
build_dir = Path(__file__).parent.parent / ".build" / "icu"
15+
16+
for icu_version in icu_versions:
17+
out_dir = OUTPUT_BASE / f"icudata/{icu_version}"
18+
out_dir.mkdir(parents=True, exist_ok=True)
19+
out_c = out_dir / filter_name / "icudata.c"
20+
print(f"Building ICU data {icu_version} -> {out_c}")
21+
if out_c.exists():
22+
print(f"Skipping {out_c} because it already exists")
23+
continue
24+
25+
args = [
26+
"python3", str(PACKAGE_SCRIPT),
27+
"--icu-version", icu_version,
28+
"--filter-json", str(filter_json),
29+
"--output", str(out_c),
30+
"--build-dir", str(build_dir / filter_name)
31+
]
32+
print(f"Running {' '.join(args)}")
33+
subprocess.run(args, check=True)
34+
35+
for swift_version in versions["swift-icu-versions"]:
36+
icu_version = versions["swift-icu-versions"][swift_version]
37+
out_dir = OUTPUT_BASE / f"ICUDataSlim_{swift_version.replace('.', '_')}" / filter_name
38+
out_dir.mkdir(parents=True, exist_ok=True)
39+
out_c = out_dir / "icudata.c"
40+
print(f"Generating C source file for Swift {swift_version} -> {out_c}")
41+
with open(out_c, "w") as f:
42+
f.write(f"// Generated by build-all.py\n")
43+
f.write(f"#include \"../../icudata/{icu_version}/{filter_name}/icudata.c\"\n")
44+
45+
out_empty_h = out_dir / "include" / "empty.h"
46+
out_empty_h.parent.mkdir(parents=True, exist_ok=True)
47+
out_empty_h.touch()
48+
49+
50+
def main():
51+
with open(ICU_VERSIONS_FILE) as f:
52+
versions = json.load(f)
53+
54+
filters_dir = Path(__file__).parent / "filters"
55+
for filter_file in filters_dir.glob("*.json"):
56+
build_with_filter(filter_file, filter_file.stem, versions)
57+
58+
if __name__ == "__main__":
59+
main()

Scripts/filters/default.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"localeFilter": {
3+
"filterType": "locale",
4+
"includeScripts": false,
5+
"includelist": [
6+
"en_US"
7+
]
8+
},
9+
"featureFilters": {
10+
"brkitr_dictionaries": {
11+
"#comment": "ubrk APIs are not used in Foundation",
12+
"filterType": "exclude"
13+
},
14+
"brkitr_rules": {
15+
"#comment": "ubrk APIs are not used in Foundation",
16+
"filterType": "exclude"
17+
},
18+
"brkitr_tree": {
19+
"#comment": "ubrk APIs are not used in Foundation",
20+
"filterType": "exclude"
21+
},
22+
"brkitr_lstm": {
23+
"#comment": "ubrk APIs are not used in Foundation",
24+
"filterType": "exclude"
25+
},
26+
"brkitr_adaboost": {
27+
"#comment": "ubrk APIs are not used in Foundation",
28+
"filterType": "exclude"
29+
},
30+
"unit_tree": {
31+
"#comment": "umeasfmt APIs are not used in Foundation",
32+
"filterType": "exclude"
33+
},
34+
"stringprep": {
35+
"#comment": "usprep APIs are not used in Foundation",
36+
"filterType": "exclude"
37+
}
38+
}
39+
}

0 commit comments

Comments
 (0)