Add beta install layout tooling

This commit is contained in:
sanjin 2026-05-22 11:43:22 +02:00
parent ee2b8e0930
commit 5180f69c4c
10 changed files with 261 additions and 11 deletions

View File

@ -17,6 +17,11 @@ complete and the full release gate passes near publication.
- `glagol new --template binary|library|workspace` supports the existing
binary scaffold plus checkable/testable library and local workspace
scaffolds.
- `scripts/install.sh` installs `bin/glagol`, `share/slovo/std/*.slo`, and
`share/slovo/runtime/runtime.c` under a configurable prefix.
- Installed `glagol` discovers both standard-library source modules and the
runtime C input relative to the executable, with `SLOVO_STD_PATH`,
`SLOVO_RUNTIME_C`, `GLAGOL_RUNTIME_C`, and `GLAGOL_CLANG` override paths.
- The release gate prints a concise success line after docs, formatting, tests,
promotion, binary, and LLVM smoke checks pass.
@ -26,15 +31,11 @@ complete and the full release gate passes near publication.
- no networking or runtime resource model
- no package registry behavior
- no stable ABI/layout promise
- no stable install layout promise until the install-path portion of this
tooling bundle is finished
- no operating-system package-manager integration
- no stable install layout promise beyond this beta toolchain layout
## Remaining Before Tagging `1.0.0-beta.1`
- document and gate public install layout for `glagol`, `runtime/`, and
`lib/std`
- add a minimal install or packaging command/script if the existing build flow
is not enough
- rerender publication PDFs only if documentation release text changes
- run the full release gate from a clean checkout state
- decide whether this tooling bundle is sufficient for the `1.0.0-beta.1` tag

View File

@ -91,6 +91,26 @@ Create alternate project shapes:
./compiler/target/debug/glagol new workspace-demo --template workspace
```
Install the current checkout:
```bash
PREFIX="$HOME/.local" ./scripts/install.sh
```
The installed layout is:
```text
<prefix>/bin/glagol
<prefix>/share/slovo/std/*.slo
<prefix>/share/slovo/runtime/runtime.c
```
Installed `glagol` discovers `share/slovo/std` and
`share/slovo/runtime/runtime.c` relative to its executable. `SLOVO_STD_PATH`
can still override standard-library search, `SLOVO_RUNTIME_C` or
`GLAGOL_RUNTIME_C` can override the runtime C input, and `GLAGOL_CLANG` can
select the Clang-compatible compiler.
## Documentation
- [Language Manifest](docs/language/MANIFEST.md)

View File

@ -2222,6 +2222,32 @@ fn parse_test_count(output: &str, suffix: &str) -> Option<usize> {
}
fn runtime_path() -> PathBuf {
runtime_path_candidates()
.into_iter()
.find(|path| path.is_file())
.unwrap_or_else(checkout_runtime_path)
}
fn runtime_path_candidates() -> Vec<PathBuf> {
let mut candidates = Vec::new();
if let Some(path) = env::var_os("SLOVO_RUNTIME_C") {
candidates.push(PathBuf::from(path));
}
if let Some(path) = env::var_os("GLAGOL_RUNTIME_C") {
candidates.push(PathBuf::from(path));
}
if let Ok(exe) = env::current_exe() {
if let Some(bin_dir) = exe.parent() {
candidates.push(bin_dir.join("runtime/runtime.c"));
candidates.push(bin_dir.join("../runtime/runtime.c"));
candidates.push(bin_dir.join("../share/slovo/runtime/runtime.c"));
}
}
candidates.push(checkout_runtime_path());
candidates
}
fn checkout_runtime_path() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("../runtime/runtime.c")
}

View File

@ -125,6 +125,64 @@ fn run_forwards_program_arguments_when_host_toolchain_is_available() {
}
}
#[test]
fn installed_layout_discovers_std_and_runtime_without_checkout_paths() {
let prefix = unique_path("installed-layout");
let bin_dir = prefix.join("bin");
let std_dir = prefix.join("share/slovo/std");
let runtime_dir = prefix.join("share/slovo/runtime");
fs::create_dir_all(&bin_dir).expect("create installed bin dir");
fs::create_dir_all(&std_dir).expect("create installed std dir");
fs::create_dir_all(&runtime_dir).expect("create installed runtime dir");
let installed_glagol = bin_dir.join(format!("glagol{}", std::env::consts::EXE_SUFFIX));
fs::copy(env!("CARGO_BIN_EXE_glagol"), &installed_glagol).expect("copy glagol");
make_executable(&installed_glagol);
let repo_root = Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("compiler has repo parent");
fs::copy(
repo_root.join("runtime/runtime.c"),
runtime_dir.join("runtime.c"),
)
.expect("copy runtime");
for entry in fs::read_dir(repo_root.join("lib/std")).expect("read std dir") {
let entry = entry.expect("read std entry");
let path = entry.path();
if path.extension().and_then(|ext| ext.to_str()) == Some("slo") {
fs::copy(
&path,
std_dir.join(path.file_name().expect("std file name")),
)
.expect("copy std module");
}
}
let project = write_project(
"installed-layout-project",
&[],
"(module main)\n\n(import std.io (print_string_zero))\n(import std.string (concat))\n\n(fn main () -> i32\n (print_string_zero (concat \"installed\" \"-ok\")))\n",
);
let check = run_installed_glagol(&installed_glagol, ["check".as_ref(), project.as_os_str()]);
assert_success("installed layout check", &check);
let run = run_installed_glagol(&installed_glagol, ["run".as_ref(), project.as_os_str()]);
if host_clang_available() {
assert_success("installed layout run", &run);
assert_eq!(String::from_utf8_lossy(&run.stdout), "installed-ok\n");
assert!(run.stderr.is_empty(), "installed run wrote stderr");
} else {
assert_exit_code("installed layout run without clang", &run, 3);
assert_stderr_contains(
"installed layout run without clang",
&run,
"ToolchainUnavailable",
);
}
}
#[test]
fn new_library_template_creates_checkable_testable_library_project() {
let project = unique_path("library-template");
@ -329,6 +387,7 @@ fn release_gate_script_exists_and_names_required_commands() {
let script = Path::new("../scripts/release-gate.sh");
let text = fs::read_to_string(script).expect("read release gate script");
assert!(text.contains("git diff --check"));
assert!(text.contains("scripts/install.sh"));
assert!(text.contains("cargo fmt --check"));
assert!(text.contains("cargo test"));
assert!(text.contains("dx_v1_7"));
@ -390,6 +449,39 @@ where
.expect("run glagol")
}
fn run_installed_glagol<I, S>(binary: &Path, args: I) -> Output
where
I: IntoIterator<Item = S>,
S: AsRef<std::ffi::OsStr>,
{
Command::new(binary)
.env_remove("SLOVO_STD_PATH")
.env_remove("SLOVO_RUNTIME_C")
.env_remove("GLAGOL_RUNTIME_C")
.args(args)
.output()
.expect("run installed glagol")
}
fn host_clang_available() -> bool {
let clang = std::env::var("GLAGOL_CLANG").unwrap_or_else(|_| "clang".to_string());
Command::new(clang)
.arg("--version")
.output()
.map(|output| output.status.success())
.unwrap_or(false)
}
fn make_executable(path: &Path) {
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut permissions = fs::metadata(path).expect("stat executable").permissions();
permissions.set_mode(0o755);
fs::set_permissions(path, permissions).expect("chmod executable");
}
}
fn assert_success(context: &str, output: &Output) {
assert!(
output.status.success(),

View File

@ -37,10 +37,9 @@ Work:
- keep PDF rendering explicit and non-mutating by default
Current main-branch progress after `1.0.0-beta`: `glagol run`,
`glagol clean`, `glagol new --template binary|library|workspace`, README
coverage, focused DX tests, and a concise release-gate success line are
implemented. Install-path polish remains in this tooling bundle before a
`1.0.0-beta.1` tag.
`glagol clean`, `glagol new --template binary|library|workspace`,
`scripts/install.sh`, installed std/runtime discovery, README coverage,
focused DX tests, and a concise release-gate success line are implemented.
Why first: it reduces friction for every later feature and gives users a better
way to exercise the beta.

View File

@ -19,6 +19,10 @@ future `1.0.0-beta.1` bundle:
- `glagol clean <file.slo|project>` removes generated `.slovo/build` artifacts
- `glagol new --template binary|library|workspace` adds library and local
workspace scaffolds beside the existing binary default
- `scripts/install.sh` installs `bin/glagol`, `share/slovo/std`, and
`share/slovo/runtime/runtime.c`
- installed native builds discover the runtime C input relative to the
executable, with `SLOVO_RUNTIME_C` and `GLAGOL_RUNTIME_C` overrides
- the release gate prints a concise final success summary
This is a toolchain workflow slice only. It does not claim a new stable ABI,

View File

@ -23,6 +23,11 @@ Post-beta main currently contains tooling hardening intended for a future
- `glagol clean <file.slo|project>` removes generated `.slovo/build` artifacts
- `glagol new --template binary|library|workspace` scaffolds binary projects,
library projects, and local package workspaces using existing manifest rules
- `scripts/install.sh` installs the compiler, `lib/std`, and runtime C input
under a configurable prefix
- installed `glagol` discovers `share/slovo/std` and
`share/slovo/runtime/runtime.c` relative to its executable, with environment
overrides still available
- the release gate prints a concise final success line after all checks pass
This unreleased slice does not add source-language syntax, stable ABI/layout

View File

@ -953,6 +953,20 @@ scaffold shapes. `binary` is the default project with `src/main.slo`.
creates a local two-package workspace using the existing `[workspace]`,
`[package]`, and local path dependency rules.
`scripts/install.sh` installs the beta toolchain layout under a configurable
prefix:
```text
<prefix>/bin/glagol
<prefix>/share/slovo/std/*.slo
<prefix>/share/slovo/runtime/runtime.c
```
Installed `glagol` must discover the standard-library sources and runtime C
input relative to its executable. `SLOVO_STD_PATH` remains the standard-library
source override. `SLOVO_RUNTIME_C` and `GLAGOL_RUNTIME_C` may override the
runtime C input for native builds.
## 4.5 v2.0.0-beta.1 Experimental Integration Readiness
Status: current experimental Slovo-side release contract, released 2026-05-17.

88
scripts/install.sh Executable file
View File

@ -0,0 +1,88 @@
#!/usr/bin/env bash
set -euo pipefail
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
repo_root="$(cd -- "${script_dir}/.." && pwd)"
prefix="${PREFIX:-${HOME}/.local}"
profile="release"
build=1
usage() {
cat <<'USAGE'
usage: scripts/install.sh [--prefix <dir>] [--debug] [--no-build]
Installs the Slovo toolchain layout:
<prefix>/bin/glagol
<prefix>/share/slovo/std/*.slo
<prefix>/share/slovo/runtime/runtime.c
Set PREFIX instead of --prefix if preferred.
USAGE
}
while [ "$#" -gt 0 ]; do
case "$1" in
--prefix)
if [ "$#" -lt 2 ]; then
echo "--prefix requires a directory" >&2
exit 2
fi
prefix="$2"
shift 2
;;
--debug)
profile="debug"
shift
;;
--no-build)
build=0
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "unexpected argument: $1" >&2
usage >&2
exit 2
;;
esac
done
if [ "${build}" -eq 1 ]; then
cargo build --manifest-path "${repo_root}/compiler/Cargo.toml" --profile "${profile}"
fi
binary="${repo_root}/compiler/target/${profile}/glagol"
if [ ! -x "${binary}" ]; then
echo "missing built compiler binary: ${binary}" >&2
echo "run cargo build --manifest-path compiler/Cargo.toml --profile ${profile}" >&2
exit 1
fi
bin_dir="${prefix}/bin"
std_dir="${prefix}/share/slovo/std"
runtime_dir="${prefix}/share/slovo/runtime"
doc_dir="${prefix}/share/doc/slovo"
install -d "${bin_dir}" "${std_dir}" "${runtime_dir}" "${doc_dir}"
install -m 755 "${binary}" "${bin_dir}/glagol"
install -m 644 "${repo_root}/runtime/runtime.c" "${runtime_dir}/runtime.c"
find "${repo_root}/lib/std" -maxdepth 1 -type f -name '*.slo' -print0 |
while IFS= read -r -d '' module; do
install -m 644 "${module}" "${std_dir}/$(basename "${module}")"
done
install -m 644 "${repo_root}/README.md" "${doc_dir}/README.md"
install -m 644 "${repo_root}/LICENSE-MIT" "${doc_dir}/LICENSE-MIT"
install -m 644 "${repo_root}/LICENSE-APACHE" "${doc_dir}/LICENSE-APACHE"
cat <<EOF
installed Slovo toolchain to ${prefix}
${bin_dir}/glagol
${std_dir}
${runtime_dir}/runtime.c
EOF

View File

@ -7,6 +7,7 @@ compiler_dir="${repo_root}/compiler"
cd "${repo_root}"
git diff --check
bash -n scripts/install.sh
required_pdfs=(
"docs/papers/SLOVO_WHITEPAPER.pdf"