Skip to content

Commit d3adf98

Browse files
committed
add post
1 parent 91f81dd commit d3adf98

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
---
2+
layout: post
3+
title: "[Swift][Tuist] 파일 경로 간의 상대 경로 계산하기"
4+
tags: [Swift, Tuist]
5+
---
6+
{% include JB/setup %}
7+
8+
Xcode의 프로젝트 파일의 빌드 세팅에서 해당 프로젝트 파일의 경로를 기준으로 상대 경로를 지정하는 것을 권장합니다. 이는, 모든 개발자가 동일한 개발 환경을 구성한다는 보장이 없기 때문입니다. 예를 들어, 특정 프레임워크의 위치를 절대 경로로 지정한다면, 모든 개발자, CI/CD 등의 모든 환경을 동일하게 구축해야하는데, 이는 불가능합니다. 따라서 상대 경로를 지정해주는 것이 좋습니다.
9+
10+
그러나, 상대 경로를 지정하는 것은 쉽지 않습니다. 프로젝트가 여러개 있는 경우, 각 프로젝트는 조금씩 다른 경로를 가질 수 있습니다.
11+
12+
```
13+
Projects
14+
ㄴ ABC
15+
ㄴ ABC
16+
ㄴ A
17+
ㄴ B
18+
ㄴ C
19+
ㄴ DEF
20+
ㄴ D
21+
ㄴ E
22+
ㄴ F
23+
```
24+
25+
따라서, 각 프로젝트 기준으로 특정 파일의 경로까지의 상대 경로를 계산하면 됩니다. 이를 위해서는 현재 파일의 위치를 알아야 합니다.
26+
27+
## 상대 경로 계산하기
28+
29+
Swift에서는 `#file`를 이용하여 해당 파일이 있는 절대 경로를 얻을 수 있습니다.
30+
31+
```swift
32+
print("#file: ", #file) // /Users/minsone/Developer/iOSApplication/iOS_App/Project.swift
33+
```
34+
35+
`#file`의 값에서 뒤의 파일 이름을 제거하면 해당 파일이 있는 디렉토리의 경로를 얻을 수 있습니다.
36+
37+
```swift
38+
let url = URL(fileURLWithPath: #file).deletingLastPathComponent()
39+
print("url: ", url) // file:///Users/minsone/Developer/iOSApplication/iOS_App/
40+
```
41+
42+
## 상대 경로 계산하기
43+
44+
Macro.macro 라는 파일의 경로를 얻으려고 합니다. `Macro.macro`의 절대 경로는 `/Users/minsone/Developer/iOSApplication/Projects/Macros/Macro/Macro.macro` 라고 가정해봅시다.
45+
46+
Tuist에서는 코드를 공유하는 모듈인 `ProjectDescriptionHelpers` 에서 `Macro.macro` 파일의 절대 경로를 만들어, 다른 파일들에서 상대 경로를 계산할 수 있도록 합니다.
47+
48+
```swift
49+
// File : Tuist/ProjectDescriptionHelpers/FilePathURL.swift
50+
51+
import Foundation
52+
53+
public func macroPathURL() -> URL {
54+
URL(fileURLWithPath: #file) // #file: /Users/minsone/Developer/iOSApplication/Tuist/ProjectDescriptionHelpers/FilePath.swift
55+
.deletingLastPathComponent()
56+
.deletingLastPathComponent()
57+
.deletingLastPathComponent()
58+
.appending(path: "Projects/Macros/Macro/Macro.macro")
59+
// Output : file:///Users/minsone/Developer/iOSApplication/Projects/Macros/Macro/Macro.macro
60+
}
61+
```
62+
63+
프로젝트 파일의 경로는 `/Users/minsone/Developer/iOSApplication/iOS_App/`, 찾으려는 Macro 파일의 경로는 `/Users/minsone/Developer/iOSApplication/Projects/Macros/Macro/Macro.macro` 입니다.
64+
65+
두 경로에서 상대 경로를 계산해봅시다.
66+
67+
```swift
68+
let basePath = URL(fileURLWithPath: #file).deletingLastPathComponent()
69+
let targetPath = macroPathURL()
70+
71+
if let relativePath = targetPath.relativePath(from: basePath) {
72+
print("Relative path: \(relativePath)") // Output: ../Projects/Macros/Macro/Macro.macro
73+
} else {
74+
print("Cannot compute relative path.")
75+
}
76+
77+
extension URL {
78+
/// 메소드는 두 경로 간의 공통 경로를 찾아 나머지 부분을 기반으로 상대 경로를 계산
79+
func relativePath(from base: URL) -> String? {
80+
// base와 target의 경로 컴포넌트를 추출
81+
let basePaths = base.standardized.pathComponents
82+
let targetPaths = standardized.pathComponents
83+
84+
// 공통 경로의 끝 지점 찾기
85+
var commonIndex = 0
86+
while commonIndex < basePaths.count &&
87+
commonIndex < targetPaths.count &&
88+
basePaths[commonIndex] == targetPaths[commonIndex] {
89+
commonIndex += 1
90+
}
91+
92+
// 공통 경로 이후의 남은 경로
93+
let backtrackPaths = Array(repeating: "..", count: basePaths.count - commonIndex)
94+
let remainingTargetPaths = targetPaths[commonIndex...]
95+
96+
// 두 배열을 결합하여 상대 경로 반환
97+
return (backtrackPaths + remainingTargetPaths).joined(separator: "/")
98+
}
99+
}
100+
```
101+
102+
위의 코드를 이용하여 상대 경로를 얻을 수 있었습니다.
103+
104+
그러면 Tuist를 활용하여 Xcode 프로젝트 파일의 Build Settings에서는 해당 프로젝트의 경로인 환경변수인 `PROJECT_DIR`, `xcodeproj` 파일이 있는 경로인 `SRCROOT`와 계산한 상대 경로를 합쳐 원하는 경로를 지정할 수 있습니다.
105+
106+
```swift
107+
let pluginPath = "$(PROJECT_DIR)/\(relativePath)"
108+
let settings: SettingsDictionary = [
109+
"OTHER_SWIFT_FLAGS": "$(inherited) -Xfrontend -load-plugin-executable \(pluginPath)#MacroPlugin"
110+
]
111+
112+
let targets: Target =
113+
.target(
114+
...
115+
settings: .settings(base: settings)
116+
)
117+
118+
```
119+
120+
## 정리
121+
122+
* Tuist를 이용하여 프로젝트를 동적으로 생성하는 과정에서 해당 프로젝트와 특정 파일의 상대 경로를 계산할 수 있습니다.

0 commit comments

Comments
 (0)