4545# Find Python headers
4646PYTHON_INCLUDE_DIRECTORY = sysconfig .get_config_var ('INCLUDEPY' )
4747
48+ S_EA64 = 'ea64'
49+ S_WITH_HEXRAYS = 'with-hexrays'
50+ S_NO_OPT = 'no-opt'
51+
4852# Swig command-line parameters
4953SWIG_OPTIONS = '-modern -python -c++ -w451 -shadow -D__GNUC__ -DNO_OBSOLETE_FUNCS'
5054
6165# Common includes for all compilations
6266COMMON_INCLUDES = [ "." , "swig" ]
6367
68+ # -----------------------------------------------------------------------
6469# List files for the binary distribution
6570BINDIST_MANIFEST = [
6671 "README.txt" ,
104109 "examples/ex_imports.py"
105110]
106111
112+ # -----------------------------------------------------------------------
107113# List files for the source distribution (appended to binary list)
108114SRCDIST_MANIFEST = [
109115 "BUILDING.txt" ,
150156 "swig/xref.i" ,
151157 "swig/graph.i" ,
152158 "swig/fpro.i" ,
159+ "swig/hexrays.i" ,
153160 "tools/gendocs.py" ,
154161]
155162
163+ # -----------------------------------------------------------------------
164+ def parse_options (args ):
165+ """Parse arguments and returned a dictionary of options"""
166+
167+ no_opt = '--' + S_NO_OPT in sys .argv
168+ ea64 = '--' + S_EA64 in sys .argv
169+ with_hexrays = '--' + S_WITH_HEXRAYS in sys .argv
170+
171+ return {
172+ S_EA64 : ea64 ,
173+ S_WITH_HEXRAYS : with_hexrays ,
174+ S_NO_OPT : no_opt
175+ }
176+
177+ # -----------------------------------------------------------------------
156178class BuilderBase :
157179 """ Base class for builders """
158180 def __init__ (self ):
159181 pass
160182
183+
161184 def compile (self , source , objectname = None , includes = [], macros = []):
162185 """
163186 Compile the source file
@@ -187,6 +210,7 @@ def compile(self, source, objectname=None, includes=[], macros=[]):
187210 print cmdstring
188211 return os .system (cmdstring )
189212
213+
190214 def link (self , objects , outfile , libpaths = [], libraries = [], extra_parameters = None ):
191215 """ Link the binary from objects and libraries """
192216 cmdstring = "%s %s %s" % (self .linker ,
@@ -217,6 +241,7 @@ def _build_command_string(self, macros, argument_delimiter):
217241 return macrostring
218242
219243
244+ # -----------------------------------------------------------------------
220245class GCCBuilder (BuilderBase ):
221246 """ Generic GCC compiler class """
222247 def __init__ (self ):
@@ -241,6 +266,7 @@ def linker_out_string(self, filename):
241266 return "-o %s" % filename
242267
243268
269+ # -----------------------------------------------------------------------
244270class MSVCBuilder (BuilderBase ):
245271 """ Generic Visual C compiler class """
246272 def __init__ (self ):
@@ -266,7 +292,7 @@ def compiler_out_string(self, filename):
266292 def linker_out_string (self , filename ):
267293 return "/out:%s" % filename
268294
269-
295+ # -----------------------------------------------------------------------
270296def build_distribution (manifest , distrootdir , ea64 , nukeold ):
271297 """ Create a distibution to a directory and a ZIP file """
272298 # (Re)create the output directory
@@ -307,7 +333,17 @@ def build_distribution(manifest, distrootdir, ea64, nukeold):
307333 zip .close ()
308334
309335
310- def build_plugin (platform , idasdkdir , plugin_name , ea64 ):
336+ # -----------------------------------------------------------------------
337+ def build_plugin (
338+ platform ,
339+ idasdkdir ,
340+ plugin_name ,
341+ options ):
342+
343+ # Get the arguments
344+ ea64 = options [S_EA64 ]
345+ with_hexrays = options [S_WITH_HEXRAYS ]
346+
311347 global SWIG_OPTIONS
312348 """ Build the plugin from the SWIG wrapper and plugin main source """
313349 # Path to the IDA SDK headers
@@ -334,7 +370,8 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
334370 ida_lib = "ida.lib"
335371 SWIG_OPTIONS += " -D__NT__ "
336372 extra_link_parameters = ""
337- builder .compiler_parameters += " -Ox"
373+ if not options [S_NO_OPT ]:
374+ builder .compiler_parameters += " -Ox"
338375 # Platform-specific settings for the Mac OS X build
339376 elif platform == "macosx" :
340377 builder = GCCBuilder ()
@@ -353,6 +390,11 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
353390 if ea64 :
354391 platform_macros .append ("__EA64__" )
355392
393+ # Build with Hex-Rays decompiler
394+ if with_hexrays :
395+ platform_macros .append ("WITH_HEXRAYS" )
396+ SWIG_OPTIONS += ' -DWITH_HEXRAYS '
397+
356398 platform_macros .append ("NDEBUG" )
357399
358400 if not '--no-early-load' in sys .argv :
@@ -388,6 +430,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
388430 extra_link_parameters )
389431 assert res == 0 , "Failed to link the plugin binary"
390432
433+ # -----------------------------------------------------------------------
391434def detect_platform (ea64 ):
392435 # Detect the platform
393436 system = platform .system ()
@@ -410,7 +453,9 @@ def detect_platform(ea64):
410453
411454 return (system , platform_string , plugin_name )
412455
413- def build_binary_package (ea64 , nukeold ):
456+ # -----------------------------------------------------------------------
457+ def build_binary_package (options , nukeold ):
458+ ea64 = options [S_EA64 ]
414459 system , platform_string , plugin_name = detect_platform (ea64 )
415460 BINDISTDIR = "idapython-%d.%d.%d_ida%d.%d_py%d.%d_%s" % (VERSION_MAJOR ,
416461 VERSION_MINOR ,
@@ -421,7 +466,7 @@ def build_binary_package(ea64, nukeold):
421466 PYTHON_MINOR_VERSION ,
422467 platform_string )
423468 # Build the plugin
424- build_plugin (platform_string , IDA_SDK , plugin_name , ea64 )
469+ build_plugin (platform_string , IDA_SDK , plugin_name , options )
425470
426471 # Build the binary distribution
427472 binmanifest = []
@@ -436,6 +481,7 @@ def build_binary_package(ea64, nukeold):
436481 build_distribution (binmanifest , BINDISTDIR , ea64 , nukeold )
437482
438483
484+ # -----------------------------------------------------------------------
439485def build_source_package ():
440486 """ Build a directory and a ZIP file with all the sources """
441487 SRCDISTDIR = "idapython-%d.%d.%d" % (VERSION_MAJOR ,
@@ -448,6 +494,7 @@ def build_source_package():
448494 srcmanifest .extend ([(x , "python" ) for x in "python/init.py" , "python/idc.py" , "python/idautils.py" ])
449495 build_distribution (srcmanifest , SRCDISTDIR , ea64 = False , nukeold = True )
450496
497+ # -----------------------------------------------------------------------
451498def gen_docs (z = False ):
452499 print "Generating documentation....."
453500 old_dir = os .getcwd ()
@@ -494,6 +541,7 @@ def gen_docs(z = False):
494541 os .chdir (old_dir )
495542 return
496543
544+ # -----------------------------------------------------------------------
497545def usage ():
498546 print """IDAPython build script.
499547
@@ -504,23 +552,36 @@ def usage():
504552 Used with '--doc' switch. It will compress the generated documentation
505553 --ea64:
506554 Builds also the 64bit version of the plugin
555+ --with-hexrays:
556+ Build with the Hex-Rays Decompiler wrappings
507557 --no-early-load:
508558 The plugin will be compiled as normal plugin
509559 This switch disables processor, plugin and loader scripts
510560"""
511561
562+ # -----------------------------------------------------------------------
512563def main ():
513564 if '--help' in sys .argv :
514565 return usage ()
515566 elif '--doc' in sys .argv :
516567 return gen_docs (z = '--zip' in sys .argv )
517568
518- # Do 64-bit build?
519- ea64 = '--ea64' in sys .argv
520- build_binary_package (ea64 = False , nukeold = True )
569+ # Parse options
570+ options = parse_options (sys .argv )
571+ ea64 = options [S_EA64 ]
572+
573+ # Always build the non __EA64__ version
574+ options [S_EA64 ] = False
575+ build_binary_package (options , nukeold = True )
576+
577+ # Rebuild package with __EA64__ if needed
521578 if ea64 :
522- build_binary_package (ea64 = True , nukeold = False )
579+ options [S_EA64 ] = True
580+ build_binary_package (options , nukeold = False )
581+
582+ # Always build the source package
523583 build_source_package ()
524584
585+ # -----------------------------------------------------------------------
525586if __name__ == "__main__" :
526587 main ()
0 commit comments