Racket编程指南——21 运行和创建可执行文件

21 运行和创建可执行文件

在开发程序时,很多Racket程序员使用DrRacket编程环境。要在没有开发环境的情况下运行程序,请使用racket(用于基于控制台的程序)或gracket(对于GUI程序)。本章主要介绍如何运行racket和gracket。

    21.1 运行racket和gracket

      21.1.1 交互模式

      21.1.2 模块模式

      21.1.3 加载模式

    21.2 脚本

      21.2.1 Unix脚本

      21.2.2 Windows批处理文件

    21.3 创建独立可执行文件

21.1 运行racketgracket

gracket可执行文件和racket一样,但表现上有小的调整,可作为GUI应用程序而不是控制台应用程序。例如,gracket在默认情况下以交互模式运行,使用GUI窗口而不是控制台提示符。然而,GUI应用程序可以以普通的racket运行。

根据命令行参数的不同,racket或gracket在交互模式模块模式加载模式下。

21.1.1 交互模式

当racket在没有命令行参数的情况下运行时(除了配置选项,如-j),那么启动REPL使用> 提示符:

  Welcome to Racket v8.4 [cs].

  >

为了增强你的REPL体验,请参见《xrepl》;有关GNU Readline支持的信息,请参见《readline》。

要初始化REPL的环境,racket首先需要racket/init模块,该模块提供所有racket,并安装pretty-print以显示结果。最后,在启动REPL之前,racket加载(find-system-path 'init-file)报告的文件(如果存在)。

如果提供了任何命令行参数(配置项除外),请添加-i或--repl以重启REPL。例如,

  racket -e '(display "hi\n")' -i

在启动时显示“hi”,但仍显示REPL

如果需要标志的模块出现在-i/--repl之前,它们将取消对racket/init的自动需求。这种行为可用来使用其它语言初始化REPL的环境。例如,

  racket -l racket/base -i

使用更小的初始语言(加载速度更快)启动REPL。请注意,大多数模块都不提供Racket的基本语法,包括函数调用语法和require。例如,

  racket -l racket/date -i

生成一个对每个表达式都失败的REPL,因为racket/date只提供了几个函数,而不是REPL里需要求值顶层函数调用所需的#%top-interaction#%app绑定。

如果一个需求标志的模块出现在-i/--repl之后,而不是出现在它之前,那么该模块需要在racket/init之后,以增强初始环境。例如,

  racket -i -l racket/date

除了racket的导出之外,可以使用racket/date启动一个有用的REPL

21.1.2 模块模式

如果一个文件参数在任何命令行开关(除了其它配置选项)之前提供给racket,那么这个文件作为一个模块导入,没有REPL启动。例如,

  racket hello.rkt

需求"hello.rkt"模块,然后退出。文件名、标志或其它内容之后的任何参数都作为命令行参数保存,以供所需的模块通过current-command-line-arguments使用。

如果使用命令行标志,则可以使用-u或--require-script标志来显示地将文件作为模块。-t或--require标志类似,只是额外的命令行标志由racket处理,而不是为需求的模块保留。例如,

  racket -t hello.rkt -t goodbye.rkt

需求"hello.rkt"模块,然后需求"goodbye.rkt"模块,再然后退出。

-l或--lib标志类似于-t/--require,但它需求一个使用lib模块路径而不是文件路径的模块。例如,

  racket -l raco

与运行不带参数的raco可执行文件是一样的,因为raco模块是可执行文件的主模块。

请注意,如果你想将命令行标志传递给上面的raco,你需要用--保护这些标志,这样racket就不会试图自己解析它们:

  racket -l raco -- --help

21.1.3 加载模式

-f或--load标志直接支持文件中的load顶级表达式,而不是模块文件中的表达式。这个求值就像启动一个REPL并直接键入表达式,只是结果不打印。例如,

  racket -f hi.rkts

load "hi.rkts"并退出。请注意,由于给有LISP/Scheme经验的读者的一个说明中解释的原因,加载模式通常是一个坏主意;使用模块模式通常更好。

-e或--eval标志接受表达式直接求值。与文件加载不同,表达式的结果是打印的,就像在REPL中一样。例如,

  racket -e '(current-seconds)'

打印自1970年1月1日以来的秒数。

对于文件加载和表达式求值,顶级环境的创建方式与交互模式相同:除非首先指定了另一个模块,否则需求racket/init。例如,

  racket -l racket/base -e '(current-seconds)'

很可能运行得更快,因为它使用较小的racket/base语言而不是racket/init初始化求值环境。

 

21.2 脚本

Racket文件可以在UNIX和Mac OS上转换为可执行脚本。在Windows中,像Cygwin这样的兼容层支持相同类型的脚本,或者可以将脚本实现为批处理文件。

21.2.1 Unix脚本

在UNIX环境(包括Linux和Mac OS)中,可以使用shell的#!约定将Racket文件转换为可执行脚本。文件的前两个字符必须是#!;下一个字符必须是空格或/,并且第一行的其余部分必须是执行脚本的命令。对于某些平台,第一行的总长度限制为32个字符,而且有时需要空间。

使用#lang racket/base代替#lang racket来生成启动时间更快的脚本。

最简单的脚本格式使用racket可执行文件的绝对路径,随后是模块声明。例如,如果racket安装在"/usr/local/bin"中,那么包含以下文本的文件将充当“Hello World”脚本:

  #! /usr/local/bin/racket

  #lang racket/base

  "Hello, world!"

特别是,如果将上述内容放入文件"hello"中,并使该文件可执行(例如,使用chmod a+x hello),然后在shell提示符处键入./hello将生成输出"Hello, world!"。

上述脚本之所以有效,是因为操作系统自动将脚本的路径作为#!启动的程序的参数行,并且因为racket将单个非标志参数视为包含要运行的模块的文件。

一种流行的代替方法是,不指定racket可执行文件的完整路径,而是需求racket位于用户的命令路径中,然后“trampoline“使用/usr/bin/env:

  #! /usr/bin/env racket

  #lang racket/base

  "Hello, world!"

在任何一种情况下,脚本的命令行参数都可以通过current-command-line-arguments获得:

  #! /usr/bin/env racket

  #lang racket/base

  (printf "Given arguments: ~s\n"

          (current-command-line-arguments))

如果需要脚本的名称,可以通过(find-system-path 'run-file)获取,而不是(current-command-line-arguments)

通常,处理命令行参数的最佳方法是使用racket提供的command-line表解析它们。默认情况下,command-line表从(current-command-line-arguments)中提取命令行参数:

  #! /usr/bin/env racket

  #lang racket

  

  (define verbose? (make-parameter #f))

  

  (define greeting

    (command-line

     #:once-each

     [("-v") "Verbose mode" (verbose? #t)]

     #:args

     (str) str))

  

  (printf "~a~a\n"

          greeting

          (if (verbose?) " to you, too!" ""))

尝试使用--help标志运行上述脚本,以查看脚本允许哪些命令行参数。

更普通的trampoline使用/bin/sh加上一些行,这些行是一种语言的注释,另一种语言是表达式。这个trampoline更复杂,但它提供了对racket命令行参数的更多控制:

  #! /bin/sh

  #|

  exec racket -e '(printf "Running...\n")' -u "$0" ${1+"$@"}

  |#

  #lang racket/base

  (printf "The above line of output had been produced via\n")

  (printf "a use of the `-e' flag.\n")

  (printf "Given arguments: ~s\n"

          (current-command-line-arguments))

请注意,#!在Racket中开始一行注释,#|...|#形成块注释。同时,#还启动了一个shell脚本注释,而exec racket则中止了shell脚本以启动racket。这样,脚本文件就变成了/bin/sh和racket的有效输入。

21.2.2 Windows批处理文件

类似的技巧也可以用于在windows中编写Racket代码.bat批处理文件:

  ; @echo off

  ; Racket.exe "%~f0" %*

  ; exit /b

  #lang racket/base

  "Hello, world!"

 

21.3 创建独立可执行文件

有关创建和分发可执行文件的信息,参见在《(part ("(lib scribblings/raco/raco.scrbl)" "top"))》中的(part ("(lib scribblings/raco/raco.scrbl)" "exe"))》和《(part ("(lib scribblings/raco/raco.scrbl)" "exe-dist"))》。

(part ("(lib scribblings/raco/raco.scrbl)" "top")).

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值