64-bit build support. Thanks to Ariel Shiftan and Itai Shaham for the initial patch.

This commit is contained in:
gergely.erdelyi 2009-05-23 14:40:01 +00:00
parent 05e10a0f25
commit 5a66395061
3 changed files with 81 additions and 107 deletions

161
build.py
View File

@ -30,7 +30,7 @@ IDA_SDK = ".." + os.sep + "swigsdk-versions" + os.sep + "%d.%d" % (IDA_MAJOR_VER
# IDAPython version # IDAPython version
VERSION_MAJOR = 1 VERSION_MAJOR = 1
VERSION_MINOR = 1 VERSION_MINOR = 1
VERSION_PATCH = 91 VERSION_PATCH = 92
# Determine Python version # Determine Python version
PYTHON_MAJOR_VERSION = int(platform.python_version()[0]) PYTHON_MAJOR_VERSION = int(platform.python_version()[0])
@ -61,10 +61,6 @@ BINDIST_MANIFEST = [
"COPYING.txt", "COPYING.txt",
"CHANGES.txt", "CHANGES.txt",
"STATUS.txt", "STATUS.txt",
"python/init.py",
"python/idc.py",
"python/idautils.py",
("idaapi.py", "python"),
"docs/notes.txt", "docs/notes.txt",
"examples/chooser.py", "examples/chooser.py",
"examples/colours.py", "examples/colours.py",
@ -83,6 +79,7 @@ SRCDIST_MANIFEST = [
"basetsd.h", "basetsd.h",
"build.py", "build.py",
"swig/allins.i", "swig/allins.i",
"swig/area.i",
"swig/auto.i", "swig/auto.i",
"swig/bytes.i", "swig/bytes.i",
"swig/dbg.i", "swig/dbg.i",
@ -93,8 +90,10 @@ SRCDIST_MANIFEST = [
"swig/fixup.i", "swig/fixup.i",
"swig/frame.i", "swig/frame.i",
"swig/funcs.i", "swig/funcs.i",
"swig/gdl.i",
"swig/ida.i", "swig/ida.i",
"swig/idaapi.i", "swig/idaapi.i",
"swig/idd.i",
"swig/idp.i", "swig/idp.i",
"swig/ints.i", "swig/ints.i",
"swig/kernwin.i", "swig/kernwin.i",
@ -119,19 +118,6 @@ SRCDIST_MANIFEST = [
"tools/gendocs.py", "tools/gendocs.py",
] ]
# Temporaty build files to remove
BUILD_TEMPFILES = [
"idaapi.cpp",
"idaapi.obj",
"idaapi.o",
"idaapi.py",
"idapython.sln",
"idapython.ncb",
"python.exp",
"python.lib",
"python.obj"
]
class BuilderBase: class BuilderBase:
""" Base class for builders """ """ Base class for builders """
def __init__(self): def __init__(self):
@ -165,7 +151,6 @@ class BuilderBase:
if VERBOSE: print cmdstring if VERBOSE: print cmdstring
return os.system(cmdstring) return os.system(cmdstring)
def link(self, objects, outfile, libpaths=[], libraries=[], extra_parameters=None): def link(self, objects, outfile, libpaths=[], libraries=[], extra_parameters=None):
""" Link the binary from objects and libraries """ """ Link the binary from objects and libraries """
cmdstring = "%s %s %s" % (self.linker, cmdstring = "%s %s %s" % (self.linker,
@ -174,20 +159,16 @@ class BuilderBase:
for objectfile in objects: for objectfile in objects:
cmdstring = "%s %s" % (cmdstring, objectfile + self.object_extension) cmdstring = "%s %s" % (cmdstring, objectfile + self.object_extension)
for libpath in libpaths: for libpath in libpaths:
cmdstring = "%s %s%s" % (cmdstring, self.libpath_delimiter, libpath) cmdstring = "%s %s%s" % (cmdstring, self.libpath_delimiter, libpath)
for library in libraries: for library in libraries:
cmdstring = "%s %s" % (cmdstring, library) cmdstring = "%s %s" % (cmdstring, library)
if extra_parameters: if extra_parameters:
cmdstring = "%s %s" % (cmdstring, extra_parameters) cmdstring = "%s %s" % (cmdstring, extra_parameters)
if VERBOSE: print cmdstring if VERBOSE: print cmdstring
return os.system(cmdstring) return os.system(cmdstring)
def _build_command_string(self, macros, argument_delimiter): def _build_command_string(self, macros, argument_delimiter):
macrostring = "" macrostring = ""
@ -225,7 +206,7 @@ class GCCBuilder(BuilderBase):
class MSVCBuilder(BuilderBase): class MSVCBuilder(BuilderBase):
""" Generic GCC compiler class """ """ Generic Visual C compiler class """
def __init__(self): def __init__(self):
self.include_delimiter = "/I" self.include_delimiter = "/I"
self.macro_delimiter = "/D" self.macro_delimiter = "/D"
@ -250,19 +231,19 @@ class MSVCBuilder(BuilderBase):
return "/out:%s" % filename return "/out:%s" % filename
def build_distribution(manifest, distrootdir): def build_distribution(manifest, distrootdir, ea64, nukeold):
""" Create dist tree and copy files to it """ """ Create a distibution to a directory and a ZIP file """
# (Re)create the output directory
# Remove the previous distibution if exits
if os.path.exists(distrootdir): if os.path.exists(distrootdir):
shutil.rmtree(distrootdir) if nukeold:
shutil.rmtree(distrootdir)
os.makedirs(distrootdir)
else:
os.makedirs(distrootdir)
# Also make a ZIP archive of the build # Also make a ZIP archive of the build
zippath = distrootdir + ".zip" zippath = distrootdir + ".zip"
zip = zipfile.ZipFile(zippath, "w", zipfile.ZIP_DEFLATED) zip = zipfile.ZipFile(zippath, nukeold and "w" or "a", zipfile.ZIP_DEFLATED)
# Create output directory
os.makedirs(distrootdir)
# Copy files, one by one # Copy files, one by one
for f in manifest: for f in manifest:
@ -275,12 +256,13 @@ def build_distribution(manifest, distrootdir):
srcfilepath = f srcfilepath = f
srcfilename = os.path.basename(f) srcfilename = os.path.basename(f)
srcdir = os.path.dirname(f) srcdir = os.path.dirname(f)
if srcdir == "": if srcdir == "":
dstdir = distrootdir dstdir = distrootdir
else: else:
dstdir = distrootdir + os.sep + srcdir dstdir = distrootdir + os.sep + srcdir
# Move the python files to python64 when building a 64-bit plugin
# if ea64:
# dstdir = dstdir.replace(os.sep+'python', os.sep+'python64')
if not os.path.exists(dstdir): if not os.path.exists(dstdir):
os.makedirs(dstdir) os.makedirs(dstdir)
@ -290,67 +272,66 @@ def build_distribution(manifest, distrootdir):
zip.close() zip.close()
def build_plugin(system, idasdkdir):
""" Build the plugin from the SWIG wrapper and plugin main source """
# Find IDA SDK headers def build_plugin(platform, idasdkdir, plugin_name, ea64):
""" Build the plugin from the SWIG wrapper and plugin main source """
# Path to the IDA SDK headers
ida_include_directory = idasdkdir + os.sep + "include" ida_include_directory = idasdkdir + os.sep + "include"
builder = None
# Platform-specific settings for the Linux build # Platform-specific settings for the Linux build
if system == "Linux": if platform == "linux":
builder = GCCBuilder() builder = GCCBuilder()
plugin_name = "python.plx"
platform_macros = [ "__LINUX__" ] platform_macros = [ "__LINUX__" ]
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "lib" python_libpath = sysconfig.EXEC_PREFIX + os.sep + "lib"
python_library = "-lpython%d.%d" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION) python_library = "-lpython%d.%d" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
ida_libpath = idasdkdir + os.sep + "libgcc32.lnx" ida_libpath = os.path.join(idasdkdir, ea64 and "libgcc64.lnx" or "libgcc32.lnx")
ida_lib = "" ida_lib = ""
extra_link_parameters = "" extra_link_parameters = ""
# Platform-specific settings for the Windows build # Platform-specific settings for the Windows build
if system == "Windows": if platform == "win32":
builder = MSVCBuilder() builder = MSVCBuilder()
plugin_name = "python.plw"
platform_macros = [ "__NT__" ] platform_macros = [ "__NT__" ]
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "libs" python_libpath = sysconfig.EXEC_PREFIX + os.sep + "libs"
python_library = "python%d%d.lib" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION) python_library = "python%d%d.lib" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
ida_libpath = idasdkdir + os.sep + "libvc.w32" ida_libpath = os.path.join(idasdkdir, ea64 and "libvc.w64" or "libvc.w32")
ida_lib = "ida.lib" ida_lib = "ida.lib"
extra_link_parameters = "" extra_link_parameters = ""
# Platform-specific settings for the Mac OS X build
# Platform-specific settings for the Linux build if platform == "macosx":
if system == "Darwin":
builder = GCCBuilder() builder = GCCBuilder()
builder.linker_parameters = "-dynamiclib" builder.linker_parameters = "-dynamiclib"
plugin_name = "python.pmc"
platform_macros = [ "__MAC__" ] platform_macros = [ "__MAC__" ]
python_libpath = "." python_libpath = "."
python_library = "-framework Python" python_library = "-framework Python"
ida_libpath = idasdkdir + os.sep + "libgcc32.mac" ida_libpath = os.path.join(idasdkdir, ea64 and "libgcc64.mac" or "libgcc32.mac")
ida_lib = "-lida" ida_lib = ea64 and "-lida64" or "-lida"
extra_link_parameters = "" extra_link_parameters = ""
assert builder, "Unknown platform! No idea how to build here..."
# Enable EA64 for the compiler if necessary
if ea64:
platform_macros.append("__EA64__")
# Build the wrapper from the interface files # Build the wrapper from the interface files
swigcmd = "swig %s -Iswig -o idaapi.cpp -I%s idaapi.i" % (SWIG_OPTIONS, ida_include_directory) ea64flag = ea64 and "-D__EA64__" or ""
swigcmd = "swig %s -Iswig -o idaapi.cpp %s -I%s idaapi.i" % (SWIG_OPTIONS, ea64flag, ida_include_directory)
if VERBOSE: print swigcmd if VERBOSE: print swigcmd
res = os.system(swigcmd) res = os.system(swigcmd)
assert res == 0, "Failed to build the wrapper with SWIG"
if res != 0: return False
# Compile the wrapper # Compile the wrapper
res = builder.compile("idaapi", res = builder.compile("idaapi",
includes=[ PYTHON_INCLUDE_DIRECTORY, ida_include_directory ], includes=[ PYTHON_INCLUDE_DIRECTORY, ida_include_directory ],
macros=platform_macros) macros=platform_macros)
assert res == 0, "Failed to build the wrapper module"
if res != 0: return False
# Compile the main plugin source # Compile the main plugin source
res = builder.compile("python", res = builder.compile("python",
includes=[ PYTHON_INCLUDE_DIRECTORY, ida_include_directory ], includes=[ PYTHON_INCLUDE_DIRECTORY, ida_include_directory ],
macros=platform_macros) macros=platform_macros)
assert res == 0, "Failed to build the main plugin object"
if res != 0: return False
# Link the final binary # Link the final binary
res = builder.link( ["idaapi", "python"], res = builder.link( ["idaapi", "python"],
@ -358,38 +339,25 @@ def build_plugin(system, idasdkdir):
[ python_libpath, ida_libpath ], [ python_libpath, ida_libpath ],
[ python_library, ida_lib ], [ python_library, ida_lib ],
extra_link_parameters) extra_link_parameters)
assert res == 0, "Failed to link the plugin binary"
if res != 0: return False
return True
def clean(manifest): def build_binary_package(ea64, nukeold):
""" Clean the temporary files """
for i in manifest:
try:
os.unlink(i)
except:
pass
if __name__ == "__main__":
# Detect the platform # Detect the platform
system = platform.system() system = platform.system()
if system == "Windows" or system == "Microsoft": if system == "Windows" or system == "Microsoft":
system = "Windows" system = "Windows"
platform_string = "win32" platform_string = "win32"
plugin_name = "python.plw" plugin_name = ea64 and "python.p64" or "python.plw"
if system == "Linux": if system == "Linux":
platform_string = "linux" platform_string = "linux"
plugin_name = "python.plx" plugin_name = ea64 and "python.plx64" or "python.plx"
if system == "Darwin": if system == "Darwin":
platform_string = "macosx" platform_string = "macosx"
plugin_name = "python.pmc" plugin_name = ea64 and "python.pmc64" or "python.pmc"
BINDISTDIR = "idapython-%d.%d.%d_ida%d.%d_py%d.%d_%s" % (VERSION_MAJOR, BINDISTDIR = "idapython-%d.%d.%d_ida%d.%d_py%d.%d_%s" % (VERSION_MAJOR,
VERSION_MINOR, VERSION_MINOR,
@ -399,28 +367,33 @@ if __name__ == "__main__":
PYTHON_MAJOR_VERSION, PYTHON_MAJOR_VERSION,
PYTHON_MINOR_VERSION, PYTHON_MINOR_VERSION,
platform_string) platform_string)
# Build the plugin
build_plugin(platform_string, IDA_SDK, plugin_name, ea64)
# Build the binary distribution
binmanifest = []
if nukeold:
binmanifest.extend(BINDIST_MANIFEST)
binmanifest.extend([(x, ea64 and "python64" or "python") for x in "python/init.py", "python/idc.py", "python/idautils.py", "idaapi.py"])
binmanifest.append((plugin_name, "plugins"))
build_distribution(binmanifest, BINDISTDIR, ea64, nukeold)
def build_source_package():
""" Build a directory and a ZIP file with all the sources """
SRCDISTDIR = "idapython-%d.%d.%d" % (VERSION_MAJOR, SRCDISTDIR = "idapython-%d.%d.%d" % (VERSION_MAJOR,
VERSION_MINOR, VERSION_MINOR,
VERSION_PATCH) VERSION_PATCH)
# Build the source distribution
# Build the plugin
res = build_plugin(system, IDA_SDK)
if not res: sys.exit(1)
# Build the binary distribution
binmanifest = []
binmanifest.extend(BINDIST_MANIFEST)
binmanifest.append((plugin_name, "plugins"))
build_distribution(binmanifest, BINDISTDIR)
# Build the binary distribution
srcmanifest = [] srcmanifest = []
srcmanifest.extend(BINDIST_MANIFEST) srcmanifest.extend(BINDIST_MANIFEST)
srcmanifest.extend(SRCDIST_MANIFEST) srcmanifest.extend(SRCDIST_MANIFEST)
build_distribution(srcmanifest, SRCDISTDIR) srcmanifest.extend([(x, "python") for x in "python/init.py", "python/idc.py", "python/idautils.py"])
build_distribution(srcmanifest, SRCDISTDIR, ea64=False, nukeold=True)
# Clean the temp files
cleanlist = [] if __name__ == "__main__":
cleanlist.extend(BUILD_TEMPFILES) # Do 64-bit build?
cleanlist.append(plugin_name) ea64 = '--ea64' in sys.argv
# clean(cleanlist) build_binary_package(ea64=False, nukeold=True)
build_binary_package(ea64=True, nukeold=False)
build_source_package()

View File

@ -45,15 +45,19 @@ extern "C"
#define IDAPYTHON_RUNSTATEMENT 1 #define IDAPYTHON_RUNSTATEMENT 1
#define IDAPYTHON_SCRIPTBOX 2 #define IDAPYTHON_SCRIPTBOX 2
#define IDAPYTHON_DATA_STATEMENT 0 #define IDAPYTHON_DATA_STATEMENT 0
#ifdef __EA64__
#define PYTHON_DIR_NAME "python64"
#else
#define PYTHON_DIR_NAME "python"
#endif
void init_idaapi(void); void init_idaapi(void);
void idaapi run(int arg); void idaapi run(int arg);
static int initialized = 0; static int initialized = 0;
/* This is a simple tracing code for debugging purposes. */ /* This is a simple tracing code for debugging purposes. */
/* It might evolve into a tracing facility for user scripts. */ /* It might evolve into a tracing facility for user scripts. */
/* #define ENABLE_PYTHON_PROFILING */ /* #define ENABLE_PYTHON_PROFILING */
@ -172,14 +176,7 @@ bool CheckFile(char *filename)
{ {
char filepath[MAXSTR+1]; char filepath[MAXSTR+1];
#if IDP_INTERFACE_VERSION >= 75 qmakepath(filepath, MAXSTR, idadir(PYTHON_DIR_NAME), filename, NULL);
qmakepath(filepath, MAXSTR, idadir(NULL), "python", filename, NULL);
#elif IDP_INTERFACE_VERSION >= 69
qmakepath(filepath, idadir(NULL), "python", filename, NULL);
#else
qmakepath(filepath, idadir(), "python", filename, NULL);
#endif
if (!qfileexist(filepath)) if (!qfileexist(filepath))
{ {
warning("IDAPython: Missing required file %s", filename); warning("IDAPython: Missing required file %s", filename);
@ -614,7 +611,7 @@ bool IDAPython_Init(void)
PyRun_SimpleString(tmp); PyRun_SimpleString(tmp);
/* Pull in the Python side of init */ /* Pull in the Python side of init */
qmakepath(tmp, MAXSTR, idadir("python"), "init.py", NULL); qmakepath(tmp, MAXSTR, idadir(PYTHON_DIR_NAME), "init.py", NULL);
if (!ExecFile(tmp)) if (!ExecFile(tmp))
{ {
warning("IDAPython: error executing init.py"); warning("IDAPython: error executing init.py");

View File

@ -99,7 +99,11 @@ sys.stdout = sys.stderr = MyStdOut()
sys.argv = [ "" ] sys.argv = [ "" ]
# Have to make sure Python finds our modules # Have to make sure Python finds our modules
sys.path.append(_idaapi.idadir("python")) if _idaapi.idainfo_is_64bit(_idaapi.cvar.inf):
pythonDir = "python64"
else:
pythonDir = "python"
sys.path.append(_idaapi.idadir(pythonDir))
print_banner() print_banner()