Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save rduplain/23eca22a971e4e3f25d142f4a00aecfd to your computer and use it in GitHub Desktop.
Save rduplain/23eca22a971e4e3f25d142f4a00aecfd to your computer and use it in GitHub Desktop.
ClojureScript - Native Executables
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ClojureScript - Native Executables\n",
"\n",
"#### Objective\n",
"\n",
"Compile a ClojureScript program to a native executable, which can be run without additional dependencies on the target machine.\n",
"\n",
"#### Summary\n",
"\n",
"* The resulting executables are working, distributable, standalone files.\n",
"* That said, the executables are quite large (34MB).\n",
"* Note that these are \"Hello, world!\" programs and do not test limitations of ClojureScript APIs or any libraries.\n",
"* Be ready to build Node.js on various platforms if the prebuilt runtimes do not match your target (though they are probably fine for many use cases).\n",
"\n",
"#### References\n",
"\n",
"* https://clojurescript.org/guides/native-executables\n",
"* https://github.com/nexe/nexe\n",
"* https://github.com/zeit/pkg"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# Note that these cells are executing bash shell commands."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Linux 4.4.0-127-generic\n"
]
}
],
"source": [
"# Print OS detail.\n",
"\n",
"uname -a | awk '{ print $1 \" \" $3 }'"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"java version \"1.8.0_171\"\n",
"Java(TM) SE Runtime Environment (build 1.8.0_171-b11)\n",
"Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, mixed mode)\n"
]
}
],
"source": [
"# Print Java version.\n",
"\n",
"java -version"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"node v8.11.2\n",
"npm 6.1.0\n",
"nexe 2.0.0-rc.29\n",
"pkg 4.3.1\n"
]
}
],
"source": [
"# Print version of each tool in use.\n",
"\n",
"for program in node npm nexe pkg; do\n",
" echo -n \"$program \"\n",
" $program --version | head -1\n",
"done"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# Download ClojureScript.\n",
"\n",
"if [ ! -e cljs.jar ]; then\n",
" wget -q https://github.com/clojure/clojurescript/releases/download/r1.10.238/cljs.jar\n",
"fi"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"cljs.jar: OK\n"
]
}
],
"source": [
"# Verify ClojureScript download.\n",
"\n",
"SHA256=4c1746a365f01fa22069d49354391d3c0e9c233f91b17c5f488a0a7f5e3784ce\n",
"echo \"$SHA256 cljs.jar\" > cljs.jar.sha256\n",
"if ! sha256sum -c cljs.jar.sha256; then\n",
" mv cljs.jar cljs.jar.rej\n",
"fi"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{:major 1, :minor 10, :incremental 0, :qualifier alpha4}\n"
]
}
],
"source": [
"# Verify ClojureScript execution by printing its version internally.\n",
"\n",
"java -cp cljs.jar clojure.main - <<EOF\n",
"(println clojure.core/*clojure-version*)\n",
"EOF"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# Create a simple \"Hello, world!\" program.\n",
"\n",
"mkdir -p src\n",
"cat > src/hello.cljs <<EOF\n",
"(ns hello)\n",
"(println \"Hello, world!\")\n",
"EOF"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"# Remove build output, for repeat run.\n",
"\n",
"rm -fr out"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"WARNING: hello is a single segment namespace at line 1 src/hello.cljs\n"
]
}
],
"source": [
"# Compile ClojureScript to JavaScript.\n",
"\n",
"java -cp cljs.jar clojure.main - <<EOF\n",
"(require 'cljs.build.api)\n",
"(cljs.build.api/build \"src\" {:optimizations :advanced :output-to \"out/main.js\"})\n",
"EOF"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"RUN\n"
]
}
],
"source": [
"# Compile a binary with nexe.\n",
"\n",
"# Choose a version (-t) that is prebuilt to speed up compilation.\n",
"# Versions: https://github.com/nexe/nexe/releases\n",
"#\n",
"# Other targets: alpine-x64-8.9.4, mac-x64-8.9.4, windows-x64-8.9.4\n",
"\n",
"mkdir -p out/nexe\n",
"nexe --silent -t linux-x64-8.9.4 -i out/main.js -o out/nexe/hello"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Hello, world!\n"
]
}
],
"source": [
"# Run nexe-built binary.\n",
"\n",
"./out/nexe/hello"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"34M out/nexe/hello\n",
"11M out/nexe/hello.bz2\n"
]
}
],
"source": [
"# Review nexe-built binary size.\n",
"\n",
"bzip2 -k out/nexe/hello\n",
"ls -lh out/nexe/hello* | awk '{ print $5 \" \" $9 }'"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"> [email protected]\n",
"'out/pkg/main' -> 'out/pkg/hello'\n"
]
}
],
"source": [
"# Compile a binary with pkg.\n",
"\n",
"# Other targets: node8-macos-x64, node8-win-x64\n",
"#\n",
"# node8-freebsd-x64?\n",
"#\n",
"# Issue: There is no freeBSD build for 2.5\n",
"# https://github.com/zeit/pkg-fetch/issues/39\n",
"\n",
"mkdir -p out/pkg\n",
"pkg --targets node8-linux-x64 --out-path out/pkg out/main.js\n",
"mv -v out/pkg/main out/pkg/hello"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"34M out/pkg/hello\n",
"11M out/pkg/hello.bz2\n"
]
}
],
"source": [
"# Review pkg-built binary size.\n",
"\n",
"bzip2 -k out/pkg/hello\n",
"ls -lh out/pkg/hello* | awk '{ print $5 \" \" $9 }'"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Hello, world!\n"
]
}
],
"source": [
"# Run pkg-built binary.\n",
"\n",
"./out/pkg/hello"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Bash",
"language": "bash",
"name": "bash"
},
"language_info": {
"codemirror_mode": "shell",
"file_extension": ".sh",
"mimetype": "text/x-sh",
"name": "bash"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
@rduplain
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment