I worked with that notion some while ago. In general it's possible to attach arbitrary data to an exe file, and thus generalize embedding into having multiple files, by overriding some file access functions to use that data where appropriate. In particular you would override
load,
file? and
read-file to use attached data where possible.
This results in two script files: one for packing, and one being a special embedding script that takes care of using the attached data as the original files. For example as follows:
File:
buildexe.lsp
Code: Select all
# Requires arguments to be run as:
# newlisp buildexe.lsp lsp1 lsp2 .... binary
(constant 'ARGS (match '(? "buildexe.lsp" * ?) (main-args)))
(constant 'HEAD "exehead.lsp")
(println "ARGS " ARGS)
(unless ARGS
(write-line 2 "Run with: newlisp buildexe.lsp lsp1 lsp2 .... binary")
(exit 1))
(unless (= (! (format "%s -x %s %s" (ARGS 0) HEAD (ARGS 2))))
(write-line 2 (format "Failed to build %s" (ARGS 2))))
(append-file (ARGS 2) (dup "x" 50))
(dolist (f (ARGS 1))
(let ((s (string (list 'EmbeddedFiles f (read-file f)))))
(append-file (ARGS 2) (string (length s) s))))
(append-file (ARGS 2) " nil ")
(append-file (ARGS 2) (string (list 'load (ARGS 1 0))))
(exit 0)
File:
exehead.lsp
Code: Select all
(constant 'main_load load)
(constant 'main_read-file read-file)
(constant 'main_file? file?)
(define EmbeddedFiles:EmbeddedFiles nil)
(define (override_load _name)
(if (EmbeddedFiles _name) (eval-string (EmbeddedFiles _name) MAIN)
(main_load _name)))
(define (override_read-file _name)
(if (EmbeddedFiles _name) (EmbeddedFiles _name)
(main_read-file _name)))
(define (override_file? _name)
(if (EmbeddedFiles _name) true (main_file? _name)))
(map constant '(load read-file file?)
(list override_load override_read-file override_file?))
(define SELF:SELF (read-file (or (real-path (main-args 0))
(real-path (string (main-args 0) ".exe")))))
(if (null? SELF)
(exit (and (write-line 2 (format "No program %s" (main-args 0))) 1))
(setf override_i (find (dup "x" 50) SELF))
(let ((override_n 50))
(while (number?
(setf override_n
(read-expr SELF MAIN nil (inc override_i override_n))))
(eval (read-expr SELF MAIN nil (inc override_i $count))))
(eval-string SELF MAIN nil (inc override_i $count)))
(exit (and (write-line 2 "No program") 1)))
(exit 0)
With those, you use
buildexe.lsp for packing your other scripts, with the first being the main script, into a self-contained executable. In actual fact, the executable is simply a newlisp embedding of
exehead.lsp with your script files as attached data that gets processed into the EmbeddedFiles hashtable. The filenames are the keys and the contents the values. The overriding functions try to find the given filename in the table first, for overriding, and otherwise fall back on the original functions.
hth