2018-12-25 20:32:42 +00:00
|
|
|
# Library to help build janet natives and other
|
|
|
|
# build artifacts.
|
|
|
|
|
|
|
|
# Windows is the OS outlier
|
|
|
|
(def- is-win (= (os/which) :windows))
|
2019-03-03 20:18:17 +00:00
|
|
|
(def- is-mac (= (os/which) :macos))
|
2018-12-27 03:40:19 +00:00
|
|
|
(def- sep (if is-win "\\" "/"))
|
|
|
|
(def- objext (if is-win ".obj" ".o"))
|
|
|
|
(def- modext (if is-win ".dll" ".so"))
|
2018-12-25 20:32:42 +00:00
|
|
|
|
2019-04-12 17:46:46 +00:00
|
|
|
(def prefix (or (os/getenv "PREFIX") "/usr/local"))
|
|
|
|
|
|
|
|
(defn shell
|
2018-12-25 20:32:42 +00:00
|
|
|
"Do a shell command"
|
|
|
|
[& args]
|
2019-04-12 17:46:46 +00:00
|
|
|
(def cmd (string ;args))
|
|
|
|
(print cmd)
|
|
|
|
(def res (os/shell cmd))
|
2018-12-25 20:39:24 +00:00
|
|
|
(unless (zero? res)
|
2019-05-04 22:55:36 +00:00
|
|
|
(error (string "command exited with status " res))))
|
2018-12-25 20:32:42 +00:00
|
|
|
|
|
|
|
(defn- rm
|
2019-04-01 15:11:15 +00:00
|
|
|
"Remove a directory and all sub directories."
|
2018-12-25 20:32:42 +00:00
|
|
|
[path]
|
2019-04-01 15:21:45 +00:00
|
|
|
(if (= (os/stat path :mode) :directory)
|
2019-04-01 15:11:15 +00:00
|
|
|
(do
|
2019-04-06 00:01:03 +00:00
|
|
|
(each subpath (os/dir path)
|
|
|
|
(rm (string path sep subpath)))
|
2019-04-01 15:11:15 +00:00
|
|
|
(os/rmdir path))
|
|
|
|
(os/rm path)))
|
2018-12-25 20:32:42 +00:00
|
|
|
|
2019-04-01 01:35:44 +00:00
|
|
|
(defn- needs-build
|
|
|
|
[dest src]
|
|
|
|
"Check if dest is older than src. Used for checking if a file should be updated."
|
|
|
|
(def f (file/open dest))
|
|
|
|
(if (not f) (break true))
|
|
|
|
(file/close f)
|
2019-04-01 15:21:45 +00:00
|
|
|
(let [mod-dest (os/stat dest :modified)
|
|
|
|
mod-src (os/stat src :modified)]
|
2019-04-01 01:35:44 +00:00
|
|
|
(< mod-dest mod-src)))
|
|
|
|
|
|
|
|
(defn- needs-build-some
|
2018-12-27 19:13:10 +00:00
|
|
|
[f others]
|
2019-04-01 01:35:44 +00:00
|
|
|
(some (partial needs-build f) others))
|
2018-12-27 19:13:10 +00:00
|
|
|
|
2018-12-27 03:40:19 +00:00
|
|
|
(defn- embed-name
|
|
|
|
"Rename a janet symbol for embedding."
|
|
|
|
[path]
|
|
|
|
(->> path
|
|
|
|
(string/replace-all sep "___")
|
|
|
|
(string/replace-all ".janet" "")))
|
|
|
|
|
|
|
|
(defn- embed-c-name
|
|
|
|
"Rename a janet file for embedding."
|
|
|
|
[path]
|
|
|
|
(->> path
|
|
|
|
(string/replace-all sep "___")
|
|
|
|
(string/replace-all ".janet" ".janet.c")
|
|
|
|
(string "build" sep)))
|
|
|
|
|
|
|
|
(defn- embed-o-name
|
|
|
|
"Get object file for c file."
|
|
|
|
[path]
|
|
|
|
(->> path
|
|
|
|
(string/replace-all sep "___")
|
|
|
|
(string/replace-all ".janet" (string ".janet" objext))
|
|
|
|
(string "build" sep)))
|
|
|
|
|
2018-12-25 20:32:42 +00:00
|
|
|
(defn- object-name
|
|
|
|
"Rename a source file so it can be built in a flat source tree."
|
|
|
|
[path]
|
2018-12-27 03:40:19 +00:00
|
|
|
(->> path
|
|
|
|
(string/replace-all sep "___")
|
|
|
|
(string/replace-all ".c" (if is-win ".obj" ".o"))
|
|
|
|
(string "build" sep)))
|
2018-12-25 20:32:42 +00:00
|
|
|
|
|
|
|
(defn- lib-name
|
|
|
|
"Generate name for dynamic library."
|
|
|
|
[name]
|
2018-12-27 03:40:19 +00:00
|
|
|
(string "build" sep name modext))
|
2018-12-25 20:32:42 +00:00
|
|
|
|
2019-01-07 00:33:27 +00:00
|
|
|
(defn- make-define
|
|
|
|
"Generate strings for adding custom defines to the compiler."
|
|
|
|
[define value]
|
2019-01-30 14:31:53 +00:00
|
|
|
(def prefix (if is-win "/D" "-D"))
|
2019-01-07 00:33:27 +00:00
|
|
|
(if value
|
|
|
|
(string prefix define "=" value)
|
|
|
|
(string prefix define)))
|
|
|
|
|
|
|
|
(defn- make-defines
|
|
|
|
"Generate many defines. Takes a dictionary of defines. If a value is
|
2019-01-30 14:31:53 +00:00
|
|
|
true, generates -DNAME (/DNAME on windows), otherwise -DNAME=value."
|
2019-01-07 00:33:27 +00:00
|
|
|
[defines]
|
|
|
|
(seq [[d v] :pairs defines] (make-define d (if (not= v true) v))))
|
|
|
|
|
2018-12-25 20:32:42 +00:00
|
|
|
# Defaults
|
|
|
|
(def OPTIMIZE 2)
|
|
|
|
(def CC (if is-win "cl" "cc"))
|
2019-04-01 01:35:44 +00:00
|
|
|
(def LD (if is-win
|
|
|
|
"link"
|
|
|
|
(string CC
|
|
|
|
" -shared"
|
2019-03-03 20:18:17 +00:00
|
|
|
(if is-mac " -undefined dynamic_lookup" ""))))
|
2019-02-19 01:27:00 +00:00
|
|
|
(def CFLAGS (string
|
|
|
|
(if is-win "/I" "-I")
|
2019-05-15 14:49:16 +00:00
|
|
|
module/*headerpath*
|
2019-02-19 01:27:00 +00:00
|
|
|
(if is-win " /O" " -std=c99 -Wall -Wextra -fpic -O")
|
|
|
|
OPTIMIZE))
|
2018-12-25 20:32:42 +00:00
|
|
|
|
|
|
|
(defn- compile-c
|
|
|
|
"Compile a C file into an object file."
|
|
|
|
[opts src dest]
|
2019-01-07 00:33:27 +00:00
|
|
|
(def cc (or (opts :compiler) CC))
|
|
|
|
(def cflags (or (opts :cflags) CFLAGS))
|
|
|
|
(def defines (interpose " " (make-defines (or (opts :defines) {}))))
|
2019-04-01 01:35:44 +00:00
|
|
|
(if (needs-build dest src)
|
2018-12-27 19:13:10 +00:00
|
|
|
(if is-win
|
2019-01-07 00:33:27 +00:00
|
|
|
(shell cc " " ;defines " /nologo /c " cflags " /Fo" dest " " src)
|
2019-01-09 16:47:29 +00:00
|
|
|
(shell cc " -c " src " " ;defines " " cflags " -o " dest))))
|
2018-12-25 20:32:42 +00:00
|
|
|
|
|
|
|
(defn- link-c
|
|
|
|
"Link a number of object files together."
|
|
|
|
[opts target & objects]
|
2019-01-07 00:33:27 +00:00
|
|
|
(def ld (or (opts :linker) LD))
|
|
|
|
(def cflags (or (opts :cflags) CFLAGS))
|
2019-01-31 12:30:37 +00:00
|
|
|
(def lflags (or (opts :lflags) ""))
|
2018-12-25 20:32:42 +00:00
|
|
|
(def olist (string/join objects " "))
|
2019-04-01 01:35:44 +00:00
|
|
|
(if (needs-build-some target objects)
|
2018-12-27 19:13:10 +00:00
|
|
|
(if is-win
|
2019-01-30 14:31:53 +00:00
|
|
|
(shell ld " /DLL /OUT:" target " " olist " %JANET_PATH%\\janet.lib")
|
2019-01-31 12:30:37 +00:00
|
|
|
(shell ld " " cflags " -o " target " " olist " " lflags))))
|
2018-12-25 20:32:42 +00:00
|
|
|
|
2018-12-27 03:40:19 +00:00
|
|
|
(defn- create-buffer-c
|
|
|
|
"Inline raw byte file as a c file."
|
|
|
|
[source dest name]
|
2019-04-01 01:35:44 +00:00
|
|
|
(when (needs-build dest source)
|
2018-12-27 19:13:10 +00:00
|
|
|
(def f (file/open source :r))
|
|
|
|
(if (not f) (error (string "file " f " not found")))
|
|
|
|
(def out (file/open dest :w))
|
|
|
|
(def chunks (seq [b :in (file/read f :all)] (string b)))
|
|
|
|
(file/write out
|
2019-05-09 21:37:46 +00:00
|
|
|
"#include <janet.h>\n"
|
2018-12-27 19:13:10 +00:00
|
|
|
"static const unsigned char bytes[] = {"
|
|
|
|
;(interpose ", " chunks)
|
|
|
|
"};\n\n"
|
|
|
|
"const unsigned char *" name "_embed = bytes;\n"
|
|
|
|
"size_t " name "_embed_size = sizeof(bytes);\n")
|
|
|
|
(file/close out)
|
|
|
|
(file/close f)))
|
2018-12-27 03:40:19 +00:00
|
|
|
|
2018-12-25 20:32:42 +00:00
|
|
|
# Public
|
|
|
|
|
|
|
|
(defn make-native
|
|
|
|
"Build a native binary. This is a shared library that can be loaded
|
|
|
|
dynamically by a janet runtime."
|
|
|
|
[& opts]
|
|
|
|
(def opt-table (table ;opts))
|
2019-04-01 01:35:44 +00:00
|
|
|
(os/mkdir "build")
|
2019-01-07 00:33:27 +00:00
|
|
|
(def sources (opt-table :source))
|
|
|
|
(def name (opt-table :name))
|
|
|
|
(loop [src :in sources]
|
2018-12-25 20:32:42 +00:00
|
|
|
(compile-c opt-table src (object-name src)))
|
2019-01-07 00:33:27 +00:00
|
|
|
(def objects (map object-name sources))
|
|
|
|
(when-let [embedded (opt-table :embedded)]
|
|
|
|
(loop [src :in embedded]
|
2018-12-27 03:40:19 +00:00
|
|
|
(def c-src (embed-c-name src))
|
|
|
|
(def o-src (embed-o-name src))
|
|
|
|
(array/push objects o-src)
|
|
|
|
(create-buffer-c src c-src (embed-name src))
|
|
|
|
(compile-c opt-table c-src o-src)))
|
2019-01-07 00:33:27 +00:00
|
|
|
(link-c opt-table (lib-name name) ;objects))
|
2018-12-25 20:32:42 +00:00
|
|
|
|
|
|
|
(defn clean
|
|
|
|
"Remove all built artifacts."
|
|
|
|
[]
|
|
|
|
(rm "build"))
|
|
|
|
|
|
|
|
(defn make-archive
|
|
|
|
"Build a janet archive. This is a file that bundles together many janet
|
2019-05-02 17:10:14 +00:00
|
|
|
scripts into a janet image. This file can the be moved to any machine with
|
2018-12-25 20:32:42 +00:00
|
|
|
a janet vm and the required dependencies and run there."
|
|
|
|
[& opts]
|
2019-05-02 17:10:14 +00:00
|
|
|
(def opt-table (table ;opts))
|
|
|
|
(os/mkdir "build")
|
|
|
|
(def entry (opt-table :entry))
|
|
|
|
(def name (opt-table :name))
|
|
|
|
(spit (string name ".jimage") (make-image (require entry))))
|
2018-12-25 20:32:42 +00:00
|
|
|
|
|
|
|
(defn make-binary
|
|
|
|
"Make a binary executable that can be run on the current platform. This function
|
|
|
|
generates a self contained binary that can be run of the same architecture as the
|
|
|
|
build machine, as the current janet vm will be packaged with the output binary."
|
|
|
|
[& opts]
|
|
|
|
(error "Not Yet Implemented."))
|