Pkg.jl

주의

0. 역자 노트

모호한 것

  • dependency 는 보통 의존성 혹은 종속성으로 번역되지만 여기서는 추상명사가 아니라 어떤 패키지/프로젝트를 실행시키는데 필요한 다른 패키지/프로젝트들의 집합을 말한다. 이것을 어떻게 번역해야 할까? 일단은 의존성으로 번역해둔다.

  • 패키지 설치를 stateful 로... (무슨뜻일까?)


1. 들어가며

Julia의 패키지 관리자인 Pkg의 문서에 오신 것을 환영합니다. 이 문서는 예를 들어 패키지 설치 관리, 패키지 개발, 패키지 레지스트리 작업 등과 같은 많은 내용을 다룹니다.

설명서 전체에서 Pkg에 대한 REPL 인터페이스인 Pkg REPL 모드가 예제에서 사용됩니다. 대화식으로 작업하지 않을 때 선호되는 함수적 API도 있습니다. 이 API는 API Reference 섹션에 설명되어 있습니다.


배경과 설계

Pkg는 Julia의 이전 패키지 관리자를 완전히 다시 작성했으며 Julia v1.0과 함께 출시되었습니다. 단일한 전역적인 패키지 집합을 설치하고 관리하는 기존 패키지 관리자와 달리 Pkg는 독립적인 패키지 세트로서 개별 프로젝트에 한정 될 수 있는 "환경(environment)"를 중심으로 설계되었으며, 이름으로 공유 되거나 선택될 수 있습니다. 환경(environment) 의 정확한 패키지 집합과 및 버전은 프로젝트 리포지토리에 체크인하고 버전 제어에서 추적할 수 있는 manifast 파일에 캡처되어 프로젝트의 재현성을 크게 향상시킵니다. 한동안 사용하지 않은 코드를 실행하려고 시도했지만 프로젝트에서 사용 중인 일부 패키지를 업데이트하거나 제거했기 때문에 아무것도 작동하지 않는다는 것을 알게 된 경우 이 접근법에 대한 동기를 이해 할 수 있을 것입니다. Pkg에서는 각 프로젝트가 독립적인 패키지 버전 세트를 유지하므로 다시는 이 문제가 발생하지 않습니다. 또한 새 시스템에서 프로젝트를 확인하는 경우 해당 매니페스트 파일에 설명된 환경을 간단히 구체화하고 알려진 양호한 의존성 집합으로 즉시 가동 및 실행할 수 있습니다.

환경이 서로 독립적으로 관리되고 업데이트되기 때문에 Pkg에서는 소위 "의존성 지옥(dependency hell)"이 크게 완화됩니다. 새 프로젝트에서 일부 패키지의 가장 최신 버전을 사용하고 싶지만 다른 프로젝트에서 이전 버전에 갇혀 있는 경우 문제가 되지 않습니다. 별도의 환경이 있기 때문에 서로 다른 버전을 사용할 수 있습니다. 시스템의 다른 위치에 동시에 설치됩니다. 각 패키지 버전의 위치는 표준적이므로 환경에서 동일한 버전의 패키지를 사용하는 경우 설치를 공유하여 불필요한 패키지 복제를 방지할 수 있습니다. 어떤 환경에서도 더 이상 사용되지 않는 이전 패키지 버전은 패키지 관리자에 의해 주기적으로 "가비지 수집(garbage collected)"됩니다.

로컬 환경에 대한 Pkg의 접근 방식은 Python의 virtualenv 또는 Ruby의 bundler를 사용해 본 사람들에게 친숙할 수 있습니다. Julia에서는 환경(environment) 을 지원하기 위해 언어의 코드 로딩 메커니즘을 해킹하는 대신 Julia가 기본적으로 이를 이해한다는 이점이 있습니다. 또한 Julia 환경은 "적층 가능(stackable)"합니다. 하나의 환경을 다른 환경에 덮을(overlay) 수 있으므로 기본 환경 외부의 추가 패키지에 액세스할 수 있습니다. 이를 통해 기본 환경(environment)을 제공하는 프로젝트에서 쉽게 작업할 수 있으며 환경에 프로파일러, 디버거 등과 같은 모든 일반적인 개발 도구들을 로드 경로(load path) 에 추가하여, REPL에서 이 개발도구들에 계속 액세스할 수 있습니다.

마지막으로 Pkg는 연합 패키지 레지스트리를 지원하도록 설계되었습니다. 즉, 서로 다른 당사자가 관리하는 여러 레지스트리가 원활하게 상호 작용할 수 있습니다. 특히 여기에는 회사 방화벽 뒤에 있을 수 있는 개인 레지스트리가 포함됩니다. 공식 Julia 패키지를 설치하고 관리하는 데 사용하는 것과 정확히 동일한 도구 및 워크플로를 사용하여 개인 레지스트리에서 자체 패키지를 설치하고 업데이트할 수 있습니다. 회사 제품에 중요한 공개 패키지에 긴급하게 핫픽스를 적용해야 하는 경우 회사 내부 레지스트리에서 비공개 버전에 태그를 지정하고 기다릴 필요 없이 빠르고 쉽게 개발자 및 운영 팀에 수정 사항을 제공할 수 있습니다. 수락 및 게시할 업스트림 패치. 그러나 공식 수정이 게시되면 의존성을 업그레이드하기만 하면 공식 릴리스로 다시 돌아올 수 있습니다.


2. 시작하기

다음은 Julia의 패키지 관리자인 Pkg에 대한 개요입니다. 새로운 사용자가 기본 Pkg 기능에 익숙해지는 데 도움이 됩니다.


기본 사용법

Pkg 는 REPL과 함께 제공됩니다. Julia REPL에서 ] 를 눌러 Pkg REPL 에 진입합니다. Julia REPL로 돌아가려면 백스페이스 또는 ^C 를 누릅니다.

주의
이 가이드는 Pkg REPL을 사용하여 Pkg 명령을 실행합니다. 비대화으로 사용하고자 하는 경우에는 Pkg API를 권장합니다. Pkg API는 Pkg 설명서의 API 참조 섹션에 전부 설명되어 있습니다.


Pkg REPL 에 진입하면 유사한 프롬프트가 표시됩니다.

(v1.1) pkg>

패키지를 설치하려면 add 를 사용합니다 :

(v1.1) pkg> add Example

주의
이 가이드에 집중하기 위해 일부 Pkg 출력이 생략되었습니다. 이것은 페이스를 잘 유지하고 세부 사항에 얽매이지 않는 데 도움이 될 것입니다. 자세한 내용이 필요한 경우 Pkg 설명서의 다음 섹션을 참조하십시오.


다수의 패키지를 한번에 지정 할 수 있습니다.

(v1.1) pkg> add JSON StaticArrays

패키지를 제거하기 위해서는 rm 을 사용합니다.

(v1.1) pkg> rm JSON StaticArrays

지금까지는 등록된 패키지만 참조했습니다. Pkg는 등록되지 않은 패키지 작업도 지원합니다. 등록되지 않은 패키지를 추가하려면 URL을 지정하십시오.

(v1.1) pkg> add https://github.com/JuliaLang/Example.jl

이 페키지를 제거하려면 이름을 사용합니다.

(v1.1) pkg> rm Example

설치된 패키지를 업데이트 하려면 update를 사용합니다.

(v1.1) pkg> update Example

모든 설치된 패키지를 업데이트 하려면 update 다음을 비웁니다.

(v1.1) pkg> update

환경(Environments)과 함께 시작하기

지금까지는 기본적인 패키지 관리(패키지 추가, 업데이트 및 제거)를 다루었습니다. 다른 패키지 관리자를 사용해봤다면 익숙할 것입니다. Pkg는 의존성을 환경으로 구성하여 기존 패키지 관리자에 비해 상당한 이점을 제공합니다.

REPL 프롬프트에서 (v1.1)을 발견했을 수 있습니다. 이를 통해 v1.1이 활성 환경임을 알 수 있습니다. 활성 환경은 add, rmupdate와 같은 Pkg 명령에 의해 수정될 환경입니다.

실험할 수 있도록 새로운 환경을 설정해 봅시다. 활성 환경을 설정하려면 activate를 사용하십시오.

(v1.1) pkg> activate tutorial
[ Info: activating new environment at `/tmp/tutorial/Project.toml`.

Pkg는 우리가 새로운 환경을 만들고 있으며 이 환경이 /tmp/tutorial 디렉토리에 저장될 것임을 알려줍니다.

Pkg는 새로운 활성 환경을 반영하기 위해 REPL 프롬프트도 업데이트했습니다.

(tutorial) pkg>

status 를 사용하여 활성화된 환경에 대한 정보를 요청할 수 있습니다.

(tutorial) pkg> status
Status `/tmp/tutorial/Project.toml`(empty environment)

/tmp/tutorial/Project.toml 은 활성 환경의 프로젝트 파일의 위치입니다. Pkg는 환경에 대한 메타데이터를 프로젝트 파일에 저장합니다. 이 새 환경은 비어 있습니다. 패키지를 추가하고 관찰해 보겠습니다.

(tutorial) pkg> add Example
...

(tutorial) pkg> status
    Status `/tmp/tutorial/Project.toml`
  [7876af07] Example v0.5.1

이제 tutorialExample 을 의존성으로 포함하는 것을 볼 수 있습니다.


의존성 변경

Example 에서 작업 중이고 새로운 기능이 필요하다고 느낀다고 가정해 보겠습니다. 소스 코드를 어떻게 수정할 수 있습니까? 우리는 Example 패키지의 git 클론을 설정하기 위해 develop 명령을 사용할 수 있습니다.

(tutorial) pkg> develop --local Example
...

(tutorial) pkg> status
    Status `/tmp/tutorial/Project.toml`
  [7876af07] Example v0.5.1+ [`dev/Example`]

피드백이 변경된것을 확인 할 수 있습니다. dev/Example 은 새로 생성된 클론의 위치를 나타냅니다. /tmp/tutorial 디렉토리를 보면 다음 파일이 있음을 알 수 있습니다.

tutorial
├── dev
│   └── Example
├── Manifest.toml
└── Project.toml

등록된 버전의 Example 을 로드하는 대신 Julia는 tutorial/dev/Example 에 포함된 소스 코드를 로드합니다.

자 이제 한번 해봅시다. 먼저 tutorial/dev/Example/src/Example.jl 에서 파일을 수정하고 간단한 함수를 추가합니다.

plusone(x::Int) = x + 1

이제 Julia REPL로 돌아가서 패키지를 로드할 수 있습니다.

julia> import Example

경고
패키지는 Julia 세션당 한 번만 로드할 수 있습니다. 현재 Julia 세션에서 import Example 을 실행한 경우 Julia를 다시 시작하고 Pkg REPL에서 activate tutorial 을 다시 실행해야 합니다. Revise.jl은 이 이 과정을 훨씬 쾌적하게 만들 수 있지만 그것을 설정하는 것은 이 가이드의 범위를 벗어납니다.


Julia는 새 코드를 로드해야 합니다. 테스트해 봅시다:

julia> Example.plusone(1)
2

우리가 생각이 바뀌어서 세상이 그런 우아한 코드를 받아들일 준비가 되어 있지 않다고 결정했다고 가정해 봅시다. Pkg에게 로컬 복제본 사용을 중지하고 대신 등록된 버전을 사용하도록 지시할 수 있습니다. free 를 사용합니다.

(tutorial) pkg> free Example

tutorial 실험을 마치면 인수 없이 activate 를 실행하여 기본 환경으로 돌아갈 수 있습니다.

(tutorial) pkg> activate

(v1.1) pkg>

도움을 요청하기

문제가 발생하면 Pkg 에 도움을 요청할 수 있습니다.

(v1.1) pkg> ?

간단한 설명과 함께 사용 가능한 명령 목록이 표시되어야 합니다. 명령을 지정하여 더 자세한 도움을 요청할 수 있습니다.

(v1.1) pkg> ?develop

이 가이드는 Pkg 를 시작하는 데 도움이 될 것입니다. Pkg 는 강력한 패키지 관리 측면에서 훨씬 더 많은 것을 제공합니다. 자세한 내용은 전체 설명서를 읽어보세요!


3. 패키지 관리


패키지 추가

패키지를 추가하는 두가지 방법은 add 명령 또는 dev 명령을 사용하는 것입니다. 가장 많이 사용되는 것은 add 를 사용하는 것이기 때문에 먼저 설명합니다.


등록된 패키지 추가

Pkg REPL에서 add 명령 다음에 패키지 이름을 사용하여 패키지를 추가할 수 있습니다. 예를 들면 다음과 같습니다.

(v1.0) pkg> add Example
   Cloning default registries into /Users/kristoffer/.julia/registries
   Cloning registry General from "https://github.com/JuliaRegistries/General.git"
  Updating registry at `~/.julia/registries/General`
  Updating git-repo `https://github.com/JuliaRegistries/General.git`
 Resolving package versions...
  Updating `~/.julia/environments/v1.0/Project.toml`
  [7876af07] + Example v0.5.1
  Updating `~/.julia/environments/v1.0/Manifest.toml`
  [7876af07] + Example v0.5.1
  [8dfed614] + Test

현재 프로젝트에 Example 패키지를 추가했습니다. 여기서는 새로 설치된 Julia 를 사용하고 있으며 Pkg를 사용하여 패키지를 추가하는 것은 이번이 처음입니다. 기본적으로 Pkg는 Julia의 General 레지스트리를 복제하고 이 레지스트리를 사용하여 현재 환경에 포함하도록 요청된 패키지를 찾습니다. 상태 업데이트는 왼쪽에 짧은 형식의 패키지 UUID, 패키지 이름 및 버전을 표시합니다. Test 와 같은 표준 라이브러리는 Julia와 함께 제공되므로 버전이 없습니다. 프로젝트 상태에는 직접 추가한 패키지(이 경우 에는 Example) 이 포함됩니다.

(v1.0) pkg> st
    Status `Project.toml`
  [7876af07] Example v0.5.1

manifest 상태는 재귀적 의존성을 포함하여 환경의 모든 패키지를 보여줍니다.

(v1.0) pkg> st --manifest
    Status `Manifest.toml`
  [7876af07] Example v0.5.1
  [8dfed614] Test

pkg> add A B C 와 같이 하나의 명령으로 여러 패키지를 추가할 수 있습니다.

패키지가 프로젝트에 추가되면 Julia에서 로드할 수 있습니다.

julia> using Example

julia> Example.hello("User")
"Hello, User"

@ 기호 뒤에 버전을 추가하여, 즉 패키지 이름 뒤에 @v0.4 와 같이 써서 특정 버전을 설치할 수 있습니다.

(v1.0) pkg> add Example@0.4
 Resolving package versions...
  Updating `~/.julia/environments/v1.0/Project.toml`
  [7876af07] + Example v0.4.1
  Updating `~/.julia/environments/v1.0/Manifest.toml`
  [7876af07] + Example v0.4.1

Example의 브랜치 (혹은 특정 커밋)에 아직 등록된 버전에 포함되지 않은 핫픽스가 있는 경우 패키지 이름에 #branchname(또는 #commitSHA1)을 추가하여 해당 브랜치 (또는 커밋)를 명시적으로 추적할 수 있습니다.

(v1.0) pkg> add Example#master
  Updating git-repo `https://github.com/JuliaLang/Example.jl.git`
 Resolving package versions...
  Updating `~/.julia/environments/v1.0/Project.toml`
  [7876af07] ~ Example v0.5.1 ⇒ v0.5.1+ #master (https://github.com/JuliaLang/Example.jl.git)
  Updating `~/.julia/environments/v1.0/Manifest.toml`
  [7876af07] ~ Example v0.5.1 ⇒ v0.5.1+ #master (https://github.com/JuliaLang/Example.jl.git)

이제 상태 출력에 Example의 마스터 분기를 추적하고 있음이 표시됩니다. 패키지를 업데이트할 때 해당 분기에서 업데이트를 가져옵니다.

주의
예를 들어 브랜치 이름 대신 커밋 id 를 지정하는 경우, 즉 add Example#025cf7e 를 이용하면 해당 커밋에 패키지를 효과적으로 "고정"할 수 있습니다. 이는 커밋 id가 업데이트될 수 있는 브랜치와 달리 항상 동일한 것을 가리키기 때문입니다.


Example 의 레지스트리 버전 추적으로 돌아가려면 free 명령을 사용합니다.

(v1.0) pkg> free Example
Resolving package versions...
Updating `~/.julia/environments/v1.0/Project.toml`
[7876af07] ~ Example v0.5.1+ #master (https://github.com/JuliaLang/Example.jl.git) ⇒ v0.5.1
Updating `~/.julia/environments/v1.0/Manifest.toml`
[7876af07] ~ Example v0.5.1+ #master )https://github.com/J

등록되지 않은 패키지 추가

패키지가 레지스트리에 없는 경우 리포지토리에 대한 URL을 지정하여 패키지를 추가할 수 있습니다.

(v1.0) pkg> add "git@github.com:fredrikekre/ImportMacros.jl.git"
    Cloning git-repo `git@github.com:fredrikekre/ImportMacros.jl.git`
   Updating git-repo `git@github.com:fredrikekre/ImportMacros.jl.git`
   Updating registry at `~/.julia/registries/General`
  Resolving package versions...
Updating `~/.julia/environments/v1/Project.toml`
  [92a963f6] + ImportMacros v1.0.0 `git@github.com:fredrikekre/ImportMacros.jl.git#master`
Updating `~/.julia/environments/v1/Manifest.toml`
  [92a963f6] + ImportMacros v1.0.0 `git@github.com:fredrikekre/ImportMacros.jl.git#master`

등록되지 않은 패키지가 의존하는 패키지(여기서는 MacroTools)가 설치되었습니다. 등록되지 않은 패키지의 경우 등록된 패키지와 마찬가지로 #을 사용하여 추적하기 위해 분기 이름(또는 커밋 SHA1)을 제공할 수 있습니다.

SSH 기반 git 프로토콜을 사용하여 패키지를 추가하려면 URL에 @가 포함되어 있으므로 따옴표를 사용해야 합니다. 예를 들어,

(v1.0) pkg> add "git@github.com:fredrikekre/ImportMacros.jl.git"
    Cloning git-repo `git@github.com:fredrikekre/ImportMacros.jl.git`
   Updating git-repo `git@github.com:fredrikekre/ImportMacros.jl.git`
   Updating registry at `~/.julia/registries/General`
  Resolving package versions...
Updating `~/.julia/environments/v1/Project.toml`
  [92a963f6] + ImportMacros v1.0.0 `git@github.com:fredrikekre/ImportMacros.jl.git#master`
Updating `~/.julia/environments/v1/Manifest.toml`
  [92a963f6] + ImportMacros v1.0.0 `git@github.com:fredrikekre/ImportMacros.jl.git#master`

로칼 패키지 추가

add 에 git repo의 URL을 쓰는 대신 git repo에 대한 로컬 경로를 제공할 수 있습니다. 이는 URL 추가와 유사하게 작동합니다. 로컬 리포지토리는 (일부 브랜치에서) 추적되고 패키지가 업데이트될 때 해당 로컬 리포지토리의 업데이트를 가져옵니다. add 를 통한 패키지 추적은 develop 와 다릅니다: 로컬 패키지 저장소의 파일에 대한 변경 사항은 해당 패키지를 로드할 때 즉시 반영되지 않습니다. 변경 사항을 적용하려면 변경 사항을 커밋하고 패키지를 업데이트해야 합니다.

또한 Manifest.toml 파일에 상대적으로 패키지를 추가할 수 있습니다. 예제는 패키지 개발(Developin package)을 참조하세요.


패키지 개발

add 만을 사용하면 매니페스트는 항상 "재현 가능한 상태"를 갖게 됩니다. 즉, 사용된 리포지토리와 레지스트리에 계속 액세스할 수 있는 한 프로젝트에 있는 모든 의존성의 정확한 상태를 검색할 수 있습니다. 이렇게 하면 프로젝트(Project.tomlManifest.toml)를 다른 사람에게 보낼 수 있고 다른 사람은 해당 프로젝트를 로컬에서와 동일한 상태로 "인스턴스화"할 수 있다는 이점이 있습니다. 그러나 패키지를 개발할 때 어떤 경로에서 현재 상태로 패키지를 로드하는 것이 더 편리합니다. 이러한 이유로 dev 명령이 존재합니다.

등록된 패키지를 dev 해 봅시다:

(v1.0) pkg> dev Example
Updating git-repo `https://github.com/JuliaLang/Example.jl.git`
Resolving package versions...
Updating `~/.julia/environments/v1.0/Project.toml`
[7876af07] + Example v0.5.1+ [`~/.julia/dev/Example`]
Updating `~/.julia/environments/v1.0/Manifest.toml`
[7876af07] + Example v0.5.1+ [`~/.julia/dev/Example`]

dev 명령은 패키지의 전체 복제본을 ~/.julia/dev/ 로 가져옵니다(경로는 JULIA_PKG_DEVDIR 환경 변수를 설정하여 변경할 수 있으며 기본값은 joinpath(DEPOT_PATH[1],"dev") 입니다). Example 을 가져올 때 julia는 이제 ~/.julia/dev/Example 에서 가져오고 해당 경로의 파일에 대한 모든 로컬 변경 사항이 결과적으로 로드된 코드에 반영됩니다. add 를 사용할 때 우리는 패키지 저장소를 추적한다고 말했지만 여기에서는 경로 자체를 추적한다고 말합니다. 패키지 관리자는 추적된 경로에 있는 파일을 건드리지 않습니다. 따라서 업데이트 가져오기, 브랜치 변경 등은 사용자에게 달려 있습니다. ~/.julia/dev/ 패키지 매니저 에 이미 존재하는 어떤 브랜치의 패키지를 dev 하면, 단순히 기존 경로를 사용합니다. 예를 들어:

(v1.0) pkg> dev Example
  Updating git-repo `https://github.com/JuliaLang/Example.jl.git`
[ Info: Path `/Users/kristoffer/.julia/dev/Example` exists and looks like the correct package, using existing path instead of cloning

기존 경로를 사용하고 있다는 Info 메시지에 유의하십시오. 경로를 추적할 때 패키지 관리자는 해당 경로의 파일을 수정하지 않습니다.

dev 가 로컬 경로에서 사용되는 경우 해당 패키지에 대한 경로가 기록되어 해당 패키지를 로드할 때 사용됩니다. 경로는 절대 경로로 지정되지 않는 한 프로젝트 파일에 상대적으로 기록됩니다.

(v1.0) pkg> dev /Users/kristoffer/Desktop/Example

경로 추적을 중지하고 등록된 버전을 다시 사용하려면 free 를 사용하십시오.

(v1.0) pkg> free Example
Resolving package versions...
Updating `~/.julia/environments/v1.0/Project.toml`
[7876af07] ↓ Example v0.5.1+ [`~/.julia/dev/Example`] ⇒ v0.5.1
Updating `~/.julia/environments/v1.0/Manifest.toml`
[7876af07] ↓ Example v0.5.1+ [`~/.julia/dev/Example`] ⇒ v0.5.1

dev를 사용하면 이제 프로젝트가 본질적으로 상태를 보존한다는(stateful) 점을 지적해야 합니다. 해당 상태는 경로에 있는 파일의 현재 내용에 따라 다르며 매니페스트는 경로를 추적하는 모든 패키지의 정확한 내용을 모른 채 다른 사람이 "인스턴스화"할 수 없습니다.

로컬 경로를 추적하는 패키지에 의존성을 추가하면 (전체 의존성 그래프를 포함하는)매니페스트가 실제 의존성 그래프와 동기화되지 않습니다. 이는 매니페스트에 기록되지 않았기 때문에 패키지가 해당 의존성을 로드할 수 없음을 의미합니다. 매니페스트를 동기화하려면 REPL 명령 resolve 를 사용하십시오.

절대 경로 외에도 adddev 는 패키지에 대한 상대 경로를 받아들일 수 있습니다. 이 경우 활성 프로젝트에서 패키지로의 상대 경로가 저장됩니다. 이 접근 방식은 추적된 의존성의 상대적 위치가 절대 위치보다 더 중요한 경우에 유용합니다. 예를 들어 추적된 의존성은 활성 프로젝트 디렉토리 내에 저장할 수 있습니다. 전체 디렉토리를 이동할 수 있으며 Pkg는 절대 경로가 변경되더라도 활성 프로젝트에 상대적인 경로가 유지되기 때문에 여전히 의존성을 찾을 수 있습니다.


저장소의 서브디렉토리에 패키지 추가하기

URL로 추가하려는 패키지가 저장소의 루트에 없으면 수동으로 subdir 키워드를 Pkg.add 또는 PackageSpec에 전달해야 합니다. 예를 들어 SnoopCompile 저장소에 SnoopCompileCore 패키지를 추가하려면:

julia> Pkg.add(url="https://github.com/timholy/SnoopCompile.jl.git", subdir="SnoopCompileCore")
     Cloning git-repo `https://github.com/timholy/SnoopCompile.jl.git`
    Updating git-repo `https://github.com/timholy/SnoopCompile.jl.git`
   Resolving package versions...
    Updating `~/.julia/environments/v1.6/Project.toml`
  [e2b509da] + SnoopCompileCore v2.7.0 `https://github.com/timholy/SnoopCompile.jl.git:SnoopCompileCore#master`
    Updating `~/.julia/environments/v1.6/Manifest.toml`
  [e2b509da] + SnoopCompileCore v2.7.0 `https://github.com/timholy/SnoopCompile.jl.git:SnoopCompileCore#master`
  [9e88b42a] + Serialization

또 다른 방법은 <repo_url>:<subdir> 형식으로 Pkg REPL을 사용하는 것입니다.

pkg> add https://github.com/timholy/SnoopCompile.jl.git:SnoopCompileCore # git HTTPS protocol
...

pkg> add "git@github.com:timholy/SnoopCompile.jl.git":SnoopCompileCore # git SSH protocol
...

Julia 1.5
서브디렉토리의 패키지를 위한 Pkg REPL 은 최소한 Julia 1.5 를 요구합니다.


패키지 제거

pkg> rm Package 를 사용하여 현재 프로젝트에서 패키지를 제거할 수 있습니다. 이렇게 하면 프로젝트에 있는 패키지만 제거됩니다. 의존성으로만 존재하는 패키지를 제거하려면 pkg> rm --manifest DepPackage 를 사용하십시오. 이렇게 하면 DepPackage에 의존하는 모든 패키지가 제거됩니다.


패키지 업데이트

프로젝트에서 사용 중인 패키지의 새 버전이 릴리스되면 업데이트하는 것이 좋습니다. up 을 호출하기만 하면 프로젝트의 모든 의존성을 최신 호환 버전으로 업데이트하려고 시도합니다. 가끔은 이것을 원하지 않을 수도 있습니다. up 에 인수로 제공하여 업그레이드할 의존성의 하위 집합을 지정할 수 있습니다:

(v1.0) pkg> up Example

어떤 명시적으로 추가된 다른 패키지의 의존성을 Example 역시 의존할 경우 해당 의존성은 업데이트되지 않습니다. 패키지의 마이너 버전만 업데이트하려는 경우 프로젝트 중단 위험을 줄이기 위해 다음과 같이 --minor 플래그를 지정할 수 있습니다.

(v1.0) pkg> up --minor Example

로컬 리포지토리를 추적하는 패키지는 마이너 업그레이드가 완료되면 업데이트되지 않습니다. 경로를 추적하는 패키지는 패키지 관리자가 건드리지 않습니다.


패키지 고정

고정된 패키지는 절대 업데이트되지 않습니다. pin 을 사용하여 패키지를 고정할 수 있습니다. 예를 들면 다음과 같습니다.

(v1.0) pkg> pin Example
 Resolving package versions...
  Updating `~/.julia/environments/v1.0/Project.toml`
  [7876af07] ~ Example v0.5.1 ⇒ v0.5.1 ⚲
  Updating `~/.julia/environments/v1.0/Manifest.toml`
  [7876af07] ~ Example v0.5.1 ⇒ v0.5.1 ⚲

패키지가 고정되었음을 나타내는 핀 기호 에 유의하십시오. 핀 제거는 free 를 사용합니다.

(v1.0) pkg> free Example
  Updating `~/.julia/environments/v1.0/Project.toml`
  [7876af07] ~ Example v0.5.1 ⚲ ⇒ v0.5.1
  Updating `~/.julia/environments/v1.0/Manifest.toml`
  [7876af07] ~ Example v0.5.1 ⚲ ⇒ v0.5.1

패키지 테스트

패키지에 대한 테스트는 test 명령을 사용하여 실행할 수 있습니다.

(v1.0) pkg> test Example
   Testing Example
   Testing Example tests passed

패키지 빌드

패키지의 빌드 단계는 패키지가 처음 설치될 때 자동으로 실행됩니다. 빌드 프로세스의 출력은 파일로 보내집니다. 패키지의 빌드 단계를 명시적으로 실행하려면 build 명령을 사용합니다.

(v1.0) pkg> build MbedTLS
  Building MbedTLS → `~/.julia/packages/MbedTLS/h1Vu/deps/build.log`

julia> print(read("~/.julia/packages/MbedTLS/h1Vu/deps/build.log", String))
┌ Warning: `wait(t::Task)` is deprecated, use `fetch(t)` instead.
│   caller = macro expansion at OutputCollector.jl:63 [inlined]
└ @ Core OutputCollector.jl:63
...
[ Info: using prebuilt binaries

버젼 충돌의 해석과 해소

환경은 상호 호환 가능한 패키지 세트로 구성됩니다. 때로는 동시에 사용하려는 두 패키지의 요구 사항이 호환되지 않는 상황에 처할 수 있습니다. 이러한 경우 "충족할 수 없는 요구 사항(Unsatisfiable requirements)" 오류가 발생합니다.

pkg> add A
Unsatisfiable requirements detected for package D [756980fe]:
 D [756980fe] log:
 ├─possible versions are: 0.1.0-0.2.1 or uninstalled
 ├─restricted by compatibility requirements with B [f4259836] to versions: 0.1.0
 │ └─B [f4259836] log:
 │   ├─possible versions are: 1.0.0 or uninstalled
 │   └─restricted to versions * by an explicit requirement, leaving only versions 1.0.0
 └─restricted by compatibility requirements with C [c99a7cb2] to versions: 0.2.0 — no versions left
   └─C [c99a7cb2] log:
     ├─possible versions are: 0.1.0-0.2.0 or uninstalled
     └─restricted by compatibility requirements with A [29c70717] to versions: 0.2.0
       └─A [29c70717] log:
         ├─possible versions are: 1.0.0 or uninstalled
         └─restricted to versions * by an explicit requirement, leaving only versions 1.0.0

이 메시지는 D 라는 패키지에 버전 충돌이 있음을 의미합니다. D 를 직접 추가한 적이 없더라도 사용하려는 다른 패키지에서 D 가 필요한 경우 이러한 종류의 오류가 발생할 수 있습니다.

주의
이러한 충돌을 해결할 때는 우선 프로젝트가 커질수록 이런 일이 발생할 가능성이 더 높다는 점을 고려하십시오. 어떤 주어진 과업에는 해당하는 프로젝트를 사용하는 것이 좋습니다. 사용하지 않는 의존성을 제거하는 것은 이러한 문제가 발생할 때 좋은 첫 번째 단계입니다. 예를 들어 일반적인 함정은 기본(예: (@1.8)) 환경에 몇 개 이상의 패키지가 있고 이를 julia를 사용하는 모든 작업의 환경으로 사용하는 것입니다. 작업 중인 작업을 위한 전용 프로젝트를 만들고 거기에 의존성을 최소화하는 것이 좋습니다. 자세한 내용은 환경을 이용한 작업을 참조하십시오.


오류 메시지에는 중요한 정보가 많이 있습니다. 낱낱이 해석하는 것이 가장 쉬울 수 있습니다.

Unsatisfiable requirements detected for package D [756980fe]:
 D [756980fe] log:
 ├─possible versions are: [0.1.0, 0.2.0-0.2.1] or uninstalled

Dv0.1.0, v0.2.0v0.2.1 의 세 가지 릴리스 버전이 있음을 의미합니다. 전혀 설치하지 않는 옵션도 있습니다. 이러한 각 옵션은 설치할 수 있는 다른 패키지 집합에 대해 서로 다른 의미를 가질 수 있습니다.

결정적으로 획문자(수직 및 수평선)와 들여쓰기를 확인하십시오. 이들은 메시지와 특정 패키지를 연결하는데 같이 사용됩니다. 예를 들어 ├─ 의 오른쪽 획은 오른쪽에 있는 메시지(possible versions...)가 수직 획(D)이 가리키는 패키지에 연결되어 있음을 나타냅니다. 다음 줄에도 동일한 원칙이 적용됩니다.

 ├─restricted by compatibility requirements with B [f4259836] to versions: 0.1.0

여기서 세로 획도 D 아래에 정렬되어 있으므로 이 메시지는 D 를 참조합니다. 특히 D 의 버전 v0.1.0 에 의존하는 다른 패키지 B가 있습니다. 이것은 D 의 최신 버전이 아닙니다.

다음은 B에 대한 정보입니다.

 │ └─B [f4259836] log:
 │   ├─possible versions are: 1.0.0 or uninstalled
 │   └─restricted to versions * by an explicit requirement, leaving only versions 1.0.0

첫 번째 줄 아래의 두 줄에는 B 와 정렬되는 세로 획이 있으므로 B 에 대한 정보를 제공합니다. Bv1.0.0 릴리스가 하나만 있음을 알려줍니다. B 의 특정 버전을 지정하지 않았지만(restricted to versions *은 모든 버전이 가능함을 의미합니다) 명시적 요구 사항은 B 가 환경의 일부가 되도록 요청했음을 의미합니다(예: pkg> add B). 이전에 B를 요청했을 수 있으며 요구 사항이 여전히 유효합니다.

선과의 충돌이 분명해집니다.

└─restricted by compatibility requirements with C [c99a7cb2] to versions: 0.2.0 — no versions left

여기서 다시 세로 획은 D 와 정렬됩니다. 이것은 D 가 다른 패키지 C 에도 필요함을 의미합니다. C 에는 Dv0.2.0 이 필요하며 이는 Dv0.1.0 에 대한 B의 요구와 충돌합니다. 이것이 충돌을 설명합니다.

하지만 잠깐, C 가 무엇이고 왜 C 가 필요한지 물을 수 있습니다. 다음 몇 줄은 문제를 소개합니다.

   └─C [c99a7cb2] log:
     ├─possible versions are: [0.1.0-0.1.1, 0.2.0] or uninstalled
     └─restricted by compatibility requirements with A [29c70717] to versions: 0.2.0

이는 C 에 대한 자세한 정보를 제공하며 v0.1.0, v0.1.1v0.2.0 의 3개 릴리스 버전이 있음을 나타냅니다. 또한 C 는 다른 패키지 A 에 필요합니다. 실제로 A 의 요구 사항은 Cv0.2.0 이 필요하다는 것입니다. A 의 출처는 다음 줄에 표시됩니다.

       └─A [29c70717] log:
         ├─possible versions are: 1.0.0 or uninstalled
         └─restricted to versions * by an explicit requirement, leaving only versions 1.0.0

따라서 A 가 명시적으로 필요하다는 것을 알 수 있습니다. 이 경우에는 A 를 환경에 추가하려고 했기 때문입니다.

요약하면 우리는 명시적으로 AB 를 사용하도록 요청했지만 이로 인해 D 와 충돌이 발생했습니다. 그 이유는 BC 가 충돌하는 버전의 D 를 필요로 하기 때문입니다. C 는 우리가 명시적으로 요청한 것이 아니지만 A 가 필요로 했습니다.

이러한 오류를 수정하려면 다음과 같은 여러 가지 옵션이 있습니다.

  • 패키지 업데이트를 시도하십시오. 패키지의 개발자가 최근 상호 호환되는 새 버전을 출시했을 가능성이 있습니다.

  • 환경에서 A 또는 B 를 제거하십시오. 아마도 B 는 이전에 작업하던 작업에서 남겨져 더 이상 필요하지 않을 수 있습니다. AB 가 동시에 필요하지 않은 경우 문제를 해결하는 가장 쉬운 방법입니다.

  • 충돌을 보고합니다. 이 경우 B 에는 오래된 버전의 D 가 필요하다고 추론할 수 있었습니다. 따라서 B.jl 의 개발 저장소에서 업데이트된 버전을 요청하는 이슈를 보고할 수 있습니다.

  • 문제를 직접 해결해 보십시오. Project.toml 파일과 파일이 호환성 요구 사항을 선언하는 방법을 이해하면 이 작업이 더 쉬워집니다. 충돌 해결에서 이 예제로 돌아갑니다.


오래되고 사용되지 않는 패키지를 가비지 컬렉팅 하기

패키지가 업데이트되고 프로젝트가 삭제되면 설치된 패키지 버전과 한 번 사용된 아티팩트는 필연적으로 오래되어 기존 프로젝트에서 사용되지 않습니다. Pkg 는 사용된 모든 프로젝트의 로그를 유지하므로 로그를 통해 어떤 프로젝트가 여전히 존재하고 해당 프로젝트에서 어떤 패키지/아티팩트가 사용되었는지 정확히 확인할 수 있습니다. 패키지 또는 아티팩트가 프로젝트에서 사용된 것으로 표시되지 않은 경우 고아 패키지(orphaned package) 목록에 추가됩니다. 다시 사용하지 않고 30일 동안 고아 목록에 있는 패키지 및 아티팩트는 다음 가비지 수집 시 시스템에서 삭제됩니다. 이 시점은 Pkg.gc()에 대한 collect_delay 키워드 인수를 통해 구성할 수 있습니다. 값이 0이면 고아 목록을 완전히 건너뛰고 현재 사용하지 않는 항목이 즉시 발생합니다. 디스크 공간이 부족하고 사용하지 않는 패키지와 아티팩트를 가능한 한 많이 정리하려는 경우 이 방법을 시도해 볼 수 있지만 이러한 버전이 다시 필요한 경우 다시 다운로드해야 합니다. 기본 인수를 사용하여 일반적인 가비지 수집을 실행하려면 pkg> REPL에서 gc 명령을 사용하면 됩니다.

(v1.0) pkg> gc
    Active manifests at:
        `~/BinaryProvider/Manifest.toml`
        ...
        `~/Compat.jl/Manifest.toml`
    Active artifacts:
        `~/src/MyProject/Artifacts.toml`

    Deleted ~/.julia/packages/BenchmarkTools/1cAj: 146.302 KiB
    Deleted ~/.julia/packages/Cassette/BXVB: 795.557 KiB
   ...
   Deleted `~/.julia/artifacts/e44cdf2579a92ad5cbacd1cddb7414c8b9d2e24e` (152.253 KiB)
   Deleted `~/.julia/artifacts/f2df5266567842bbb8a06acca56bcabf813cd73f` (21.536 MiB)

   Deleted 36 package installations (113.205 MiB)
   Deleted 15 artifact installations (20.759 GiB)

~/.julia/packages 에 포함된 패키지만 삭제되는 것을 확인 할 수 있습니다.


오프라인 모드

오프라인 모드에서 Pkg는 인터넷에 연결하지 않고 가능한 한 많은 일을 하려고 합니다. 예를 들어 패키지를 추가할 때 Pkg는 버전 확인에서 이미 다운로드된 버전만 고려합니다.

오프라인 모드에서 작업하려면 import Pkg 를 사용하십시오. Pkg.offline(true) 또는 환경 변수 JULIA_PKG_OFFLINE 을 "true" 로 설정합니다.


Pkg 클라이언트/서버

Julia 1.4
Pkg 클라이언트/서버 기능에는 Julia 1.4 이상이 필요합니다. Julia 1.4 에서는 선택사항이며 Julia 1.5 부터는 기본적으로 활성화됩니다.


등록된 패키지를 새로 추가하면 일반적으로 다음 세 가지가 발생합니다.

  1. 레지스트리 업데이트,

  2. 패키지의 소스 코드 다운로드,

  3. 사용할 수 없는 경우 패키지에 필요한 아티팩트를 다운로드.

General 레지스트리와 그 안에 있는 대부분의 패키지는 Github에서 개발되며 아티팩트 데이터는 다양한 플랫폼에서 호스팅됩니다. Github 및 AWS S3에 대한 네트워크 연결이 안정적이지 않은 경우 일반적으로 패키지를 설치하거나 업데이트하는 것은 좋은 경험이 아닙니다. 다행스럽게도 pkg 클라이언트/서버 기능은 다음과 같은 측면에서 경험을 향상시킵니다.

  1. 설정된 경우 pkg 클라이언트는 먼저 pkg 서버에서 데이터 다운로드를 시도합니다.

  2. 실패하면 원래 소스(예: Github)에서 다시 다운로드합니다.

Julia 1.5부터 https://pkg.julialang.org 는 JuliaLang.org 에서 제공하며 기본 pkg 서버로 사용됩니다. 대부분의 경우 이것은 투명해야 하지만 사용자는 여전히 환경 변수 JULIA_PKG_SERVER 를 통해 pkg 서버 업스트림을 설정/해제 할 수 있습니다.

# manually set it to some pkg server
julia> ENV["JULIA_PKG_SERVER"] = "pkg.julialang.org"
"pkg.julialang.org"

# unset to always download data from original sources
julia> ENV["JULIA_PKG_SERVER"] = ""
""

명확하게 하자면, 일부 소스는 Pkg 서버에서 제공하지 않습니다.

  • git을 통해 가져온 패키지/레지스트리

    • ]add https://github.com/JuliaLang/Example.jl.git

    • ]add Example#v0.5.3 (이것은 ]add Example@0.5.3과 다릅니다)

    • ]registry add https://github.com/JuliaRegistries/General.git, 1.4 이전에 Julia가 설치한 레지스트리 포함됨

  • 다운로드 정보가 없는 아티팩트

주의
pkg 서버를 통해 새 레지스트리를 설치한 경우 이전 Julia 버전이 레지스트리를 업데이트하는 것은 불가능합니다. 1.4 이전의 Julia는 새 데이터를 가져오는 방법을 모르기 때문입니다. 따라서 여러 julia 버전 간에 자주 전환하는 사용자의 경우 git 제어 레지스트리를 계속 사용하는 것이 좋습니다.


pkg 서버 배포에 대해서는 PkgServer.jl을 참조하십시오.


4. 환경을 이용한 작업

다음은 Pkg와 환경의 상호 작용에 대해 설명합니다. 코드를 로드할 수 있는 환경의 "스택"을 포함하여 코드를 로딩할 때의 환경의 역할에 대한 자세한 내용은 Julia 설명서의 이 섹션을 참조하세요.


당신의 프로젝트를 생성하기

지금까지 ~/.julia/environments/v1.6 의 기본 프로젝트에 패키지를 추가했습니다. 그러나 다른 독립적인 프로젝트를 만드는 것은 쉽습니다. 이 접근 방식은 Project.toml 및 원하는 경우 Manifest.toml 을 코드와 함께 버전 제어(예: git)에 체크인할 수 있는 이점이 있습니다. 두 프로젝트가 동일한 버전의 동일한 패키지를 사용하는 경우 이 패키지의 내용이 중복되지 않는다는 점에 유의해야 합니다. 새 프로젝트를 만들려면 디렉터리를 만든 다음 해당 디렉터리를 활성화하여 패키지 작업이 처리하는 "활성 프로젝트(active project)"로 만듭니다.

julia> mkdir("MyProject")

julia> cd("MyProject")
/Users/kristoffer/MyProject

# we can now use "." instead of a longer relative or full path:
(v1.0) pkg> activate .

(MyProject) pkg> st
    Status `Project.toml`

새 프로젝트가 활성화되면 REPL 프롬프트가 변경되었습니다. 이것은 새로 생성된 프로젝트이므로 상태 명령은 패키지가 포함되어 있지 않으며 실제로 패키지를 추가할 때까지 프로젝트 또는 메니패스트 파일이 없음을 보여줍니다.

julia> readdir()
0-element Array{String,1}

(MyProject) pkg> add Example
  Updating registry at `~/.julia/registries/General`
  Updating git-repo `https://github.com/JuliaRegistries/General.git`
 Resolving package versions...
  Updating `Project.toml`
  [7876af07] + Example v0.5.1
  Updating `Manifest.toml`
  [7876af07] + Example v0.5.1
  [8dfed614] + Test
Precompiling project...
  1 dependency successfully precompiled in 2 seconds

julia> readdir()
2-element Array{String,1}:
 "Manifest.toml"
 "Project.toml"

julia> print(read("Project.toml", String))
[deps]
Example = "7876af07-990d-54b4-ab0e-23690620f79a"

julia> print(read("Manifest.toml", String))
[[Example]]
deps = ["Test"]
git-tree-sha1 = "8eb7b4d4ca487caade9ba3e85932e28ce6d6e1f8"
uuid = "7876af07-990d-54b4-ab0e-23690620f79a"
version = "0.5.1"

[[Test]]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

이 새로운 환경은 이전에 사용했던 환경과 완전히 별개입니다.


프로젝트 사전 컴파일(Precompile)

패키지를 임포트 하기 전에 Julia는 소스 코드를 디스크상에서의 더 효율적인 중간 캐시로 "사전 컴파일(precompile)"합니다. 임포트 되지 않은 패키지가 새 패키지이거나 마지막 캐시 이후 변경된 패키지일 경우 코드 로드를 통해 사전 컴파일이 개시될 수 있습니다.

julia> using Example
[ Info: Precompiling Example [7876af07-990d-54b4-ab0e-23690620f79a]

또는 전체 프로젝트나 지정된 의존성을 사전 컴파일할 수 있는 Pkg의 사전 컴파일 옵션을 사용하여 병렬로 수행할 수 있는데, 이 방법이 위의 코드 로드 경로보다 훨씬 빠를 수 있습니다.

(@v1.6) pkg> precompile
Precompiling project...
  23 dependencies successfully precompiled in 36 seconds

그러나 Pkg의 자동 사전 컴파일로 인해 이들 중 어느 것도 일상적으로 필요하지 않습니다.


자동 사전 컴파일 (Automatic Precompilation)

기본적으로 프로젝트에 추가되거나 Pkg 작업에서 업데이트되는 모든 패키지는 해당 의존성과 함께 자동으로 미리 컴파일됩니다.

(@v1.6) pkg> add Images
   Resolving package versions...
    Updating `~/.julia/environments/v1.9/Project.toml`
  [916415d5] + Images v0.25.2
    Updating `~/.julia/environments/v1.9/Manifest.toml`
    ...
Precompiling project...
  Progress [===================>                     ]  45/97
  ✓ NaNMath
  ✓ IntervalSets
  ◐ CoordinateTransformations
  ◑ ArnoldiMethod
  ◑ IntegralArrays
  ◒ RegionTrees
  ◐ ChangesOfVariables
  ◓ PaddedViews

develop 명령은 예외인데 패키지를 빌드하거나 미리 컴파일하지 않습니다. 언제 할지는 사용자가 결정할 수 있습니다.

자동 사전 컴파일 중에 지정된 패키지 버전 오류가 발생하면 Pkg는 자동으로 시도하는 이후의 시간동안 기억하고 간단한 경고와 함께 해당 패키지를 건너뜁니다. pkg> precompile 은 항상 모든 패키지를 재시도하므로 수동 사전 컴파일을 사용하여 이러한 패키지를 강제로 재시도할 수 있습니다.

자동 사전 컴파일을 비활성화하려면 ENV["JULIA_PKG_PRECOMPILE_AUTO"]=0을 설정합니다.


로드된 패키지의 새 버젼을 사전 컴파일하기

업데이트된 패키지가 이미 세션에 로드된 경우 사전 컴파일 프로세스가 계속 진행되어 새 버전과 이에 의존하는 모든 패키지를 사전 컴파일하지만 세션을 다시 시작할 때까지 패키지를 사용할 수 없다는 점에 유의하십시오.


다른 사람의 프로젝트를 사용하기

git clone 과 같은 명령어를 이용하여 프로젝트를 복제하기만 하면 됩니다. cd 로 프로젝트 디렉토리로 이동하고 다음을 호출합니다.

(v1.0) pkg> activate .

(SomeProject) pkg> instantiate

프로젝트에 manifest가 포함된 경우 해당 manifest에서 제공하는 것과 동일한 상태로 패키지를 설치합니다. 그렇지 않으면 프로젝트와 호환되는 최신 버전의 의존성으로 결정합니다.

activate 자체는 누락된 의존성을 설치하지 않습니다. Project.toml만 있는 경우 환경을 "분석(resolving)"하여 Manifest.toml 을 생성한 다음 누락된 패키지를 모두 설치하고 미리 컴파일해야 합니다. instantiate 는 이 모든 작업을 수행합니다.

해결된 Manifest.toml 이 이미 있는 경우에도 패키지가 올바른 버전으로 설치되어 있는지 확인해야 합니다. 다시 instantiate 를 실행하면 이 작업이 수행됩니다.

즉, instantiate 는 환경을 사용할 준비가 되었는지 확인하는 당신의 친구입니다. 할 일이 없으면 instantiate 는 아무 작업도 수행하지 않습니다.

시작시의 프로젝트 지정
Julia 내에서 activate 를 사용하는 대신 --project=<path> 플래그를 사용하여 시작할 때 프로젝트를 지정할 수 있습니다. 예를 들어 현재 디렉토리의 환경을 사용하여 명령줄에서 스크립트를 실행하려면 다음을 실행할 수 있습니다.

$ julia --project=. myscript.jl

5. 패키지 작성

패키지는 Project.toml 파일의 name, uuidversion 항목과 PackageName 모듈을 정의하는 src/PackageName.jl 파일이 있는 프로젝트입니다. 이 파일은 패키지가 로드될 때 실행됩니다.


패키지용 파일 생성

주의
PkgTemplates 패키지는 새 패키지용 파일을 생성하는 매우 쉽고 반복 가능하며 사용자 맞춤식의 방법을 제공합니다. 아래에 설명된 최소한의 pkg> generate 기능을 사용하는 대신 PkgTemplates 를 사용하여 새 패키지를 만드는 것이 좋습니다.


새 패키지에 대한 파일을 생성하려면 pkg> generate 를 실행하십시오.

(v1.0) pkg> generate HelloWorld

이렇게 하면 다음 파일이 포함된 새 프로젝트 HelloWorld가 생성됩니다(외부 tree 명령으로 시각화됩니다).

julia> cd("HelloWorld")

shell> tree .
.
├── Project.toml
└── src
    └── HelloWorld.jl

1 directory, 2 files

Project.toml 파일에는 패키지 이름, 고유한 UUID, 버전, 작성자 및 잠재적 의존성이 포함됩니다.

name = "HelloWorld"
uuid = "b4cd1eb8-1e24-11e8-3319-93036a3eb9f3"
version = "0.1.0"
authors = ["Some One <someone@email.com>"]

[deps]

src/HelloWorld.jl 의 내용은 다음과 같습니다

module HelloWorld

greet() = print("Hello World!")

end # module

이제 프로젝트를 활성화하고 패키지를 로드할 수 있습니다.

pkg> activate .

julia> import HelloWorld

julia> HelloWorld.greet()
Hello World!

프로젝트에 의존성 추가

프로젝트에서 표준 라이브러리 패키지인 Random 과 등록된 패키지 JSON 을 사용하고 싶다고 가정해 보겠습니다. 이 패키지를 add 하기만 하면 됩니다(새로 생성된 프로젝트를 actvate 한 이후에는 프롬프트에 이제 프로젝트 이름이 표시됩니다).

(HelloWorld) pkg> add Random JSON
 Resolving package versions...
  Updating "~/Documents/HelloWorld/Project.toml"
 [682c06a0] + JSON v0.17.1
 [9a3f8284] + Random
  Updating "~/Documents/HelloWorld/Manifest.toml"
 [34da2185] + Compat v0.57.0
 [682c06a0] + JSON v0.17.1
 [4d1e1d77] + Nullables v0.0.4
 ...

RandomJSON 이 모두 프로젝트의 Project.toml 파일에 추가되었고 결과 의존성이 Manifest.toml 파일에 추가되었습니다. 리졸버(resolver)는 가능한 가장 높은 버전의 각 패키지를 설치했지만 각 패키지가 해당 의존성에 적용하는 호환성을 여전히 존중합니다.

이제 프로젝트에서 RandomJSON 을 모두 사용할 수 있습니다. src/HelloWorld.jl 을 아래와 같이 변경하고

module HelloWorld

import Random
import JSON

greet() = print("Hello World!")
greet_alien() = print("Hello ", Random.randstring(8))

end # module

다시 패키지를 로딩하면 Random 을 사용하는 새로운 greet_alien 함수를 호출 할 수 있습니다.

julia> HelloWorld.greet_alien()
Hello aT157rHV

패키지에 빌드 단계를 추가하기

빌드 단계는 패키지가 처음 설치되거나 build 를 통해 명시적으로 호출될 때 실행됩니다. 패키지는 deps/build.jl 파일을 실행하여 빌드됩니다.

julia> print(read("deps/build.jl", String))
println("I am being built...")

(HelloWorld) pkg> build
  Building HelloWorld → `deps/build.log`
 Resolving package versions...

julia> print(read("deps/build.log", String))
I am being built...

빌드 단계가 실패하면 빌드 단계의 출력이 콘솔에 인쇄됩니다.

julia> print(read("deps/build.jl", String))
error("Ooops")

(HelloWorld) pkg> build
  Building HelloWorld → `deps/build.log`
 Resolving package versions...
┌ Error: Error building `HelloWorld`:
│ ERROR: LoadError: Ooops
│ Stacktrace:
│  [1] error(::String) at ./error.jl:33
│  [2] top-level scope at none:0
│  [3] include at ./boot.jl:317 [inlined]
│  [4] include_relative(::Module, ::String) at ./loading.jl:1071
│  [5] include(::Module, ::String) at ./sysimg.jl:29
│  [6] include(::String) at ./client.jl:393
│  [7] top-level scope at none:0
│ in expression starting at /Users/kristoffer/.julia/dev/Pkg/HelloWorld/deps/build.jl:1
└ @ Pkg.Operations Operations.jl:938

패키지에 테스트 추가하기

패키지가 테스트되면 test/runtests.jl 파일이 실행됩니다.

julia> print(read("test/runtests.jl", String))
println("Testing...")

(HelloWorld) pkg> test
   Testing HelloWorld
 Resolving package versions...
Testing...
   Testing HelloWorld tests passed

테스트는 패키지 자체와 테스트 관련 의존성을 사용할 수 있는 새로운 Julia 프로세스에서 실행됩니다(아래 참조).


Julia 1.2 이후에서의 테스트용 의존성

Julia1.2
이 섹션은 Julia 1.2 이상에만 적용됩니다. 이전 Julia 버전에 대한 테스트용 의존성을 지정하려면 Julia 1.0 및 1.1의 테스트용 의존성을 참조하십시오. (본 문서에서는 생략함)


주의
Project.toml, test/Project.toml 및 해당 Manifest.toml 간의 정확한 상호 작용은 완전히 결정되지 않았으며 향후 버전에서 변경될 수 있습니다. 따라서 다음 섹션에서 설명하는 테스트용 의존성을 추가하는 예전 방법은 모든 Julia 1.X 릴리스에서 지원됩니다.


Julia 1.2 이상에서 테스트 환경은 test/Project.toml 에 의해 제공됩니다. 따라서 테스트를 실행할 때 이것이 활성 프로젝트가 되며 test/Project.toml 프로젝트에 대한 의존성만 사용할 수 있습니다. Pkg는 테스트된 패키지 자체를 암시적으로 추가합니다.

주의
test/Project.toml이 없으면 Pkg는 Julia 1.0 및 1.1의 테스트용 의존성에 설명된 대로 이전 스타일의 테스트 설정을 사용합니다.


테스트용 의존성, 즉 테스트할 때만 사용할 수 있는 의존성을 추가하려면 이 의존성을 test/Project.toml 프로젝트에 추가하는 것으로 충분합니다. 이 작업은 이 환경을 활성화하여 Pkg REPL에서 수행할 수 있으며 평소처럼 add 를 사용할 수 있습니다. Test 표준 라이브러리를 테스트 의존성으로 추가해 보겠습니다.

(HelloWorld) pkg> activate ./test
[ Info: activating environment at `~/HelloWorld/test/Project.toml`.

(test) pkg> add Test
 Resolving package versions...
  Updating `~/HelloWorld/test/Project.toml`
  [8dfed614] + Test
  Updating `~/HelloWorld/test/Manifest.toml`
  [...]

이제 테스트 스크립트에서 Test 를 사용할 수 있으며 테스트할 때 설치되는 것을 볼 수 있습니다.

julia> print(read("test/runtests.jl", String))
using Test
@test 1 == 1

(HelloWorld) pkg> test
   Testing HelloWorld
 Resolving package versions...
  Updating `/var/folders/64/76tk_g152sg6c6t0b4nkn1vw0000gn/T/tmpPzUPPw/Project.toml`
  [d8327f2a] + HelloWorld v0.1.0 [`~/.julia/dev/Pkg/HelloWorld`]
  [8dfed614] + Test
  Updating `/var/folders/64/76tk_g152sg6c6t0b4nkn1vw0000gn/T/tmpPzUPPw/Manifest.toml`
  [d8327f2a] + HelloWorld v0.1.0 [`~/.julia/dev/Pkg/HelloWorld`]
   Testing HelloWorld tests passed```

패키지 작명 가이드

패키지 이름은 도메인 전문가가 아니더라도 대부분의 Julia 사용자가 이해할 수 있어야 합니다. 다음 지침은 General 레지스트리에 적용되지만 다른 패키지 레지스트리에도 유용할 수 있습니다.

General 레지스트리는 전체 커뮤니티에 속하므로 패키지 이름을 게시할 때 사람들이 패키지 이름에 대해 의견을 가질 수 있습니다. 특히 패키지 이름이 모호하거나 다른 이름과 혼동될 수 있는 경우 더욱 그렇습니다. 일반적으로 패키지에 더 잘 맞는 새 이름에 대한 제안을 받게 됩니다.

  1. 전문 용어를 사용하지 마십시오. 특히 혼동의 가능성이 최소화되지 않는 한 두문자어를 사용하지 마십시오.

    • 미국에 대해 이야기할 때는 USA 라고 말하는 것이 좋습니다.
    • 정적인 정신 자세에 대해 이야기하더라도 PMA(Positive Mental Attitude) 라고 말하는 것은 옳지 않습니다.
  2. 패키지 이름에 Julia를 사용하거나 접두사로 Ju를 사용하지 마십시오.

    • 패키지가 Julia 패키지라는 것은 일반적으로 컨텍스트와 사용자에게 명확합니다.
    • 패키지 이름에는 이미 .jl 확장자가 있어 Package.jl 이 Julia 패키지임을 사용자에게 알립니다.
    • 이름에 Julia가 있으면 패키지가 Julia 언어 자체에 대한 기여자와 연관되어 있거나 기여자가 승인했음을 의미할 수 있습니다.
  3. 새로운 유형과 관련하여 대부분의 기능을 제공하는 패키지에는 복수형 이름이 있어야 합니다.

    • DataFramesDataFrame 유형을 제공합니다.
    • BloomFiltersBloomFilter 유형을 제공합니다.
    • 반대로 JuliaParser 는 새로운 유형을 제공하지 않지만 대신 JuliaParser.parse() 함수에서 새로운 기능을 제공합니다.
  4. 명확성이 당신에게 오래 걸리는 것처럼 보이더라도 명확성의 측면에 오류가 있습니다.

    • RandomMatricesRndMat 또는 RMT 가 더 짧지만 덜 모호한 이름입니다.
    • 덜 체계적인 이름은 해당 도메인에 대한 여러 가능한 접근 방식 중 하나를 구현하는 패키지에 적합할 수 있습니다.
    • Julia는 포괄적인 단일 플로팅 패키지가 없습니다. 대신 Gadfly, PyPlot, Winston 및 기타 패키지는 각각 특정 디자인 철학을 기반으로 고유한 접근 방식을 구현합니다.
    • 대조적으로, SortingAlgorithms 는 많은 잘 정립된 정렬 알고리즘을 사용하기 위한 일관된 인터페이스를 제공합니다.
  5. 외부 라이브러리나 프로그램을 래핑하는 패키지는 해당 라이브러리나 프로그램의 이름을 따서 명명해야 합니다.

    • CPLEX.jl은 웹 검색에서 쉽게 식별할 수 있는 CPLEX 라이브러리를 래핑합니다.
    • MATLAB.jl은 Julia 내에서 MATLAB 엔진을 호출하는 인터페이스를 제공합니다.
  6. 패키지 이름을 기존 패키지에 유사하게 지정하지 마십시오.

    • WebsocketWebSockets 과 너무 유사하고 사용자에게 혼란을 줄 수 있습니다. 대신 SimpleWebsockets 과 같은 새 이름을 사용하십시오.

패키지 등록

패키지가 준비되면 일반 레지스트리(General Registray)에 등록할 수 있습니다(FAQ 참조). 현재 패키지는 Registrator를 통해 제출됩니다. 등록자 외에도 TagBot은 릴리스 태그 지정 프로세스를 관리하는 데 도움이 됩니다.


Best Practices

패키지는 자체 상태 변경(패키지 디렉토리 내의 파일에 쓰기)을 피해야 합니다. 일반적으로 패키지는 쓰기 가능한 위치(예: 시스템 전체 저장소의 일부로 설치된 경우) 또는 안정적인 위치(예: PackageCompiler.jl에 의해 시스템 이미지에 번들된 경우)에 있다고 가정하지 않아야 합니다. Julia 패키지 생태계의 다양한 사용 사례를 지원하기 위해 Pkg 개발자는 패키지 작성자가 독립적이고 변경 불가능하며 재배치 가능한 패키지를 만드는 데 도움이 되는 여러 보조 패키지 및 기술을 만들었습니다.

  • 아티팩트(Artifacts) 를 사용하여 패키지와 함께 데이터 더미를 뭉치고 요청에 의해 다운로드할 수 있습니다. 재배치가 불가능하므로 joinpath(@__DIR__, "data", "my_dataset.csv") 와 같은 경로를 통해 파일을 열려고 시도하는 것보다 아티팩트를 선호하십시오. 패키지가 사전 컴파일되면 @__DIR__ 의 결과가 미리 컴파일된 패키지 데이터에 구워지며 이 패키지를 배포하려고 하면 잘못된 위치에서 파일을 로드하려고 시도합니다. 아티팩트를 뭉치고 artifact"name" 문자열 매크로를 사용하여 쉽게 액세스할 수 있습니다. 아티팩트는 Julia 1.3부터 사용할 수 있습니다.

  • Scratch.jl 은 패키지에 대한 변경 가능한 데이터 컨테이너인 "스크래치 공간"이라는 개념을 제공합니다. 스크래치 공간은 패키지에 의해 완전히 관리되는 데이터 캐시를 위해 설계되었으며 패키지 자체가 제거될 때 제거되어야 합니다. 중요한 사용자 생성 데이터의 경우 패키지는 Julia 또는 Pkg에서 관리하지 않는 사용자 지정 경로에 계속 작성해야 합니다. Scratch는 Julia 1.5부터 사용할 수 있습니다.

  • Preferences.jl을 사용하면 패키지가 최상위 Project.toml에 대한 기본 설정을 읽고 쓸 수 있습니다. 이러한 기본 설정은 패키지 동작의 다양한 측면을 활성화 또는 비활성화하기 위해 런타임 또는 컴파일 타임에 읽을 수 있습니다. 이전에는 패키지가 사용자 또는 환경에서 설정한 옵션을 기록하기 위해 자체 패키지 디렉토리에 파일을 작성했지만 이제는 Preferences 를 사용할 수 있으므로 권장하지 않습니다. Preferences 는 Julia 1.6부터 사용할 수 있습니다.


6. 호환성 (Compatiblity)

호환성은 프로젝트가 호환되는 의존성의 버전을 제한하는 기능을 말합니다. 의존성에 대한 호환성이 지정되지 않은 경우 프로젝트는 해당 의존성의 모든 버전과 호환되는 것으로 간주됩니다.

의존성에 대한 호환성은 Project.toml 파일에 다음과 같이 입력됩니다.

[compat]
julia = "1.0"
Example = "0.4.3"

프로젝트 파일에 호환성 항목을 입력한 후 up 을 사용하여 적용할 수 있습니다.

버전 지정자의 형식은 아래에 자세히 설명되어 있습니다.

Info
compat 명령을 사용하여 Pkg REPL의 compat 항목을 편집하거나 프로젝트 파일을 수동으로 편집합니다.


버젼 지정 형식

다른 패키지 관리자와 마찬가지로 Julia 패키지 관리자는 semantic versioning(semver)을 따릅니다. 예를 들어 1.2.3 과 같이 주어진 버젼 지정자는 버전 [1.2.3 - 2.0.0) 과 호환되는 것으로 가정합니다. 여기서 ) 는 비포함 상한입니다. 보다 구체적으로 지정하기 위해 버전 지정자는 ^1.2.3 와 같은 캐럿 지정자 나, ~1.2.3 와 같은 물결표 지정자 가 될 수 있습니다. 캐럿 지정자가 기본값이므로 1.2.3 == ^1.2.3입니다. 캐럿과 물결표의 차이점은 다음 섹션에서 설명합니다. 여러 버전 지정자의 합집합은 개별 버전 지정자를 쉼표로 구분하여 형성할 수 있습니다. 예를 들어,

[compat]
Example = "1.2, 2"

의 결과는 [1.2.0, 3.0.0) 입니다. 가장 앞에 0 이 나오면 다르게 취급됩니다. Example = "0.2, 1"[0.2.0 - 0.3.0) \cup [1.0.0 - 2.0.0)만 됩니다. 가장 앞에 0 이 있는 버전에 대한 자세한 내용은 다음 섹션을 참조하세요.


0 으로 시작하는 버젼의 행동 (0.0.x 와 0.x.y)

semver 사양에는 주 버전이 0인 모든 버전(1.0.0 이전 버전)이 서로 호환되지 않는다고 나와 있지만 주 버전과 부 버전이 모두 0인 경우에만 적용하기로 했습니다. 즉, 0.0.1과 0.0.2는 호환되지 않는 것으로 간주됩니다. 0이 아닌 부 버전(0.a.b 에서 a != 0인 경우 )이 있는 1.0 이전 버전은 동일한 부 버전 및 더 작거나 동일한 패치 버전(0.a.c 에서 c <= b 인 경우)이 있는 버전과 호환되는 것으로 간주됩니다. 즉, 버전 0.2.2 및 0.2.3은 0.2.1 및 0.2.0과 호환됩니다. 주 버전이 0이고 다른 부 버전이 있는 버전은 호환되는 것으로 간주되지 않으므로 버전 0.3.0은 0.2.0에서 주요 변경 사항이 있을 수 있습니다. 이를 위한 [compat]항목은 다음과 같습니다.

[compat]
Example = "0.0.1"

여기서는 [0.0.1, 0.0.2)(버전 0.0.1에만 해당)로 Example 에 대한 버전 바인딩이 발생하는 반면 [compat]

[compat]
Example = "0.2.1"

라면,[0.2.1, 0.3.0) 으로 버전 바인딩이 발생합니다.

특히 패키지는 0.2.0과 역호환성을 유지하는 한 0.2.3과 비교하여 기능 추가가 있을 때 버전 = "0.2.4"를 설정할 수 있습니다. version 필드 도 참조하십시오.


캐럿 지정자

캐럿(^) 지정자는 semver에 따라 호환되는 업그레이드를 허용합니다. 지정자가 사용되지 않는 경우 이것이 기본 동작입니다. 업데이트된 의존성은 새 버전이 버전 지정자에서 가장 왼쪽의 0이 아닌 숫자를 수정하지 않는 경우 호환되는 것으로 간주됩니다.

몇 가지 예가 아래에 나와 있습니다.

[compat]
PkgA = "^1.2.3" # [1.2.3, 2.0.0)
PkgB = "^1.2"   # [1.2.0, 2.0.0)
PkgC = "^1"     # [1.0.0, 2.0.0)
PkgD = "^0.2.3" # [0.2.3, 0.3.0)
PkgE = "^0.0.3" # [0.0.3, 0.0.4)
PkgF = "^0.0"   # [0.0.0, 0.1.0)
PkgG = "^0"     # [0.0.0, 1.0.0)

물결표 지정자

물결표 지정자는 보다 제한된 업그레이드 가능성을 제공합니다. 주 버전, 부 버전, 패치 버전을 지정하거나 주 버전과 부 버전을 지정할 때 패치 버전만 변경할 수 있습니다. 주 버전만 지정하면 부 버전과 패치 버전을 모두 업그레이드할 수 있습니다(따라서 ~1^1과 같습니다). 예를 들어:

[compat]
PkgA = "~1.2.3" # [1.2.3, 1.3.0)
PkgB = "~1.2"   # [1.2.0, 1.3.0)
PkgC = "~1"     # [1.0.0, 2.0.0)
PkgD = "~0.2.3" # [0.2.3, 0.3.0)
PkgE = "~0.0.3" # [0.0.3, 0.0.4)
PkgF = "~0.0"   # [0.0.0, 0.1.0)
PkgG = "~0"     # [0.0.0, 1.0.0)

주 버전이 0인 모든 버전에서 물결표 및 캐럿 지정자는 동일합니다.


부등식 지정자

부등식을 사용하여 버전 범위를 지정할 수도 있습니다.

[compat]
PkgB = ">= 1.2.3" # [1.2.3,  ∞)
PkgC = "≥ 1.2.3"  # [1.2.3,  ∞)
PkgD = "< 1.2.3"  # [0.0.0, 1.2.3) = [0.0.0, 1.2.2]

하이픈 지정자

하이픈 구문을 사용하여 버전 범위를 지정할 수도 있습니다. 하이픈 양쪽에 공백이 있는지 확인하십시오.

[compat]
PkgA = "1.2.3 - 4.5.6" # [1.2.3, 4.5.6]
PkgA = "0.2.3 - 4.5.6" # [0.2.3, 4.5.6]

두 번째 끝점의 지정되지 않은 후행 숫자는 와일드카드로 간주됩니다.

[compat]
PkgA = "1.2.3 - 4.5"   # 1.2.3 - 4.5.* = [1.2.3, 4.6.0)
PkgA = "1.2.3 - 4"     # 1.2.3 - 4.*.* = [1.2.3, 5.0.0)
PkgA = "1.2 - 4.5"     # 1.2.0 - 4.5.* = [1.2.0, 4.6.0)
PkgA = "1.2 - 4"       # 1.2.0 - 4.*.* = [1.2.0, 5.0.0)
PkgA = "1 - 4.5"       # 1.0.0 - 4.5.* = [1.0.0, 4.6.0)
PkgA = "1 - 4"         # 1.0.0 - 4.*.* = [1.0.0, 5.0.0)
PkgA = "0.2.3 - 4.5"   # 0.2.3 - 4.5.* = [0.2.3, 4.6.0)
PkgA = "0.2.3 - 4"     # 0.2.3 - 4.*.* = [0.2.3, 5.0.0)
PkgA = "0.2 - 4.5"     # 0.2.0 - 4.5.* = [0.2.0, 4.6.0)
PkgA = "0.2 - 4"       # 0.2.0 - 4.*.* = [0.2.0, 5.0.0)
PkgA = "0.2 - 0.5"     # 0.2.0 - 0.5.* = [0.2.0, 0.6.0)
PkgA = "0.2 - 0"       # 0.2.0 - 0.*.* = [0.2.0, 1.0.0)

Julia 1.4
하이픈 지정자는 최소한 Julia 1.4가 필요하므로 사용할 때 프로젝트 파일에 add 하는 것이 좋습니다

[compat]
julia = "1.4"

충돌 수정

버전 충돌은 다른 두 패키지인 BC 에서 사용하는 패키지 D 에서 발생하는 충돌의 예와 함께 이전에 소개되었습니다. 오류 메시지를 분석한 결과 B가 오래된 버전의 D를 사용하고 있음이 밝혀졌습니다. 이를 해결하기 위해 가장 먼저 시도하는 것은 B 와 해당 호환성 요구 사항을 수정할 수 있도록 pkg> dev B 를 수행하는 것입니다. 편집기에서 Project.toml파일을 열면 다음과 같은 내용을 알 수 있습니다.

[compat]
D = "0.1"

일반적으로 첫 번째 단계는 이것을 다음과 같이 수정하는 것입니다.

[compat]
D = "0.1, 0.2"

이는 B가 버전 0.1 및 버전 0.2 모두와 호환됨을 나타냅니다. pkg> up 하면 패키지 오류가 수정됩니다. 그러나 먼저 해결해야 할 한 가지 중요한 문제가 있습니다. 아마도 Dv0.2B 를 손상시키는 호환되지 않는 변경이 있었을 수 있습니다. 더 진행하기 전에 모든 패키지를 업데이트한 다음 B 의 테스트를 실행하여 pkg> test B 의 출력을 스캔해서 Dv0.2가 실제로 사용되고 있는지 확인해야 합니다. (D 의 추가 의존성으로 인해 v0.1 에 고정될 수 있으며 최신 버전에서 B 를 테스트했다고 잘못 생각하고 싶지 않을 것입니다.) 새 버전이 사용되었고 테스트가 여전히 통과된 경우, Dv0.2 를 수용하기 위해 B 가 추가 업데이트가 필요하지 않다고 가정할 수 있습니다. 새 릴리스가 만들어지도록 이 변경 사항을 풀 요청으로 B 에 안전하게 제출할 수 있습니다. 대신 오류가 발생하면 BD 의 최신 버전과 호환되기 위해 더 광범위한 업데이트가 필요함을 나타냅니다. 이러한 업데이트는 AB 를 동시에 사용할 수 있게 되기 전에 완료되어야 합니다. 그러나 서로 독립적으로 계속 사용할 수 있습니다.


7. 레지스트리

레지스트리에는 사용 가능한 릴리스, 의존성, 다운로드할 수 있는 위치와 같은 패키지에 대한 정보가 포함되어 있습니다. General 레지스트리(https://github.com/JuliaRegistries/General) 는 기본 레지스트리이며 다른 레지스트리가 설치되어 있지 않으면 자동으로 설치됩니다.


레지스트리 관리

Julia 1.1
Pkg의 레지스트리 처리에는 최소한 Julia 1.1이 필요합니다.


레지스트리는 Pkg REPL에서, 또는 함수적 API(functional API)를 사용하여 추가하거나 제거할수 있고, 업데이트할 수 있습니다. 이 섹션에서는 REPL 인터페이스에 대해 설명합니다. 레지스트리 API는 Registry API Reference에 설명되어 있습니다.


레지스트리 추가

Pkg REPL에서 registry add 명령을 사용하여 사용자 지정 레지스트리를 추가할 수 있습니다. 일반적으로 이것은 레지스트리에 대한 URL로 수행됩니다.

사용자 지정 레지스트리를 추가하면 General 레지스트리가 자동으로 추가되지 않을 수 있습니다. 이 경우 General 레지스트리를 수동으로 추가하기만 하면 됩니다.

pkg> registry add https://github.com/JuliaRegistries/General
   Cloning registry from "https://github.com/JuliaRegistries/General"
     Added registry `General` to `~/.julia/registries/General`

이제 General 에 등록된 모든 패키지를 추가하는 등에 사용할 수 있습니다. 현재 설치된 레지스트리를 확인하려면 registry status(또는 registry st) 명령을 사용할 수 있습니다.

pkg> registry st
Registry Status
 [23338594] General (https://github.com/JuliaRegistries/General.git)

레지스트리는 항상 DEPOT_PATH의 첫 번째 항목인 사용자 저장소에 추가됩니다(용어 섹션 참조).


레지스트리 제거

레지스트리는 registry remove(또는 registry rm) 명령으로 제거할 수 있습니다. 여기에서 General 레지스트리를 제거합니다.

pkg> registry rm General
  Removing registry `General` from ~/.julia/registries/General

pkg> registry st
Registry Status
  (no registries found)

General 이라는 이름의 레지스트리가 여러 개 설치되어 있는 경우 패키지를 조작할 때와 마찬가지로 uuid 로 구분해야 합니다.

pkg> registry rm General=23338594-aafe-5451-b93e-139f81909106
  Removing registry `General` from ~/.julia/registries/General

레지스트리 업데이트

registry update(또는 registry up) 명령을 사용하여 레지스트리를 업데이트할 수 있습니다. 여기에서 General 레지스트리를 업데이트합니다.

pkg> registry up General
  Updating registry at `~/.julia/registries/General`
  Updating git-repo `https://github.com/JuliaRegistries/General`

설치된 모든 레지스트리를 업데이트하려면 다음을 수행하십시오.

pkg> registry up
  Updating registry at `~/.julia/registries/General`
  Updating git-repo `https://github.com/JuliaRegistries/General`

레지스트리 개설과 유지

Pkg는 레지스트리를 생성하거나 유지 관리하는 기능이 아니라 레지스트리에 대한 클라이언트 기능만 제공합니다. 그러나 Registrator.jlLocalRegistry.jl 은 레지스트리를 만들고 업데이트하는 방법을 제공하고 RegistryCI.jl 은 레지스트리 유지 관리를 위한 자동화된 테스트 및 병합 기능을 제공합니다.


8. 아티팩트(Artifacts)

Julia 1.3
Pkg의 아티팩트 기능에는 최소한 Julia 1.3이 필요합니다.


Pkg는 Julia 패키지가 아닌 데이터 컨테이너를 설치하고 관리할 수 있습니다. 이러한 컨테이너는 플랫폼 마다의 바이너리, 데이터 세트, 텍스트 또는 다른 종류의 데이터(변경 불가능한 수명 주기 데이터 저장소(immutable, life-cycled datastore) 내에 배치하기에 편리한)를 포함할 수 있습니다. ("아티팩트(artifacts)" 라고 불리는) 이러한 컨테이너는 로컬에서 생성되고 어디에서나 호스팅되며 Julia 패키지 설치 시 자동으로 다운로드 및 압축 해제될 수 있습니다. 이 메커니즘은 BinaryBuilder.jl로 빌드된 패키지에 대한 바이너리 의존성을 제공하는 데에도 사용됩니다.


기본적인 사용법

Pkg 아티팩트는 Artifacts.toml 파일에서 선언되며 현재 디렉터리나 패키지의 루트에 배치할 수 있습니다. 현재 Pkg는 URL로부터 압축 가능한 tar 파일 다운로드를 지원합니다. 다음은 github.com 에서 socrates.tar.gz 파일을 다운로드할 수 있는 최소한의 Artifacts.toml 파일입니다. 이 예에서는 socrates 라는 이름이 지정된 단일 아티팩트가 정의됩니다.

# a simple Artifacts.toml file
[socrates]
git-tree-sha1 = "43563e7631a7eafae1f9f8d9d332e3de44ad7239"

    [[socrates.download]]
    url = "https://github.com/staticfloat/small_bin/raw/master/socrates.tar.gz"
    sha256 = "e65d2f13f2085f2c279830e863292312a72930fee5ba3c792b14c33ce5c5cc58"

Artifacts.toml 파일이 현재 디렉토리에 있는 경우 socrates.tar.gz 를 다운로드하고 압축을 풀고 artifact"socrates"와 함께 사용할 수 있습니다. 이 tarball에는 bin 폴더와 해당 폴더 내에 socrates 라는 텍스트 파일이 포함되어 있으므로 다음과 같이 해당 파일의 내용에 액세스할 수 있습니다.

using Pkg.Artifacts

rootpath = artifact"socrates"
open(joinpath(rootpath, "bin", "socrates")) do file
    println(read(file, String))
end

URL을 통해 액세스할 수 있는 기존 tarball이 있는 경우 이 방식으로도 액세스할 수 있습니다. Artifacts.toml 을 만들려면 다운로드 파일의 sha256 해시와 압축을 푼 콘텐츠의 git-tree-sha1 이라는 두 가지 해시를 계산해야 합니다. 다음과 같이 계산할 수 있습니다.

using Tar, Inflate, SHA

filename = "socrates.tar.gz"
println("sha256: ", bytes2hex(open(sha256, filename)))
println("git-tree-sha1: ", Tar.tree_hash(IOBuffer(inflate_gzip(filename))))

Artifacts.toml 파일

Pkg 는 패키지에서 아티팩트 사용을 기록하고 패키지 설치 시 아티팩트 다운로드를 자동화하기 위해 TOML 파일 형식뿐만 아니라 아티팩트 작업을 위한 API를 제공합니다. 아티팩트는 항상 콘텐츠 해시에 의해 참조될 수 있지만 일반적으로 프로젝트의 소스 트리에 있는 Artifacts.toml 파일의 콘텐츠 해시에 바인딩된 이름으로 액세스됩니다.

주의
Project.tomlManifest.toml 대신 JuliaProject.tomlJuliaManifest.toml을 사용할 수 있는 것과 비슷하게 JuliaArtifacts.toml 을 사용할 수 있습니다.


Artifacts.toml 파일의 예는 다음과 같습니다.

# Example Artifacts.toml file
[socrates]
git-tree-sha1 = "43563e7631a7eafae1f9f8d9d332e3de44ad7239"
lazy = true

    [[socrates.download]]
    url = "https://github.com/staticfloat/small_bin/raw/master/socrates.tar.gz"
    sha256 = "e65d2f13f2085f2c279830e863292312a72930fee5ba3c792b14c33ce5c5cc58"

    [[socrates.download]]
    url = "https://github.com/staticfloat/small_bin/raw/master/socrates.tar.bz2"
    sha256 = "13fc17b97be41763b02cbb80e9d048302cec3bd3d446c2ed6e8210bddcd3ac76"

[[c_simple]]
arch = "x86_64"
git-tree-sha1 = "4bdf4556050cb55b67b211d4e78009aaec378cbc"
libc = "musl"
os = "linux"

    [[c_simple.download]]
    sha256 = "411d6befd49942826ea1e59041bddf7dbb72fb871bb03165bf4e164b13ab5130"
    url = "https://github.com/JuliaBinaryWrappers/c_simple_jll.jl/releases/download/c_simple+v1.2.3+0/c_simple.v1.2.3.x86_64-linux-musl.tar.gz"

[[c_simple]]
arch = "x86_64"
git-tree-sha1 = "51264dbc770cd38aeb15f93536c29dc38c727e4c"
os = "macos"

    [[c_simple.download]]
    sha256 = "6c17d9e1dc95ba86ec7462637824afe7a25b8509cc51453f0eb86eda03ed4dc3"
    url = "https://github.com/JuliaBinaryWrappers/c_simple_jll.jl/releases/download/c_simple+v1.2.3+0/c_simple.v1.2.3.x86_64-apple-darwin14.tar.gz"

[processed_output]
git-tree-sha1 = "1c223e66f1a8e0fae1f9fcb9d3f2e3ce48a82200"

Artifacts.toml은 세 가지 아티팩트를 바인딩합니다. 하나는 socrates, 하나는 c_simple, 다른 하나는 processed_output 입니다. 아티팩트에 필요한 단일 정보는 git-tree-sha1 입니다. 아티팩트는 콘텐츠 해시로만 처리되기 때문에 Artifacts.toml 파일의 목적은 사람이 읽을 수 있는 이름을 콘텐츠 해시에 바인딩하고, 아티팩트를 다운로드할 수 있는 위치에 대한 정보를 제공하는 것과 같은 아티팩트에 대한 메타데이터를 제공하는 것입니다. 또는 단일 이름을 운영 체제 또는 libgfortran 버전과 같은 플랫폼별 제약 조건에 의해 키가 지정되는 여러 해시에 바인딩할 수도 있습니다.


아티팩트 타입과 프로퍼티

위의 예에서 socrates 아티팩트는 여러 다운로드 위치가 있는 플랫폼 독립적 아티팩트를 보여줍니다. socrates 아티팩트를 다운로드하고 설치할 때 URL은 성공할 때까지 순서대로 시도됩니다. socrates 아티팩트는 lazy 로 표시됩니다. 즉, 포함 패키지가 설치될 때 자동으로 다운로드되지 않고 패키지가 처음 사용하려고 할 때 주문형으로 다운로드됩니다.

c_simple 아티팩트는 플랫폼 의존적인 아티팩트를 보여줍니다. 여기서 c_simple 배열의 각 항목에는 호출 패키지가 호스트 시스템의 특정 사항을 기반으로 적절한 다운로드를 선택하는 데 도움이 되는 키가 포함되어 있습니다. 각 아티팩트에는 각 다운로드 항목에 대한 git-tree-sha1sha256 이 모두 포함되어 있습니다. 이것은 압축을 풀기 전에 다운로드한 타르볼이 안전한지 확인하고 모든 타르볼이 동일한 전체 트리 해시로 확장되도록 하기 위한 것입니다.

processed_output 아티팩트에는 download 구문이 포함되어 있지 않으므로 설치할 수 없습니다. 이런 아티팩트는 이전에 실행되어 새 아티팩트를 생성하고 결과 해시를 이 프로젝트 내의 이름에 바인딩하는 코드의 결과물이 될 것입니다.


아티팩트 사용

Pkg.Artifacts 네임스페이스에서 노출되는 편리한 API를 사용하여 아티팩트를 조작할 수 있습니다. 동기를 부여하는 예로 Iris 기계 학습 데이터 세트를 로드해야 하는 패키지를 작성한다고 가정해 보겠습니다. 빌드 단계에서 패키지 디렉토리로 데이터 세트를 다운로드할 수 있고 현재 많은 패키지가 이를 정확하게 수행하지만 몇 가지 중요한 단점이 있습니다.

  • 첫째, 이는 패키지 디렉토리를 수정하여, 패키지 설치를 stateful 로 만드는데 이는 우리가 피하고 싶은 것입니다. 앞으로는 패키지가 설치 후 자체적으로 수정되는 대신 완전히 읽기 전용으로 설치될 수 있는 지점에 도달하고자 합니다.

  • 둘째, 다운로드된 데이터는 패키지의 다른 버전 간에 공유되지 않습니다. 다양한 프로젝트에서 사용하기 위해 설치된 세 가지 다른 버전의 패키지가 있는 경우 해당 버전 간에 변경되지 않았더라도 데이터의 세 가지 다른 복사본이 필요합니다. 또한 패키지를 업그레이드하거나 다운그레이드할 때마다 영리한(아마도 안전하지 않은) 작업을 수행하지 않는 한 데이터를 다시 다운로드해야 합니다.

아티팩트를 사용하면 iris 아티팩트가 디스크에 이미 존재하는지 확인하고 그렇지 않은 경우에만 다운로드하여 설치한 다음 결과를 Artifacts.toml 파일에 바인딩할 수 있습니다.

using Pkg.Artifacts

# This is the path to the Artifacts.toml we will manipulate
artifact_toml = joinpath(@__DIR__, "Artifacts.toml")

# Query the `Artifacts.toml` file for the hash bound to the name "iris"
# (returns `nothing` if no such binding exists)
iris_hash = artifact_hash("iris", artifact_toml)

# If the name was not bound, or the hash it was bound to does not exist, create it!
if iris_hash == nothing || !artifact_exists(iris_hash)
    # create_artifact() returns the content-hash of the artifact directory once we're finished creating it
    iris_hash = create_artifact() do artifact_dir
        # We create the artifact by simply downloading a few files into the new artifact directory
        iris_url_base = "https://archive.ics.uci.edu/ml/machine-learning-databases/iris"
        download("$(iris_url_base)/iris.data", joinpath(artifact_dir, "iris.csv"))
        download("$(iris_url_base)/bezdekIris.data", joinpath(artifact_dir, "bezdekIris.csv"))
        download("$(iris_url_base)/iris.names", joinpath(artifact_dir, "iris.names"))
    end

    # Now bind that hash within our `Artifacts.toml`.  `force = true` means that if it already exists,
    # just overwrite with the new content-hash.  Unless the source files change, we do not expect
    # the content hash to change, so this should not cause unnecessary version control churn.
    bind_artifact!(artifact_toml, "iris", iris_hash)
end

# Get the path of the iris dataset, either newly created or previously generated.
# this should be something like `~/.julia/artifacts/dbd04e28be047a54fbe9bf67e934be5b5e0d357a`
iris_dataset_path = artifact_path(iris_hash)

이전에 바인딩된 아티팩트를 사용하는 특별한 사례의 경우 현재 패키지에 포함된 Artifacts.toml 파일을 자동으로 검색하고 지정된 아티팩트를 이름으로 조회하고 설치하는 약식 표기인 artifact"name" 이 있습니다. 아직 설치되지 않은 경우 해당 아티팩트의 경로를 반환합니다. 이 약식 표기법의 예는 다음과 같습니다.

using Pkg.Artifacts

# For this to work, an `Artifacts.toml` file must be in the current working directory
# (or in the root of the current package) and must define a mapping for the "iris"
# artifact.  If it does not exist on-disk, it will be downloaded.
iris_dataset_path = artifact"iris"

Pkg.Artifacts API

Artifacts API는 해시 인식 기능, 이름 인식 기능 및 유틸리티 기능의 세 가지 수준으로 나뉩니다.

  • 해시 인식 기능은 콘텐츠 해시를 처리하며 본질적으로 다른 것은 처리하지 않습니다. 이러한 메서드를 사용하면 아티팩트가 있는지 여부, 경로가 무엇인지 쿼리하고 아티팩트가 디스크의 콘텐츠 해시를 충족하는지 확인하는 등의 작업을 수행할 수 있습니다. 해시 인식 기능에는 다음이 포함됩니다 : artifact_exists(), artifact_path(), remove_artifact(), verify_artifact()archive_artifact(). 일반적으로 remove_artifact() 를 사용하지 말고 대신 Pkg.gc() 를 사용하여 아티팩트 설치를 정리해야 합니다.

  • 이름 인식 기능은 Artifacts.toml 파일 내에서 바인딩된 이름을 처리하므로 일반적으로 Artifacts.toml 파일에 대한 경로와 아티팩트 이름이 모두 필요합니다. 이름 인식 기능에는 다음이 포함됩니다 : artifact_meta(), artifact_hash(), bind_artifact!(), unbind_artifact!(), download_artifact() and ensure_artifact_installed().

  • 유틸리티 함수는 create_artifact(), ensure_all_artifacts_installed(), 심지어 @artifact_str 문자열 매크로와 같은 아티팩트 수명의 여러가지 측면을 처리합니다.

docstring 및 메서드의 전체 목록은 Artifacts API 레퍼런스 섹션을 참조하세요.


아티팩트 위치 오버라이딩

경우에 따라 아티팩트의 위치와 콘텐츠를 재정의할 수 있어야 합니다. 일반적인 사용 사례는 패키지가 게시된 이 의존성의 버전에 관계없이 특정 버전의 이진 의존성을 사용해야 하는 컴퓨팅 환경입니다. 일반적인 Julia 구성이 일반 라이브러리를 다운로드하고 압축을 풀고 연결하는 동안 시스템 관리자는 이를 비활성화하고 대신 로컬 시스템에 이미 설치된 라이브러리를 사용할 수 있습니다. 이를 활성화하기 위해 Pkg 는 아티팩트 저장소 디렉터리(예: 기본 사용자 저장소의 경우 ~/.julia/artifacts/Overrides.toml)에 있는 저장소별 Overrides.toml 파일을 지원합니다. 해시 또는 패키지 UUID 및 바인딩된 아티팩트 이름으로. 또한 대상 위치는 절대 경로이거나 대체 아티팩트 콘텐츠 해시일 수 있습니다. 이를 통해 시스템 관리자는 새 아티팩트를 사용하도록 다른 패키지를 재정의하여 사용할 수 있는 자체 아티팩트를 생성할 수 있습니다.

# Override single hash to absolute path
78f35e74ff113f02274ce60dab6e92b4546ef806 = "/path/to/replacement"

# Override single hash to new artifact content-hash
683942669b4639019be7631caa28c38f3e1924fe = "d826e316b6c0d29d9ad0875af6ca63bf67ed38c3"

# Override package bindings by specifying the package UUID and bound artifact name
# For demonstration purposes we assume this package is called `Foo`
[d57dbccd-ca19-4d82-b9b8-9d660942965b]
libfoo = "/path/to/libfoo"
libbar = "683942669b4639019be7631caa28c38f3e1924fe"

Pkg 저장소의 계층적 특성으로 인해 여러 Overrides.toml 파일이 한 번에 적용될 수 있습니다. 이렇게 하면 "내부" Overrides.toml 파일이 "외부" Overrides.toml 파일 내에 배치된 재정의를 재정의할 수 있습니다. 재정의를 제거하고 아티팩트에 대한 기본 위치 논리를 다시 활성화하려면 빈 문자열에 대한 항목 매핑을 삽입합니다.

78f35e74ff113f02274ce60dab6e92b4546ef806 = "/path/to/new/replacement"
683942669b4639019be7631caa28c38f3e1924fe = ""

[d57dbccd-ca19-4d82-b9b8-9d660942965b]
libfoo = ""

위에 주어진 두 개의 Overrides.toml 스니펫이 서로 위에 겹쳐 있는 경우 최종 결과는 콘텐츠 해시 78f35e74ff113f02274ce60dab6e92b4546ef806"/path/to/new/replacement" 에 매핑하고 Foo.libbar 를 콘텐츠 해시 683942669b4639019be7631caa28c38f3e1924fe 에 의해 식별된 아티팩트에 매핑합니다. 해당 해시는 이전에 재정의되었지만 더 이상 재정의되지 않으므로 Foo.libbar~/.julia/artifacts/683942669b4639019be7631caa28c38f3e1924fe 와 같은 위치를 직접 확인합니다.

재정의의 영향을 받는 대부분의 메서드는 honor_overrides=false 를 키워드 인수로 설정하여 재정의를 무시할 수 있습니다. UUID/이름 기반의 오버라이드가 작동하려면 Artifacts.toml 파일을 로드하는 패키지의 UUID 를 알고 로드해야 합니다. 이것은 artifacts"" 문자열 매크로에 의해 자동으로 추론되지만 어떤 이유로 패키지 내에서 Pkg.Artifacts API를 수동으로 사용하고 재정의를 적용하려는 경우에는 artifact_meta()pkg_uuid 키워드 인자를 통한 ensure_artifact_installed() 와 같은 API 호출에 패키지 UUID 가 필요합니다.


플랫폼 선택 확장

Julia 1.7
Pkg의 확장된 플랫폼 선택에는 최소한 Julia 1.7이 필요하며 실험적인 것으로 간주됩니다.


Julia 1.6의 새로운 기능인 Platform 개체는 확장된 특성을 적용할 수 있으므로 아티팩트에 CUDA 드라이버 버전 호환성, 마이크로아키텍처 호환성, Julia 버전 호환성 등과 같은 태그를 지정할 수 있습니다! 이 기능은 실험적인 것으로 간주되며 향후 변경될 수 있습니다. 패키지 개발자로서 이 기능이 필요한 경우 전체 생태계의 이익을 위해 발전할 수 있도록 우리에게 문의하십시오. Pkg.add() 시간에 아티팩트 선택을 지원하기 위해 Pkg 는 특별하게 이름지어진 파일 <project_root>/.pkg/select_artifacts.jl 을 실행하여 현재 플랫폼 트리플릿을 첫 번째 인수로 전달합니다. 이 아티팩트 선택 스크립트는 지정된 플랫폼에 따라 이 패키지에 필요한 아티팩트를 나타내는 TOML 직렬화된 사전을 출력하고 지정된 플랫폼에서 플랫폼 트리플릿을 명시적으로 제공하지 않는 경우 플랫폼 기능을 자동 감지하는 데 필요한 시스템 검사를 수행해야 합니다. 사전의 형식은 Artifacts.select_downloadable_artifacts() 에서 반환된 형식과 일치해야 하며 실제로 대부분의 패키지는 확장된 Platform 객체로 해당 함수를 호출해야 합니다. 아티팩트 선택 후크 정의의 예는 다음과 같을 수 있으며 두 파일로 분할됩니다.

# .pkg/platform_augmentation.jl
using Libdl, Base.BinaryPlatforms
function augment_platform!(p::Platform)
    # If this platform object already has a `cuda` tag set, don't augment
    if haskey(p, "cuda")
        return p
    end

    # Open libcuda explicitly, so it gets `dlclose()`'ed after we're done
    dlopen("libcuda") do lib
        # find symbol to ask for driver version; if we can't find it, just silently continue
        cuDriverGetVersion = dlsym(lib, "cuDriverGetVersion"; throw_error=false)
        if cuDriverGetVersion !== nothing
            # Interrogate CUDA driver for driver version:
            driverVersion = Ref{Cint}()
            ccall(cuDriverGetVersion, UInt32, (Ptr{Cint},), driverVersion)

            # Store only the major version
            p["cuda"] = div(driverVersion, 1000)
        end
    end

    # Return possibly-altered `Platform` object
    return p
end
using TOML, Artifacts, Base.BinaryPlatforms
include("./platform_augmentation.jl")
artifacts_toml = joinpath(dirname(@__DIR__), "Artifacts.toml")

# Get "target triplet" from ARGS, if given (defaulting to the host triplet otherwise)
target_triplet = get(ARGS, 1, Base.BinaryPlatforms.host_triplet())

# Augment this platform object with any special tags we require
platform = augment_platform!(HostPlatform(parse(Platform, target_triplet)))

# Select all downloadable artifacts that match that platform
artifacts = select_downloadable_artifacts(artifacts_toml; platform)

# Output the result to `stdout` as a TOML dictionary
TOML.print(stdout, artifacts)

이 후크 정의에서 우리의 플랫폼 보강 루틴은 시스템 라이브러리(libcuda)를 열고 CUDA 드라이버 버전을 제공하는 기호를 검색한 다음 해당 버전 번호의 주 버전을 우리가 보강하는 Platform 개체의 cuda 속성에 포함합니다. 이 코드가 실제로 로드된 라이브러리를 닫으려고 시도하는 것은 중요하지 않지만(패키지 작업이 완료된 직후 CUDA 패키지에 의해 다시 열릴 가능성이 높으므로) 후크를 가능한 한 가볍고 투명하게 만드는 것이 가장 좋은데 이는 향후 다른 Pkg 유틸리티에서 사용할 수 있기 때문입니다. 자체 패키지에서 다음과 같이 @artifact_str 매크로를 사용할 때 확장된 플랫폼 개체도 사용해야 합니다.

include("../.pkg/platform_augmentation.jl")

function __init__()
    p = augment_platform!(HostPlatform())
    global my_artifact_dir = @artifact_str("MyArtifact", p)
end

이렇게 하면 Pkg가 설치를 시도할 때 동일한 아티팩트가 코드에서 사용됩니다.

9. 용어 (Glossary)

프로젝트(Project): 표준 레이아웃이 있는 소스 트리로 다음을 포함합니다 : 1) Julia 코드의 본문을 위한 src 디렉토리, 2) 프로젝트 테스트를 위한 test 디렉토리, 3) 문서 파일을 위한 docs 디렉토리, 4) 선택적으로 빌드 스크립트 및 해당 출력을 위한 deps 디렉토리. 프로젝트에는 일반적으로 project 파일도 있으며 선택적으로 manifest 파일이 있을 수 있습니다.

  • Project 파일: Project.toml(또는 JuliaProject.toml)이라는 이름의 프로젝트 루트 디렉터리에 있는 파일로 프로젝트 이름, UUID(패키지용), 작성자, 라이선스, 의존하는 패키지와 라이브러리의 이름 및 UUID를 포함하여 프로젝트에 대한 메타데이터를 설명합니다.

  • Manifest 파일: 프로젝트의 루트 디렉터리에 있는 Manifest.toml(또는 JuliaManifest.toml)이라는 이름의 파일로, 전체 의존성 그래프와 프로젝트에서 사용하는 각 패키지 및 라이브러리의 정확한 버전을 설명합니다.

패키지(Package): import X 또는 using X를 사용하여 다른 Julia 프로젝트에서 사용할 수 있는 재사용 가능한 기능을 제공하는 프로젝트입니다. 패키지에는 패키지 UUID를 제공하는 uuid 항목이 있는 프로젝트 파일이 있어야 합니다. 이 UUID는 의존하는 프로젝트에서 패키지를 식별하는 데 사용됩니다.


주의
하위호환성을 위해 REPL 또는 스크립트의 최상위 수준에서 프로젝트 파일이나 UUID 없이 패키지를 로드할 수 있습니다. 그러나 프로젝트 파일이나 UUID가 없는 패키지는 프로젝트에서 로드할 수 없습니다. 프로젝트 파일에서 로드하면 프로젝트 파일과 UUID가 모두 필요합니다.


응용프로그램(Application): 다른 Julia 프로젝트에서 재사용할 의도가 없는 독립 실행 기능을 제공하는 프로젝트입니다. 예를 들어 웹 애플리케이션이나 커맨드라인 유틸리티 또는 과학 논문과 함께 제공되는 시뮬레이션/분석 코드가 있습니다. 응용프로그램에 UUID가 있을 수 있지만 필요하지는 않습니다. 응용 프로그램은 의존하는 패키지에 대한 전역 구성 옵션을 제공할 수도 있습니다. 반면에 패키지는 기본 응용 프로그램의 구성과 충돌할 수 있으므로 전역 구성을 제공하지 않을 수 있습니다.


주의
프로젝트 vs. 패키지 vs. 응용프로그램

  1. 프로젝트는 포괄적인 용어입니다 : 패키지와 응용프로그램은 일종의 프로젝트입니다.
  2. 패키지에는 UUID가 있어야 하며 응용프로그램에는 UUID가 있을 수 있지만 필요하지는 않습니다.
  3. 응용프로그램은 글로벌 구성을 제공할 수 있지만 패키지는 제공할 수 없습니다.

환경(Environment): 다음 세가지의 조합입니다 - 1) 프로젝트 파일에서 제공하는 최상위 이름 맵 2) 의존성 그래프 3) 매니페스트 파일에서 제공하는 패키지에서 진입점까지의 맵. 자세한 내용은 코드 로딩에 대한 설명서 섹션을 참조하십시오.

  • 명시적 환경 (Explicit environment): 명시적인 프로젝트 파일 형식으로 된 환경(environment)과 선택사항인 해당 매니페스트 파일이 디렉터리에 함께 있습니다. 매니페스트 파일이 없으면 묵시적 의존성 그래프와 위치 맵이 비어 있습니다.

  • 암시적 환경 (Implicit environment): X.jl, X.jl/src/X.jl 또는 X/src/X.jl 형식의 진입지점이 있는 패키지를 포함하는 디렉토리(프로젝트 파일 또는 매니페스트 파일 없음)로 제공되는 환경입니다. 최상위 이름 맵은 이러한 진입점에 의해 암시됩니다. 의존성 그래프는 패키지 디렉토리 내부에 X.jl/Project.toml 또는 X/Project.toml 와 같은 프로젝트 파일의 존재로부터 암시됩니다. . X 패키지의 의존성은 해당 프로젝트 파일(있는 경우)의 의존성입니다. 위치 맵은 진입점 자체에 의해 암시됩니다.


레지스트리(Registry): 표준 레이아웃이 존재하는 메타데이터를 기록하는 소스트리 입니다. 이 메타데이터의 내용은 1) 등록된 패키지 집합, 2) 패키지들이 사용 가능한지, 어떤 버젼에서 서로 호환되거나 되지 않는지에 대한 태그된 버젼 입니다. 레지스트리는 패키지 이름과 UUID로 인덱싱되며 아래의 메타데이터를 제공하는 등록된 각 패키지에 대한 디렉토리가 있습니다.

  • name - 예를 들면 DataFrames

  • UUID - 예를 들면 a93c6f00-e57d-5684-b7b6-d8193f3e46c0

  • repository - 예를 들면 https://github.com/JuliaData/DataFrames.jl.git

  • versions - 모든 등록된 버젼 태그들의 목록

각각의 등록된 패키지 버젼들에 대해 아래의 정보가 제공된다

  • semantic version name - 예를 들면 v1.2.3

  • git tree SHA-1 hash - 예를 들면 7ffb18ea3245ef98e368b02b81e8a86543a11103

  • 이름부터 의존성의 UUID 에 대한 맵

  • 호환가능하거나 호환 불가능한 다른 패키지의 버젼들

의존성과 호환성은 압축되었지만 사람이 읽을 수 있는 패키지 버젼의 범위를 사용하는 형식으로 저장됩니다.


저장소 (Depot) : 다양한 패키지 관련 리소스들이 위치하는 시스템상의 디렉토리로 다음을 포함합니다.

  • environment : 공유되는 이름이 붙여진 환경 (예를 들면 v1.0 devtools)

  • clones : 패키지 저장소에 있는 그대로의 복제본

  • compiled : 컴파일되어 캐쉬된 패키지 이미지 (.jl 파일들)

  • config : 전역적인 설정 파일들 (예를 들면 startup.jl)

  • dev : 패키지 개발의 기본 디렉토리

  • logs : 로그 파일들 (예를 들면 manifest_usage.toml, repl_history.jl)

  • packages : 설치된 패키지 버젼

  • registries : 레지스트리의 복제본 (예를 들면 General)

로드 경로 (Load path): 패키지 ID 와 의존성 및 진입점이 검색되는 환경의 스택입니다. 로드 경로는 JULIA_LOAD_PATH 환경 변수의 값을 기반으로 시작할 때 채워지는 LOAD_PATH 전역 변수에 의해 Julia에서 제어됩니다. 첫 번째 항목은 주로 현재 프로젝트인 기본 환경이며, 이후 항목은 REPL 또는 최상위 스크립트에서 사용할 수 있는 추가 패키지를 제공합니다.

저장소 경로 (Depot path): 패키지 관리자와 Julia의 코드 로딩 메커니즘이 레지스트리, 설치된 패키지, 명명된 환경, repo 클론, 캐시된 컴파일된 패키지 이미지 및 구성 파일을 찾는 저장소 위치의 스택입니다. 저장소 경로는 JULIA_DEPOT_PATH 환경 변수의 값을 기반으로 시작 시 채워지는 Julia DEPOT_PATH 전역 변수에 의해 제어됩니다. 첫 번째 항목은 "사용자 저장소"이며 현재 사용자가 쓰기 가능하고 소유해야 합니다. 사용자 저장소는 레지스트리 복제, 새 패키지 버전 설치, 명명된 환경 생성 및 업데이트, 패키지 저장소 복제, 새로 컴파일된 패키지 이미지 파일 저장, 로그 파일 작성, 기본적으로 개발 패키지 체크아웃 및 전역 구성 데이터가 저장됩니다. 저장소 경로의 이후 항목은 읽기 전용으로 처리되며 시스템 관리자가 설치하고 관리하는 레지스트리, 패키지 등에 적합합니다.

10. Project.tomlManifest.toml

Pkg의 핵심인 두 파일은 Project.tomlManifest.toml 입니다. Project.tomlManifest.tomlTOML(따라서 .toml 확장자)로 작성되며 의존성, 버전, 패키지 이름, UUID 등에 대한 정보를 포함합니다.

주의
Project.tomlManifest.toml 파일은 패키지 관리자만 사용하는 것이 아닙니다. 그들은 또한 Julia의 코드 로딩에 의해 사용되며 예를 들자면 using Example 이 무슨 일을 해야하는지를 결정합니다. 자세한 내용은 Julia 설명서의 Code Loading 섹션을 참조하십시오.


Project.toml

프로젝트 파일은 상위 수준에서 프로젝트를 설명합니다. 예를 들어 패키지/프로젝트 의존성 및 호환성 제약 조건이 프로젝트 파일에 나열됩니다. 파일 항목은 아래에 설명되어 있습니다.


authors 필드

패키지의 경우 선택적인 authors 필드는 NAME <EMAIL> 형식으로 패키지 작성자를 설명하는 문자열 목록입니다. 예를 들어:

authors = ["Some One <someone@email.com>",
           "Foo Bar <foo@bar.com>"]

name 필드

패키지/프로젝트의 이름은 name 필드에 의해 결정됩니다:

name = "Example"

이름은 유효한 식별자(identifier) (숫자로 시작하지 않고 truefalse 도 아닌 일련의 유니코드 문자)여야 합니다. 패키지의 경우 패키지 작명 가이드를 따르는 것이 좋습니다. name 필드는 패키지의 필수 항목입니다.


uuid 필드

uuid 는 패키지/프로젝트에 대한 범용 고유 식별자 입니다. 예를 들어,

uuid = "7876af07-990d-54b4-ab0e-23690620f79a"

uuid 필드는 패키지의 대해 필수 항목입니다.

주의
임의의 UUIDs 를 생성하는데 UUIDs.uuid4() 를 사용하는 것을 추천합니다.


version 필드

version 은 패키지/프로젝트의 버전 번호가 포함된 문자열입니다. 주 버전, 부 버전 및 패치 번호의 3개 숫자로 구성되어야 하며 . 로 구분됩니다. 예를 들면 다음과 같습니다.

version = "1.2.5"

Julia는 Semantic Versioning(SemVer)를 사용하며 version 필드는 SemVer를 따라야 합니다. 기본 규칙은 다음과 같습니다.

  • 1.0.0 이전에는 모든 것이 가능하지만 주요 변경 사항을 만들면 부 버전이 증가해야 합니다.

  • 1.0.0 이후에는 주 버전을 올릴 때만 주요 변경 사항을 만듭니다.

  • 1.0.0 이후에는 마이너 버전을 올리지 않고 새로운 공개 API를 추가할 수 없습니다. 여기에는 특히 Base 또는 기타 패키지의 새로운 유형, 함수, 메서드 및 메서드 오버로드가 포함됩니다.

호환성 세션을 참고하세요.

Pkg.jl은 1.0.0 이전 버전의 경우 SemVer 사양과 다릅니다. 자세한 내용은 1.0 이전 동작 섹션을 참조하십시오.


[deps] 섹션

패키지/프로젝트의 모든 의존성은 [deps] 섹션에 열거됩니다. 각각의 의존성들은 name-uuid 쌍으로 열거됩니다. 예를 듦면 :

[deps]
Example = "7876af07-990d-54b4-ab0e-23690620f79a"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

보통은 [deps] 섹션에 수동으로 추가할 필요가 없습니다; 대신에 add 같은 Pkg 연산으로 다루어집니다.


[compat] 섹션

[deps] 에 열거된 의존성에 대한 호환성의 제약들은 [compat] 섹션에 열거됩니다. 예를 들면

[deps]
Example = "7876af07-990d-54b4-ab0e-23690620f79a"

[compat]
Example = "1.2"

호환성 섹션에 서로 다른 다양한 호환성 제약들이 자세히 설명하였습니다. 비록 julia[deps] 섹션에 의존성이 열거되지 않더라도, julia 자체에 대한 제약들을 열거할수도 있습니다. :

[compat]
julia = "1.1"

Manifest.toml

Manifest 파일은 환경 내의 패키지 상태에 대한 절대적인 기록입니다. 여기에는 프로젝트의 (직접 및 간접) 의존성에 대한 정확한 정보가 포함됩니다. Project.toml + Manifest.toml 쌍이 주어지면 정확히 동일한 패키지 환경을 인스턴스화할 수 있으며 이는 재현성에 매우 유용합니다. 자세한 내용은 Pkg.instantiate를 참조하세요.

주의
Manifest.toml 파일은 Pkg에서 생성되고 및 유지되며, 일반적으로 이 파일은 수동으로 수정하면 안 됩니다.


Manifest.toml 항목들

각각의 의존성은 manifest 파일에 자체 섹션이 있으며 해당 내용은 의존성이 환경에 추가된 방식에 따라 다릅니다. 모든 의존성 섹션에는 다음 항목의 조합이 포함됩니다.

  • uuid : the UUID for the dependency, for example uuid = "7876af07-990d-54b4-ab0e-23690620f79a".

  • deps: a vector listing the dependencies of the dependency, for example deps = ["Example", "JSON"].

  • version: a version number, for example version = "1.2.6".

  • path: a file path to the source code, for example path = /home/user/Example.

  • repo-url: a URL to the repository where the source code was found, for example repo-url = "https://github.com/JuliaLang/Example.jl.git".

  • repo-rev: a git revision, for example a branch repo-rev = "master" or a commit repo-rev = "66607a62a83cb07ab18c0b35c038fcd62987c9b1".

  • git-tree-sha1 : a content hash of the source tree, for example git-tree-sha1 = "ca3820cc4e66f473467d912c4b2b3ae5dc968444" .


추가된 패키지

예를 들어 pkg> add Example 와 같이 페키지 레지스트리로부터 패키지가 추가되거나 plg> add Example@1.2 와 같이 특정 버젼이 추가될 때, Manifest.toml 은 다음과 비슷합니다 :

[[Example]]
deps = ["DependencyA", "DependencyB"]
git-tree-sha1 = "8eb7b4d4ca487caade9ba3e85932e28ce6d6e1f8"
uuid = "7876af07-990d-54b4-ab0e-23690620f79a"
version = "1.2.3"

특히 이 패키지가 발견된 레지스트리에 해당 정보가 포함되어 있으므로 repo-url 이 존재하지 않는다는 점에 유의하십시오.


브랜치로 추가된 패키지

예를 들어 pkg> Example#masterpkg> add https://github.com/JuliaLang/Example.jl.git 와 같이 패키지의 특정 브랜치를 지정하여 를 추가할 때 의존성 섹션은 다음과 같습니다.

[[Example]]
deps = ["DependencyA", "DependencyB"]
git-tree-sha1 = "54c7a512469a38312a058ec9f429e1db1f074474"
repo-rev = "master"
repo-url = "https://github.com/JuliaLang/Example.jl.git"
uuid = "7876af07-990d-54b4-ab0e-23690620f79a"
version = "1.2.4"

우리가 추적하는 브랜치 (master) 와 원격 저장소 ulr ("https://github.com/JuliaLang/Example.jl.git") 모두 manifest 에 저장되는것을 알 수 있습니다.


커밋(commit) 을 통해 추가된 패키지

pkg> add Example#cf6ba6cc0be0bb5f56840188563579d67048be34 와 같이 커밋에 의해 지정되어 패키지를 추적할 때의 의존성 섹션은 다음과 같습니다.

[[Example]]
deps = ["DependencyA", "DependencyB"]
git-tree-sha1 = "54c7a512469a38312a058ec9f429e1db1f074474"
repo-rev = "cf6ba6cc0be0bb5f56840188563579d67048be34"
repo-url = "https://github.com/JuliaLang/Example.jl.git"
uuid = "7876af07-990d-54b4-ab0e-23690620f79a"
version = "1.2.4"

브랜치를 추적할 때와의 유일한한 차이점은 repo-rev 내용입니다.


개발된 패키지

pkg> develop Example 이나 pkg> develop /path/to/local/folder/Example 처럼 develop 를 통해 패키지를 추가하면 의존성 섹션은 다음과 같습니다.

[[Example]]
deps = ["DependencyA", "DependencyB"]
path = "/home/user/.julia/dev/Example/"
uuid = "7876af07-990d-54b4-ab0e-23690620f79a"
version = "1.2.4"

소스코드 경로가 포함되며 소스 트리에의 변화가 직접적으로 반영되는것에 주의하십시요.


고정된 패키지

고정된 패키지(pinned packages) 역시 manifest 파일에 기록됩니다; pkg> add Example; pin Example 에 의한 의존성 섹션은 다음과 같습니다.

[[Example]]
deps = ["DependencyA", "DependencyB"]
git-tree-sha1 = "54c7a512469a38312a058ec9f429e1db1f074474"
pinned = true
uuid = "7876af07-990d-54b4-ab0e-23690620f79a"
version = "1.2.4"

유일한 차이는 pinned = true 항목이 추가된 것입니다.


같은 이름을 가진 복수의 패키지

Julia는 UUID를 기반으로 패키지를 구분하므로 이름만으로는 패키지를 식별하기에 충분하지 않습니다. 동일한 환경에 이름은 같지만 UUID가 다른 여러 패키지가 있을 수 있습니다. 이러한 상황에서 Manifest.toml 파일은 약간 다르게 보입니다. 예를 들어 환경에 AB를 추가하고 Project.toml 파일이 다음과 같이 표시되는 상황을 고려하십시오.

[deps]
A = "ead4f63c-334e-11e9-00e6-e7f0a5f21b60"
B = "edca9bc6-334e-11e9-3554-9595dbb4349c"

A가 이제 B = "f41f7b98-334e-11e9-1257-49272045fb24"에 의존하는 경우, 즉 B 라는 이름을 가진 또 다른 패키지가 있을 경우, Manifest.toml 파일에 두 개의 다른 B 패키지가 있습니다. 이 경우 명확성을 위해 git-tree-sha1version 필드가 제거된 전체 Manifest.toml 파일은 다음과 같습니다.

[[A]]
uuid = "ead4f63c-334e-11e9-00e6-e7f0a5f21b60"

    [A.deps]
    B = "f41f7b98-334e-11e9-1257-49272045fb24"

[[B]]
uuid = "f41f7b98-334e-11e9-1257-49272045fb24"
[[B]]
uuid = "edca9bc6-334e-11e9-3554-9595dbb4349c"

이제 두 개의 B 패키지 배열이 있으며 A[deps] 섹션은 A가 의존하는 B 패키지에 대해 명시적으로 확장되었습니다.


11. REPL 모드 레퍼런스

영문 원문 참고


12. API 레퍼런스

영문 원문 참고

profile
Julia, Python, JS;Physics, Math, Image processing

0개의 댓글

Powered by GraphCDN, the GraphQL CDN