[Package] 라이브러리 생성 및 배포

Sean·2023년 5월 9일
1

라이브러리

목록 보기
1/3

누군가에게 알려주기 보다는 나 스스로 정리 하며 언젠가 다시 사용할 때를 대비하는 글을 작성할것이다.

시작

시작글

  • 갑자기 코드를 작성하다가 그동안 프로젝트를 작성할 때 매번 만들곤 했던 요소들에 대해서 굳이? 라는 생각이 들기 시작했다.
    그리고 다른 사람이 만들어 둔 코드를 매번 가져다 쓰는것도 맘에 안들기 시작했고 import 에 마구마구 쌓이는것도 보기 싫어졌다.

    그럴바에는 조잡하더라도 내가 만들어서 직접 사용하며 부족한건 계속 보완하면서 작업하면 좋지 않을까? 라는 생각을 하게 되었고 이렇게 도전해보기로 했다.

분석

SPM: Swift Package Manager

  • CocoaPods 이나 Carthage 같은 서드파티툴 처럼 종속성 관리를 위한 기능이다.
    단, Apple의 공식 지원이 된다는게 중요하다.

  • 아직도 사용하는 라이브러리 중에서도 SPM 지원 안하는 라이브러리들이 있어서 CocoaPods도 사용하기는 하는데 설치를 하게 되면 .xcodeproj 파일 말고 새로운 .xcworkspace 파일이 생겨서 해당 파일로 작업하지 않으면 라이브러리를 사용할 수 없다던가 하는 이슈가 있어서 정말 싫어한다.

  • 그럼에도 점차 많은 라이브러리들이 SPM을 지원하고 있고 지원할 예정이라 처음부터 SPM으로 하기로 가닥을 잡았다.

Package 생성하기

  • 확실히 Apple 공식 지원 툴이라 그런지 만드는것도 엄청나게 쉽다.
  • 구글링 해보면 터미널로 하라는 말들도 있는데 그 방법으로 해도 되고 이 방법으로 해도 아무 문제 없이 잘 만들어진다.


Package.swift 파일 수정

  • Package를 잘 만들고 나면 내부의 Package.swift 파일을 건들여 준다.
  • 패키지의 이름과 외부 의존성 등 패키지에 대한 정보를 가지고 있기에 해당 파일은 라이브러리의 옵션 설정이라 생각하면 된다.
// swift-tools-version: 5.8
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "SunBase",
    products: [
        // Products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "SunBase",
            targets: ["SunBase"]),
    ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages this package depends on.
        .target(
            name: "SunBase",
            dependencies: []),
        .testTarget(
            name: "SunBaseTests",
            dependencies: ["SunBase"]),
    ]
)
  • 처음 생성된 파일을 들어가서 보게 되면 다음과 같은 코드가 작성되어있는것을 볼 수 있다.

  • 하나하나 확인해보자
    1. swift-tools-version: 해당 버전은 패키지를 빌드 하는데 필요한 Swift 컴파일러의 최소 버전이다.
    2. import PackageDescription: manifest 파일이 패키지 생성하는데 사용할 API포함하고 있다.
    3. name: 라이브러리명을 따라 간다.
    4. product: 라이브러리의 패키지를 정의해준다. 해당 패키지로부터 어떠한 타겟을 보여주고 다른 패키지에서 사용 할 수 있도록 해준다.
    targets 파라미터는 다수의 타겟 선언이 가능하고 하나의 라이브러리로 여러 타겟 노출도 가능하다.
    5. dependencies: 현재 패키지에서 사용하고 있는 다른 Package들을 명시한다.

        .package(url:"링크링크", from: "1.0.0")

     6. targets: 기본 빌드 단위
      - target: 패키지는 target 에 대한 표준 구조를 가진다. Sources 디렉터리에 타겟의 모든 파일이 위치하고, 각 타겟은 타겟 이름과 동일한 이름으로 하위에 위치한다.
      - targetTest: Tests 디렉터리 아래 위치하고, 다른 타겟을 테스트 하기에 dependencies 선언해야 한다.

  • 처음 설정된 구조에는 Scources 디렉터리에 하나의 파일만 있었기에 타겟이 하나만 있어도 괜찮았지만 NewSunBase 라는 타겟을 더 추가하기 위해서는 다음과 같이 작성을 해줘야 한다.

	targets: [
    	  .target(
        	  name: "SunBase",
	          dependencies: []),
	      .target(
	          name: "NewSunBase",
	          dependencies: []),
	]
  • 하지만 이렇게 선언만 한다고 되는것이 아니고 product의 library 타입으로 정의를 해줘야 배포 후에 사용자가 사용할 수 있다.
	products: [
        .library(
            name: "SunBase",
            targets: ["SunBase"]),
        .library(
            name: "NewSunBase",
            targets: ["NewSunBase"]),
    ],
  • 그리고 Sources 디렉터리 밑에 NewSunBase디렉터리를 만들고 밑에 .swift 파일을 만들어서 구현해야 한다.

  • 이렇게 기능 별로 분리해서 여러 개의 product를 배포했을 경우, 사용자가 패키지 설치할 때 어떤 모듈을 사용할지 선택 할 수 있다.

//RxSwift 의 Package.swift 파일 중 일부
  products: ([
    [
      .library(name: "RxSwift", targets: ["RxSwift"]),
      .library(name: "RxCocoa", targets: ["RxCocoa"]),
      .library(name: "RxRelay", targets: ["RxRelay"]),
      .library(name: "RxBlocking", targets: ["RxBlocking"]),
      .library(name: "RxTest", targets: ["RxTest"]),
      .library(name: "RxSwift-Dynamic", type: .dynamic, targets: ["RxSwift"]),
      .library(name: "RxCocoa-Dynamic", type: .dynamic, targets: ["RxCocoa"]),
      .library(name: "RxRelay-Dynamic", type: .dynamic, targets: ["RxRelay"]),
      .library(name: "RxBlocking-Dynamic", type: .dynamic, targets: ["RxBlocking"]),
      .library(name: "RxTest-Dynamic", type: .dynamic, targets: ["RxTest"]),
    ],
    Product.allTests()
  ] as [[Product]]).flatMap { $0 },

Package 배포

  • GitHub 를 이용할 계획이며 여기서는 Xcode에 Git을 연동하는 작업에 대해서 설명을 작성하지는 않을것이다.
    후에 기회가 된다면 따로 작성하도록 하겠다.
  • 해당방법은 public 이기에 private을 원하는 경우는 옵션 변경을 해주면 된다.

    주의 사항

    패키지생성 시에 하단부에 Source Control 에 Create Git repository on my Mac의 체크박스가 활성화 되어 있는지 확인

  1. 위에 적힌것들을 잘 따라서 패키지를 만들었으면 Xcode의 Source Control Navigator 영역으로 이동한다.
    좌측에 있는 영역인데 도저히 모르겠다면 Xcode 아무 곳이나 클릭하고 command + 2를 누르면 왼쪽에 떠있는 영역이 바뀌는것을 볼 수 있다.

  2. 해당 영역에서 상단에 보면 Repositories 라는 곳이 있는데 해당 부분으로 이동한다. (난 여기서 직접 보면서 하는게 편하다)

  3. 2로 이동한 영역 아무 곳에서 우클릭New "git" Remote라고 쓰인 버튼을 누른다. 내부의 "git" 부분은 각자 설정마다 다르므로 New ~~~ Remote 버튼을 누르면 된다.

  4. 그러면 무슨 창이 뜨게 되는데 GitHub에 대해서 너무 잘 알아서 이것저것 다 잘 알아서 수정해도 상관없다면 모르겠지만 그런게 아니라면 다 그대로 놔두고 중간에 Repository Name항목만 바꿔준다.
    git 이름이 될 부분이니까 원하는 데로 바꿔서 하단의 Create 를 눌러주면 된다.

  5. 잠시 기다리면 배포 끝


버전관리

  • SPM은 git tag로 패키지의 버전을 관리하기에 패키지의 버전 관리를 하고 싶다면 tag도 생성해줘야 한다.

사용

  • 위에서 생성하고 푸시까지 마친 repository URL을 입력하면 패키지를 사용할 수 있다.

참고자료

기타

당연 틀린 부분 지적은 감사하나 비난은 정중하게 사양하겠다.

profile
"잘 할 수 있을까?"를 고민하기보단 재밌어 보이는건 일단 하고, 잘하기 위해 그냥 계속합니다.

0개의 댓글