Initial revision
This commit is contained in:
14
intern/python/freeze/Makefile
Normal file
14
intern/python/freeze/Makefile
Normal file
@@ -0,0 +1,14 @@
|
||||
# $Id$
|
||||
# This is the makefile for the bytecode freezing of all modules which
|
||||
# the main file depends on (last argument in importer rule)
|
||||
|
||||
SRCDIR = ../modules
|
||||
|
||||
TARGETDIR = ../../../source/blender/bpython/frozen
|
||||
|
||||
PYFLAGS = -S -O
|
||||
|
||||
default: importer
|
||||
|
||||
importer:
|
||||
python $(PYFLAGS) freeze.py -d -x os -x pprint -x Blender -I $(SRCDIR) -o $(TARGETDIR) $(SRCDIR)/VRMLmain.py
|
173
intern/python/freeze/README
Normal file
173
intern/python/freeze/README
Normal file
@@ -0,0 +1,173 @@
|
||||
THE FREEZE SCRIPT
|
||||
=================
|
||||
|
||||
(Directions for Windows are at the end of this file.)
|
||||
|
||||
|
||||
What is Freeze?
|
||||
---------------
|
||||
|
||||
Freeze make it possible to ship arbitrary Python programs to people
|
||||
who don't have Python. The shipped file (called a "frozen" version of
|
||||
your Python program) is an executable, so this only works if your
|
||||
platform is compatible with that on the receiving end (this is usually
|
||||
a matter of having the same major operating system revision and CPU
|
||||
type).
|
||||
|
||||
The shipped file contains a Python interpreter and large portions of
|
||||
the Python run-time. Some measures have been taken to avoid linking
|
||||
unneeded modules, but the resulting binary is usually not small.
|
||||
|
||||
The Python source code of your program (and of the library modules
|
||||
written in Python that it uses) is not included in the binary --
|
||||
instead, the compiled byte-code (the instruction stream used
|
||||
internally by the interpreter) is incorporated. This gives some
|
||||
protection of your Python source code, though not much -- a
|
||||
disassembler for Python byte-code is available in the standard Python
|
||||
library. At least someone running "strings" on your binary won't see
|
||||
the source.
|
||||
|
||||
|
||||
How does Freeze know which modules to include?
|
||||
----------------------------------------------
|
||||
|
||||
Previous versions of Freeze used a pretty simple-minded algorithm to
|
||||
find the modules that your program uses, essentially searching for
|
||||
lines starting with the word "import". It was pretty easy to trick it
|
||||
into making mistakes, either missing valid import statements, or
|
||||
mistaking string literals (e.g. doc strings) for import statements.
|
||||
|
||||
This has been remedied: Freeze now uses the regular Python parser to
|
||||
parse the program (and all its modules) and scans the generated byte
|
||||
code for IMPORT instructions. It may still be confused -- it will not
|
||||
know about calls to the __import__ built-in function, or about import
|
||||
statements constructed on the fly and executed using the 'exec'
|
||||
statement, and it will consider import statements even when they are
|
||||
unreachable (e.g. "if 0: import foobar").
|
||||
|
||||
This new version of Freeze also knows about Python's new package
|
||||
import mechanism, and uses exactly the same rules to find imported
|
||||
modules and packages. One exception: if you write 'from package
|
||||
import *', Python will look into the __all__ variable of the package
|
||||
to determine which modules are to be imported, while Freeze will do a
|
||||
directory listing.
|
||||
|
||||
One tricky issue: Freeze assumes that the Python interpreter and
|
||||
environment you're using to run Freeze is the same one that would be
|
||||
used to run your program, which should also be the same whose sources
|
||||
and installed files you will learn about in the next section. In
|
||||
particular, your PYTHONPATH setting should be the same as for running
|
||||
your program locally. (Tip: if the program doesn't run when you type
|
||||
"python hello.py" there's little chance of getting the frozen version
|
||||
to run.)
|
||||
|
||||
|
||||
How do I use Freeze?
|
||||
--------------------
|
||||
|
||||
Normally, you should be able to use it as follows:
|
||||
|
||||
python freeze.py hello.py
|
||||
|
||||
where hello.py is your program and freeze.py is the main file of
|
||||
Freeze (in actuality, you'll probably specify an absolute pathname
|
||||
such as /usr/joe/python/Tools/freeze/freeze.py).
|
||||
|
||||
|
||||
What do I do next?
|
||||
------------------
|
||||
|
||||
Freeze creates a number of files: frozen.c, config.c and Makefile,
|
||||
plus one file for each Python module that gets included named
|
||||
M_<module>.c. To produce the frozen version of your program, you can
|
||||
simply type "make". This should produce a binary file. If the
|
||||
filename argument to Freeze was "hello.py", the binary will be called
|
||||
"hello".
|
||||
|
||||
Note: you can use the -o option to freeze to specify an alternative
|
||||
directory where these files are created. This makes it easier to
|
||||
clean up after you've shipped the frozen binary. You should invoke
|
||||
"make" in the given directory.
|
||||
|
||||
|
||||
Freezing Tkinter programs
|
||||
-------------------------
|
||||
|
||||
Unfortunately, it is currently not possible to freeze programs that
|
||||
use Tkinter. It *seems* to work, but when you ship the frozen program
|
||||
to a site without a Tcl/Tk installation, it will fail with a complaint
|
||||
about missing Tcl/Tk initialization files.
|
||||
|
||||
A workaround would be possible, in which the Tcl/Tk library files are
|
||||
incorporated in a frozen Python module as string literals and written
|
||||
to a temporary location when the program runs; this is currently left
|
||||
as an exercise for the reader. (If you implement this, please post to
|
||||
the Python newsgroup!)
|
||||
|
||||
Of course, you can also simply require that Tcl/Tk is required on the
|
||||
target installation.
|
||||
|
||||
|
||||
A warning against shared library modules
|
||||
----------------------------------------
|
||||
|
||||
When your Python installation uses shared library modules, these will
|
||||
not be incorporated in the frozen program. Again, the frozen program
|
||||
will work when you test it, but it won't work when you ship it to a
|
||||
site without a Python installation.
|
||||
|
||||
Freeze prints a warning when this is the case at the end of the
|
||||
freezing process:
|
||||
|
||||
Warning: unknown modules remain: ...
|
||||
|
||||
When this occurs, the best thing to do is usually to rebuild Python
|
||||
using static linking only.
|
||||
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
If you have trouble using Freeze for a large program, it's probably
|
||||
best to start playing with a really simple program first (like the file
|
||||
hello.py). If you can't get that to work there's something
|
||||
fundamentally wrong -- perhaps you haven't installed Python. To do a
|
||||
proper install, you should do "make install" in the Python root
|
||||
directory.
|
||||
|
||||
|
||||
Usage under Windows 95 or NT
|
||||
----------------------------
|
||||
|
||||
Under Windows 95 or NT, you *must* use the -p option and point it to
|
||||
the top of the Python source tree.
|
||||
|
||||
WARNING: the resulting executable is not self-contained; it requires
|
||||
the Python DLL, currently PYTHON20.DLL (it does not require the
|
||||
standard library of .py files though). It may also require one or
|
||||
more extension modules loaded from .DLL or .PYD files; the module
|
||||
names are printed in the warning message about remaining unknown
|
||||
modules.
|
||||
|
||||
The driver script generates a Makefile that works with the Microsoft
|
||||
command line C compiler (CL). To compile, run "nmake"; this will
|
||||
build a target "hello.exe" if the source was "hello.py". Only the
|
||||
files frozenmain.c and frozen.c are used; no config.c is generated or
|
||||
used, since the standard DLL is used.
|
||||
|
||||
In order for this to work, you must have built Python using the VC++
|
||||
(Developer Studio) 5.0 compiler. The provided project builds
|
||||
python20.lib in the subdirectory pcbuild\Release of thje Python source
|
||||
tree, and this is where the generated Makefile expects it to be. If
|
||||
this is not the case, you can edit the Makefile or (probably better)
|
||||
winmakemakefile.py (e.g., if you are using the 4.2 compiler, the
|
||||
python20.lib file is generated in the subdirectory vc40 of the Python
|
||||
source tree).
|
||||
|
||||
You can freeze programs that use Tkinter, but Tcl/Tk must be installed
|
||||
on the target system.
|
||||
|
||||
It is possible to create frozen programs that don't have a console
|
||||
window, by specifying the option '-s windows'.
|
||||
|
||||
--Guido van Rossum (home page: http://www.python.org/~guido/)
|
12
intern/python/freeze/README.NaN
Normal file
12
intern/python/freeze/README.NaN
Normal file
@@ -0,0 +1,12 @@
|
||||
$Id$
|
||||
|
||||
This is a modification of the freeze.py script used to freeze python
|
||||
modules as byte code in Blender.
|
||||
|
||||
To create this byte code, simply type 'make'. Freeze will then generate
|
||||
the C source files in the TARGETDIR (specified in the Makefile), provided
|
||||
that you have a valid python installation.
|
||||
|
||||
Be warned: testing of the module dependencies is needed, as these are
|
||||
resolved AT RUNTIME!
|
||||
|
47
intern/python/freeze/bkfile.py
Normal file
47
intern/python/freeze/bkfile.py
Normal file
@@ -0,0 +1,47 @@
|
||||
_orig_open = open
|
||||
|
||||
class _BkFile:
|
||||
def __init__(self, file, mode, bufsize):
|
||||
import os
|
||||
self.__filename = file
|
||||
self.__backup = file + '~'
|
||||
try:
|
||||
os.unlink(self.__backup)
|
||||
except os.error:
|
||||
pass
|
||||
try:
|
||||
os.rename(file, self.__backup)
|
||||
except os.error:
|
||||
self.__backup = None
|
||||
self.__file = _orig_open(file, mode, bufsize)
|
||||
self.closed = self.__file.closed
|
||||
self.fileno = self.__file.fileno
|
||||
self.flush = self.__file.flush
|
||||
self.isatty = self.__file.isatty
|
||||
self.mode = self.__file.mode
|
||||
self.name = self.__file.name
|
||||
self.read = self.__file.read
|
||||
self.readinto = self.__file.readinto
|
||||
self.readline = self.__file.readline
|
||||
self.readlines = self.__file.readlines
|
||||
self.seek = self.__file.seek
|
||||
self.softspace = self.__file.softspace
|
||||
self.tell = self.__file.tell
|
||||
self.truncate = self.__file.truncate
|
||||
self.write = self.__file.write
|
||||
self.writelines = self.__file.writelines
|
||||
|
||||
def close(self):
|
||||
self.__file.close()
|
||||
if self.__backup is None:
|
||||
return
|
||||
import filecmp
|
||||
if filecmp.cmp(self.__backup, self.__filename, shallow = 0):
|
||||
import os
|
||||
os.unlink(self.__filename)
|
||||
os.rename(self.__backup, self.__filename)
|
||||
|
||||
def open(file, mode = 'r', bufsize = -1):
|
||||
if 'w' not in mode:
|
||||
return _orig_open(file, mode, bufsize)
|
||||
return _BkFile(file, mode, bufsize)
|
91
intern/python/freeze/checkextensions.py
Normal file
91
intern/python/freeze/checkextensions.py
Normal file
@@ -0,0 +1,91 @@
|
||||
# Check for a module in a set of extension directories.
|
||||
# An extension directory should contain a Setup file
|
||||
# and one or more .o files or a lib.a file.
|
||||
|
||||
import os
|
||||
import string
|
||||
import parsesetup
|
||||
|
||||
def checkextensions(unknown, extensions):
|
||||
files = []
|
||||
modules = []
|
||||
edict = {}
|
||||
for e in extensions:
|
||||
setup = os.path.join(e, 'Setup')
|
||||
liba = os.path.join(e, 'lib.a')
|
||||
if not os.path.isfile(liba):
|
||||
liba = None
|
||||
edict[e] = parsesetup.getsetupinfo(setup), liba
|
||||
for mod in unknown:
|
||||
for e in extensions:
|
||||
(mods, vars), liba = edict[e]
|
||||
if not mods.has_key(mod):
|
||||
continue
|
||||
modules.append(mod)
|
||||
if liba:
|
||||
# If we find a lib.a, use it, ignore the
|
||||
# .o files, and use *all* libraries for
|
||||
# *all* modules in the Setup file
|
||||
if liba in files:
|
||||
break
|
||||
files.append(liba)
|
||||
for m in mods.keys():
|
||||
files = files + select(e, mods, vars,
|
||||
m, 1)
|
||||
break
|
||||
files = files + select(e, mods, vars, mod, 0)
|
||||
break
|
||||
return files, modules
|
||||
|
||||
def select(e, mods, vars, mod, skipofiles):
|
||||
files = []
|
||||
for w in mods[mod]:
|
||||
w = treatword(w)
|
||||
if not w:
|
||||
continue
|
||||
w = expandvars(w, vars)
|
||||
for w in string.split(w):
|
||||
if skipofiles and w[-2:] == '.o':
|
||||
continue
|
||||
# Assume $var expands to absolute pathname
|
||||
if w[0] not in ('-', '$') and w[-2:] in ('.o', '.a'):
|
||||
w = os.path.join(e, w)
|
||||
if w[:2] in ('-L', '-R') and w[2:3] != '$':
|
||||
w = w[:2] + os.path.join(e, w[2:])
|
||||
files.append(w)
|
||||
return files
|
||||
|
||||
cc_flags = ['-I', '-D', '-U']
|
||||
cc_exts = ['.c', '.C', '.cc', '.c++']
|
||||
|
||||
def treatword(w):
|
||||
if w[:2] in cc_flags:
|
||||
return None
|
||||
if w[:1] == '-':
|
||||
return w # Assume loader flag
|
||||
head, tail = os.path.split(w)
|
||||
base, ext = os.path.splitext(tail)
|
||||
if ext in cc_exts:
|
||||
tail = base + '.o'
|
||||
w = os.path.join(head, tail)
|
||||
return w
|
||||
|
||||
def expandvars(str, vars):
|
||||
i = 0
|
||||
while i < len(str):
|
||||
i = k = string.find(str, '$', i)
|
||||
if i < 0:
|
||||
break
|
||||
i = i+1
|
||||
var = str[i:i+1]
|
||||
i = i+1
|
||||
if var == '(':
|
||||
j = string.find(str, ')', i)
|
||||
if j < 0:
|
||||
break
|
||||
var = str[i:j]
|
||||
i = j+1
|
||||
if vars.has_key(var):
|
||||
str = str[:k] + vars[var] + str[i:]
|
||||
i = k
|
||||
return str
|
190
intern/python/freeze/checkextensions_win32.py
Normal file
190
intern/python/freeze/checkextensions_win32.py
Normal file
@@ -0,0 +1,190 @@
|
||||
"""Extension management for Windows.
|
||||
|
||||
Under Windows it is unlikely the .obj files are of use, as special compiler options
|
||||
are needed (primarily to toggle the behavior of "public" symbols.
|
||||
|
||||
I dont consider it worth parsing the MSVC makefiles for compiler options. Even if
|
||||
we get it just right, a specific freeze application may have specific compiler
|
||||
options anyway (eg, to enable or disable specific functionality)
|
||||
|
||||
So my basic stragtegy is:
|
||||
|
||||
* Have some Windows INI files which "describe" one or more extension modules.
|
||||
(Freeze comes with a default one for all known modules - but you can specify
|
||||
your own).
|
||||
* This description can include:
|
||||
- The MSVC .dsp file for the extension. The .c source file names
|
||||
are extraced from there.
|
||||
- Specific compiler/linker options
|
||||
- Flag to indicate if Unicode compilation is expected.
|
||||
|
||||
At the moment the name and location of this INI file is hardcoded,
|
||||
but an obvious enhancement would be to provide command line options.
|
||||
"""
|
||||
|
||||
import os, string, sys
|
||||
try:
|
||||
import win32api
|
||||
except ImportError:
|
||||
win32api = None # User has already been warned
|
||||
|
||||
class CExtension:
|
||||
"""An abstraction of an extension implemented in C/C++
|
||||
"""
|
||||
def __init__(self, name, sourceFiles):
|
||||
self.name = name
|
||||
# A list of strings defining additional compiler options.
|
||||
self.sourceFiles = sourceFiles
|
||||
# A list of special compiler options to be applied to
|
||||
# all source modules in this extension.
|
||||
self.compilerOptions = []
|
||||
# A list of .lib files the final .EXE will need.
|
||||
self.linkerLibs = []
|
||||
|
||||
def GetSourceFiles(self):
|
||||
return self.sourceFiles
|
||||
|
||||
def AddCompilerOption(self, option):
|
||||
self.compilerOptions.append(option)
|
||||
def GetCompilerOptions(self):
|
||||
return self.compilerOptions
|
||||
|
||||
def AddLinkerLib(self, lib):
|
||||
self.linkerLibs.append(lib)
|
||||
def GetLinkerLibs(self):
|
||||
return self.linkerLibs
|
||||
|
||||
def checkextensions(unknown, extra_inis, prefix):
|
||||
# Create a table of frozen extensions
|
||||
|
||||
defaultMapName = os.path.join( os.path.split(sys.argv[0])[0], "extensions_win32.ini")
|
||||
if not os.path.isfile(defaultMapName):
|
||||
sys.stderr.write("WARNING: %s can not be found - standard extensions may not be found" % mapFileName)
|
||||
else:
|
||||
# must go on end, so other inis can override.
|
||||
extra_inis.append(defaultMapName)
|
||||
|
||||
ret = []
|
||||
for mod in unknown:
|
||||
for ini in extra_inis:
|
||||
# print "Looking for", mod, "in", win32api.GetFullPathName(ini),"...",
|
||||
defn = get_extension_defn( mod, ini, prefix )
|
||||
if defn is not None:
|
||||
# print "Yay - found it!"
|
||||
ret.append( defn )
|
||||
break
|
||||
# print "Nope!"
|
||||
else: # For not broken!
|
||||
sys.stderr.write("No definition of module %s in any specified map file.\n" % (mod))
|
||||
|
||||
return ret
|
||||
|
||||
def get_extension_defn(moduleName, mapFileName, prefix):
|
||||
if win32api is None: return None
|
||||
os.environ['PYTHONPREFIX'] = prefix
|
||||
dsp = win32api.GetProfileVal(moduleName, "dsp", "", mapFileName)
|
||||
if dsp=="":
|
||||
return None
|
||||
|
||||
# We allow environment variables in the file name
|
||||
dsp = win32api.ExpandEnvironmentStrings(dsp)
|
||||
# If the path to the .DSP file is not absolute, assume it is relative
|
||||
# to the description file.
|
||||
if not os.path.isabs(dsp):
|
||||
dsp = os.path.join( os.path.split(mapFileName)[0], dsp)
|
||||
# Parse it to extract the source files.
|
||||
sourceFiles = parse_dsp(dsp)
|
||||
if sourceFiles is None:
|
||||
return None
|
||||
|
||||
module = CExtension(moduleName, sourceFiles)
|
||||
# Put the path to the DSP into the environment so entries can reference it.
|
||||
os.environ['dsp_path'] = os.path.split(dsp)[0]
|
||||
os.environ['ini_path'] = os.path.split(mapFileName)[0]
|
||||
|
||||
cl_options = win32api.GetProfileVal(moduleName, "cl", "", mapFileName)
|
||||
if cl_options:
|
||||
module.AddCompilerOption(win32api.ExpandEnvironmentStrings(cl_options))
|
||||
|
||||
exclude = win32api.GetProfileVal(moduleName, "exclude", "", mapFileName)
|
||||
exclude = string.split(exclude)
|
||||
|
||||
if win32api.GetProfileVal(moduleName, "Unicode", 0, mapFileName):
|
||||
module.AddCompilerOption('/D UNICODE /D _UNICODE')
|
||||
|
||||
libs = string.split(win32api.GetProfileVal(moduleName, "libs", "", mapFileName))
|
||||
for lib in libs:
|
||||
module.AddLinkerLib(win32api.ExpandEnvironmentStrings(lib))
|
||||
|
||||
for exc in exclude:
|
||||
if exc in module.sourceFiles:
|
||||
modules.sourceFiles.remove(exc)
|
||||
|
||||
return module
|
||||
|
||||
# Given an MSVC DSP file, locate C source files it uses
|
||||
# returns a list of source files.
|
||||
def parse_dsp(dsp):
|
||||
# print "Processing", dsp
|
||||
# For now, only support
|
||||
ret = []
|
||||
dsp_path, dsp_name = os.path.split(dsp)
|
||||
try:
|
||||
lines = open(dsp, "r").readlines()
|
||||
except IOError, msg:
|
||||
sys.stderr.write("%s: %s\n" % (dsp, msg))
|
||||
return None
|
||||
for line in lines:
|
||||
fields = string.split(string.strip(line), "=", 2)
|
||||
if fields[0]=="SOURCE":
|
||||
if string.lower(os.path.splitext(fields[1])[1]) in ['.cpp', '.c']:
|
||||
ret.append( win32api.GetFullPathName(os.path.join(dsp_path, fields[1] ) ) )
|
||||
return ret
|
||||
|
||||
def write_extension_table(fname, modules):
|
||||
fp = open(fname, "w")
|
||||
try:
|
||||
fp.write (ext_src_header)
|
||||
# Write fn protos
|
||||
for module in modules:
|
||||
# bit of a hack for .pyd's as part of packages.
|
||||
name = string.split(module.name,'.')[-1]
|
||||
fp.write('extern void init%s(void);\n' % (name) )
|
||||
# Write the table
|
||||
fp.write (ext_tab_header)
|
||||
for module in modules:
|
||||
name = string.split(module.name,'.')[-1]
|
||||
fp.write('\t{"%s", init%s},\n' % (name, name) )
|
||||
|
||||
fp.write (ext_tab_footer)
|
||||
fp.write(ext_src_footer)
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
|
||||
ext_src_header = """\
|
||||
#include "Python.h"
|
||||
"""
|
||||
|
||||
ext_tab_header = """\
|
||||
|
||||
static struct _inittab extensions[] = {
|
||||
"""
|
||||
|
||||
ext_tab_footer = """\
|
||||
/* Sentinel */
|
||||
{0, 0}
|
||||
};
|
||||
"""
|
||||
|
||||
ext_src_footer = """\
|
||||
extern DL_IMPORT(int) PyImport_ExtendInittab(struct _inittab *newtab);
|
||||
|
||||
int PyInitFrozenExtensions()
|
||||
{
|
||||
return PyImport_ExtendInittab(extensions);
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
|
461
intern/python/freeze/freeze.py
Executable file
461
intern/python/freeze/freeze.py
Executable file
@@ -0,0 +1,461 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
# changes made by strubi@blender.nl
|
||||
|
||||
"""Freeze a Python script into a binary.
|
||||
|
||||
usage: freeze [options...] script [module]...
|
||||
|
||||
Options:
|
||||
-p prefix: This is the prefix used when you ran ``make install''
|
||||
in the Python build directory.
|
||||
(If you never ran this, freeze won't work.)
|
||||
The default is whatever sys.prefix evaluates to.
|
||||
It can also be the top directory of the Python source
|
||||
tree; then -P must point to the build tree.
|
||||
|
||||
-P exec_prefix: Like -p but this is the 'exec_prefix', used to
|
||||
install objects etc. The default is whatever sys.exec_prefix
|
||||
evaluates to, or the -p argument if given.
|
||||
If -p points to the Python source tree, -P must point
|
||||
to the build tree, if different.
|
||||
|
||||
-e extension: A directory containing additional .o files that
|
||||
may be used to resolve modules. This directory
|
||||
should also have a Setup file describing the .o files.
|
||||
On Windows, the name of a .INI file describing one
|
||||
or more extensions is passed.
|
||||
More than one -e option may be given.
|
||||
|
||||
-o dir: Directory where the output files are created; default '.'.
|
||||
|
||||
-m: Additional arguments are module names instead of filenames.
|
||||
|
||||
-a package=dir: Additional directories to be added to the package's
|
||||
__path__. Used to simulate directories added by the
|
||||
package at runtime (eg, by OpenGL and win32com).
|
||||
More than one -a option may be given for each package.
|
||||
|
||||
-l file: Pass the file to the linker (windows only)
|
||||
|
||||
-d: Debugging mode for the module finder.
|
||||
|
||||
-q: Make the module finder totally quiet.
|
||||
|
||||
-h: Print this help message.
|
||||
|
||||
-x module Exclude the specified module.
|
||||
|
||||
-i filename: Include a file with additional command line options. Used
|
||||
to prevent command lines growing beyond the capabilities of
|
||||
the shell/OS. All arguments specified in filename
|
||||
are read and the -i option replaced with the parsed
|
||||
params (note - quoting args in this file is NOT supported)
|
||||
|
||||
-s subsystem: Specify the subsystem (For Windows only.);
|
||||
'console' (default), 'windows', 'service' or 'com_dll'
|
||||
|
||||
-w: Toggle Windows (NT or 95) behavior.
|
||||
(For debugging only -- on a win32 platform, win32 behavior
|
||||
is automatic.)
|
||||
|
||||
Arguments:
|
||||
|
||||
script: The Python script to be executed by the resulting binary.
|
||||
|
||||
module ...: Additional Python modules (referenced by pathname)
|
||||
that will be included in the resulting binary. These
|
||||
may be .py or .pyc files. If -m is specified, these are
|
||||
module names that are search in the path instead.
|
||||
|
||||
NOTES:
|
||||
|
||||
In order to use freeze successfully, you must have built Python and
|
||||
installed it ("make install").
|
||||
|
||||
The script should not use modules provided only as shared libraries;
|
||||
if it does, the resulting binary is not self-contained.
|
||||
"""
|
||||
|
||||
|
||||
# Import standard modules
|
||||
|
||||
import getopt
|
||||
import os
|
||||
import string
|
||||
import sys
|
||||
|
||||
|
||||
# Import the freeze-private modules
|
||||
|
||||
import checkextensions
|
||||
import modulefinder
|
||||
import makeconfig
|
||||
import makefreeze
|
||||
import makemakefile
|
||||
import parsesetup
|
||||
import bkfile
|
||||
|
||||
|
||||
# Main program
|
||||
|
||||
def main():
|
||||
# overridable context
|
||||
prefix = None # settable with -p option
|
||||
exec_prefix = None # settable with -P option
|
||||
extensions = []
|
||||
exclude = [] # settable with -x option
|
||||
addn_link = [] # settable with -l, but only honored under Windows.
|
||||
path = sys.path[:]
|
||||
modargs = 0
|
||||
debug = 1
|
||||
odir = ''
|
||||
win = sys.platform[:3] == 'win'
|
||||
|
||||
# default the exclude list for each platform
|
||||
if win: exclude = exclude + [
|
||||
'dos', 'dospath', 'mac', 'macpath', 'macfs', 'MACFS', 'posix', 'os2', 'ce']
|
||||
|
||||
# modules that are imported by the Python runtime
|
||||
#implicits = ["site", "exceptions"]
|
||||
implicits = ["exceptions"]
|
||||
|
||||
# output files
|
||||
frozen_c = 'frozen.c'
|
||||
config_c = 'config.c'
|
||||
target = 'a.out' # normally derived from script name
|
||||
makefile = 'Makefile.freeze'
|
||||
subsystem = 'console'
|
||||
|
||||
# parse command line by first replacing any "-i" options with the file contents.
|
||||
pos = 1
|
||||
while pos < len(sys.argv)-1: # last option can not be "-i", so this ensures "pos+1" is in range!
|
||||
if sys.argv[pos] == '-i':
|
||||
try:
|
||||
options = string.split(open(sys.argv[pos+1]).read())
|
||||
except IOError, why:
|
||||
usage("File name '%s' specified with the -i option can not be read - %s" % (sys.argv[pos+1], why) )
|
||||
# Replace the '-i' and the filename with the read params.
|
||||
sys.argv[pos:pos+2] = options
|
||||
pos = pos + len(options) - 1 # Skip the name and the included args.
|
||||
pos = pos + 1
|
||||
|
||||
# Now parse the command line with the extras inserted.
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'a:de:hmo:p:P:I:qs:wx:l:')
|
||||
except getopt.error, msg:
|
||||
usage('getopt error: ' + str(msg))
|
||||
|
||||
# proces option arguments
|
||||
for o, a in opts:
|
||||
if o == '-h':
|
||||
print __doc__
|
||||
return
|
||||
if o == '-d':
|
||||
debug = debug + 1
|
||||
if o == '-e':
|
||||
extensions.append(a)
|
||||
if o == '-I': # include path
|
||||
path.append(a)
|
||||
if o == '-m':
|
||||
modargs = 1
|
||||
if o == '-o':
|
||||
odir = a
|
||||
if o == '-p':
|
||||
prefix = a
|
||||
if o == '-P':
|
||||
exec_prefix = a
|
||||
if o == '-q':
|
||||
debug = 0
|
||||
if o == '-w':
|
||||
win = not win
|
||||
if o == '-s':
|
||||
if not win:
|
||||
usage("-s subsystem option only on Windows")
|
||||
subsystem = a
|
||||
if o == '-x':
|
||||
exclude.append(a)
|
||||
if o == '-l':
|
||||
addn_link.append(a)
|
||||
if o == '-a':
|
||||
apply(modulefinder.AddPackagePath, tuple(string.split(a,"=", 2)))
|
||||
|
||||
# default prefix and exec_prefix
|
||||
if not exec_prefix:
|
||||
if prefix:
|
||||
exec_prefix = prefix
|
||||
else:
|
||||
exec_prefix = sys.exec_prefix
|
||||
if not prefix:
|
||||
prefix = sys.prefix
|
||||
|
||||
# determine whether -p points to the Python source tree
|
||||
ishome = os.path.exists(os.path.join(prefix, 'Python', 'ceval.c'))
|
||||
|
||||
# locations derived from options
|
||||
version = sys.version[:3]
|
||||
if win:
|
||||
extensions_c = 'frozen_extensions.c'
|
||||
if ishome:
|
||||
print "(Using Python source directory)"
|
||||
binlib = exec_prefix
|
||||
incldir = os.path.join(prefix, 'Include')
|
||||
config_h_dir = exec_prefix
|
||||
config_c_in = os.path.join(prefix, 'Modules', 'config.c.in')
|
||||
frozenmain_c = os.path.join(prefix, 'Python', 'frozenmain.c')
|
||||
makefile_in = os.path.join(exec_prefix, 'Modules', 'Makefile')
|
||||
if win:
|
||||
frozendllmain_c = os.path.join(exec_prefix, 'Pc\\frozen_dllmain.c')
|
||||
else:
|
||||
binlib = os.path.join(exec_prefix,
|
||||
'lib', 'python%s' % version, 'config')
|
||||
incldir = os.path.join(prefix, 'include', 'python%s' % version)
|
||||
config_h_dir = os.path.join(exec_prefix, 'include',
|
||||
'python%s' % version)
|
||||
config_c_in = os.path.join(binlib, 'config.c.in')
|
||||
frozenmain_c = os.path.join(binlib, 'frozenmain.c')
|
||||
makefile_in = os.path.join(binlib, 'Makefile')
|
||||
frozendllmain_c = os.path.join(binlib, 'frozen_dllmain.c')
|
||||
supp_sources = []
|
||||
defines = []
|
||||
includes = ['-I' + incldir, '-I' + config_h_dir]
|
||||
|
||||
# sanity check of directories and files
|
||||
check_dirs = [prefix, exec_prefix, binlib, incldir]
|
||||
if not win: check_dirs = check_dirs + extensions # These are not directories on Windows.
|
||||
for dir in check_dirs:
|
||||
if not os.path.exists(dir):
|
||||
usage('needed directory %s not found' % dir)
|
||||
if not os.path.isdir(dir):
|
||||
usage('%s: not a directory' % dir)
|
||||
if win:
|
||||
files = supp_sources + extensions # extensions are files on Windows.
|
||||
else:
|
||||
files = [config_c_in, makefile_in] + supp_sources
|
||||
for file in supp_sources:
|
||||
if not os.path.exists(file):
|
||||
usage('needed file %s not found' % file)
|
||||
if not os.path.isfile(file):
|
||||
usage('%s: not a plain file' % file)
|
||||
if not win:
|
||||
for dir in extensions:
|
||||
setup = os.path.join(dir, 'Setup')
|
||||
if not os.path.exists(setup):
|
||||
usage('needed file %s not found' % setup)
|
||||
if not os.path.isfile(setup):
|
||||
usage('%s: not a plain file' % setup)
|
||||
|
||||
# check that enough arguments are passed
|
||||
if not args:
|
||||
usage('at least one filename argument required')
|
||||
|
||||
# check that file arguments exist
|
||||
for arg in args:
|
||||
if arg == '-m':
|
||||
break
|
||||
# if user specified -m on the command line before _any_
|
||||
# file names, then nothing should be checked (as the
|
||||
# very first file should be a module name)
|
||||
if modargs:
|
||||
break
|
||||
if not os.path.exists(arg):
|
||||
usage('argument %s not found' % arg)
|
||||
if not os.path.isfile(arg):
|
||||
usage('%s: not a plain file' % arg)
|
||||
|
||||
# process non-option arguments
|
||||
scriptfile = args[0]
|
||||
modules = args[1:]
|
||||
|
||||
# derive target name from script name
|
||||
base = os.path.basename(scriptfile)
|
||||
base, ext = os.path.splitext(base)
|
||||
if base:
|
||||
if base != scriptfile:
|
||||
target = base
|
||||
else:
|
||||
target = base + '.bin'
|
||||
|
||||
# handle -o option
|
||||
base_frozen_c = frozen_c
|
||||
base_config_c = config_c
|
||||
base_target = target
|
||||
if odir and not os.path.isdir(odir):
|
||||
try:
|
||||
os.mkdir(odir)
|
||||
print "Created output directory", odir
|
||||
except os.error, msg:
|
||||
usage('%s: mkdir failed (%s)' % (odir, str(msg)))
|
||||
base = ''
|
||||
if odir:
|
||||
base = os.path.join(odir, '')
|
||||
frozen_c = os.path.join(odir, frozen_c)
|
||||
config_c = os.path.join(odir, config_c)
|
||||
target = os.path.join(odir, target)
|
||||
makefile = os.path.join(odir, makefile)
|
||||
if win: extensions_c = os.path.join(odir, extensions_c)
|
||||
|
||||
# Handle special entry point requirements
|
||||
# (on Windows, some frozen programs do not use __main__, but
|
||||
# import the module directly. Eg, DLLs, Services, etc
|
||||
custom_entry_point = None # Currently only used on Windows
|
||||
python_entry_is_main = 1 # Is the entry point called __main__?
|
||||
# handle -s option on Windows
|
||||
if win:
|
||||
import winmakemakefile
|
||||
try:
|
||||
custom_entry_point, python_entry_is_main = \
|
||||
winmakemakefile.get_custom_entry_point(subsystem)
|
||||
except ValueError, why:
|
||||
usage(why)
|
||||
|
||||
|
||||
# Actual work starts here...
|
||||
|
||||
# collect all modules of the program
|
||||
dir = os.path.dirname(scriptfile)
|
||||
path[0] = dir
|
||||
mf = modulefinder.ModuleFinder(path, debug, exclude)
|
||||
|
||||
if win and subsystem=='service':
|
||||
# If a Windows service, then add the "built-in" module.
|
||||
mod = mf.add_module("servicemanager")
|
||||
mod.__file__="dummy.pyd" # really built-in to the resulting EXE
|
||||
|
||||
for mod in implicits:
|
||||
mf.import_hook(mod)
|
||||
for mod in modules:
|
||||
if mod == '-m':
|
||||
modargs = 1
|
||||
continue
|
||||
if modargs:
|
||||
if mod[-2:] == '.*':
|
||||
mf.import_hook(mod[:-2], None, ["*"])
|
||||
else:
|
||||
mf.import_hook(mod)
|
||||
else:
|
||||
mf.load_file(mod)
|
||||
|
||||
# Add the main script as either __main__, or the actual module name.
|
||||
if python_entry_is_main:
|
||||
mf.run_script(scriptfile)
|
||||
else:
|
||||
mf.load_file(scriptfile)
|
||||
|
||||
if debug > 0:
|
||||
mf.report()
|
||||
print
|
||||
dict = mf.modules
|
||||
|
||||
# generate output for frozen modules
|
||||
files = makefreeze.makefreeze(base, dict, debug, custom_entry_point, 1)
|
||||
# look for unfrozen modules (builtin and of unknown origin)
|
||||
builtins = []
|
||||
unknown = []
|
||||
mods = dict.keys()
|
||||
mods.sort()
|
||||
for mod in mods:
|
||||
if dict[mod].__code__:
|
||||
continue
|
||||
if not dict[mod].__file__:
|
||||
builtins.append(mod)
|
||||
else:
|
||||
unknown.append(mod)
|
||||
|
||||
# search for unknown modules in extensions directories (not on Windows)
|
||||
addfiles = []
|
||||
frozen_extensions = [] # Windows list of modules.
|
||||
if unknown or (not win and builtins):
|
||||
if not win:
|
||||
addfiles, addmods = \
|
||||
checkextensions.checkextensions(unknown+builtins,
|
||||
extensions)
|
||||
for mod in addmods:
|
||||
if mod in unknown:
|
||||
unknown.remove(mod)
|
||||
builtins.append(mod)
|
||||
else:
|
||||
# Do the windows thang...
|
||||
import checkextensions_win32
|
||||
# Get a list of CExtension instances, each describing a module
|
||||
# (including its source files)
|
||||
frozen_extensions = checkextensions_win32.checkextensions(
|
||||
unknown, extensions, prefix)
|
||||
for mod in frozen_extensions:
|
||||
unknown.remove(mod.name)
|
||||
|
||||
# report unknown modules
|
||||
if unknown:
|
||||
sys.stderr.write('Warning: unknown modules remain: %s\n' %
|
||||
string.join(unknown))
|
||||
|
||||
# windows gets different treatment
|
||||
if win:
|
||||
# Taking a shortcut here...
|
||||
import winmakemakefile, checkextensions_win32
|
||||
checkextensions_win32.write_extension_table(extensions_c,
|
||||
frozen_extensions)
|
||||
# Create a module definition for the bootstrap C code.
|
||||
xtras = [frozenmain_c, os.path.basename(frozen_c),
|
||||
frozendllmain_c, os.path.basename(extensions_c)] + files
|
||||
maindefn = checkextensions_win32.CExtension( '__main__', xtras )
|
||||
frozen_extensions.append( maindefn )
|
||||
outfp = open(makefile, 'w')
|
||||
try:
|
||||
winmakemakefile.makemakefile(outfp,
|
||||
locals(),
|
||||
frozen_extensions,
|
||||
os.path.basename(target))
|
||||
finally:
|
||||
outfp.close()
|
||||
return
|
||||
|
||||
# generate config.c and Makefile
|
||||
builtins.sort()
|
||||
infp = open(config_c_in)
|
||||
outfp = bkfile.open(config_c, 'w')
|
||||
try:
|
||||
makeconfig.makeconfig(infp, outfp, builtins)
|
||||
finally:
|
||||
outfp.close()
|
||||
infp.close()
|
||||
|
||||
cflags = defines + includes + ['$(OPT)']
|
||||
libs = [os.path.join(binlib, 'libpython$(VERSION).a')]
|
||||
|
||||
somevars = {}
|
||||
if os.path.exists(makefile_in):
|
||||
makevars = parsesetup.getmakevars(makefile_in)
|
||||
for key in makevars.keys():
|
||||
somevars[key] = makevars[key]
|
||||
|
||||
somevars['CFLAGS'] = string.join(cflags) # override
|
||||
files = ['$(OPT)', '$(LDFLAGS)', base_config_c, base_frozen_c] + \
|
||||
files + supp_sources + addfiles + libs + \
|
||||
['$(MODLIBS)', '$(LIBS)', '$(SYSLIBS)']
|
||||
|
||||
outfp = bkfile.open(makefile, 'w')
|
||||
try:
|
||||
makemakefile.makemakefile(outfp, somevars, files, base_target)
|
||||
finally:
|
||||
outfp.close()
|
||||
|
||||
# Done!
|
||||
|
||||
if odir:
|
||||
print 'Now run "make" in', odir,
|
||||
print 'to build the target:', base_target
|
||||
else:
|
||||
print 'Now run "make" to build the target:', base_target
|
||||
|
||||
|
||||
# Print usage message and exit
|
||||
|
||||
def usage(msg):
|
||||
sys.stdout = sys.stderr
|
||||
print "Error:", msg
|
||||
print "Use ``%s -h'' for help" % sys.argv[0]
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
main()
|
1
intern/python/freeze/hello.py
Normal file
1
intern/python/freeze/hello.py
Normal file
@@ -0,0 +1 @@
|
||||
print 'Hello world...'
|
61
intern/python/freeze/makeconfig.py
Normal file
61
intern/python/freeze/makeconfig.py
Normal file
@@ -0,0 +1,61 @@
|
||||
import regex
|
||||
|
||||
|
||||
# Write the config.c file
|
||||
|
||||
never = ['marshal', '__main__', '__builtin__', 'sys', 'exceptions']
|
||||
|
||||
def makeconfig(infp, outfp, modules, with_ifdef=0):
|
||||
m1 = regex.compile('-- ADDMODULE MARKER 1 --')
|
||||
m2 = regex.compile('-- ADDMODULE MARKER 2 --')
|
||||
while 1:
|
||||
line = infp.readline()
|
||||
if not line: break
|
||||
outfp.write(line)
|
||||
if m1 and m1.search(line) >= 0:
|
||||
m1 = None
|
||||
for mod in modules:
|
||||
if mod in never:
|
||||
continue
|
||||
if with_ifdef:
|
||||
outfp.write("#ifndef init%s\n"%mod)
|
||||
outfp.write('extern void init%s();\n' % mod)
|
||||
if with_ifdef:
|
||||
outfp.write("#endif\n")
|
||||
elif m2 and m2.search(line) >= 0:
|
||||
m2 = None
|
||||
for mod in modules:
|
||||
if mod in never:
|
||||
continue
|
||||
outfp.write('\t{"%s", init%s},\n' %
|
||||
(mod, mod))
|
||||
if m1:
|
||||
sys.stderr.write('MARKER 1 never found\n')
|
||||
elif m2:
|
||||
sys.stderr.write('MARKER 2 never found\n')
|
||||
|
||||
|
||||
# Test program.
|
||||
|
||||
def test():
|
||||
import sys
|
||||
if not sys.argv[3:]:
|
||||
print 'usage: python makeconfig.py config.c.in outputfile',
|
||||
print 'modulename ...'
|
||||
sys.exit(2)
|
||||
if sys.argv[1] == '-':
|
||||
infp = sys.stdin
|
||||
else:
|
||||
infp = open(sys.argv[1])
|
||||
if sys.argv[2] == '-':
|
||||
outfp = sys.stdout
|
||||
else:
|
||||
outfp = open(sys.argv[2], 'w')
|
||||
makeconfig(infp, outfp, sys.argv[3:])
|
||||
if outfp != sys.stdout:
|
||||
outfp.close()
|
||||
if infp != sys.stdin:
|
||||
infp.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
115
intern/python/freeze/makefreeze.py
Normal file
115
intern/python/freeze/makefreeze.py
Normal file
@@ -0,0 +1,115 @@
|
||||
##
|
||||
##
|
||||
## Customized makefreeze for NaN
|
||||
##
|
||||
##
|
||||
## 1.11.2001, strubi@blender.nl
|
||||
##
|
||||
##
|
||||
import marshal
|
||||
import string
|
||||
import bkfile
|
||||
|
||||
|
||||
# Write a file containing frozen code for the modules in the dictionary.
|
||||
|
||||
header = """
|
||||
#include "Python.h"
|
||||
|
||||
static struct _frozen _PyImport_FrozenModules[] = {
|
||||
"""
|
||||
trailer = """\
|
||||
{0, 0, 0} /* sentinel */
|
||||
};
|
||||
"""
|
||||
|
||||
# if __debug__ == 0 (i.e. -O option given), set Py_OptimizeFlag in frozen app.
|
||||
main_entry_point = """
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
extern int Py_FrozenMain(int, char **);
|
||||
init_frozen_modules();
|
||||
return Py_FrozenMain(argc, argv);
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
default_entry_point = """
|
||||
void
|
||||
init_frozenmodules(void)
|
||||
{
|
||||
""" + ((not __debug__ and """
|
||||
Py_OptimizeFlag++;
|
||||
""") or "") + """
|
||||
PyImport_FrozenModules = _PyImport_FrozenModules;
|
||||
}
|
||||
"""
|
||||
|
||||
HEADER = """
|
||||
/* This is a generated file, containing frozen bytecode.
|
||||
* Check $(HOME)/develop/intern/python/freeze/README for more information.
|
||||
*/
|
||||
|
||||
"""
|
||||
|
||||
def makefreeze(base, dict, debug=0, entry_point = None, exclude_main = 0):
|
||||
if entry_point is None: entry_point = default_entry_point
|
||||
done = []
|
||||
files = []
|
||||
mods = dict.keys()
|
||||
if exclude_main:
|
||||
mods.remove("__main__")
|
||||
mods.sort()
|
||||
for mod in mods:
|
||||
m = dict[mod]
|
||||
mangled = string.join(string.split(mod, "."), "__")
|
||||
if m.__code__:
|
||||
file = 'M_' + mangled + '.c'
|
||||
outfp = bkfile.open(base + file, 'w')
|
||||
outfp.write(HEADER)
|
||||
files.append(file)
|
||||
if debug:
|
||||
print "freezing", mod, "..."
|
||||
str = marshal.dumps(m.__code__)
|
||||
size = len(str)
|
||||
if m.__path__:
|
||||
# Indicate package by negative size
|
||||
size = -size
|
||||
done.append((mod, mangled, size))
|
||||
writecode(outfp, mangled, str)
|
||||
outfp.close()
|
||||
if debug:
|
||||
print "generating table of frozen modules"
|
||||
outfp = bkfile.open(base + 'frozen.c', 'w')
|
||||
for mod, mangled, size in done:
|
||||
outfp.write('extern unsigned char M_%s[];\n' % mangled)
|
||||
outfp.write(header)
|
||||
for mod, mangled, size in done:
|
||||
outfp.write('\t{"%s", M_%s, %d},\n' % (mod, mangled, size))
|
||||
outfp.write(trailer)
|
||||
outfp.write(entry_point)
|
||||
outfp.close()
|
||||
#outfp = bkfile.open(base + 'main.c', 'w')
|
||||
#outfp.write(main_entry_point)
|
||||
#outfp.close()
|
||||
return files
|
||||
|
||||
|
||||
|
||||
# Write a C initializer for a module containing the frozen python code.
|
||||
# The array is called M_<mod>.
|
||||
|
||||
def writecode(outfp, mod, str):
|
||||
outfp.write('unsigned char M_%s[] = {' % mod)
|
||||
for i in range(0, len(str), 16):
|
||||
outfp.write('\n\t')
|
||||
for c in str[i:i+16]:
|
||||
outfp.write('%d,' % ord(c))
|
||||
outfp.write('\n};\n')
|
||||
|
||||
## def writecode(outfp, mod, str):
|
||||
## outfp.write('unsigned char M_%s[%d] = "%s";\n' % (mod, len(str),
|
||||
## string.join(map(lambda s: `s`[1:-1], string.split(str, '"')), '\\"')))
|
57
intern/python/freeze/makemakefile.py
Normal file
57
intern/python/freeze/makemakefile.py
Normal file
@@ -0,0 +1,57 @@
|
||||
# Write the actual Makefile.
|
||||
##
|
||||
##
|
||||
## Customized makemakefile for NaN
|
||||
##
|
||||
##
|
||||
## 1.11.2001, strubi@blender.nl
|
||||
##
|
||||
##
|
||||
|
||||
|
||||
import os
|
||||
import string
|
||||
|
||||
def makemakefile(outfp, makevars, files, target):
|
||||
outfp.write("# Makefile generated by freeze.py script\n\n")
|
||||
|
||||
target = "frozen"
|
||||
libtarget = "lib" + target
|
||||
targetlib = libtarget + ".a"
|
||||
#targetlib = "libpyfrozen.a"
|
||||
|
||||
keys = makevars.keys()
|
||||
keys.sort()
|
||||
for key in keys:
|
||||
outfp.write("%s=%s\n" % (key, makevars[key]))
|
||||
outfp.write("\nall: %s\n\n" % libtarget)
|
||||
|
||||
deps = []
|
||||
for i in range(len(files)):
|
||||
file = files[i]
|
||||
if file[-2:] == '.c':
|
||||
base = os.path.basename(file)
|
||||
dest = base[:-2] + '.o'
|
||||
# outfp.write("%s: %s\n" % (dest, file))
|
||||
# outfp.write("\t$(CC) $(CFLAGS) -c %s\n" % file)
|
||||
files[i] = dest
|
||||
deps.append(dest)
|
||||
|
||||
mainfile = 'M___main__.o'
|
||||
|
||||
try:
|
||||
deps.remove(mainfile)
|
||||
except:
|
||||
pass
|
||||
outfp.write("OBJS = %s\n" % string.join(deps))
|
||||
|
||||
# libfiles.remove('M___main__.o') # don't link with __main__
|
||||
|
||||
outfp.write("\n%s: $(OBJS)\n" % (libtarget))
|
||||
outfp.write("\t$(AR) ruv %s $(OBJS)\n" % (targetlib))
|
||||
|
||||
outfp.write("\n%s: %s $(OBJS)\n" % (target, mainfile))
|
||||
outfp.write("\t$(CC) %s %s -o %s $(LDLAST)\n" %
|
||||
(mainfile, " ".join(deps), target))
|
||||
|
||||
outfp.write("\nclean:\n\t-rm -f *.o *.a %s\n" % target)
|
444
intern/python/freeze/modulefinder.py
Normal file
444
intern/python/freeze/modulefinder.py
Normal file
@@ -0,0 +1,444 @@
|
||||
"""Find modules used by a script, using introspection."""
|
||||
|
||||
import dis
|
||||
import imp
|
||||
import marshal
|
||||
import os
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
|
||||
if sys.platform=="win32":
|
||||
# On Windows, we can locate modules in the registry with
|
||||
# the help of the win32api package.
|
||||
try:
|
||||
import win32api
|
||||
except ImportError:
|
||||
print "The win32api module is not available - modules listed"
|
||||
print "in the registry will not be found."
|
||||
win32api = None
|
||||
|
||||
|
||||
IMPORT_NAME = dis.opname.index('IMPORT_NAME')
|
||||
IMPORT_FROM = dis.opname.index('IMPORT_FROM')
|
||||
STORE_NAME = dis.opname.index('STORE_NAME')
|
||||
STORE_FAST = dis.opname.index('STORE_FAST')
|
||||
STORE_GLOBAL = dis.opname.index('STORE_GLOBAL')
|
||||
STORE_OPS = [STORE_NAME, STORE_FAST, STORE_GLOBAL]
|
||||
|
||||
# Modulefinder does a good job at simulating Python's, but it can not
|
||||
# handle __path__ modifications packages make at runtime. Therefore there
|
||||
# is a mechanism whereby you can register extra paths in this map for a
|
||||
# package, and it will be honored.
|
||||
|
||||
# Note this is a mapping is lists of paths.
|
||||
packagePathMap = {}
|
||||
|
||||
# A Public interface
|
||||
def AddPackagePath(packagename, path):
|
||||
paths = packagePathMap.get(packagename, [])
|
||||
paths.append(path)
|
||||
packagePathMap[packagename] = paths
|
||||
|
||||
class Module:
|
||||
|
||||
def __init__(self, name, file=None, path=None):
|
||||
self.__name__ = name
|
||||
self.__file__ = file
|
||||
self.__path__ = path
|
||||
self.__code__ = None
|
||||
|
||||
def __repr__(self):
|
||||
s = "Module(%s" % `self.__name__`
|
||||
if self.__file__ is not None:
|
||||
s = s + ", %s" % `self.__file__`
|
||||
if self.__path__ is not None:
|
||||
s = s + ", %s" % `self.__path__`
|
||||
s = s + ")"
|
||||
return s
|
||||
|
||||
|
||||
class ModuleFinder:
|
||||
|
||||
def __init__(self, path=None, debug=0, excludes = []):
|
||||
if path is None:
|
||||
path = sys.path
|
||||
self.path = path
|
||||
self.modules = {}
|
||||
self.badmodules = {}
|
||||
self.debug = debug
|
||||
self.indent = 0
|
||||
self.excludes = excludes
|
||||
|
||||
def msg(self, level, str, *args):
|
||||
if level <= self.debug:
|
||||
for i in range(self.indent):
|
||||
print " ",
|
||||
print str,
|
||||
for arg in args:
|
||||
print repr(arg),
|
||||
print
|
||||
|
||||
def msgin(self, *args):
|
||||
level = args[0]
|
||||
if level <= self.debug:
|
||||
self.indent = self.indent + 1
|
||||
apply(self.msg, args)
|
||||
|
||||
def msgout(self, *args):
|
||||
level = args[0]
|
||||
if level <= self.debug:
|
||||
self.indent = self.indent - 1
|
||||
apply(self.msg, args)
|
||||
|
||||
def run_script(self, pathname):
|
||||
self.msg(2, "run_script", pathname)
|
||||
fp = open(pathname)
|
||||
stuff = ("", "r", imp.PY_SOURCE)
|
||||
self.load_module('__main__', fp, pathname, stuff)
|
||||
|
||||
def load_file(self, pathname):
|
||||
dir, name = os.path.split(pathname)
|
||||
name, ext = os.path.splitext(name)
|
||||
fp = open(pathname)
|
||||
stuff = (ext, "r", imp.PY_SOURCE)
|
||||
self.load_module(name, fp, pathname, stuff)
|
||||
|
||||
def import_hook(self, name, caller=None, fromlist=None):
|
||||
self.msg(3, "import_hook", name, caller, fromlist)
|
||||
parent = self.determine_parent(caller)
|
||||
q, tail = self.find_head_package(parent, name)
|
||||
m = self.load_tail(q, tail)
|
||||
if not fromlist:
|
||||
return q
|
||||
if m.__path__:
|
||||
self.ensure_fromlist(m, fromlist)
|
||||
|
||||
def determine_parent(self, caller):
|
||||
self.msgin(4, "determine_parent", caller)
|
||||
if not caller:
|
||||
self.msgout(4, "determine_parent -> None")
|
||||
return None
|
||||
pname = caller.__name__
|
||||
if caller.__path__:
|
||||
parent = self.modules[pname]
|
||||
assert caller is parent
|
||||
self.msgout(4, "determine_parent ->", parent)
|
||||
return parent
|
||||
if '.' in pname:
|
||||
i = string.rfind(pname, '.')
|
||||
pname = pname[:i]
|
||||
parent = self.modules[pname]
|
||||
assert parent.__name__ == pname
|
||||
self.msgout(4, "determine_parent ->", parent)
|
||||
return parent
|
||||
self.msgout(4, "determine_parent -> None")
|
||||
return None
|
||||
|
||||
def find_head_package(self, parent, name):
|
||||
self.msgin(4, "find_head_package", parent, name)
|
||||
if '.' in name:
|
||||
i = string.find(name, '.')
|
||||
head = name[:i]
|
||||
tail = name[i+1:]
|
||||
else:
|
||||
head = name
|
||||
tail = ""
|
||||
if parent:
|
||||
qname = "%s.%s" % (parent.__name__, head)
|
||||
else:
|
||||
qname = head
|
||||
q = self.import_module(head, qname, parent)
|
||||
if q:
|
||||
self.msgout(4, "find_head_package ->", (q, tail))
|
||||
return q, tail
|
||||
if parent:
|
||||
qname = head
|
||||
parent = None
|
||||
q = self.import_module(head, qname, parent)
|
||||
if q:
|
||||
self.msgout(4, "find_head_package ->", (q, tail))
|
||||
return q, tail
|
||||
self.msgout(4, "raise ImportError: No module named", qname)
|
||||
raise ImportError, "No module named " + qname
|
||||
|
||||
def load_tail(self, q, tail):
|
||||
self.msgin(4, "load_tail", q, tail)
|
||||
m = q
|
||||
while tail:
|
||||
i = string.find(tail, '.')
|
||||
if i < 0: i = len(tail)
|
||||
head, tail = tail[:i], tail[i+1:]
|
||||
mname = "%s.%s" % (m.__name__, head)
|
||||
m = self.import_module(head, mname, m)
|
||||
if not m:
|
||||
self.msgout(4, "raise ImportError: No module named", mname)
|
||||
raise ImportError, "No module named " + mname
|
||||
self.msgout(4, "load_tail ->", m)
|
||||
return m
|
||||
|
||||
def ensure_fromlist(self, m, fromlist, recursive=0):
|
||||
self.msg(4, "ensure_fromlist", m, fromlist, recursive)
|
||||
for sub in fromlist:
|
||||
if sub == "*":
|
||||
if not recursive:
|
||||
all = self.find_all_submodules(m)
|
||||
if all:
|
||||
self.ensure_fromlist(m, all, 1)
|
||||
elif not hasattr(m, sub):
|
||||
subname = "%s.%s" % (m.__name__, sub)
|
||||
submod = self.import_module(sub, subname, m)
|
||||
if not submod:
|
||||
raise ImportError, "No module named " + subname
|
||||
|
||||
def find_all_submodules(self, m):
|
||||
if not m.__path__:
|
||||
return
|
||||
modules = {}
|
||||
suffixes = [".py", ".pyc", ".pyo"]
|
||||
for dir in m.__path__:
|
||||
try:
|
||||
names = os.listdir(dir)
|
||||
except os.error:
|
||||
self.msg(2, "can't list directory", dir)
|
||||
continue
|
||||
for name in names:
|
||||
mod = None
|
||||
for suff in suffixes:
|
||||
n = len(suff)
|
||||
if name[-n:] == suff:
|
||||
mod = name[:-n]
|
||||
break
|
||||
if mod and mod != "__init__":
|
||||
modules[mod] = mod
|
||||
return modules.keys()
|
||||
|
||||
def import_module(self, partname, fqname, parent):
|
||||
self.msgin(3, "import_module", partname, fqname, parent)
|
||||
try:
|
||||
m = self.modules[fqname]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
self.msgout(3, "import_module ->", m)
|
||||
return m
|
||||
if self.badmodules.has_key(fqname):
|
||||
self.msgout(3, "import_module -> None")
|
||||
if parent:
|
||||
self.badmodules[fqname][parent.__name__] = None
|
||||
return None
|
||||
try:
|
||||
fp, pathname, stuff = self.find_module(partname,
|
||||
parent and parent.__path__)
|
||||
except ImportError:
|
||||
self.msgout(3, "import_module ->", None)
|
||||
return None
|
||||
try:
|
||||
m = self.load_module(fqname, fp, pathname, stuff)
|
||||
finally:
|
||||
if fp: fp.close()
|
||||
if parent:
|
||||
setattr(parent, partname, m)
|
||||
self.msgout(3, "import_module ->", m)
|
||||
return m
|
||||
|
||||
def load_module(self, fqname, fp, pathname, (suffix, mode, type)):
|
||||
self.msgin(2, "load_module", fqname, fp and "fp", pathname)
|
||||
if type == imp.PKG_DIRECTORY:
|
||||
m = self.load_package(fqname, pathname)
|
||||
self.msgout(2, "load_module ->", m)
|
||||
return m
|
||||
if type == imp.PY_SOURCE:
|
||||
co = compile(fp.read()+'\n', pathname, 'exec')
|
||||
elif type == imp.PY_COMPILED:
|
||||
if fp.read(4) != imp.get_magic():
|
||||
self.msgout(2, "raise ImportError: Bad magic number", pathname)
|
||||
raise ImportError, "Bad magic number in %s" % pathname
|
||||
fp.read(4)
|
||||
co = marshal.load(fp)
|
||||
else:
|
||||
co = None
|
||||
m = self.add_module(fqname)
|
||||
m.__file__ = pathname
|
||||
if co:
|
||||
m.__code__ = co
|
||||
self.scan_code(co, m)
|
||||
self.msgout(2, "load_module ->", m)
|
||||
return m
|
||||
|
||||
def scan_code(self, co, m):
|
||||
code = co.co_code
|
||||
n = len(code)
|
||||
i = 0
|
||||
lastname = None
|
||||
while i < n:
|
||||
c = code[i]
|
||||
i = i+1
|
||||
op = ord(c)
|
||||
if op >= dis.HAVE_ARGUMENT:
|
||||
oparg = ord(code[i]) + ord(code[i+1])*256
|
||||
i = i+2
|
||||
if op == IMPORT_NAME:
|
||||
name = lastname = co.co_names[oparg]
|
||||
if not self.badmodules.has_key(lastname):
|
||||
try:
|
||||
self.import_hook(name, m)
|
||||
except ImportError, msg:
|
||||
self.msg(2, "ImportError:", str(msg))
|
||||
if not self.badmodules.has_key(name):
|
||||
self.badmodules[name] = {}
|
||||
self.badmodules[name][m.__name__] = None
|
||||
elif op == IMPORT_FROM:
|
||||
name = co.co_names[oparg]
|
||||
assert lastname is not None
|
||||
if not self.badmodules.has_key(lastname):
|
||||
try:
|
||||
self.import_hook(lastname, m, [name])
|
||||
except ImportError, msg:
|
||||
self.msg(2, "ImportError:", str(msg))
|
||||
fullname = lastname + "." + name
|
||||
if not self.badmodules.has_key(fullname):
|
||||
self.badmodules[fullname] = {}
|
||||
self.badmodules[fullname][m.__name__] = None
|
||||
elif op in STORE_OPS:
|
||||
# Skip; each IMPORT_FROM is followed by a STORE_* opcode
|
||||
pass
|
||||
else:
|
||||
lastname = None
|
||||
for c in co.co_consts:
|
||||
if isinstance(c, type(co)):
|
||||
self.scan_code(c, m)
|
||||
|
||||
def load_package(self, fqname, pathname):
|
||||
self.msgin(2, "load_package", fqname, pathname)
|
||||
m = self.add_module(fqname)
|
||||
m.__file__ = pathname
|
||||
m.__path__ = [pathname]
|
||||
|
||||
# As per comment at top of file, simulate runtime __path__ additions.
|
||||
m.__path__ = m.__path__ + packagePathMap.get(fqname, [])
|
||||
|
||||
fp, buf, stuff = self.find_module("__init__", m.__path__)
|
||||
self.load_module(fqname, fp, buf, stuff)
|
||||
self.msgout(2, "load_package ->", m)
|
||||
return m
|
||||
|
||||
def add_module(self, fqname):
|
||||
if self.modules.has_key(fqname):
|
||||
return self.modules[fqname]
|
||||
self.modules[fqname] = m = Module(fqname)
|
||||
return m
|
||||
|
||||
def find_module(self, name, path):
|
||||
if name in self.excludes:
|
||||
self.msgout(3, "find_module -> Excluded")
|
||||
raise ImportError, name
|
||||
|
||||
if path is None:
|
||||
if name in sys.builtin_module_names:
|
||||
return (None, None, ("", "", imp.C_BUILTIN))
|
||||
|
||||
# Emulate the Registered Module support on Windows.
|
||||
if sys.platform=="win32" and win32api is not None:
|
||||
HKEY_LOCAL_MACHINE = 0x80000002
|
||||
try:
|
||||
pathname = win32api.RegQueryValue(HKEY_LOCAL_MACHINE, "Software\\Python\\PythonCore\\%s\\Modules\\%s" % (sys.winver, name))
|
||||
fp = open(pathname, "rb")
|
||||
# XXX - To do - remove the hard code of C_EXTENSION.
|
||||
stuff = "", "rb", imp.C_EXTENSION
|
||||
return fp, pathname, stuff
|
||||
except win32api.error:
|
||||
pass
|
||||
|
||||
path = self.path
|
||||
return imp.find_module(name, path)
|
||||
|
||||
def report(self):
|
||||
print
|
||||
print " %-25s %s" % ("Name", "File")
|
||||
print " %-25s %s" % ("----", "----")
|
||||
# Print modules found
|
||||
keys = self.modules.keys()
|
||||
keys.sort()
|
||||
for key in keys:
|
||||
m = self.modules[key]
|
||||
if m.__path__:
|
||||
print "P",
|
||||
else:
|
||||
print "m",
|
||||
print "%-25s" % key, m.__file__ or ""
|
||||
|
||||
# Print missing modules
|
||||
keys = self.badmodules.keys()
|
||||
keys.sort()
|
||||
for key in keys:
|
||||
# ... but not if they were explicitly excluded.
|
||||
if key not in self.excludes:
|
||||
mods = self.badmodules[key].keys()
|
||||
mods.sort()
|
||||
print "?", key, "from", string.join(mods, ', ')
|
||||
|
||||
|
||||
def test():
|
||||
# Parse command line
|
||||
import getopt
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "dmp:qx:")
|
||||
except getopt.error, msg:
|
||||
print msg
|
||||
return
|
||||
|
||||
# Process options
|
||||
debug = 1
|
||||
domods = 0
|
||||
addpath = []
|
||||
exclude = []
|
||||
for o, a in opts:
|
||||
if o == '-d':
|
||||
debug = debug + 1
|
||||
if o == '-m':
|
||||
domods = 1
|
||||
if o == '-p':
|
||||
addpath = addpath + string.split(a, os.pathsep)
|
||||
if o == '-q':
|
||||
debug = 0
|
||||
if o == '-x':
|
||||
exclude.append(a)
|
||||
|
||||
# Provide default arguments
|
||||
if not args:
|
||||
script = "hello.py"
|
||||
else:
|
||||
script = args[0]
|
||||
|
||||
# Set the path based on sys.path and the script directory
|
||||
path = sys.path[:]
|
||||
path[0] = os.path.dirname(script)
|
||||
path = addpath + path
|
||||
if debug > 1:
|
||||
print "path:"
|
||||
for item in path:
|
||||
print " ", `item`
|
||||
|
||||
# Create the module finder and turn its crank
|
||||
mf = ModuleFinder(path, debug, exclude)
|
||||
for arg in args[1:]:
|
||||
if arg == '-m':
|
||||
domods = 1
|
||||
continue
|
||||
if domods:
|
||||
if arg[-2:] == '.*':
|
||||
mf.import_hook(arg[:-2], None, ["*"])
|
||||
else:
|
||||
mf.import_hook(arg)
|
||||
else:
|
||||
mf.load_file(arg)
|
||||
mf.run_script(script)
|
||||
mf.report()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
test()
|
||||
except KeyboardInterrupt:
|
||||
print "\n[interrupt]"
|
98
intern/python/freeze/parsesetup.py
Normal file
98
intern/python/freeze/parsesetup.py
Normal file
@@ -0,0 +1,98 @@
|
||||
# Parse Makefiles and Python Setup(.in) files.
|
||||
|
||||
import regex
|
||||
import string
|
||||
|
||||
|
||||
# Extract variable definitions from a Makefile.
|
||||
# Return a dictionary mapping names to values.
|
||||
# May raise IOError.
|
||||
|
||||
makevardef = regex.compile('^\([a-zA-Z0-9_]+\)[ \t]*=\(.*\)')
|
||||
|
||||
def getmakevars(filename):
|
||||
variables = {}
|
||||
fp = open(filename)
|
||||
try:
|
||||
while 1:
|
||||
line = fp.readline()
|
||||
if not line:
|
||||
break
|
||||
if makevardef.match(line) < 0:
|
||||
continue
|
||||
name, value = makevardef.group(1, 2)
|
||||
# Strip trailing comment
|
||||
i = string.find(value, '#')
|
||||
if i >= 0:
|
||||
value = value[:i]
|
||||
value = string.strip(value)
|
||||
variables[name] = value
|
||||
finally:
|
||||
fp.close()
|
||||
return variables
|
||||
|
||||
|
||||
# Parse a Python Setup(.in) file.
|
||||
# Return two dictionaries, the first mapping modules to their
|
||||
# definitions, the second mapping variable names to their values.
|
||||
# May raise IOError.
|
||||
|
||||
setupvardef = regex.compile('^\([a-zA-Z0-9_]+\)=\(.*\)')
|
||||
|
||||
def getsetupinfo(filename):
|
||||
modules = {}
|
||||
variables = {}
|
||||
fp = open(filename)
|
||||
try:
|
||||
while 1:
|
||||
line = fp.readline()
|
||||
if not line:
|
||||
break
|
||||
# Strip comments
|
||||
i = string.find(line, '#')
|
||||
if i >= 0:
|
||||
line = line[:i]
|
||||
if setupvardef.match(line) >= 0:
|
||||
name, value = setupvardef.group(1, 2)
|
||||
variables[name] = string.strip(value)
|
||||
else:
|
||||
words = string.split(line)
|
||||
if words:
|
||||
modules[words[0]] = words[1:]
|
||||
finally:
|
||||
fp.close()
|
||||
return modules, variables
|
||||
|
||||
|
||||
# Test the above functions.
|
||||
|
||||
def test():
|
||||
import sys
|
||||
import os
|
||||
if not sys.argv[1:]:
|
||||
print 'usage: python parsesetup.py Makefile*|Setup* ...'
|
||||
sys.exit(2)
|
||||
for arg in sys.argv[1:]:
|
||||
base = os.path.basename(arg)
|
||||
if base[:8] == 'Makefile':
|
||||
print 'Make style parsing:', arg
|
||||
v = getmakevars(arg)
|
||||
prdict(v)
|
||||
elif base[:5] == 'Setup':
|
||||
print 'Setup style parsing:', arg
|
||||
m, v = getsetupinfo(arg)
|
||||
prdict(m)
|
||||
prdict(v)
|
||||
else:
|
||||
print arg, 'is neither a Makefile nor a Setup file'
|
||||
print '(name must begin with "Makefile" or "Setup")'
|
||||
|
||||
def prdict(d):
|
||||
keys = d.keys()
|
||||
keys.sort()
|
||||
for key in keys:
|
||||
value = d[key]
|
||||
print "%-15s" % key, str(value)
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
146
intern/python/freeze/winmakemakefile.py
Normal file
146
intern/python/freeze/winmakemakefile.py
Normal file
@@ -0,0 +1,146 @@
|
||||
import sys, os, string
|
||||
|
||||
# Template used then the program is a GUI program
|
||||
WINMAINTEMPLATE = """
|
||||
#include <windows.h>
|
||||
|
||||
int WINAPI WinMain(
|
||||
HINSTANCE hInstance, // handle to current instance
|
||||
HINSTANCE hPrevInstance, // handle to previous instance
|
||||
LPSTR lpCmdLine, // pointer to command line
|
||||
int nCmdShow // show state of window
|
||||
)
|
||||
{
|
||||
extern int Py_FrozenMain(int, char **);
|
||||
PyImport_FrozenModules = _PyImport_FrozenModules;
|
||||
return Py_FrozenMain(__argc, __argv);
|
||||
}
|
||||
"""
|
||||
|
||||
SERVICETEMPLATE = """
|
||||
extern int PythonService_main(int, char **);
|
||||
|
||||
int main( int argc, char **argv)
|
||||
{
|
||||
PyImport_FrozenModules = _PyImport_FrozenModules;
|
||||
return PythonService_main(argc, argv);
|
||||
}
|
||||
"""
|
||||
|
||||
subsystem_details = {
|
||||
# -s flag : (C entry point template), (is it __main__?), (is it a DLL?)
|
||||
'console' : (None, 1, 0),
|
||||
'windows' : (WINMAINTEMPLATE, 1, 0),
|
||||
'service' : (SERVICETEMPLATE, 0, 0),
|
||||
'com_dll' : ("", 0, 1),
|
||||
}
|
||||
|
||||
def get_custom_entry_point(subsystem):
|
||||
try:
|
||||
return subsystem_details[subsystem][:2]
|
||||
except KeyError:
|
||||
raise ValueError, "The subsystem %s is not known" % subsystem
|
||||
|
||||
|
||||
def makemakefile(outfp, vars, files, target):
|
||||
save = sys.stdout
|
||||
try:
|
||||
sys.stdout = outfp
|
||||
realwork(vars, files, target)
|
||||
finally:
|
||||
sys.stdout = save
|
||||
|
||||
def realwork(vars, moddefns, target):
|
||||
version_suffix = `sys.version_info[0]`+`sys.version_info[1]`
|
||||
print "# Makefile for Microsoft Visual C++ generated by freeze.py script"
|
||||
print
|
||||
print 'target = %s' % target
|
||||
print 'pythonhome = %s' % vars['prefix']
|
||||
print
|
||||
print 'DEBUG=0 # Set to 1 to use the _d versions of Python.'
|
||||
print '!IF $(DEBUG)'
|
||||
print 'debug_suffix=_d'
|
||||
print 'c_debug=/Zi /Od /DDEBUG /D_DEBUG'
|
||||
print 'l_debug=/DEBUG'
|
||||
print 'temp_dir=Build\\Debug'
|
||||
print '!ELSE'
|
||||
print 'debug_suffix='
|
||||
print 'c_debug=/Ox'
|
||||
print 'l_debug='
|
||||
print 'temp_dir=Build\\Release'
|
||||
print '!ENDIF'
|
||||
print
|
||||
|
||||
print '# The following line assumes you have built Python using the standard instructions'
|
||||
print '# Otherwise fix the following line to point to the library.'
|
||||
print 'pythonlib = "$(pythonhome)/pcbuild/python%s$(debug_suffix).lib"' % version_suffix
|
||||
print
|
||||
|
||||
# We only ever write one "entry point" symbol - either
|
||||
# "main" or "WinMain". Therefore, there is no need to
|
||||
# pass a subsystem switch to the linker as it works it
|
||||
# out all by itself. However, the subsystem _does_ determine
|
||||
# the file extension and additional linker flags.
|
||||
target_link_flags = ""
|
||||
target_ext = ".exe"
|
||||
if subsystem_details[vars['subsystem']][2]:
|
||||
target_link_flags = "-dll"
|
||||
target_ext = ".dll"
|
||||
|
||||
|
||||
print "# As the target uses Python%s.dll, we must use this compiler option!" % version_suffix
|
||||
print "cdl = /MD"
|
||||
print
|
||||
print "all: $(target)$(debug_suffix)%s" % (target_ext)
|
||||
print
|
||||
|
||||
print '$(temp_dir):'
|
||||
print ' if not exist $(temp_dir)\. mkdir $(temp_dir)'
|
||||
print
|
||||
|
||||
objects = []
|
||||
libs = ["shell32.lib", "comdlg32.lib", "wsock32.lib", "user32.lib", "oleaut32.lib"]
|
||||
for moddefn in moddefns:
|
||||
print "# Module", moddefn.name
|
||||
for file in moddefn.sourceFiles:
|
||||
base = os.path.basename(file)
|
||||
base, ext = os.path.splitext(base)
|
||||
objects.append(base + ".obj")
|
||||
print '$(temp_dir)\%s.obj: "%s"' % (base, file)
|
||||
print "\t@$(CC) -c -nologo /Fo$* $(cdl) $(c_debug) /D BUILD_FREEZE",
|
||||
print '"-I$(pythonhome)/Include" "-I$(pythonhome)/PC" \\'
|
||||
print "\t\t$(cflags) $(cdebug) $(cinclude) \\"
|
||||
extra = moddefn.GetCompilerOptions()
|
||||
if extra:
|
||||
print "\t\t%s \\" % (string.join(extra),)
|
||||
print '\t\t"%s"' % file
|
||||
print
|
||||
|
||||
# Add .lib files this module needs
|
||||
for modlib in moddefn.GetLinkerLibs():
|
||||
if modlib not in libs:
|
||||
libs.append(modlib)
|
||||
|
||||
print "ADDN_LINK_FILES=",
|
||||
for addn in vars['addn_link']: print '"%s"' % (addn),
|
||||
print ; print
|
||||
|
||||
print "OBJS=",
|
||||
for obj in objects: print '"$(temp_dir)\%s"' % (obj),
|
||||
print ; print
|
||||
|
||||
print "LIBS=",
|
||||
for lib in libs: print '"%s"' % (lib),
|
||||
print ; print
|
||||
|
||||
print "$(target)$(debug_suffix)%s: $(temp_dir) $(OBJS)" % (target_ext)
|
||||
print "\tlink -out:$(target)$(debug_suffix)%s %s" % (target_ext, target_link_flags),
|
||||
print "\t$(OBJS) \\"
|
||||
print "\t$(LIBS) \\"
|
||||
print "\t$(ADDN_LINK_FILES) \\"
|
||||
print "\t$(pythonlib) $(lcustom) $(l_debug)\\"
|
||||
print "\t$(resources)"
|
||||
print
|
||||
print "clean:"
|
||||
print "\t-rm -f *.obj"
|
||||
print "\t-rm -f $(target).exe"
|
Reference in New Issue
Block a user