blob: 15e9e146768d8eeecba4c19abfec74f5069b324e [file] [log] [blame]
Guido van Rossumf06ee5f1996-11-27 19:52:01 +00001#! /usr/bin/env python
Guido van Rossumdbaf3321994-10-03 10:25:54 +00002
Guido van Rossum96c4dd91996-08-26 05:14:20 +00003"""Freeze a Python script into a binary.
Guido van Rossumdbaf3321994-10-03 10:25:54 +00004
Guido van Rossum1e074031998-03-05 04:05:38 +00005usage: freeze [options...] script [module]...
Guido van Rossum00ff4331994-10-03 16:33:08 +00006
Guido van Rossum96c4dd91996-08-26 05:14:20 +00007Options:
Guido van Rossum00ff4331994-10-03 16:33:08 +00008
Guido van Rossum9a6e8551997-08-10 16:47:17 +00009-p prefix: This is the prefix used when you ran ``make install''
Guido van Rossum96c4dd91996-08-26 05:14:20 +000010 in the Python build directory.
Guido van Rossumd8336c21994-10-05 16:13:01 +000011 (If you never ran this, freeze won't work.)
Guido van Rossum96c4dd91996-08-26 05:14:20 +000012 The default is whatever sys.prefix evaluates to.
Guido van Rossum0b4b8a21997-08-10 16:56:48 +000013 It can also be the top directory of the Python source
14 tree; then -P must point to the build tree.
Guido van Rossumd8336c21994-10-05 16:13:01 +000015
Guido van Rossum150316e1995-08-08 14:21:07 +000016-P exec_prefix: Like -p but this is the 'exec_prefix', used to
Guido van Rossum0b4b8a21997-08-10 16:56:48 +000017 install objects etc. The default is whatever sys.exec_prefix
18 evaluates to, or the -p argument if given.
19 If -p points to the Python source tree, -P must point
20 to the build tree, if different.
Guido van Rossum150316e1995-08-08 14:21:07 +000021
Guido van Rossumd8336c21994-10-05 16:13:01 +000022-e extension: A directory containing additional .o files that
23 may be used to resolve modules. This directory
24 should also have a Setup file describing the .o files.
25 More than one -e option may be given.
26
Guido van Rossum96c4dd91996-08-26 05:14:20 +000027-o dir: Directory where the output files are created; default '.'.
28
Guido van Rossum75dc4961998-03-05 03:42:00 +000029-m: Additional arguments are module names instead of filenames.
30
Guido van Rossum78fc3631998-03-20 17:37:24 +000031-l file: Pass the file to the linker (windows only)
32
Guido van Rossum75dc4961998-03-05 03:42:00 +000033-d: Debugging mode for the module finder.
34
35-q: Make the module finder totally quiet.
36
Guido van Rossum9a6e8551997-08-10 16:47:17 +000037-h: Print this help message.
38
Guido van Rossum58a59481997-08-14 01:45:33 +000039-w: Toggle Windows (NT or 95) behavior.
40 (For debugging only -- on a win32 platform, win32 behaviour
41 is automatic.)
42
Guido van Rossum78fc3631998-03-20 17:37:24 +000043-x module Exclude the specified module.
44
45-s subsystem: Specify the subsystem (For Windows only.);
46 'console' (default), 'windows', 'service' or 'com_dll'
47
Guido van Rossum58a59481997-08-14 01:45:33 +000048
Guido van Rossum96c4dd91996-08-26 05:14:20 +000049Arguments:
50
Guido van Rossum1e074031998-03-05 04:05:38 +000051script: The Python script to be executed by the resulting binary.
Guido van Rossumd8336c21994-10-05 16:13:01 +000052
53module ...: Additional Python modules (referenced by pathname)
54 that will be included in the resulting binary. These
Guido van Rossum75dc4961998-03-05 03:42:00 +000055 may be .py or .pyc files. If -m is specified, these are
56 module names that are search in the path instead.
Guido van Rossum150316e1995-08-08 14:21:07 +000057
58NOTES:
59
60In order to use freeze successfully, you must have built Python and
Guido van Rossumd4cc04c1996-06-17 17:49:13 +000061installed it ("make install").
Guido van Rossum150316e1995-08-08 14:21:07 +000062
Guido van Rossum96c4dd91996-08-26 05:14:20 +000063The script should not use modules provided only as shared libraries;
64if it does, the resulting binary is not self-contained.
Guido van Rossumd8336c21994-10-05 16:13:01 +000065"""
Guido van Rossum00ff4331994-10-03 16:33:08 +000066
67
Guido van Rossum00ff4331994-10-03 16:33:08 +000068# Import standard modules
69
Guido van Rossumd8336c21994-10-05 16:13:01 +000070import cmp
Guido van Rossumdbaf3321994-10-03 10:25:54 +000071import getopt
Guido van Rossum00ff4331994-10-03 16:33:08 +000072import os
Guido van Rossumdbaf3321994-10-03 10:25:54 +000073import string
Guido van Rossum00ff4331994-10-03 16:33:08 +000074import sys
Guido van Rossumdbaf3321994-10-03 10:25:54 +000075
Guido van Rossumdbaf3321994-10-03 10:25:54 +000076
Guido van Rossum00ff4331994-10-03 16:33:08 +000077# Import the freeze-private modules
78
Guido van Rossumd8336c21994-10-05 16:13:01 +000079import checkextensions
Guido van Rossum75dc4961998-03-05 03:42:00 +000080import modulefinder
Guido van Rossum00ff4331994-10-03 16:33:08 +000081import makeconfig
82import makefreeze
83import makemakefile
84import parsesetup
85
Guido van Rossum00ff4331994-10-03 16:33:08 +000086
87# Main program
88
Guido van Rossumdbaf3321994-10-03 10:25:54 +000089def main():
Guido van Rossum0b4b8a21997-08-10 16:56:48 +000090 # overridable context
91 prefix = None # settable with -p option
92 exec_prefix = None # settable with -P option
93 extensions = []
Guido van Rossum78fc3631998-03-20 17:37:24 +000094 exclude = [] # settable with -x option
95 addn_link = [] # settable with -l, but only honored under Windows.
Guido van Rossum1e074031998-03-05 04:05:38 +000096 path = sys.path[:]
Guido van Rossum75dc4961998-03-05 03:42:00 +000097 modargs = 0
98 debug = 1
Guido van Rossum0b4b8a21997-08-10 16:56:48 +000099 odir = ''
Guido van Rossum58a59481997-08-14 01:45:33 +0000100 win = sys.platform[:3] == 'win'
Guido van Rossum00ff4331994-10-03 16:33:08 +0000101
Guido van Rossum78fc3631998-03-20 17:37:24 +0000102 # default the exclude list for each platform
103# if win: exclude = exclude + ['dos', 'dospath', 'mac', 'macpath', 'MACFS', 'posix', 'os2']
104
Guido van Rossum94ce0d11997-12-08 05:01:06 +0000105 # modules that are imported by the Python runtime
106 implicits = ["site", "exceptions"]
107
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000108 # output files
109 frozen_c = 'frozen.c'
110 config_c = 'config.c'
111 target = 'a.out' # normally derived from script name
112 makefile = 'Makefile'
Guido van Rossum58a59481997-08-14 01:45:33 +0000113 subsystem = 'console'
Guido van Rossum00ff4331994-10-03 16:33:08 +0000114
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000115 # parse command line
116 try:
Guido van Rossum78fc3631998-03-20 17:37:24 +0000117 opts, args = getopt.getopt(sys.argv[1:], 'de:hmo:p:P:qs:wx:l:')
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000118 except getopt.error, msg:
119 usage('getopt error: ' + str(msg))
Guido van Rossum00ff4331994-10-03 16:33:08 +0000120
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000121 # proces option arguments
122 for o, a in opts:
123 if o == '-h':
124 print __doc__
125 return
Guido van Rossum75dc4961998-03-05 03:42:00 +0000126 if o == '-d':
127 debug = debug + 1
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000128 if o == '-e':
129 extensions.append(a)
Guido van Rossum75dc4961998-03-05 03:42:00 +0000130 if o == '-m':
131 modargs = 1
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000132 if o == '-o':
133 odir = a
134 if o == '-p':
135 prefix = a
136 if o == '-P':
137 exec_prefix = a
Guido van Rossum75dc4961998-03-05 03:42:00 +0000138 if o == '-q':
139 debug = 0
Guido van Rossum58a59481997-08-14 01:45:33 +0000140 if o == '-w':
141 win = not win
142 if o == '-s':
143 if not win:
144 usage("-s subsystem option only on Windows")
145 subsystem = a
Guido van Rossum78fc3631998-03-20 17:37:24 +0000146 if o == '-x':
147 exclude.append(a)
148 if o == '-l':
149 addn_link.append(a)
Guido van Rossumdbaf3321994-10-03 10:25:54 +0000150
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000151 # default prefix and exec_prefix
152 if not exec_prefix:
153 if prefix:
154 exec_prefix = prefix
155 else:
156 exec_prefix = sys.exec_prefix
157 if not prefix:
158 prefix = sys.prefix
Guido van Rossum9a6e8551997-08-10 16:47:17 +0000159
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000160 # determine whether -p points to the Python source tree
Guido van Rossume0394251998-03-05 05:39:50 +0000161 ishome = os.path.exists(os.path.join(prefix, 'Python', 'ceval.c'))
Guido van Rossumdbaf3321994-10-03 10:25:54 +0000162
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000163 # locations derived from options
164 version = sys.version[:3]
165 if ishome:
166 print "(Using Python source directory)"
167 binlib = exec_prefix
168 incldir = os.path.join(prefix, 'Include')
169 config_c_in = os.path.join(prefix, 'Modules', 'config.c.in')
Guido van Rossum58a59481997-08-14 01:45:33 +0000170 frozenmain_c = os.path.join(prefix, 'Python', 'frozenmain.c')
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000171 makefile_in = os.path.join(exec_prefix, 'Modules', 'Makefile')
Guido van Rossum78fc3631998-03-20 17:37:24 +0000172 if win: frozendllmain_c = os.path.join(exec_prefix, 'Pc\\frozen_dllmain.c')
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000173 else:
174 binlib = os.path.join(exec_prefix,
175 'lib', 'python%s' % version, 'config')
176 incldir = os.path.join(prefix, 'include', 'python%s' % version)
177 config_c_in = os.path.join(binlib, 'config.c.in')
178 frozenmain_c = os.path.join(binlib, 'frozenmain.c')
179 makefile_in = os.path.join(binlib, 'Makefile')
180 supp_sources = []
181 defines = []
182 includes = ['-I' + incldir, '-I' + binlib]
Guido van Rossumd8336c21994-10-05 16:13:01 +0000183
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000184 # sanity check of directories and files
185 for dir in [prefix, exec_prefix, binlib, incldir] + extensions:
186 if not os.path.exists(dir):
187 usage('needed directory %s not found' % dir)
188 if not os.path.isdir(dir):
189 usage('%s: not a directory' % dir)
Guido van Rossum58a59481997-08-14 01:45:33 +0000190 if win:
191 files = supp_sources
192 else:
193 files = [config_c_in, makefile_in] + supp_sources
194 for file in supp_sources:
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000195 if not os.path.exists(file):
196 usage('needed file %s not found' % file)
197 if not os.path.isfile(file):
198 usage('%s: not a plain file' % file)
Guido van Rossum58a59481997-08-14 01:45:33 +0000199 if not win:
200 for dir in extensions:
201 setup = os.path.join(dir, 'Setup')
202 if not os.path.exists(setup):
203 usage('needed file %s not found' % setup)
204 if not os.path.isfile(setup):
205 usage('%s: not a plain file' % setup)
Guido van Rossum00ff4331994-10-03 16:33:08 +0000206
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000207 # check that enough arguments are passed
208 if not args:
209 usage('at least one filename argument required')
Guido van Rossumd4cc04c1996-06-17 17:49:13 +0000210
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000211 # check that file arguments exist
212 for arg in args:
Guido van Rossum1e074031998-03-05 04:05:38 +0000213 if arg == '-m':
214 break
Guido van Rossum78fc3631998-03-20 17:37:24 +0000215 # if user specified -m on the command line before _any_
216 # file names, then nothing should be checked (as the
217 # very first file should be a module name)
218 if modargs:
219 break
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000220 if not os.path.exists(arg):
221 usage('argument %s not found' % arg)
222 if not os.path.isfile(arg):
223 usage('%s: not a plain file' % arg)
Guido van Rossum00ff4331994-10-03 16:33:08 +0000224
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000225 # process non-option arguments
226 scriptfile = args[0]
227 modules = args[1:]
Guido van Rossum00ff4331994-10-03 16:33:08 +0000228
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000229 # derive target name from script name
230 base = os.path.basename(scriptfile)
231 base, ext = os.path.splitext(base)
232 if base:
233 if base != scriptfile:
234 target = base
235 else:
236 target = base + '.bin'
Guido van Rossum00ff4331994-10-03 16:33:08 +0000237
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000238 # handle -o option
239 base_frozen_c = frozen_c
240 base_config_c = config_c
241 base_target = target
242 if odir and not os.path.isdir(odir):
243 try:
244 os.mkdir(odir)
245 print "Created output directory", odir
246 except os.error, msg:
247 usage('%s: mkdir failed (%s)' % (odir, str(msg)))
248 if odir:
249 frozen_c = os.path.join(odir, frozen_c)
250 config_c = os.path.join(odir, config_c)
251 target = os.path.join(odir, target)
252 makefile = os.path.join(odir, makefile)
Guido van Rossum00ff4331994-10-03 16:33:08 +0000253
Guido van Rossum78fc3631998-03-20 17:37:24 +0000254 # Handle special entry point requirements
255 # (on Windows, some frozen programs do not use __main__, but
256 # import the module directly. Eg, DLLs, Services, etc
257 custom_entry_point = None # Currently only used on Windows
258 python_entry_is_main = 1 # Is the entry point called __main__?
259 # handle -s option on Windows
260 if win:
261 import winmakemakefile
262 try:
263 custom_entry_point, python_entry_is_main = winmakemakefile. get_custom_entry_point(subsystem)
264 except ValueError, why:
265 usage(why)
266
267
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000268 # Actual work starts here...
Guido van Rossumd8336c21994-10-05 16:13:01 +0000269
Guido van Rossum75dc4961998-03-05 03:42:00 +0000270 # collect all modules of the program
Guido van Rossum1e074031998-03-05 04:05:38 +0000271 dir = os.path.dirname(scriptfile)
272 path[0] = dir
Guido van Rossum78fc3631998-03-20 17:37:24 +0000273 mf = modulefinder.ModuleFinder(path, debug, exclude)
274
275 if win and subsystem=='service':
276 # If a Windows service, then add the "built-in" module.
277 mod = mf.add_module("servicemanager")
278 mod.__file__="dummy.pyd" # really built-in to the resulting EXE
279
Guido van Rossum75dc4961998-03-05 03:42:00 +0000280 for mod in implicits:
281 mf.import_hook(mod)
282 for mod in modules:
283 if mod == '-m':
284 modargs = 1
285 continue
286 if modargs:
287 if mod[-2:] == '.*':
288 mf.import_hook(mod[:-2], None, ["*"])
289 else:
290 mf.import_hook(mod)
291 else:
292 mf.load_file(mod)
Guido van Rossum78fc3631998-03-20 17:37:24 +0000293
294 # Add the main script as either __main__, or the actual module name.
295 if python_entry_is_main:
296 mf.run_script(scriptfile)
297 else:
298 if modargs:
299 mf.import_hook(scriptfile)
300 else:
301 mf.load_file(scriptfile)
302
Guido van Rossum75dc4961998-03-05 03:42:00 +0000303 if debug > 0:
304 mf.report()
305 print
306 dict = mf.modules
Guido van Rossumdbaf3321994-10-03 10:25:54 +0000307
Guido van Rossum75dc4961998-03-05 03:42:00 +0000308 # generate output for frozen modules
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000309 backup = frozen_c + '~'
310 try:
311 os.rename(frozen_c, backup)
312 except os.error:
313 backup = None
314 outfp = open(frozen_c, 'w')
315 try:
Guido van Rossum78fc3631998-03-20 17:37:24 +0000316 makefreeze.makefreeze(outfp, dict, debug, custom_entry_point)
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000317 finally:
318 outfp.close()
319 if backup:
320 if cmp.cmp(backup, frozen_c):
Guido van Rossume0394251998-03-05 05:39:50 +0000321 sys.stderr.write('%s not changed, not written\n' % frozen_c)
322 os.unlink(frozen_c)
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000323 os.rename(backup, frozen_c)
Guido van Rossumdbaf3321994-10-03 10:25:54 +0000324
Guido van Rossuma0e18351998-03-07 04:51:03 +0000325 # look for unfrozen modules (builtin and of unknown origin)
326 builtins = []
327 unknown = []
328 mods = dict.keys()
329 mods.sort()
330 for mod in mods:
331 if dict[mod].__code__:
332 continue
333 if not dict[mod].__file__:
334 builtins.append(mod)
335 else:
336 unknown.append(mod)
337
338 # search for unknown modules in extensions directories (not on Windows)
339 addfiles = []
Guido van Rossum78fc3631998-03-20 17:37:24 +0000340 addmoddefns = [] # Windows list of modules.
Guido van Rossuma937afd1998-04-23 14:39:24 +0000341 if unknown or (not win and builtins):
Guido van Rossum78fc3631998-03-20 17:37:24 +0000342 if not win:
343 addfiles, addmods = \
Guido van Rossuma937afd1998-04-23 14:39:24 +0000344 checkextensions.checkextensions(unknown+builtins,
345 extensions)
Guido van Rossum78fc3631998-03-20 17:37:24 +0000346 for mod in addmods:
Guido van Rossuma937afd1998-04-23 14:39:24 +0000347 if mod in unknown:
348 unknown.remove(mod)
349 builtins.append(mod)
Guido van Rossum78fc3631998-03-20 17:37:24 +0000350 else:
351 # Do the windows thang...
352 import checkextensions_win32
353 # Get a list of CExtension instances, each describing a module
354 # (including its source files)
355 addmoddefns = checkextensions_win32.checkextensions(unknown, extensions)
356 maindefn = checkextensions_win32.CExtension( '__main__',
357 [frozenmain_c, os.path.basename(frozen_c),frozendllmain_c])
358
359 for mod in addmoddefns:
360 unknown.remove(mod.name)
361 builtins.append(mod.name)
362
363 addmoddefns.append( maindefn )
364
Guido van Rossuma0e18351998-03-07 04:51:03 +0000365
366 # report unknown modules
367 if unknown:
368 sys.stderr.write('Warning: unknown modules remain: %s\n' %
369 string.join(unknown))
370
Guido van Rossum75dc4961998-03-05 03:42:00 +0000371 # windows gets different treatment
Guido van Rossum58a59481997-08-14 01:45:33 +0000372 if win:
373 # Taking a shortcut here...
374 import winmakemakefile
375 outfp = open(makefile, 'w')
376 try:
377 winmakemakefile.makemakefile(outfp,
378 locals(),
Guido van Rossum78fc3631998-03-20 17:37:24 +0000379 addmoddefns,
Guido van Rossum31d53ed1998-03-07 04:08:04 +0000380 os.path.basename(target))
Guido van Rossum58a59481997-08-14 01:45:33 +0000381 finally:
382 outfp.close()
383 return
384
Guido van Rossum75dc4961998-03-05 03:42:00 +0000385 # generate config.c and Makefile
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000386 builtins.sort()
387 infp = open(config_c_in)
388 backup = config_c + '~'
389 try:
390 os.rename(config_c, backup)
391 except os.error:
392 backup = None
393 outfp = open(config_c, 'w')
394 try:
395 makeconfig.makeconfig(infp, outfp, builtins)
396 finally:
397 outfp.close()
398 infp.close()
399 if backup:
400 if cmp.cmp(backup, config_c):
Guido van Rossume0394251998-03-05 05:39:50 +0000401 sys.stderr.write('%s not changed, not written\n' % config_c)
402 os.unlink(config_c)
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000403 os.rename(backup, config_c)
Guido van Rossumdbaf3321994-10-03 10:25:54 +0000404
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000405 cflags = defines + includes + ['$(OPT)']
406 libs = [os.path.join(binlib, 'libpython$(VERSION).a')]
Guido van Rossum00ff4331994-10-03 16:33:08 +0000407
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000408 somevars = {}
Guido van Rossum345df171997-11-22 22:10:01 +0000409 if os.path.exists(makefile_in):
410 makevars = parsesetup.getmakevars(makefile_in)
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000411 for key in makevars.keys():
412 somevars[key] = makevars[key]
Guido van Rossum00ff4331994-10-03 16:33:08 +0000413
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000414 somevars['CFLAGS'] = string.join(cflags) # override
415 files = ['$(OPT)', '$(LDFLAGS)', base_config_c, base_frozen_c] + \
416 supp_sources + addfiles + libs + \
417 ['$(MODLIBS)', '$(LIBS)', '$(SYSLIBS)']
Guido van Rossum00ff4331994-10-03 16:33:08 +0000418
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000419 backup = makefile + '~'
Guido van Rossume0394251998-03-05 05:39:50 +0000420 if os.path.exists(makefile):
421 try:
422 os.unlink(backup)
423 except os.error:
424 pass
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000425 try:
426 os.rename(makefile, backup)
427 except os.error:
428 backup = None
429 outfp = open(makefile, 'w')
430 try:
431 makemakefile.makemakefile(outfp, somevars, files, base_target)
432 finally:
433 outfp.close()
434 if backup:
435 if not cmp.cmp(backup, makefile):
436 print 'previous Makefile saved as', backup
437 else:
Guido van Rossume0394251998-03-05 05:39:50 +0000438 sys.stderr.write('%s not changed, not written\n' % makefile)
439 os.unlink(makefile)
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000440 os.rename(backup, makefile)
441
442 # Done!
443
444 if odir:
445 print 'Now run "make" in', odir,
446 print 'to build the target:', base_target
447 else:
448 print 'Now run "make" to build the target:', base_target
Guido van Rossum00ff4331994-10-03 16:33:08 +0000449
Guido van Rossumd8336c21994-10-05 16:13:01 +0000450
451# Print usage message and exit
452
Guido van Rossum9a6e8551997-08-10 16:47:17 +0000453def usage(msg):
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000454 sys.stdout = sys.stderr
455 print "Error:", msg
456 print "Use ``%s -h'' for help" % sys.argv[0]
457 sys.exit(2)
Guido van Rossumd8336c21994-10-05 16:13:01 +0000458
459
Guido van Rossumdbaf3321994-10-03 10:25:54 +0000460main()
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000461
462# Local Variables:
463# indent-tabs-mode: nil
464# End: