사전 패키지
용어함정

패키지

gabury1고친 사람 github-actions[bot]

패키지는 흩어진 코드를 이름 하나로 묶어 한 덩어리로 다루게 해 줍니다. 그런데 무엇을 위해 묶느냐에 따라 가리키는 물건이 갈립니다. 코드 안에서는 이름이 서로 부딪히지 않게 나누는 묶음을 말합니다. 배포할 때는 내려받아 설치하는 소프트웨어 한 벌을 말합니다.

쉽고 빠른 이해

무슨 일을 하는 물건인가 — 코드 여러 개에 이름 하나를 붙여 묶습니다. 자바 소스 파일 맨 위에 적어 두는 묶음 이름이 그 하나입니다. pip install 로 내려받는 라이브러리도 패키지입니다. 두 물건은 서로 다르지만 따로 놀지는 않습니다. 배포 패키지를 설치하면 그 안에 든 코드 패키지를 바로 쓸 수 있습니다. 코드 이야기에 나오면 앞의 뜻, 설치 이야기에 나오면 뒤의 뜻입니다.

왜 이렇게 하나 — 코드 쪽은 두 팀이 같은 클래스 이름을 써도 부딪히지 않게 하려고 묶습니다. 배포 쪽은 남이 만든 소프트웨어를 이름과 버전으로 받아 오게 하려고 묶습니다. 필요한 다른 패키지까지 함께 챙기게 합니다.

어떻게 도나

  1. 코드 패키지는 묶음마다 이름 집합을 따로 가져 서로 부딪히지 않게 합니다
  2. 배포 패키지는 결과물에 이름과 버전과 필요한 패키지 목록을 붙입니다
  3. 설치 도구가 그 목록을 읽고 빠진 것이 있으면 알려 줍니다

대가 — 설치할 때 쓰는 이름과 코드에서 부르는 이름이 다를 수 있습니다. 코드에 적힌 이름만 보고 같은 이름을 설치하면 엉뚱한 패키지가 깔릴 수 있습니다.

상세

이 절은 「패키지」가 가리키는 두 물건을 차례로 봅니다. 하나는 코드 안에서 이름을 나누는 코드 패키지입니다. 다른 하나는 내려받아 설치하는 배포 패키지입니다. 끝에서는 두 물건이 한 라이브러리 안에서 만나는 대목을 봅니다.

두 뜻은 서로 다른 물건을 가리키지만 따로 노는 것은 아닙니다. 배포 패키지를 설치하면 그 안에 든 코드 패키지를 바로 쓸 수 있습니다. 그래서 한 라이브러리를 두고 두 뜻이 함께 나옵니다.

코드를 나누는 패키지

자바 프로그램은 패키지들의 모음으로 짜입니다. 패키지마다 클래스와 인터페이스 이름의 집합을 따로 갖습니다. 그래서 이름 충돌을 막는 데 도움이 됩니다. 이렇게 이름이 겹치지 않게 나눈 구역을 네임스페이스라고 부릅니다.

자바에서는 소스 파일 맨 위에 그 파일이 속할 패키지를 적습니다.

Java
package jag.scrabble.board;   // 이 파일의 클래스는 jag.scrabble.board 패키지에 속한다

패키지 이름은 점으로 이은 계층입니다. 작은 프로그램이나 가볍게 짜는 코드는 패키지에 이름을 안 붙여도 되고 짧은 이름으로도 됩니다. 널리 배포할 코드라면 점으로 이은 긴 이름으로 겹치지 않는 이름을 골라야 합니다. 두 개발 그룹이 우연히 같은 패키지 이름을 골랐다가 나중에 한 프로그램에서 만나면 충돌이 납니다. 긴 이름을 고르면 그 충돌을 막는 데 도움이 됩니다.

간단한 구성에서는 패키지 이름을 디렉터리 경로로 바꿔 저장할 수 있습니다. 점을 디렉터리 구분자로 바꿔 jag.scrabble.board 를 jag/scrabble/board 로 두는 식입니다. 이것은 방법의 하나일 뿐입니다. 패키지를 어떻게 만들고 저장할지는 자바를 돌리는 쪽 시스템이 정합니다.

패키지 이름은 소스 코드 안의 이름입니다. 실행할 때 자바가 읽는 것은 컴파일한 클래스 파일입니다. 클래스 파일 여럿을 한 파일로 묶은 것이 JAR(Java ARchive, 자바 아카이브) 파일입니다.

그 클래스 파일을 어디서 찾을지는 클래스패스가 정합니다. 클래스패스는 클래스 파일을 찾아볼 디렉터리와 JAR 파일 같은 것의 목록입니다. 패키지 이름을 적어 두는 일과 그 코드를 찾아 싣는 일은 이렇게 따로 놓여 있습니다.

파이썬은 패키지를 모듈의 한 종류로 둡니다. 모듈은 파이썬 코드를 불러오는 단위입니다. 패키지는 그 모듈 가운데 다른 모듈을 안에 담을 수 있는 종류입니다. 예를 들어 email 패키지 안에 email.mime 하위 패키지가 있습니다. 그 안에 email.mime.text 모듈이 있습니다.

파이썬 패키지는 흔히 디렉터리에, 모듈은 그 안의 파일에 빗대어 설명합니다. 패키지와 모듈이 꼭 파일 시스템에서 오는 것은 아니라서 이 대응은 빗댄 것입니다.

코드 패키지가 하는 일이 하나 더 있습니다. 패키지 밖에서 무엇이 보일지를 정합니다. 언어마다 감추는 방법이 다릅니다.

언어 무엇이 한 패키지가 되나 패키지 밖에 감추는 법
자바 맨 위에 같은 package 선언을 단 소스 파일들 public 같은 접근 제어자를 안 붙인 최상위 클래스와 인터페이스는 그 패키지 안에서만 쓸 수 있다
파이썬 하위 모듈을 담을 수 있는 모듈. 대개 디렉터리 하나 밑줄 하나로 시작하는 이름은 내부용이라는 약한 표시다. from M import * 에 딸려 오지 않는다
Go 같은 디렉터리에서 함께 컴파일되는 소스 파일들. 파일마다 맨 위에 package 절을 단다 첫 글자가 대문자이고, 패키지 블록에서 선언한 이름이거나 필드 이름 · 메서드 이름인 것만 밖으로 내보낸다. 나머지는 내보내지 않는다

배포하는 패키지

남이 만든 라이브러리를 쓰려면 코드 파일만으로는 모자랍니다. 그 라이브러리의 이름과 버전을 알아야 합니다. 그 라이브러리가 기대는 다른 패키지도 함께 있어야 합니다. 이렇게 먼저 깔려 있어야 하는 다른 패키지를 의존성이라고 부릅니다.

배포 패키지는 내려받아 설치할 수 있는 소프트웨어 한 벌입니다. 버전이 붙은 압축 파일입니다. 그 안에 코드와 함께 쓰는 자원 파일이 들어 있습니다. 사용자가 인터넷에서 내려받아 설치하는 것이 이 파일입니다.

결과물에 붙는 이름 · 버전 · 의존성 같은 정보를 메타데이터라고 부릅니다. 메타데이터를 어디에 적는지는 생태계마다 다릅니다.

생태계 패키지의 모양 이름 · 버전 · 의존성이 적히는 곳
npm package.json 이 기술하는 폴더, 또는 그 폴더를 압축한 파일 package.json
파이썬 버전이 붙은 압축 파일 의존성은 pyproject.toml 의 dependencies 에 이름으로 적는다. 이름과 버전이 적히는 곳은 자료에 없다(미확인)
자바(Maven) 대개 JAR 파일과 POM(Project Object Model, 프로젝트 객체 모델) 파일 POM. 프로젝트 정보와 버전 · 의존성을 담는 XML(Extensible Markup Language) 파일이다
데비안 계열 리눅스 .deb 파일 패키지 안에 든 control 파일의 Package · Version · Depends 필드

이 정보를 읽고 패키지를 설치하는 도구를 패키지 관리자라고 부릅니다. 파이썬의 pip, 자바스크립트의 npm, 데비안의 dpkg 가 그런 도구입니다. dpkg 는 apt 같은 앞단 도구를 거쳐 쓰기도 합니다.

의존성이 어떻게 쓰이는지는 데비안의 예가 잘 보여 줍니다. C 컴파일러 gcc 를 담은 패키지는 링커와 어셈블러를 담은 binutils 패키지에 기댑니다. binutils 없이 gcc 를 설치하려 하면 dpkg 가 binutils 도 필요하다는 오류를 내고 설치를 멈춥니다.

패키지를 모아 두고 내려받게 해 주는 곳도 생태계마다 있습니다. 이런 곳을 패키지 색인이라고 부릅니다. 파이썬에서 가장 널리 알려진 색인이 PyPI(Python Package Index, 파이썬 패키지 색인)입니다. npm 에서는 npm 레지스트리, 데비안에서는 데비안 아카이브가 그 곳입니다.

PyPI 같은 색인 안에서도, 데비안 아카이브 안에서도 배포 패키지 이름은 하나뿐이어야 합니다.

두 뜻이 한 라이브러리에서 만나는 대목

두 뜻은 따로 노는 것 같습니다. 하지만 한 라이브러리 안에서 동시에 나옵니다. 배포 패키지 하나가 코드 패키지를 담아 오기 때문입니다.

파이썬에서 pip install pkg 의 pkg 는 배포 패키지 이름입니다. import pkg 의 pkg 는 코드 패키지 이름입니다. 배포 패키지를 설치하고 나면 그 안에 든 코드 패키지를 import 할 수 있습니다.

대개는 배포 패키지 하나가 이름이 같은 코드 패키지 하나를 줍니다. 코드 패키지가 아닌 모듈 하나를 줄 때도 있습니다. pip install numpy 로 설치하면 import numpy 로 부릅니다. 그런데 이름이 같은 것은 관례일 뿐입니다. PyPI 를 비롯한 패키지 색인은 두 이름 사이의 관계를 강제하지 않습니다.

그래서 두 이름이 갈리는 라이브러리가 있습니다. 이미지 처리 라이브러리 Pillow 는 설치할 때는 Pillow 라는 배포 이름을 씁니다. 코드에서는 PIL 로 부릅니다. 까닭은 포크에 있습니다. 포크는 기존 라이브러리의 코드를 복제해 따로 이어 가는 것입니다.

Pillow 는 PIL 라이브러리의 포크로 시작했습니다. 기존 PIL 사용자가 적은 수고로 옮겨 오게 하려고 코드 이름을 PIL 로 남겼습니다. 더 넓게 보면 포크가 배포 이름과 코드 이름이 갈리는 흔한 원인입니다.

배포 패키지 하나가 코드 패키지 여럿을 주기도 합니다. 덜 흔한 경우입니다. attrs 배포 패키지는 새 API(Application Programming Interface, 애플리케이션 프로그래밍 인터페이스)를 담은 attrs 코드 패키지를 줍니다. 예전 API 를 담은 attr 코드 패키지도 함께 줍니다. attr 쪽도 계속 지원합니다.

flowchart TD
    I1["pip install Pillow"] --> D1
    subgraph D1["배포 패키지 · Pillow"]
        C1["코드 패키지 · PIL"]
    end
    C1 --> U1["import PIL"]
    I2["pip install attrs"] --> D2
    subgraph D2["배포 패키지 · attrs"]
        C2["코드 패키지 · attrs"]
        C3["코드 패키지 · attr"]
    end
    C2 --> U2["import attrs"]
    C3 --> U3["import attr"]

그림에서 바깥 상자를 다루는 쪽은 패키지 관리자입니다. 안쪽 상자를 다루는 쪽은 개발자가 쓴 코드입니다.

배포 이름은 색인 안에서 하나뿐이어야 합니다. 코드 패키지 이름에는 그런 제약이 없습니다. 같은 이름의 코드 패키지를 여러 배포 패키지가 줄 수 있습니다. 이때도 포크가 흔한 원인입니다.

두 뜻을 섞으면 대가가 따릅니다. 코드에서 import foo 를 봤다고 PyPI 의 foo 를 덮어놓고 설치하면 안 됩니다. 의도하지 않은 패키지가 깔릴 수 있습니다. 경우에 따라 그것이 악성 패키지일 수도 있습니다.

맥락별 뜻

이 절은 「패키지」를 쓰는 세 맥락을 갈라 봅니다. 맥락마다 그 뜻을 정의한 문서를 따로 댑니다. 재는 것은 세 뜻이 같은 물건을 가리키느냐입니다.

맥락 이 맥락에서의 뜻 출처
프로그래밍 언어의 코드 구성 클래스 · 함수 같은 이름을 나눠 담는 묶음. 패키지마다 이름 집합을 따로 갖는다 자바 언어 명세 7장 · 파이썬 언어 레퍼런스 「Packages」 · Go 언어 명세 「Packages」
언어 생태계의 배포 내려받아 설치할 수 있는 소프트웨어 한 벌. 프로젝트를 가리키기도 하고, 그 프로젝트의 특정 버전을 담은 파일을 가리키기도 한다 파이썬 패키징 안내서 「Distribution package vs. import package」 · 같은 안내서의 용어집 · npm 문서 「About packages and modules」
리눅스 배포판 배포판의 패키지 관리 시스템이 시스템에 설치하는 묶음. 실행 파일 · 설정 파일 · 매뉴얼 페이지 · 문서를 담는다 데비안 FAQ(Frequently Asked Questions, 자주 묻는 질문) 7장 · 데비안 정책 3장

첫째 줄과 나머지 두 줄은 가리키는 물건의 종류가 다릅니다. 첫째 줄은 코드 안의 이름 구역입니다. 둘째와 셋째 줄은 설치하는 파일 묶음입니다.

flowchart TD
    P["「패키지」"]
    P --> K1["코드 안의 이름 구역"]
    P --> K2["설치하는 파일 묶음"]
    K1 --> C1["코드 구성 맥락 · 파이썬 용어로 import package"]
    K2 --> C2["언어 생태계의 배포 맥락 · 파이썬 용어로 distribution package"]
    K2 --> C3["리눅스 배포판 맥락"]

코드 구성 맥락

이 맥락에서 패키지는 프로그램을 짜는 동안 쓰는 이름 구역입니다. 패키지에는 클래스와 인터페이스가 들어 있습니다. 하위 패키지도 들 수 있습니다.

파이썬 쪽 용어로는 이것을 import package 라고 부릅니다. import 문으로 불러오는 이름이기 때문입니다.

언어 생태계의 배포 맥락

이 맥락에서 패키지는 내려받아 설치하는 단위입니다. 앞에서 배포 패키지라고 부른 것이 이것입니다. pip install pkg 를 칠 때나 pyproject.toml 에 dependencies = ["pkg"] 를 적을 때 pkg 가 이 뜻입니다. PyPI 를 검색해서 나오는 목록도 이 뜻의 패키지들입니다.

파이썬 쪽 용어로는 이것을 distribution package 라고 부릅니다. 이 말은 대개 「프로젝트」와 같은 뜻입니다. 한편 한 프로젝트의 특정 버전을 담은 파일 하나를 가리킬 때도 씁니다.

파이썬 쪽은 두 뜻을 헷갈리지 않게 하려고 필요할 때마다 import package 와 distribution package 를 풀어 씁니다. 평소에는 둘 다 그냥 「package」라고 부르기 때문입니다.

npm 에서도 패키지는 이 뜻입니다. package.json 이 기술하는 파일이나 디렉터리가 패키지입니다. npm 레지스트리에 올리려면 package.json 이 반드시 있어야 합니다.

리눅스 배포판 맥락

이 맥락에서 패키지는 운영체제에 소프트웨어를 까는 단위입니다. 데비안 패키지는 두 종류입니다. 원래 소스와 데비안용 변경을 담는 소스 패키지가 하나입니다. 실행 파일 · 설정 파일 · 매뉴얼 페이지 · 저작권 정보 · 문서를 담는 바이너리 패키지가 다른 하나입니다. 바이너리 패키지는 대개 확장자가 .deb 입니다.

.deb 패키지 하나에는 파일이 두 벌 들어 있습니다. 한 벌은 설치할 때 시스템에 놓을 파일입니다. 다른 한 벌은 패키지 메타데이터 파일입니다. 설치나 제거 때 도는 스크립트와 control 파일이 여기 듭니다.

언어 생태계의 배포 맥락과 이 맥락은 둘 다 설치하는 묶음을 말합니다. 갈리는 것은 설치를 맡는 주체입니다. 언어 쪽은 pip 과 npm 이 설치합니다. 리눅스 배포판 쪽은 배포판의 패키지 관리 시스템인 dpkg 와 그 앞단 apt 가 설치합니다. 파이썬 쪽 용어에서도 리눅스 배포판의 패키지는 다른 뜻으로 셉니다.

어느 뜻인지 가르는 단서

글이나 대화에서 「패키지」가 나오면 함께 붙은 낱말을 봅니다. 대개 그것만으로 어느 맥락인지 갈립니다.

함께 나오는 말 맥락
import 한다 · package 선언 · 하위 패키지 · 패키지 안에서만 보인다 코드 구성
pip install · npm install · 의존성에 적는다 · PyPI · 레지스트리에 올린다 언어 생태계의 배포
.deb · apt · dpkg · 데비안 아카이브 리눅스 배포판

경계

「패키지」와 가장 자주 섞이는 이웃 말이 「모듈」입니다. 다만 그 둘의 관계는 생태계마다 다릅니다. 파이썬에서는 패키지가 모듈의 한 종류입니다. Go 에서는 모듈이 패키지 여럿을 묶는 단위입니다. npm 에서는 두 말이 일부만 겹칩니다. 이 절은 그중 npm 의 정의를 가지고 한 경우를 판정합니다.

node_modules 안에 있는 자바스크립트 파일 하나는 require() 로 불러올 수 있습니다. 이 파일은 패키지인가. 아닙니다. 모듈입니다.

npm 에서 모듈은 node_modules 디렉터리 안에서 Node.js 의 require() 나 import 로 불러올 수 있는 파일이나 디렉터리입니다. require() 로 불러오려면 둘 중 하나여야 합니다. package.json 에 main 항목을 적어 둔 폴더이거나, 자바스크립트 파일 하나입니다. main 항목이 무엇을 가리키는지는 자료에 없습니다(미확인).

패키지는 package.json 이 기술하는 파일이나 디렉터리입니다. 모듈은 package.json 이 없어도 됩니다. 그래서 모든 모듈이 패키지인 것은 아닙니다. package.json 을 가진 모듈만 패키지이기도 합니다.

flowchart TD
    subgraph M["모듈 · require 로 불러올 수 있는 파일이나 디렉터리"]
        F["자바스크립트 파일 하나 · package.json 없음"]
        subgraph P["패키지이기도 한 모듈"]
            D["main 항목을 적어 둔 package.json 을 가진 폴더"]
        end
    end

판정의 근거는 package.json 의 유무입니다. 자바스크립트 파일 하나에는 package.json 이 없습니다. 그러니 불러올 수는 있어도 패키지는 아닙니다.

이견

맥락별 뜻은 낱말 하나가 여러 물건을 가리키는 갈림이었습니다. 이 절은 방향이 반대인 갈림을 봅니다. 여러 프로젝트가 가져다 쓰는 단위 하나를 생태계마다 다른 이름으로 부르는 갈림입니다. 그 단위는 앞에서 「배포 패키지」라고 부른 것과 같습니다.

생태계 가져다 쓰는 단위를 부르는 이름 그 생태계에서 「package」가 가리키는 것 누가 그렇게 부르나
Go module. 함께 릴리스되고 버전이 붙고 배포된다 같은 디렉터리에서 함께 컴파일되는 소스 파일 묶음. 코드 단위다 Go 모듈 레퍼런스 · How to Write Go Code
Rust crate. 라이브러리와 바꿔 쓰는 말이다 Cargo.toml 을 갖고 crate 를 하나 이상 묶는 단위 The Rust Programming Language 7.1
Maven artifact. Maven 이 내려받고 설치하고 배포하는 파일이다 packaging 설정값의 이름에 낱말이 들어 있다. 그 값의 기본은 jar 다 Maven 문서 「Introduction to the POM」 · 「Artifacts」
npm · PyPI · 데비안 package 가져다 쓰는 단위와 같다 npm 문서 · 파이썬 패키징 안내서 · 데비안 FAQ

Go — module 과 package

Go 문서는 함께 릴리스되고 버전이 붙고 배포되는 패키지들의 묶음을 module 이라고 부릅니다. 모듈은 go.mod 파일에 선언한 모듈 경로로 가리킵니다. go.mod 에는 그 모듈의 의존성 정보도 함께 적힙니다.

Go 에서 package 는 코드 단위로 남습니다. 모듈 안의 패키지 경로는 모듈 경로에 하위 디렉터리를 이은 것입니다. 예를 들어 golang.org/x/net 모듈의 html 디렉터리에 든 패키지는 경로가 golang.org/x/net/html 입니다.

Rust — crate 와 package

The Rust Programming Language 는 crate 를 Rust 컴파일러가 한 번에 다루는 가장 작은 코드 단위라고 정의합니다. 라이브러리 crate 는 여러 프로젝트가 나눠 쓸 기능을 정의합니다. 같은 책에 따르면 Rust 개발자들이 「crate」라고 하면 대개 라이브러리 crate 를 뜻합니다. 이 말을 「라이브러리」와 바꿔 쓰기도 합니다.

같은 책에서 package 는 crate 를 하나 이상 묶어 기능 한 벌을 내는 단위입니다. 패키지에는 그 crate 들을 어떻게 빌드할지 적은 Cargo.toml 파일이 있습니다. 패키지 하나에 라이브러리 crate 는 많아야 하나입니다. 바이너리 crate 는 여럿 둘 수 있습니다.

flowchart TD
    subgraph GO["Go — package 가 안쪽에 선다"]
        M["module · go.mod 에 경로를 선언한다"]
        M --> GP["package · golang.org/x/net/html"]
    end
    subgraph RS["Rust — package 가 바깥쪽에 선다"]
        PK["package · Cargo.toml 을 갖는다"]
        PK --> CR1["라이브러리 crate · 많아야 하나"]
        PK --> CR2["바이너리 crate · 여럿 둘 수 있다"]
    end

같은 낱말이 Go 에서는 안쪽 층에 붙고 Rust 에서는 바깥쪽 층에 붙습니다.

Maven — artifact 와 packaging

Maven 문서는 Maven 이 내려받고 설치하고 배포하는 파일을 artifact 라고 부릅니다. artifact 는 대개 POM 과 JAR 입니다. groupId:artifactId:version 꼴의 좌표로 가리킵니다. 셋을 이어 붙인 것이 그 프로젝트의 완전한 artifact 이름입니다.

Maven 에서 「package」 낱말은 packaging 이라는 설정값의 이름으로 나옵니다. 모든 Maven 프로젝트가 이 값을 하나씩 갖습니다. POM 에 따로 적지 않으면 기본값은 jar 입니다. 이 값이 무엇을 정하는지는 자료에 없습니다(미확인).

npm · PyPI · 데비안 문서는 이 단위를 그냥 package 라고 부릅니다.

관련 항목

코드 패키지와 함께 이름을 나누는 언어 요소

네임스페이스 · 모듈 · 하위 패키지 · 클래스 · 인터페이스 · 접근 제어자 · import · 식별자

자바가 코드 패키지를 찾아 싣는 데 쓰는 요소

클래스패스 · 클래스 파일 · JAR · 자바 언어 명세 · 자바 모듈 시스템

배포 패키지를 받아서 설치하는 도구

패키지 관리자 · npm · pip · Maven · Gradle · Cargo

배포 패키지를 담는 파일 형식

WAR · wheel · tarball · 컨테이너 이미지

배포 패키지에 붙는 이름 · 버전 · 의존성 정보

메타데이터 · 버전 번호 · 시맨틱 버저닝 · 의존성 · package.json · pom.xml · pyproject.toml · go.mod · Cargo.toml · 락 파일

배포 패키지가 올라가는 저장소

PyPI · npm 레지스트리 · Maven 중앙 저장소 · 아티팩트 저장소 · 패키지 저장소

리눅스 배포판에서 시스템 패키지를 다루는 도구와 형식

리눅스 배포판 · 데비안 · dpkg · apt · deb · 데비안 아카이브

배포 단위를 패키지 대신 가리키는 다른 이름

Go 모듈 · crate · 아티팩트 · 라이브러리

배포 패키지가 거치는 릴리스 단계

빌드 · 빌드 아티팩트 · 릴리스 엔지니어링 · 배포 · 패키지 서명

배포 패키지에서 자주 나는 장애

의존성 지옥 · 버전 충돌 · 타이포스쿼팅 · 소프트웨어 공급망 보안

다른 이름: package