Bundle El runtime as installable framework
- runtime/stdlib.el: master import file for the full El standard library in correct dependency order (string→math→time→env→fs→exec→json→http→ state→thread→channel→engram→manifest); test.el excluded (dev-only) - tools/install.sh: installs El to a prefix (default /usr/local/el); copies elc binary, runtime .el files, headers, compiles libel.a from el_seed.c + el_runtime.c, generates an installed stdlib.el with absolute paths - tools/new-project.sh: scaffolds a new El project with src/main.el, build.sh (auto-discovers local elc/runtime), README.md, .gitignore; verified working end-to-end - AGENTS.md: fix elc rebuild docs — elc writes to stdout, not to its second argument; correct usage is ./dist/platform/elc elc-cli.el > elc-new.c
This commit is contained in:
Executable
+127
@@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env bash
|
||||
# install.sh — install El as a proper local framework tool.
|
||||
#
|
||||
# Copies the compiler binary, runtime source files, headers, and stdlib
|
||||
# from the local source tree into the install prefix. After install,
|
||||
# El programs can be built against an installed, stable copy of the runtime.
|
||||
#
|
||||
# Usage:
|
||||
# ./tools/install.sh
|
||||
# ./tools/install.sh --prefix /opt/el
|
||||
#
|
||||
# Environment:
|
||||
# EL_HOME Override install prefix (same as --prefix)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
EL_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
PREFIX="${EL_HOME:-/usr/local/el}"
|
||||
|
||||
# Parse --prefix flag
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--prefix)
|
||||
PREFIX="$2"
|
||||
shift 2
|
||||
;;
|
||||
--prefix=*)
|
||||
PREFIX="${1#--prefix=}"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
echo "Usage: $0 [--prefix <path>]" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
BIN_DIR="${PREFIX}/bin"
|
||||
RUNTIME_DIR="${PREFIX}/runtime"
|
||||
INCLUDE_DIR="${PREFIX}/include"
|
||||
LIB_DIR="${PREFIX}/lib"
|
||||
|
||||
ELC_SRC="${EL_ROOT}/dist/platform/elc"
|
||||
RUNTIME_SRC="${EL_ROOT}/el-compiler/runtime"
|
||||
STDLIB_SRC="${EL_ROOT}/runtime"
|
||||
|
||||
echo "==> Installing El framework to ${PREFIX}"
|
||||
echo " bin: ${BIN_DIR}"
|
||||
echo " runtime: ${RUNTIME_DIR}"
|
||||
echo " include: ${INCLUDE_DIR}"
|
||||
echo " lib: ${LIB_DIR}"
|
||||
echo
|
||||
|
||||
# Create directories
|
||||
mkdir -p "${BIN_DIR}" "${RUNTIME_DIR}" "${INCLUDE_DIR}" "${LIB_DIR}"
|
||||
|
||||
# 1. Install elc binary
|
||||
if [[ ! -f "${ELC_SRC}" ]]; then
|
||||
echo "Error: elc binary not found at ${ELC_SRC}" >&2
|
||||
echo "Build it first or run from the el repo root." >&2
|
||||
exit 1
|
||||
fi
|
||||
install -m 755 "${ELC_SRC}" "${BIN_DIR}/elc"
|
||||
echo " installed: ${BIN_DIR}/elc"
|
||||
|
||||
# 2. Install runtime .el files
|
||||
for f in "${STDLIB_SRC}"/*.el; do
|
||||
[[ -f "$f" ]] || continue
|
||||
install -m 644 "$f" "${RUNTIME_DIR}/$(basename "$f")"
|
||||
done
|
||||
echo " installed: ${RUNTIME_DIR}/*.el ($(ls "${STDLIB_SRC}"/*.el | wc -l | tr -d ' ') files)"
|
||||
|
||||
# 3. Install headers
|
||||
for header in el_seed.h el_runtime.h; do
|
||||
src="${RUNTIME_SRC}/${header}"
|
||||
if [[ -f "${src}" ]]; then
|
||||
install -m 644 "${src}" "${INCLUDE_DIR}/${header}"
|
||||
echo " installed: ${INCLUDE_DIR}/${header}"
|
||||
fi
|
||||
done
|
||||
|
||||
# 4. Build libel.a from el_seed.c + el_runtime.c
|
||||
echo " compiling libel.a..."
|
||||
TMP_DIR="$(mktemp -d)"
|
||||
trap 'rm -rf "${TMP_DIR}"' EXIT
|
||||
|
||||
cc -std=c11 -O2 -I"${RUNTIME_SRC}" -c "${RUNTIME_SRC}/el_seed.c" -o "${TMP_DIR}/el_seed.o"
|
||||
cc -std=c11 -O2 -I"${RUNTIME_SRC}" -c "${RUNTIME_SRC}/el_runtime.c" -o "${TMP_DIR}/el_runtime.o"
|
||||
ar rcs "${LIB_DIR}/libel.a" "${TMP_DIR}/el_seed.o" "${TMP_DIR}/el_runtime.o"
|
||||
echo " installed: ${LIB_DIR}/libel.a"
|
||||
|
||||
# 5. Generate stdlib.el with absolute paths to installed runtime files
|
||||
STDLIB_OUT="${PREFIX}/stdlib.el"
|
||||
{
|
||||
echo "// stdlib.el — El standard library (installed at ${PREFIX})"
|
||||
echo "// Generated by tools/install.sh — do not edit by hand."
|
||||
echo "// Import this file to get the full El runtime:"
|
||||
echo "// import \"${PREFIX}/stdlib.el\""
|
||||
echo
|
||||
for f in "${STDLIB_SRC}"/*.el; do
|
||||
[[ -f "$f" ]] || continue
|
||||
base="$(basename "$f")"
|
||||
# Skip stdlib.el itself to avoid circular import
|
||||
[[ "${base}" == "stdlib.el" ]] && continue
|
||||
# Skip test.el — dev-only
|
||||
[[ "${base}" == "test.el" ]] && continue
|
||||
echo "import \"${RUNTIME_DIR}/${base}\""
|
||||
done
|
||||
} > "${STDLIB_OUT}"
|
||||
echo " installed: ${STDLIB_OUT}"
|
||||
|
||||
echo
|
||||
echo "==> El installed to ${PREFIX}"
|
||||
echo
|
||||
echo "Add ${BIN_DIR} to your PATH:"
|
||||
echo " export PATH=\"${BIN_DIR}:\$PATH\""
|
||||
echo
|
||||
echo "To use the stdlib in your El programs:"
|
||||
echo " import \"${PREFIX}/stdlib.el\""
|
||||
echo
|
||||
echo "To link El programs against the installed runtime:"
|
||||
echo " elc src/main.el > dist/main.c"
|
||||
echo " cc -std=c11 -O2 -I${INCLUDE_DIR} -o dist/main dist/main.c ${LIB_DIR}/libel.a -lcurl -lpthread"
|
||||
echo
|
||||
Executable
+164
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env bash
|
||||
# new-project.sh — scaffold a new El project.
|
||||
#
|
||||
# Usage:
|
||||
# ./tools/new-project.sh <project-name>
|
||||
#
|
||||
# Creates:
|
||||
# <project-name>/
|
||||
# src/main.el — hello world entry point
|
||||
# build.sh — build script using elc + el_runtime.c
|
||||
# README.md — minimal project docs
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Usage: $0 <project-name>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NAME="$1"
|
||||
|
||||
if [[ -e "${NAME}" ]]; then
|
||||
echo "Error: '${NAME}' already exists." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Discover elc — prefer PATH, fall back to the local foundation/el tree
|
||||
ELC="elc"
|
||||
if ! command -v elc >/dev/null 2>&1; then
|
||||
# Try a sibling or parent path convention
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
LOCAL_ELC="${SCRIPT_DIR}/../dist/platform/elc"
|
||||
if [[ -x "${LOCAL_ELC}" ]]; then
|
||||
ELC="$(cd "$(dirname "${LOCAL_ELC}")" && pwd)/$(basename "${LOCAL_ELC}")"
|
||||
else
|
||||
echo "Warning: elc not found in PATH or at ${LOCAL_ELC}" >&2
|
||||
echo " The generated build.sh may need manual adjustment." >&2
|
||||
ELC="elc"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Discover el_runtime.c
|
||||
EL_RUNTIME=""
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
LOCAL_RUNTIME="${SCRIPT_DIR}/../el-compiler/runtime/el_runtime.c"
|
||||
if [[ -f "${LOCAL_RUNTIME}" ]]; then
|
||||
EL_RUNTIME="$(cd "$(dirname "${LOCAL_RUNTIME}")" && pwd)/$(basename "${LOCAL_RUNTIME}")"
|
||||
EL_INCLUDE="$(dirname "${EL_RUNTIME}")"
|
||||
else
|
||||
# Check installed location
|
||||
if [[ -f "/usr/local/el/lib/libel.a" ]]; then
|
||||
EL_RUNTIME_LINK="-L/usr/local/el/lib -lel"
|
||||
EL_INCLUDE="/usr/local/el/include"
|
||||
fi
|
||||
EL_RUNTIME="${EL_RUNTIME_LINK:-}"
|
||||
fi
|
||||
|
||||
echo "==> Scaffolding El project: ${NAME}"
|
||||
|
||||
mkdir -p "${NAME}/src" "${NAME}/dist"
|
||||
|
||||
# src/main.el
|
||||
cat > "${NAME}/src/main.el" <<'ELEOF'
|
||||
// main.el — entry point for this El program.
|
||||
|
||||
fn run() -> String {
|
||||
println("hello from El!")
|
||||
return ""
|
||||
}
|
||||
|
||||
run()
|
||||
ELEOF
|
||||
|
||||
# build.sh — adapts to whether we found elc/runtime locally or installed
|
||||
if [[ -n "${EL_RUNTIME}" && -f "${EL_RUNTIME}" ]]; then
|
||||
# Local source tree runtime
|
||||
EL_INCLUDE_DIR="$(dirname "${EL_RUNTIME}")"
|
||||
cat > "${NAME}/build.sh" <<BUILDEOF
|
||||
#!/usr/bin/env bash
|
||||
# build.sh — build ${NAME}
|
||||
set -euo pipefail
|
||||
|
||||
ELC="${ELC}"
|
||||
EL_RUNTIME="${EL_RUNTIME}"
|
||||
EL_INCLUDE="${EL_INCLUDE_DIR}"
|
||||
|
||||
mkdir -p dist
|
||||
|
||||
echo "==> Compiling El -> C"
|
||||
"\${ELC}" src/main.el > dist/main.c
|
||||
|
||||
echo "==> Compiling C -> binary"
|
||||
cc -std=c11 -O2 -I"\${EL_INCLUDE}" -o dist/${NAME} dist/main.c "\${EL_RUNTIME}" -lcurl -lpthread
|
||||
|
||||
echo "==> Built: dist/${NAME}"
|
||||
BUILDEOF
|
||||
else
|
||||
# Installed framework
|
||||
cat > "${NAME}/build.sh" <<BUILDEOF
|
||||
#!/usr/bin/env bash
|
||||
# build.sh — build ${NAME}
|
||||
# Requires El installed via tools/install.sh (elc in PATH, /usr/local/el/lib/libel.a)
|
||||
set -euo pipefail
|
||||
|
||||
ELC="\${ELC:-elc}"
|
||||
EL_PREFIX="\${EL_HOME:-/usr/local/el}"
|
||||
|
||||
mkdir -p dist
|
||||
|
||||
echo "==> Compiling El -> C"
|
||||
"\${ELC}" src/main.el > dist/main.c
|
||||
|
||||
echo "==> Compiling C -> binary"
|
||||
cc -std=c11 -O2 -I"\${EL_PREFIX}/include" -o dist/${NAME} dist/main.c -L"\${EL_PREFIX}/lib" -lel -lcurl -lpthread
|
||||
|
||||
echo "==> Built: dist/${NAME}"
|
||||
BUILDEOF
|
||||
fi
|
||||
|
||||
chmod +x "${NAME}/build.sh"
|
||||
|
||||
# README.md
|
||||
cat > "${NAME}/README.md" <<READMEEOF
|
||||
# ${NAME}
|
||||
|
||||
An El language project.
|
||||
|
||||
## Build
|
||||
|
||||
\`\`\`bash
|
||||
./build.sh
|
||||
\`\`\`
|
||||
|
||||
## Run
|
||||
|
||||
\`\`\`bash
|
||||
./dist/${NAME}
|
||||
\`\`\`
|
||||
|
||||
## Structure
|
||||
|
||||
\`\`\`
|
||||
src/main.el — entry point
|
||||
build.sh — build script
|
||||
dist/ — compiled output (gitignored)
|
||||
\`\`\`
|
||||
READMEEOF
|
||||
|
||||
# .gitignore
|
||||
cat > "${NAME}/.gitignore" <<'IGNEOF'
|
||||
dist/
|
||||
*.c
|
||||
IGNEOF
|
||||
|
||||
echo
|
||||
echo "==> Created ${NAME}/"
|
||||
echo " src/main.el"
|
||||
echo " build.sh"
|
||||
echo " README.md"
|
||||
echo " .gitignore"
|
||||
echo
|
||||
echo "To build:"
|
||||
echo " cd ${NAME} && ./build.sh"
|
||||
echo
|
||||
Reference in New Issue
Block a user