9.10. rok - 패키지 / 빌드 front-end
rok 는 cargo 식 front-end 입니다. 매니페스트 rok.rokon 과 lockfile rok.lock, 의존성, 환경, toolchain 고정, 스크립트 의존성을 맡고, 컴파일은 컴파일러 rokc (9.1) 를 불러 처리합니다. 런타임은 rokr (librokr.a) 입니다.
의존성이 없는 패키지는 매니페스트 없이 파일 규약만으로 빌드됩니다 (0.3.4). 이때 rok build 는 rokc build 와 같습니다.
9.10.1. 서브명령과 전역 옵션
| 서브명령 | 동작 |
|---|---|
new, init | 패키지 생성 (9.10.2) |
add, remove, update, deps | 의존성 (9.10.4) |
search, publish, yank, login, logout | stone (9.10.4a) |
env | 환경 (9.10.5) |
toolchain | toolchain (9.10.6) |
install, uninstall | REPL / Jupyter 용 라이브러리와 실행 파일 (9.10.5a) |
build, check, run, emit | 의존성을 붙여 rokc 에 위임 |
test, bench | rokc 가 의존성을 붙여 하네스를 빌드하고, rok 가 실행 (9.1) |
doc, lint, repl [path], lsp | 의존성을 붙여 rokc 에 위임 |
fmt, clean, demangle, profdata | 의존성 없이 rokc 에 위임 |
jupyter | 커널 실행 (--connection-file) 은 위임, jupyter install [--env <name>] 은 kernelspec 설치 (9.8.3) |
version, help | |
| (없음) | rok repl 과 같음 - REPL 시작 |
위임하는 서브명령은 같은 이름의 rokc 서브명령을 실행합니다. rok 는 자기 전역 옵션 (--env / --offline / --locked / --cwd, -- 앞 어디든) 만 소비하고, 나머지 인자는 그대로 넘기며 다음을 더합니다. test 와 bench 는 rok 가 rokc 로 하네스를 빌드하게만 하고 (--emit-harness) 실행은 직접 하므로 (9.1), 러너는 컴파일러에 속하지 않습니다.
- 의존 패키지마다
--extern name=<소스 디렉토리>.rok.lock을 따라 준비하며, 의존되는 쪽이 의존하는 쪽보다 앞입니다 (rok deps가 출력하는 순서). 미리 빌드는rokc가 합니다 (9.2.3). - 패키지 자신의 feature 는
--cfg feature=<f>로, 각 의존 패키지의 feature 는--extern-feature <name>=<f>로 (9.10.4c). build / run / test / bench / check / lint / doc / emit / repl / lsp / jupyter / deps 의 feature 옵션--features <f,..>(여러 번 가능,<dep>/<f>도),--all-features,--no-default-features는rok이 소비합니다 (--앞). - 매니페스트의
lints를-A/-W/-D로 (인자 앞에). 매니페스트는 경로가 고르는 프로젝트의 것입니다:.rok파일이면 그 파일 위치나 그 위에서src/main.rok,src/lib.rok,rok.rokon중 하나가 있는 가장 가까운 디렉토리. 패키지src/안의 파일은 그 패키지를 고릅니다 (9.1.1).rok.rokon이 있는 디렉토리의 그 밖의 단독 파일 (패키지src/옆의 스크립트, 또는rok.rokon만 있는 디렉토리) 은 그 매니페스트의lints(와lints_from) 와 의존성을 가진 단일 파일 패키지로 컴파일합니다. - 패키지 밖 (환경, 스크립트) 이면
--target-dir에 그 환경이나 스크립트의target/.
rok repl <path> 는 run 처럼 그 경로의 프로젝트에서 의존성과 lint 를 정하고, 매니페스트 이름을 넘깁니다 (--name).
옵션과 출력, 종료 코드는 rokc 의 것 (9.1) 을 따릅니다. rok 는 닫힌 표준 출력이나 표준 에러를 rokc 와 같은 방식으로 다룹니다 (9.1.6). rokls 는 rok lsp 와 같은 독립 실행 파일입니다.
서브명령 없이 rok [옵션] 만 실행하면 rok repl 과 같이 REPL 을 시작합니다.
rok # = rok repl
rok --env sci # = rok repl --env sci
rok [options] <file> [args..] 은 스크립트를 실행합니다: rok run -q <file> -- args.. 와 같습니다. 파일 뒤의 모든 인자는 그대로 프로그램에 넘기며, 종료 코드는 프로그램의 것입니다. 그 단어는 / (Windows 에서는 \ 도) 를 담거나 확장자가 .rok 이면 파일입니다. 그런 서브명령은 없으므로 서브명령을 파일로 오인하는 일은 없습니다. shebang 줄 (1.2.3) 과 함께 쓰면 ./script.rok args 가 스크립트를 실행합니다.
위임하는 명령의 경로는 옵션도 옵션의 값도 아닌 첫 인자이므로, 옵션이 그 앞에 와도 됩니다 (rok run --release t.rok).
rok 의 전역 옵션은 다음과 같습니다.
| 옵션 | 의미 |
|---|---|
--env <name> | 그 이름 있는 환경에서 작업함 (REPL, Jupyter, rok install). 패키지에 작용하는 명령에서는 에러 (9.10.5) |
--offline | 네트워크를 쓰지 않음. git 의존은 캐시에 있어야 함 |
--locked | rok.lock 을 바꿔야 하면 바꾸지 않고 에러 (CI 용) |
--cwd <dir> | 디렉토리를 바꾼 뒤 실행 |
-q, --quiet | 출력을 줄임 |
환경 변수는 ROK_HOME (기본 ~/.rok), ROK_ENV (9.10.5), ROK_TOOLCHAIN (9.10.6), ROK_REGISTRY (index) 와 ROK_REGISTRY_TOKEN (registry API 토큰) (9.10.4a), 그리고 ROK_DIST (릴리스 서버, 9.10.6) 입니다.
9.10.2. rok new / rok init: 패키지 생성
rok new [--lib] [--bin] <name>
rok init [--lib] [--bin] [dir]
rok init --script <file.rok>
rok new 는 <name> 디렉토리를 만들고 기본 파일을 채웁니다. --bin (기본값) 은 인사말을 출력하는 src/main.rok 를, --lib 는 예시 함수와 #[test] 하나를 담은 src/lib.rok 를 만듭니다. 둘을 함께 주면 둘 다 만들며, 그러면 src/main.rok 는 use <name>::add; 로 라이브러리의 함수를 부릅니다 (0.3.1). <name> 이 이미 있으면 에러입니다.
rok init 은 이미 있는 디렉토리 (생략하면 현재 디렉토리) 를 패키지로 만듭니다. 그 디렉토리에 src/main.rok 나 src/lib.rok 가 이미 있으면 에러입니다.
rok init --script <file.rok> 은 스크립트 (9.10.7) 를 그 스크립트의 디렉토리에서 파일 이름 (.rok 를 뗀 것) 을 딴 패키지로 바꿉니다. rok.rokon 은 스크립트 블록들을 합친 deps (와 native) 를 받으며, 경로는 그것 기준으로 다시 씁니다. 스크립트는 src/main.rok 가 되고, 그 mod 가 읽는 모든 파일은 같은 상대 경로로 src/ 아래로 옮기며, 각각 블록은 뺍니다. 스크립트가 패키지 안에 있거나, 옮길 파일이나 rok.rokon 이 이미 있거나, 서브모듈 파일이 스크립트의 디렉토리 밖에 있으면 에러입니다.
두 명령은 정규 형식 (ROKON 3.9.4) 의 rok.rokon 과 target/ 을 담은 .gitignore 도 쓰며, git 저장소 안이 아니면 git init 을 합니다. init 은 디렉토리 이름을 이름 규칙 (9.10.3) 에 맞게 바꿔 패키지 이름으로 씁니다.
hello/
├── .gitignore <- target/
├── rok.rokon
└── src/
└── main.rok
9.10.3. rok.rokon / rok.lock
패키지 루트의 rok.rokon 이 매니페스트이고, 같은 자리의 rok.lock 이 lockfile 입니다. 둘 다 ROKON 형식입니다. 이름은 이 철자 그대로 (모두 소문자) 입니다. 대소문자만 다른 파일 (Rok.rokon 등) 은 경고와 함께 무시하며, 읽지 않습니다.
매니페스트는 ROKON 값 하나, 즉 Package { .. } struct 입니다 (루트 이름 Package 는 생략 가능). 읽기만 하며 컴파일하거나 실행하지 않습니다.
Package {
name: "geom", // 문자열, 선택
version: "0.3.1", // 문자열, 선택
toolchain: "0.4", // 문자열, 선택 - toolchain 고정 (9.10.6)
description: "2D geometry", // 문자열, 선택
license: "MIT OR Apache-2.0", // 문자열, 선택 (SPDX 식)
repository: "https://example.com/geom.git", // 문자열, 선택
deps: { // 패키지 이름 (문자열) -> Dep
"util": Dep::path("../util"),
"parser": Dep::git("https://example.com/parser.git", tag: "v1.2"),
"http": "0.9", // stone (= Dep::version("0.9"))
"json": Dep::version("^1.4", optional: true), // feature 가 켤 때만 (9.10.4c)
"csv": Dep::version("^0.3", registry: "https://example.com/index"),
},
dev_deps: { // deps 와 같은 형태. test / bench 에서만
"fixtures": Dep::path("tests/fixtures"),
},
features: { "default": ["json"], "json": ["dep:json"], "tls": ["http/tls"], "full": ["json", "tls"] },
native: { "zlib": "^1.3", "png": Dep::native(url: "vendor/png.rokon", sha256: "<64 hex>") },
lints_from: "..", // 문자열, 선택 - ../rok.rokon 의 lints 에서 시작
lints: { "dead_code": "allow", "nonstandard_style": "deny" },
}
- 값은 ROKON 의 리터럴 (문자열,
{ "k": v }dict, 빈 dict{}) 과Dep::path("..")/Dep::git("url", rev | tag | branch: "..")/Dep::version("req", registry: "url")입니다.Dep::git의rev/tag/branch는 많아야 하나이고,Dep::version의registry는 선택입니다. 의존성 값이 문자열 하나면Dep::version의 줄임입니다. Dep::path/Dep::git/Dep::version은optional: true,features: ["<f>", ..],default_features: false도 받습니다 (9.10.4c). optional 인 dev 의존은 에러입니다.Dep::registry는rok.lock전용이며rok.rokon에 쓰면 에러입니다.- 패키지 이름 (
deps의 키,name) 은[a-z0-9_-]+의 소문자 ASCII 이며 글자로 시작합니다 (숫자,-,_로 시작하면 에러). 이름rok은 표준 라이브러리용으로 예약되어 있습니다: 패키지, 의존 패키지, native 패키지, registry 이름이rok이면 에러이며 (`rok` is reserved for the standard library; name the package something else, e.g. `rok_util`), 그것으로rok new/rok init/rok add해도 마찬가지입니다. 코드가 패키지를 이름으로 부를 수 있어야 하므로, 코드 이름 (아래) 은 키워드 (1.5:fn,match,self, ..) 나 경로 시작점 (5.5.7:pkg,sup) 일 수 없습니다. 실행 파일의use pkg::add;는 언제나 자기 루트를 가리킵니다 (`pkg` already names a package's own root (`pkg::`), so code can't name a package called that; name the package something else, e.g. `pkg_util`). 키는 문자열입니다 ("rok-syntax": Dep::version("^0.1")). - 코드에서는
-를_로 바꾼 이름이 그 패키지를 가리키는 최상위 경로입니다 (rok-syntax→use rok_syntax::..,--extern rok_syntax=..). - 레지스트리와 한 의존 그래프 안에서 이름은
-와_를 같게, 대소문자를 구분하지 않고 비교합니다. 그래서rok-syntax와rok_syntax는 함께 있을 수 없습니다. - 의존 패키지는
src/lib.rok를 가져야 하며, 그 패키지에src/main.rok도 있든 없든 그 라이브러리가 의존하는 쪽이 얻는 것입니다.src/main.rok만 있는 의존 패키지는 그것이rok install용 프로그램이라고 알리는 에러입니다. 전이 의존은 의존 패키지의deps입니다 (dev_deps는 전이되지 않음). native는 native 패키지 이름 (자기 이름 공간: 패키지와 native 패키지는 같은 이름을 쓸 수 있음) 을Dep::native("req"[, registry: "url"]), 요구 문자열, 또는Dep::native(url: "<url 또는 매니페스트 기준 경로>", sha256: "<64 자리 hex>")에 대응시킵니다 (9.10.4b).deps/dev_deps의Dep::native는 에러입니다. 그래프의 모든 패키지의 native 의존이 실행 파일에 링크됩니다 (dev_deps로만 닿는 것은 test / bench 에서만).lints는 lint 수준을 정합니다 (lint 나 그룹 이름 →"allow"|"warn"|"deny", 6.2.9).rok이 실행하는 모든rokc명령의 CLI 플래그 앞에 붙은 것처럼 다뤄지므로, CLI-A/-W/-D와 코드의 속성이 이를 덮습니다.lints_from은 시작 lint 수준을 주는rok.rokon이 있는 디렉토리를 가리킵니다 (이 매니페스트의 디렉토리 기준 상대 경로, 또는 절대 경로). 그 매니페스트의lints를 그 자신의lints_from사슬 뒤에 먼저 적용하고, 이 매니페스트의lints가 그 뒤에 오므로, 여기 항목이 사슬의 같은 lint 나 그룹을 덮습니다 (모든 항목은 이 순서로-A/-W/-D로 넘어가며 뒤의 플래그가 이깁니다). 빌드하거나 검사하는 패키지 (와 환경의 매니페스트) 에만 적용되며, 의존 패키지의 매니페스트는 lint 에 쓰지 않습니다. 디렉토리가 없거나,rok.rokon이 없거나, 사슬이 이미 지난 매니페스트로 돌아오면 (순환) 에러입니다.rok env import는 상대lints_from을 절대 경로로 바꿔 씁니다. 스크립트의//! ```rokon블록에서는 쓸 수 없습니다.- 에러: 모르는 필드 /
Dep종류 / 이름 있는 인자, 중복, 9.10.4c 의 규칙을 어기는features, 규칙에 맞지 않는 패키지 이름, ROKON 이 아닌 문법,Package { .. }하나가 아닌 것, 뒤에 남은 토큰. 진단은file:line:col과 caret 으로 위치를 보여 줍니다.
| 의존성 출처 | 형태 | rok.lock 에 고정 |
|---|---|---|
| path | Dep::path("..") (매니페스트 기준 상대 경로) | 없음 (늘 현재 내용) |
| git | Dep::git("url"), 선택으로 rev: / tag: / branch: 중 하나 | 커밋과 tree hash |
| stone | Dep::version("req"[, registry: "url"]) 또는 문자열 "req" (9.10.4a) | 버전, 커밋, tree hash |
| native | Dep::native("req") / Dep::native(url:, sha256:) (9.10.4b) | 버전과 항목 SHA-256 (index), 없음 (해시가 고정) |
rok 에는 build script 가 없습니다: 빌드 시점에 패키지의 코드는 실행되지 않습니다. C / C++ 라이브러리는 미리 빌드된 native 패키지로 들어옵니다 (9.10.4b).
한 빌드 안에서 한 이름은 한 패키지입니다. 같은 이름이 서로 다른 출처 (다른 경로, 또는 다른 url / 커밋) 로 요구되면 두 요구처를 보여 주는 에러입니다.
rok.lock 형식
rok.lock 은 rok 가 결정적으로 쓰는 ROKON (정규 형식) 입니다. 머리 주석 뒤에 git 패키지와 stone 마다 Locked 하나를 이름 순으로 둡니다. path 의존은 고정하지 않으므로 나오지 않습니다.
// rok.lock: generated by `rok`; do not edit. Commit it with your sources.
Lock {
version: 1,
packages: [
Locked {
name: "parser",
source: Dep::git("https://example.com/parser.git", tag: "v1.2"),
commit: "4f0c2a9e1b7d3c58a6e09f21d4b8c7a3e5f60123",
tree: "9a1e7c3b5d2f4a6081c9e3b7d5f2a4c6e8b0d1f3",
},
Locked {
name: "json",
vers: "1.4.2",
source: Dep::registry("https://github.com/rok-lang/rokstones.io-index"),
commit: "0b6d..",
tree: "77e1..",
},
],
}
| 필드 | 뜻 |
|---|---|
version | lock 형식 버전 (1) |
name | rok.rokon 의 deps 키 |
vers | stone 만. 해소된 버전 |
source | git 은 rok.rokon 에 적은 Dep::git(..) 그대로, stone 은 Dep::registry("<index url>") |
commit | 해소된 커밋 (40 자리 16 진수) |
tree | 그 커밋의 git tree hash. 캐시의 checkout 을 검증하는 데 씀 |
Locked의source는Dep::git(..)또는Dep::registry(..)입니다.packages필드가 없으면 빈 리스트로 읽습니다.- feature 는 기록하지 않습니다: lock 은 optional 인 것을 포함해 그래프의 모든 패키지를 고정하므로, 빌드가 켜는 feature 에 의존하지 않습니다.
- index 의 native 패키지는 선택 필드
natives: [LockedNative { name, vers, source: Dep::registry("<index>"), sha256 }]에 고정하며, 이름 순으로 정렬하고 비어 있지 않을 때만 씁니다.sha256은yanked: false로 둔 항목의 정규 index 줄의 SHA-256 이며, 항목이 바뀌면 "runrok update" 에러입니다. version이1이 아니면 "unsupported lockfile version" 에러입니다.- lock 을 읽다 난 모든 에러는 "(delete rok.lock and run
rok updateto make it again)" 를 덧붙입니다.
9.10.4. 의존성: rok add / remove / update / deps
rok add <name> --path <dir> [--dev]
rok add <name> --git <url> [--rev <rev> | --tag <tag> | --branch <branch>] [--dev]
rok add <name>[@<req>] [--registry <url>] [--dev] # stone
rok add <name> .. [--features <f,..>] [--no-default-features] [--optional] # 위의 어느 것과도
rok remove <name>
rok add .. <file.rok> # 스크립트의 //! rokon 블록에
rok remove [--native] <name> <file.rok>
rok update [name...]
rok deps [--dev] [--features <f,..>] [--all-features] [--no-default-features]
add/remove는rok.rokon을 고치며, 주석과 배치를 보존합니다.--dev는dev_deps에 넣습니다.add/remove는 패키지의rok.rokon을 고칩니다. 마지막 인자로 스크립트 파일을 주면add/remove는 대신 그 파일의//! rokon블록을 고칩니다 (9.10.7): 블록이 없으면 shebang 줄과 맨 앞의//!줄 뒤에 만들고 (정규 형식으로 쓰며, 이미 있는 블록은 배치와 주석을 유지함), 비게 된 블록은 지우며, path 는 스크립트 기준으로 쓰고,--dev/--optional은 에러입니다. 패키지 안의 스크립트는 에러입니다 (패키지의rok.rokon을 씀). 스크립트 없이 패키지 밖에서, 또는--env와 함께 쓰면rok add <name> <file.rok>와rok install/rok uninstall을 알리는 에러입니다 (9.10.5a). stone 을 요구 없이 더하면^<가장 새 버전>을 적습니다.--features,--no-default-features,--optional은Dep::..에 적습니다.--optional은 패키지에 같은 이름의 feature 가 없으면 feature"<name>": ["dep:<name>"]도 더합니다.- 빌드는
rok.lock의 커밋과 버전을 씁니다. 새로 선언된 의존은 lock 에 더하고 지운 의존은 정리하지만, 이미 고정된 것을 옮기는 것은update뿐입니다.update는 이름을 주면 그 패키지만, 없으면 모든 git 의존과 stone 을 다시 해소합니다. deps는 해소한 의존 패키지를<코드 이름>=<그 src/lib.rok 경로>줄로 (코드 이름은-를_로 바꾼 것), 의존되는 쪽이 먼저 오는 순서로 출력합니다 (--dev는 dev 의존 포함). 각 줄 뒤에는 그--extern-feature=<코드 이름>=<f>줄들이 옵니다.deps는 feature 옵션과--dev를 받습니다. native 패키지마다 (의존하는 쪽이 먼저, host 용)# native <name> <vers>와 그rokc인자를 한 줄에 하나씩 출력합니다.rok.lock은 버전 관리에 함께 넣습니다.rok update는rok.lock을 다시 해소하고,rok toolchain update는 toolchain 을 교체합니다 (9.10.6).
캐시
가져온 git 소스는 $ROK_HOME/cache/ 에 두고 모든 프로젝트가 공유합니다.
| 경로 | 내용 |
|---|---|
cache/git/db/<repo>-<hash>/ | 저장소의 bare clone (url 마다 하나) |
cache/registry/db/<repo>-<hash>/ | stone index 의 bare clone (index 마다 하나) |
cache/git/checkouts/<commit>/ | 커밋의 checkout. 쓰기 전에 tree hash 로 검증하고, 다르면 다시 풀어 놓음 |
cache/scripts/<hash>/ | 스크립트의 rok.lock 과 target/. <hash> 는 스크립트의 경로와, 그것이 닿는 모든 파일의 경로와 블록을 덮음 (9.10.7) |
cache/native/<sha256>/ | SHA-256 이 맞은 뒤 푼 native archive. 다시 받지 않음 (9.10.4b) |
cache/native/meta/<sha256>.rokon | Dep::native(url:) 파일 |
9.10.4a. stone 과 rokstones.io
레지스트리의 패키지를 stone 이라 합니다. 기본 레지스트리는 rokstones.io 이며, index 는 별도 git 저장소 https://github.com/rok-lang/rokstones.io-index 입니다.
버전 요구
Cargo 와 같습니다.
| 요구 | 뜻 |
|---|---|
1.2.3, ^1.2.3 | >=1.2.3, <2.0.0 (^0.2.3 은 <0.3.0, ^0.0.3 은 <0.0.4) |
~1.2.3 | >=1.2.3, <1.3.0 |
=1.2.3 | 정확히 |
>= > < <= | 비교 |
*, 1.*, 1.2.x | 와일드카드 |
>=1.2, <1.5 | 쉼표는 모두 만족 |
pre-release 버전 (1.3.0-beta.1) 은 요구가 같은 major.minor.patch 의 pre-release 를 적었을 때만 맞습니다.
어느 index 인가
ROK_REGISTRY > $ROK_HOME/config.rokon 의 Config { registry: "<url>" } > 기본 (rokstones.io index) 순입니다. Dep::version 의 registry: 와 rok add --registry 는 그 의존 하나의 index 를 정합니다.
index 형식
index 저장소의 루트에는 config.rokon, Config { api: "<url>" } 가 있습니다: registry API 의 기준 URL 입니다 (rokstones.io 는 https://rokstones.io). https:// 여야 하며, http://127.0.0.1 과 http://localhost 만 예외입니다. stone 하나는 publish 된 소문자 이름 (- 는 그대로) 의 shard 경로에 있는 파일 하나입니다.
| 이름 길이 | 경로 |
|---|---|
| 1 | 1/a |
| 2 | 2/ab |
| 3 | 3/a/abc |
| 4 이상 | ab/cd/abcd.. |
파일의 각 줄은 버전 하나이며, 정규 형식의 한 줄 ROKON 입니다. 오래된 버전이 먼저입니다.
Stone { name: "json", vers: "1.4.2", deps: [{ name: "util", req: "^0.3", kind: "normal" }], source: Dep::git("https://example.com/json.git", rev: "0b6d.."), cksum: "77e1..", yanked: false }
deps의kind는"normal","dev","native"중 하나이며,registry는 선택입니다.- feature 가 있는 stone 은
deps뒤에features: { "<name>": ["<entry>", ..] }를 가지며, 9.10.4c 처럼 검사합니다.normal의존은optional: true,features: [..],default_features: false를 가질 수 있습니다 (기본값이 아닐 때만 적음).dev/native의존은 optional 일 수 없고, native 의존에는 feature 가 없습니다.rok publish가rok.rokon에서 이것들을 적고, 해소는 항목에서 읽습니다. checkout 한 뒤 항목의features는 그 commit 의 stone 의rok.rokon의 것과 같아야 하며 (순서 무관), 그렇지 않으면 에러입니다. native/<shard path>는 native 패키지를 한 줄에Native { .. }하나씩 담습니다 (9.10.4b).- 매니페스트의
description,license,repository는 선택인 뒤쪽 필드로 들어갑니다. - 패키지는
source저장소의 루트에 있습니다.cksum은 그 커밋의 git tree hash 이며, checkout 뒤에 검증합니다.
해소
- 맞는 버전 가운데 yank 되지 않은 가장 높은 것을 고릅니다. lock 에 고정된 버전은 여전히 맞으면 (그 뒤 yank 되었더라도) 그대로 둡니다.
- 한 의존 그래프에서 이름 하나는 버전 하나입니다. 전이 의존은 index 항목의
deps를 따릅니다. - 두 요구가 겹치지 않으면 두 요구를 밝히는 에러입니다. backtracking 은 없으며, 둘 다 받아들이는 요구를 루트에 적으면 풀립니다.
- lock 은 index 와 대조합니다. 고정된 버전의
rev가 바뀌었으면 "runrok update" 에러입니다. --offline은 캐시된 index 를 쓰고,--locked를 지킵니다.
rok search / publish / yank / login / logout
rok search [--native] <query>
rok login [<token>]
rok logout
rok publish [--index <checkout>] [--commit]
rok yank [--native] --vers <version> [--undo] [--index <checkout>] [name] # --native 면 name 필수
search는 index 에서 이름으로 찾아, 찾은 것마다 한 줄<name> <newest version> - <description>을 출력합니다 (항목에 description 이 없으면 그 부분은 생략). index 조회는-/_어느 쪽 철자든 받습니다.publish는 기본이 dry run 입니다. 깨끗한 work tree, 저장소 루트의 패키지, 그리고src/lib.rok,src/main.rok, 또는 둘 다를 요구합니다.src/main.rok만 있는 stone 은 프로그램입니다:rok install이 그것을 빌드하며, 의존 패키지가 될 수 없습니다. path / git 의 normal 의존은 거부하고, path / git 의 dev 의존은 뺍니다. 같은 버전과,-/_와 대소문자를 같게 본 이름의 충돌을 검사합니다. 다른 철자가 이미 가진 이름은 거부합니다.--index없는 dry run 은 항목만 출력하고,--index가 있으면 그 checkout 에 대해서도 검사합니다. 항목의 source 는 설정된 그대로의 (insteadOf재작성 전) git remoteoriginurl 이며,https://여야 합니다.http://127.0.0.1과http://localhost만 예외입니다.--commit이면publish는 항목을 더합니다:--index가 있으면 그 checkout 에 "Publish <name> <vers>" 커밋으로 (push 하지 않음), 없으면 설정된 index ("Which index") 의 registry API 로 더하며, API 가 그것을 index 에 넣습니다. 클라이언트는 index 저장소에 직접 쓰지 않습니다.yank는 그 버전의yanked를 켭니다 (--undo면 끕니다):--index가 있으면 그 checkout 의 커밋으로, 없으면 registry API 로.registry API 는 index 의
config.rokon의api에 있습니다. 요청은Authorization: Bearer <token>을 실으며, body 는 한 줄 ROKON (application/rokon; charset=utf-8) 입니다:GET <api>/api/v1/me→Me { login: "..", publish: <bool> }POST <api>/api/v1/publish, body 는 index 줄 (Stone { .. }/Native { .. }) →Published { name, vers, file }POST <api>/api/v1/yank, bodyYank { name, vers, undo: <bool>, native: <bool> }→Yanked { name, vers, yanked }
실패는 4xx / 5xx 상태와
Error { message: ".." }이며,rok는 그 message 를 보고합니다. 401 은 토큰이 유효하지 않다는 뜻입니다.registry API 에는 토큰이 필요하며,
--indexcheckout 에는 필요 없습니다. 토큰은ROK_REGISTRY_TOKEN이 설정되어 비어 있지 않으면 그것, 아니면rok login이 저장한 것입니다. 둘 다 없으면 "runrok loginfirst" 에러입니다.rok login은 웹사이트에서 만든 rokstones.io 계정 토큰을 받습니다 (<api>/me, GitHub 로 로그인. 지금은 registry 의 maintainer 만 만들 수 있음). 생략하면 표준 입력에서 화면에 보이지 않게 읽습니다 (Ctrl-C 에도 echo 를 되돌림).login은/api/v1/me에 물어, API 가 거부하는 토큰과publish가 false 인 계정 ("this account cannot publish yet: publishing is open to rokstones.io maintainers only") 은 아무것도 저장하지 않고 거절합니다. 그 밖이면$ROK_HOME/credentials.rokon에Credentials { token: ".." }를 저장하고 (Unix 에서는 mode 0600) "Logged in as <login>" 을 출력합니다.rok logout은 그 파일을 지웁니다.토큰은
curl의 표준 입력으로만 전달되며, 명령줄이나 환경에 들어가지 않고 출력되지도 않습니다 (에러는***로 보임).
9.10.4b. Native 패키지
rok 은 C 를 컴파일하지 않습니다. native 패키지는 target triple 마다의 미리 빌드된 archive 와 다음 값입니다:
Native {
name: "png", vers: "1.6.43",
deps: { "zlib": Dep::native("^1.3") },
targets: {
"x86_64-unknown-linux-gnu": Artifact {
url: "https://example.com/png-1.6.43-x86_64-linux.tar.gz",
sha256: "<64 hex>",
links: { "png16": "static" },
runtime: [],
},
},
yanked: false, description: "PNG codec", license: "Libpng", repository: "https://example.com/png",
}
이 값은 index 한 줄이거나, Dep::native(url:, sha256:) 의 파일이며 파일의 artifact url 은 그 파일 기준 상대 경로일 수 있습니다.
- archive (tar 로 읽을 수 있는 어떤 형식이든) 는
lib/를 담습니다:lib<n>.a,lib<n>.dylib/lib<n>.so, Windows<n>.lib(static 또는 import library).runtime파일과 라이선스 파일도 담습니다. 그 안의 어떤 것도 실행하지 않습니다. - 해시는 필수입니다. archive 는 풀기 전에 검사하며, 절대 경로나
..경로, 밖으로 나가는 링크가 있거나, 이름 붙은 라이브러리나 runtime 파일이 없으면 거부합니다. - Apple 대상에서 runtime dylib 은
@rpath/install name 을 가져야 합니다. - 빌드는 target triple 의 artifact 를 씁니다. 없으면 가진 triple 들을 나열하는 에러입니다.
rok는rokc에-L <archive>/lib, link 마다-l kind=name, runtime 파일마다--native-runtime을 넘기며, 의존하는 쪽이 의존되는 쪽보다 앞입니다.
rok add --native <name>[@<req>]
rok remove --native <name>
rok search --native <query>
rok publish --native <file> [--index <dir>] [--commit]
rok yank --native --vers <version> [--undo] [--index <dir>] <name>
publish --native 는 모든 target 을 받아 검사하며, 절대 url, 라이선스 파일, index 에서 온 의존성만을 요구합니다. --commit 과 yank --native 는 stone 과 같은 규칙을 따릅니다: --index checkout, 없으면 토큰으로 registry API (Yank 의 native: true).
- ELF 대상에서 runtime 라이브러리의 soname 은 파일 이름과 같아야 합니다.
-musl대상의dyliblink 는 에러입니다. repl/jupyter는 native 패키지를 로드합니다: 공유 라이브러리는 시스템 loader 로, static archive 는 세션에 링크합니다.check/lint/doc는 아무것도 링크하지 않습니다.- 실행 파일 옆의 사본은 빌드 산출물입니다.
9.10.4c. Features
패키지는 features 에 feature 를 선언합니다. feature 이름에서 그 feature 가 켜는 것들의 리스트로 가는 dict 입니다. 이름은 [a-z0-9][a-z0-9_-]* 이며, 무엇인지 말해 주는 단어입니다 (http1, http2, tls). 각 항목은 다음 중 하나입니다.
| 항목 | 켜는 것 |
|---|---|
<f> | 이 패키지의 feature f |
dep:<d> | optional 의존 d |
<d>/<f> | 의존 d 의 feature f, 그리고 d 가 optional 이면 d 자체 |
<d>?/<f> | optional 의존 d 의 feature f. 다른 무언가가 d 를 켤 때만 |
default는 끄지 않는 한 켜져 있는 보통의 feature 입니다. 빌드하는 패키지는--no-default-features로, 의존에서는default_features: false로 끕니다.- optional 의존 (
optional: true) 은 켜진 feature 의dep:<d>나<d>/<f>항목이 켤 때만 빌드에 들어갑니다. 그 이름의 묵시 feature 는 없으며, 켜는 항목이 하나도 없으면 에러입니다. - 항목이 패키지에 없는 feature 나 (
deps의) 의존을 가리키거나,dep:나?가 optional 이 아닌 의존을 가리키거나, feature 가 순환하면 에러입니다. 진단은file:line:col을 보여 줍니다. 의존 패키지에 없는 feature 를 요구해도 에러입니다. - 해소: lock 은 그래프 전체를 덮습니다. 빌드는 루트 패키지의 feature (끄지 않으면
default,--features,--all-features이면 모든 feature) 에서 시작해, 켜진 의존마다 그 의존에 요구한 feature 와 그 의존의default를 가지고 따라갑니다. feature 는 더해지기만 하고 합쳐집니다: 패키지마다 그래프 전체에서 feature 집합은 하나입니다. 루트의dev_deps와 그것들이 요구하는 feature 는test/bench에서만 셉니다. 결과는 어떤 것의 순서에도 의존하지 않습니다. --features는 루트의 feature 이름과, 직접 의존에 대한<dep>/<f>를 받습니다.- 각 패키지는 켜진 feature 에 대해서만 정확히
cfg(feature = "<f>")로 컴파일됩니다 (6.3.6). native 패키지에는 feature 가 없습니다. - 스크립트의
```rokon블록에는features가 없습니다 (9.10.7).
9.10.5. 환경
환경은 conda / venv 를 대신합니다. 활성화 단계는 없습니다.
- 패키지 (
src/main.rok,src/lib.rok,rok.rokon중 하나가 있는 디렉토리) 는 자기rok.rokon의 의존성만 씁니다. 환경에 설치한 라이브러리는 결코 보지 않습니다. 스크립트도 마찬가지입니다. 패키지에 작용하는 명령을--env와 함께 쓰면 에러입니다. - 이름 있는 환경은
$ROK_HOME/envs/<name>/에rok.rokon,rok.lock,target/을 둡니다. 그deps는 REPL 과 Jupyter 를 위해rok install(9.10.5a) 로 설치한 라이브러리이며, 그것을 바꾸는 것은rok install/rok uninstall과rok env import뿐입니다. 그 안의 path 의존은 절대 경로입니다. 설치한 라이브러리는 그target/에 미리 빌드합니다. - 패키지 밖 (REPL, Jupyter, language server,
rok install) 에서 쓸 환경은--env <name>>ROK_ENV>rok env use($ROK_HOME/envs/CURRENT) >default순으로 정합니다.default는 거기로 처음rok install할 때 만들어집니다. 패키지 안에서 경로 없는rok repl/jupyter/lsp는 그 패키지를 쓰며,--env가 있으면 그 환경을 씁니다.
의존성의 출처
| 컴파일 대상 | 의존성 | Lock | 미리 빌드하는 곳 |
|---|---|---|---|
| 패키지 | 그 rok.rokon 의 deps (test / bench 는 dev_deps) | <package>/rok.lock | <package>/target/<profile>/deps/ |
| 스크립트 | 그것과 그 mod 가 읽는 파일들의 //! rokon 블록을 합친 deps | cache/scripts/<hash>/rok.lock | cache/scripts/<hash>/target/ |
| 패키지 밖의 REPL / Jupyter | 활성 환경에 설치한 라이브러리 | 환경의 것 | 환경의 target/ |
rok env create <name>
rok env list # 현재 환경에 * 표시
rok env remove <name>
rok env use <name> # 프로젝트 밖의 기본 환경을 바꿈
rok env export <name> <dir> # rok.rokon / rok.lock 을 <dir> 에 씀
rok env import <name> <dir | rok.rokon> # 프로젝트나 export 에서 만듦 (상대 path 는 절대로)
rok env shell [name] # ROK_ENV=<name> 인 $SHELL
rok repl --env <name>
REPL 의 :add <dep> .. 는 현재 환경으로 rok install <dep> .. 을, 패키지의 세션에서는 rok add 를 실행합니다. 그 뒤 의존성을 다시 읽어 세션에 붙입니다.
9.10.5a. rok install / rok uninstall
rok install <name>[@<req>] [--registry <url>]
rok install [<name>] --path <dir | file.rok>
rok install [<name>] --git <url> [--rev <rev> | --tag <tag> | --branch <branch>]
rok install .. [--features <f,..>] [--no-default-features] [--lib] [--force]
rok install --native <name>[@<req>] [--registry <url>]
rok install --list
rok uninstall [--native] <name>..
- 소스의 패키지는 먼저 캐시로 가져옵니다 (9.10.4).
src/main.rok가 있는 패키지나 스크립트 파일은 실행 파일입니다:cargo install처럼--release로 빌드해 그 실행 파일을$ROK_HOME/bin/<name>에 둡니다. git 이나 stone 패키지는 checkout 의 임시 사본에서, path 패키지와 스크립트 파일은 제자리에서 빌드합니다.$ROK_HOME/installs.rokon(Package { deps: { "<name>": <source> } }) 이 각 실행 파일과 그 정확한 출처 (stone 은=<version>, git 패키지는 그rev:와 함께) 를 기록합니다. 패키지에src/lib.rok도 있으면rok install은 그것을 알리고,--lib가 대신 라이브러리를 설치한다고 알립니다. src/lib.rok만 있는 패키지, 또는--lib를 준src/lib.rok가 있는 패키지는 라이브러리이며,pip install처럼rok repl,rok jupyter,:add를 위해 활성 환경 (9.10.5) 에 들어갑니다: 환경의rok.rokon에 적고 (요구 없는 stone 은^<가장 새 버전>, path 는 절대 경로), 그rok.lock으로 해소하며, 그target/에 미리 빌드합니다. 스크립트는 그것을 보지 않습니다: 스크립트는rok add <name> <file.rok>로 라이브러리를 얻으며, 출력 줄이 이것을 알립니다. 빌드되지 않으면 아무것도 설치하지 않습니다.src/lib.rok가 없는 패키지나 스크립트에--lib를 주면 에러입니다.<name>은 라이브러리의 최상위 이름, 또는 실행 파일의 파일 이름입니다. 생략하면 패키지의name, 없으면 디렉토리 이름 (path),.git을 뗀 저장소 이름 (git), 파일 stem (스크립트) 입니다. 9.10.3 의 이름 규칙을 따릅니다.--features/--no-default-features는 라이브러리의Dep에, 또는 실행 파일의 빌드에 들어가며,--dev/--optional은 에러입니다.--native는 환경의native에 native 패키지를 더합니다 (9.10.4b).- proxy
rok,rokc,rokls(9.10.6) 는 결코 교체하지 않으며,rok install이 두지 않은$ROK_HOME/bin의 파일도 마찬가지입니다 (에러). 실행 파일을 다시 설치할 때: 같은 stone 버전이나 git commit 에 같은 feature 인 것은 다시 빌드하지 않고 유지하며 (`tool` 0.1.0 is installed already (<path>); to rebuild it, run `rok install tool --force`),--force가 다시 빌드합니다 (Reinstalled). 다른 버전은 그것을 교체하며 (Upgraded tool from 0.1.0 to 0.2.0,Downgraded ...), 다른 git commit 도 마찬가지입니다 (Replaced <url> at <commit> with ...). path 나 스크립트 파일에서 온 것은cargo install --path처럼 언제나 다시 빌드합니다. 라이브러리 설치는 그대로입니다. --list는libraries (environment `<env>`):와executables (<bin dir>):를 출력하며, 각각 뒤에 설치 순서대로<name> <source>줄이 옵니다.rok uninstall <name>..은 각 이름을 활성 환경의 라이브러리에서 지우거나 (lock 을 다시 해소), 아니면rok install이$ROK_HOME/bin에 둔 실행 파일을 지웁니다.--native는 환경에서 native 패키지를 지웁니다. 둘 다 아닌 이름은 에러입니다.rok install말고$ROK_HOME아래에 쓰는 것은rok toolchain(toolchain, proxy,config.rokon),rok login(credentials.rokon),rok env(환경), 그리고 캐시뿐입니다.
9.10.6. toolchain
$ROK_HOME/bin/ 의 rok / rokc / rokls 는 활성 toolchain 의 같은 실행 파일을 실행하는 proxy 입니다 (rustup 식). 활성 toolchain 은 다음 순서로 정합니다.
- 명령줄의
+<version>(rok +0.4 build) - 환경 변수
ROK_TOOLCHAIN - 매니페스트의
toolchain: "X"(가장 가까운rok.rokon) - 기본 (
$ROK_HOME/config.rokon의Config { registry, toolchain })
버전 접두는 그 아래 버전과 맞습니다 (0.3 은 0.3.* 의 가장 높은 것). 맞는 toolchain 이 없으면 rok toolchain install 을 안내하는 에러입니다.
rok toolchain list
rok toolchain install <version> --from <dir | archive | url>
rok toolchain default [<version>] # 인자 없으면 지금의 기본을 출력
rok toolchain remove <version>
rok toolchain update [<version>]
rok toolchain clean # 기본값을 제외한 설치된 모든 toolchain 제거
- 설치본은
$ROK_HOME/toolchains/<version>-<triple>/이며 자기 완결입니다 (9.2.19).install은--from이 필수입니다. install은bin/rokc --version --verbose로 검증하며, 버전과 host 가 맞아야 합니다.- 처음 설치한 toolchain 이 기본이 되고, 이때
bin/proxy 를 만듭니다. rok toolchain update는$ROK_HOME아래의 기본 toolchain 을 교체합니다. 인자가 없으면 최신 릴리스를, 버전을 주면 그 버전을 설치합니다. 설치한 toolchain 이 기본값이 되고bin/proxy 를 다시 씁니다. Windows 에서는 실행 중인 proxy 의 이름을 바꾼 뒤 그 사본으로 교체합니다. 릴리스 archive 를 받아 SHA-256 을 검증하고 (아래 배포), 따로 풀어 제자리로 옮긴 뒤 proxy 가 그것을 실행하는지 확인합니다. 실패하면 이전 기본값과 proxy 를 되돌리고 새 toolchain 을 지웁니다. 이전 toolchain 들은 설치된 채로 남습니다. 이미 설치된 버전은 다운로드 없이 기본값이 됩니다.rok update는rok.lock을 다시 해소하고,rok toolchain update는 toolchain 을 교체합니다 (9.10.4).rok toolchain clean은 지금의 기본값을 제외한 설치된 모든 toolchain 을 지웁니다.update가 남겨 둔 이전 버전을 정리하는 선택적(opt-in) 명령입니다. 프로젝트가 고정한 버전도 함께 지워지므로 빌드에 필요하면 다시 설치해야 하며, 기본 toolchain 이 없으면 에러입니다.
배포
- 릴리스 archive 는
rok-<version>-<triple>.tar.gz(Windows 는.zip) 이며, 안은 toolchain 레이아웃입니다. Windows 가 아니면 같은 파일을 담은rok-<version>-<triple>.tar.xz도 옆에 있습니다. 각 archive 옆에<archive>.sha256이 있습니다: archive 의 SHA-256 을 hex 로 적고, 그 뒤에 파일 이름이 올 수 있습니다 (sha256sum 형식). install.sh,install.ps1,rok toolchain install --from <url>은 같은 곳에서<url>.sha256을 받아, SHA-256 이 다른 archive 를 거부합니다..sha256이 없으면 에러입니다. 경로로 준 archive 는<path>.sha256이 있을 때 그것과 대조합니다. 서명은 정의하지 않으며, 출처는 HTTPS 가 보증합니다.install.sh(https://rok-lang.org/install.sh) 는 archive 나rok-lang조직의 GitHub release 에서$ROK_HOME에 설치합니다. tar 가 읽을 수 있고 (macOS, 또는PATH에xz) 릴리스에 있으면.tar.xz를, 아니면.tar.gz를 받습니다.rok toolchain install은.tar.gz를 받습니다.- 릴리스는
$ROK_DIST(기본값https://github.com/rok-lang/rok/releases) 에서 제공됩니다:<dist>/download/v<version>/<archive>와 그.sha256, 그리고 최신 릴리스의 버전을 담은<dist>/latest/download/rok-version.
9.10.7. 단일 파일 스크립트의 inline 매니페스트
익명 패키지 (4.16.8) 는 의존성을 그 파일과 그 mod 가 읽는 각 파일의 맨 앞 (shebang 줄 뒤) //! 줄 안에 Package { deps: { .. } } (와 native) 를 담은 ```rokon 블록에서만 얻습니다 (uv 의 inline script metadata 와 같음). 환경에 설치한 라이브러리는 결코 쓰지 않습니다. 블록에는 deps 와 native 만 둘 수 있습니다 (features 가 없으므로 optional 의존도 없음). 다른 언어의 코드 블록은 무시합니다. 블록 안의 path 는 그 블록을 담은 파일 기준입니다. 블록들은 합쳐지며, 두 파일이 한 라이브러리에 서로 다른 항목을 주면 두 파일과 두 항목을 알리는 에러입니다. 서브모듈 파일을 직접 실행하면 그 실행이 닿는 파일들의 블록만 씁니다. rok add <name> .. <file.rok> / rok remove <name> <file.rok> 이 블록을 쓰며 (9.10.4), rok init --script 는 스크립트를 패키지로 바꿉니다 (9.10.2). 스크립트는 그 lockfile 과 빌드를 cache/scripts/<hash>/ 에 두며, key 는 그 경로와 그것이 닿는 모든 파일의 경로와 블록입니다. 스크립트의 실행 파일은 그것이 포함하는 모든 파일과 그 라이브러리를 포함해 빌드를 이루는 모든 것으로 캐시합니다. 스크립트에 없는 패키지의 use x::.. 는 실행할 명령 run `rok add x <file>` 을 help 로 주는 에러이며, 활성 환경에 x 가 있으면 note 를 덧붙입니다. 패키지 안에서는 rok add x 를 제안합니다. import x (와 include / require) 는 에러이며, help 는 파일 옆에 x.rok 가 있으면 mod x;, x 가 경로 루트이거나 파일이 선언한 모듈이면 use, 그 밖에는 rok add x <file> 입니다.
//! ```rokon
//! Package {
//! deps: { "util": Dep::git("https://example.com/util.git", tag: "v1") },
//! }
//! ```
use util::greet;
greet();
단일 파일 스크립트의 실행은 그 실행 파일을 재사용합니다. 익명 패키지의 rokc run 은 실행 파일을 <target>/<profile>/scripts/<key>/ 에 두며, <target> 은 스크립트의 target/ (cache/scripts/<hash>/ 아래, 그 rok.lock 옆) 입니다. <key> 는 빌드를 이루는 모든 것의 해시입니다: toolchain, 빌드 옵션, lint 수준과 target, 소스와 그것이 포함하는 모든 파일, toolchain 이 그 target 용으로 배포하는 런타임과 C 라이브러리, 그리고 미리 빌드한 라이브러리와 함께 넘긴 의존 패키지. key 가 맞으면 아무것도 컴파일하지 않으며, 그 실행 파일을 만든 빌드의 경고를 다시 출력합니다. 새 실행 파일은 임시 이름으로 쓴 뒤 제자리로 이름을 바꾸므로, 한 스크립트를 동시에 실행해도 안전합니다. 하루 동안 쓰지 않은 항목은 다른 항목을 빌드할 때 지웁니다.