support cross-compilation of installers

At least, support Windows installer creation on a non-Windows
machine.
This commit is contained in:
Matthew Flatt 2015-08-29 18:10:10 -06:00
parent cf4e6d2b8a
commit 8a1d196ff3
8 changed files with 71 additions and 20 deletions

View File

@ -5,7 +5,8 @@
racket/runtime-path racket/runtime-path
ds-store ds-store
ds-store/alias ds-store/alias
compiler/exe-dylib-path) compiler/exe-dylib-path
setup/cross-system)
(provide installer-dmg (provide installer-dmg
make-dmg) make-dmg)
@ -148,7 +149,7 @@
(define (installer-dmg human-name base-name dist-suffix readme sign-identity) (define (installer-dmg human-name base-name dist-suffix readme sign-identity)
(define dmg-name (format "bundle/~a-~a~a.dmg" (define dmg-name (format "bundle/~a-~a~a.dmg"
base-name base-name
(system-library-subpath #f) (cross-system-library-subpath #f)
dist-suffix)) dist-suffix))
(make-dmg human-name "bundle/racket" dmg-name bg-image readme sign-identity) (make-dmg human-name "bundle/racket" dmg-name bg-image readme sign-identity)
dmg-name) dmg-name)

View File

@ -4,7 +4,8 @@
racket/system racket/system
racket/path racket/path
racket/runtime-path racket/runtime-path
setup/getinfo) setup/getinfo
setup/cross-system)
(provide installer-exe) (provide installer-exe)
@ -405,15 +406,21 @@ SectionEnd
(display script o) (display script o)
(newline o))) (newline o)))
(parameterize ([current-directory "bundle"]) (parameterize ([current-directory "bundle"])
(system* makensis "/V3" "installer.nsi"))) (define verbose (if (eq? 'windows (system-type))
"/V3"
"-V3"))
(system* makensis verbose "installer.nsi")))
(define (installer-exe human-name base-name versionless? dist-suffix readme) (define (installer-exe human-name base-name versionless? dist-suffix readme)
(define makensis (or (find-executable-path "makensis.exe") (define makensis (or (case (system-type)
(try-exe "c:\\Program Files\\NSIS\\makensis.exe") [(windows)
(try-exe "c:\\Program Files (x86)\\NSIS\\makensis.exe") (or (find-executable-path "makensis.exe")
(try-exe "c:\\Program Files\\NSIS\\makensis.exe")
(try-exe "c:\\Program Files (x86)\\NSIS\\makensis.exe"))]
[else (find-executable-path "makensis")])
(error 'installer-exe "cannot find \"makensis.exe\""))) (error 'installer-exe "cannot find \"makensis.exe\"")))
(define platform (let-values ([(base name dir?) (split-path (system-library-subpath #f))]) (define platform (let-values ([(base name dir?) (split-path (cross-system-library-subpath #f))])
(path->string name))) (bytes->string/utf-8 (path-element->bytes name))))
(define exe-path (format "bundle/~a-~a-win32~a.exe" base-name platform dist-suffix)) (define exe-path (format "bundle/~a-~a-win32~a.exe" base-name platform dist-suffix))
(when readme (when readme
(call-with-output-file* (call-with-output-file*

View File

@ -5,7 +5,8 @@
racket/runtime-path racket/runtime-path
ds-store ds-store
ds-store/alias ds-store/alias
xml) xml
setup/cross-system)
(provide installer-pkg) (provide installer-pkg)
@ -151,7 +152,7 @@
(define (installer-pkg human-name base-name dist-suffix readme sign-identity) (define (installer-pkg human-name base-name dist-suffix readme sign-identity)
(define pkg-name (format "bundle/~a-~a~a.pkg" (define pkg-name (format "bundle/~a-~a~a.pkg"
base-name base-name
(system-library-subpath #f) (cross-system-library-subpath #f)
dist-suffix)) dist-suffix))
(make-pkg human-name "bundle/racket" pkg-name readme sign-identity) (make-pkg human-name "bundle/racket" pkg-name readme sign-identity)
pkg-name) pkg-name)

View File

@ -4,6 +4,7 @@
racket/port racket/port
racket/format racket/format
racket/runtime-path racket/runtime-path
setup/cross-system
file/tar) file/tar)
(provide installer-sh) (provide installer-sh)
@ -78,7 +79,7 @@
(define (installer-sh human-name base-name dir-name release? dist-suffix readme) (define (installer-sh human-name base-name dir-name release? dist-suffix readme)
(define sh-path (format "bundle/~a-~a~a.sh" (define sh-path (format "bundle/~a-~a~a.sh"
base-name base-name
(system-library-subpath #f) (cross-system-library-subpath #f)
dist-suffix)) dist-suffix))
(generate-installer-sh "bundle/racket" sh-path (generate-installer-sh "bundle/racket" sh-path
dir-name human-name dir-name human-name

View File

@ -9,6 +9,7 @@
racket/file racket/file
racket/path racket/path
racket/port racket/port
setup/cross-system
"display-time.rkt") "display-time.rkt")
(module test racket/base) (module test racket/base)
@ -70,7 +71,7 @@
(define installer-file (define installer-file
(if source? (if source?
(installer-tgz base-name dir-name dist-suffix readme) (installer-tgz base-name dir-name dist-suffix readme)
(case (system-type) (case (cross-system-type)
[(unix) (installer-sh human-name base-name dir-name release? dist-suffix readme)] [(unix) (installer-sh human-name base-name dir-name release? dist-suffix readme)]
[(macosx) (if mac-pkg? [(macosx) (if mac-pkg?
(installer-pkg (if (or release? versionless?) (installer-pkg (if (or release? versionless?)

View File

@ -58,7 +58,7 @@ default accepts only connections via @racket["localhost"].
On the client machine, all work is performed at a specified directory On the client machine, all work is performed at a specified directory
as specified by @racket[#:dir]. The directory defaults to as specified by @racket[#:dir]. The directory defaults to
@filepath{build/plt} (Unix, Mac OS X) or @filepath{build\plt} @filepath{build/plt} (Unix or Mac OS X) or @filepath{build\plt}
(Windows), except when the host is @racket["localhost"] and the client (Windows), except when the host is @racket["localhost"] and the client
is @racket[#f], in which case the current directory (i.e., the is @racket[#f], in which case the current directory (i.e., the
server's directory) is used. server's directory) is used.
@ -110,7 +110,7 @@ installers.
@section{Machine Requirements} @section{Machine Requirements}
Each Unix or Mac OS X @tech{client machines} needs the following available: Each Unix or Mac OS X @tech{client machine} needs the following available:
@itemlist[ @itemlist[
@ -120,6 +120,10 @@ Each Unix or Mac OS X @tech{client machines} needs the following available:
@item{@exec{gcc}, @exec{make}, etc.} @item{@exec{gcc}, @exec{make}, etc.}
@item{when creating a Windows installer (via cross-compilation),
Nullsoft Scriptable Install System (NSIS) version 2.x with
@exec{makensis} in @envvar{PATH}}
] ]
Each Windows @tech{client machine} needs the following: Each Windows @tech{client machine} needs the following:
@ -138,15 +142,18 @@ Each Windows @tech{client machine} needs the following:
or or
@filepath{C:\Program Files (x86)\Microsoft Visual Studio @nonterm{vers}}} @filepath{C:\Program Files (x86)\Microsoft Visual Studio @nonterm{vers}}}
@item{Nullsoft Scriptable Install System (NSIS) verstion 2.x, installed @item{Nullsoft Scriptable Install System (NSIS) version 2.x, installed
in the default folder: in the default folder:
@filepath{C:\Program Files\NSIS\makensis.exe} @filepath{C:\Program Files\NSIS\makensis.exe}
or or
@filepath{C:\Program Files (x86)\NSIS\makensis.exe} @filepath{C:\Program Files (x86)\NSIS\makensis.exe}
or installed so that @exec{makensis} in your @envvar{PATH}.} or installed so that @exec{makensis} in @envvar{PATH}}
] ]
Currently, Windows and Unix variants can be cross-compiled using a
same-versioned native Racket installation on a client machine that
runs Unix or Mac OS X.
@; ---------------------------------------- @; ----------------------------------------
@ -209,6 +216,13 @@ spaces, etc.):
directory if the host is @racket["localhost"] and the user is directory if the host is @racket["localhost"] and the user is
@racket[#f]} @racket[#f]}
@item{@racket[#:env (list (list _string* _string) ...)] ---
environment-variable settings to prefix all client-machine
interactions for a Unix or Mac OS X client; for example
@racket['(("PATH" "/usr/local/bin:/usr/bin"))] configures the
client machine's @envvar{PATH} enviornment variable to have
only @filepath{/usr/local/bin} and @filepath{/usr/bin}}
@item{@racket[#:server _string*] --- the address of the server as @item{@racket[#:server _string*] --- the address of the server as
accessed by the client; when SSH remote tunneling works, then accessed by the client; when SSH remote tunneling works, then
@racket["localhost"] should work to reach the server; defaults to @racket["localhost"] should work to reach the server; defaults to
@ -234,6 +248,13 @@ spaces, etc.):
@item{@racket[#:pkgs (list _string* ...)] --- packages to install; @item{@racket[#:pkgs (list _string* ...)] --- packages to install;
defaults to the @tt{PKGS} makefile variable} defaults to the @tt{PKGS} makefile variable}
@item{@racket[#:racket _string-or-false] --- path to a native Racket
executable when using the client machine for cross-compilation; if
the value is @racket[#f], the the Racket executable generated for
the client machine is used to prepare the installer; a
non-@racket[#f] typically must be combined with
@racket[#:configure] arguments to set up cross-compilation}
@item{@racket[#:dist-base-url _string] --- a URL that is used to @item{@racket[#:dist-base-url _string] --- a URL that is used to
construct a default for @racket[#:doc-search] and construct a default for @racket[#:doc-search] and
@racket[#:dist-catalogs], where the constructed values are @racket[#:dist-catalogs], where the constructed values are
@ -349,8 +370,8 @@ spaces, etc.):
@item{@racket[#:source-runtime? _boolean] --- if true, then create @item{@racket[#:source-runtime? _boolean] --- if true, then create
an archive that contains the run-time system in source form an archive that contains the run-time system in source form
(possibly with built packages), instead of a platform-specific (possibly with built packages), instead of a platform-specific
installer; a @racket[#t] value works best when used with a Unix installer; a @racket[#t] value works best when used for a Unix
client machine, since Unix clients typically have no build, since Unix clients typically have no
native-library packages; the default is the value of native-library packages; the default is the value of
@racket[#:source?]} @racket[#:source?]}

View File

@ -113,6 +113,7 @@
(define (check-group-keyword kw val) (define (check-group-keyword kw val)
(case kw (case kw
[(#:pkgs) (and (list? val) (andmap simple-string? val))] [(#:pkgs) (and (list? val) (andmap simple-string? val))]
[(#:racket) (or (not val) (string? val))]
[(#:doc-search) (string? val)] [(#:doc-search) (string? val)]
[(#:dist-name) (string? val)] [(#:dist-name) (string? val)]
[(#:dist-base) (simple-string? val)] [(#:dist-base) (simple-string? val)]
@ -130,6 +131,13 @@
[(#:user) (or (not val) (simple-string? val))] [(#:user) (or (not val) (simple-string? val))]
[(#:port) (port-no? val)] [(#:port) (port-no? val)]
[(#:dir) (path-string? val)] [(#:dir) (path-string? val)]
[(#:env) (and (list? val)
(andmap (lambda (p)
(and (list? p)
(= 2 (length p))
(simple-string? (car p))
(string? (cadr p))))
val))]
[(#:vbox) (string? val)] [(#:vbox) (string? val)]
[(#:platform) (memq val '(unix macosx windows windows/bash))] [(#:platform) (memq val '(unix macosx windows windows/bash))]
[(#:configure) (and (list? val) (andmap string? val))] [(#:configure) (and (list? val) (andmap string? val))]

View File

@ -239,6 +239,7 @@
(if l (if l
(apply ~a #:separator " " l) (apply ~a #:separator " " l)
default-pkgs))) default-pkgs)))
(define racket (get-opt c '#:racket))
(define doc-search (choose-doc-search c default-doc-search)) (define doc-search (choose-doc-search c default-doc-search))
(define dist-name (or (get-opt c '#:dist-name) (define dist-name (or (get-opt c '#:dist-name)
default-dist-name)) default-dist-name))
@ -264,6 +265,9 @@
(~a " SERVER=" server (~a " SERVER=" server
" SERVER_PORT=" server-port " SERVER_PORT=" server-port
" PKGS=" (q pkgs) " PKGS=" (q pkgs)
(if racket
(~a " PLAIN_RACKET=" (q racket))
"")
" DOC_SEARCH=" (q doc-search) " DOC_SEARCH=" (q doc-search)
" DIST_DESC=" (q desc) " DIST_DESC=" (q desc)
" DIST_NAME=" (q dist-name) " DIST_NAME=" (q dist-name)
@ -286,8 +290,15 @@
(define (unix-build c platform host port user server server-port repo clean? pull? readme) (define (unix-build c platform host port user server server-port repo clean? pull? readme)
(define dir (get-path-opt c '#:dir "build/plt" #:localhost (current-directory))) (define dir (get-path-opt c '#:dir "build/plt" #:localhost (current-directory)))
(define env (get-opt c '#:env null))
(define (sh . args) (define (sh . args)
(list "/bin/sh" "-c" (apply ~a args))) (append
(if (null? env)
null
(list* "/usr/bin/env"
(for/list ([e (in-list env)])
(format "~a=~a" (car e) (cadr e)))))
(list "/bin/sh" "-c" (apply ~a args))))
(define j (or (get-opt c '#:j) 1)) (define j (or (get-opt c '#:j) 1))
(try-until-ready c host port user server-port 'unix (sh "echo hello")) (try-until-ready c host port user server-port 'unix (sh "echo hello"))
(ssh-script (ssh-script