include ../../allmake.mak #---------------------------------------------------------------------- # WARNING: Many rules in this file use pattern matching, where 'make' # first considers rules as simple strings, not paths. Consequently, # it is necessary that we don't end up with 'some_dir//some_file'. # Thus, we have to settle for a makefile-wide policy of either: # - terminating dir paths with '/', in which case we have to write: # $(SOMEDIR)somefile, or # - not terminating dir paths with '/', in which case it becomes: # $(SOMEDIR)/somefile # In other makefiles sitting in IDA's source tree, we use the first approach, # but this one demands the second: not only is this more natural for # non-hexrays people looking at the file, it also allows us to work in # a more natural manner with other tools (such as the build.py wrapper, that # uses os.path.join()) #---------------------------------------------------------------------- # default goals .PHONY: configs modules pyfiles deployed_modules idapython_modules api_check api_contents qt_bindings bins public_tree test_idc docs docs_md tbd examples examples_index test_pywraps all: configs modules pyfiles deployed_modules idapython_modules api_check api_contents qt_bindings bins examples examples_index test_pywraps # public_tree test_idc docs docs_md ifeq ($(OUT_OF_TREE_BUILD),) IDAPYSWITCH:=$(R)idapyswitch$(B) IDAPYSWITCH_DEP:=$(IDAPYSWITCH) IDAPYSWITCH_PATH:=$(IDAPYSWITCH) TEST_PYWRAPS_RESULT_FNAME:=test_pywraps$(ADRSIZE).txt ifdef __NT__ # On Windows, we cannot afford to use `test_pywraps` during a # debug build: since `test_pywraps.exe` relies on `python3.dll` # (and corresponding headers), Python will force optimized # iterators resulting in errors such as: # dumb.obj : error LNK2038: mismatch detected for '_ITERATOR_DEBUG_LEVEL': value '2' doesn't match value '0' in test_pywraps.obj # And as it turns out, doing it during an optimized build # is problematic as well, because it'll typically not find # `python3.dll`. I tried to support it by patching `PATH`, # but now we're dealing with cygwin confusion... ifdef NDEBUG HAS_TEST_PYWRAPS:=1 PYTHON_ROOT_CYGPATH:=$(shell cygpath $(PYTHON_ROOT)) TEST_PYWRAPS_ENV:=PATH="$$PATH:$(PYTHON_ROOT_CYGPATH)" endif else HAS_TEST_PYWRAPS:=1 endif ifeq ($(HAS_TEST_PYWRAPS),1) TEST_PYWRAPS:=$(F)$(TEST_PYWRAPS_RESULT_FNAME).marker endif BINS += $(IDAPYSWITCH) else ifdef __NT__ IDAPYSWITCH_PATH:=$(IDA_INSTALL)/idapyswitch.exe else IDAPYSWITCH_PATH:=$(IDA_INSTALL)/idapyswitch endif endif BINS += $(IDAPYSWITCH_DEP) bins: $(BINS) #---------------------------------------------------------------------- # Build system hacks # HACK HIJACK the $(I) variable to point to our staging SDK # (but don't let mkdep know about it) IDA_INCLUDE = ../../include ST_SDK = $(F)idasdk ifndef __MKDEP__ I = $(ST_SDK)/ endif # HACK HIJACK the $(LIBDIR) variable to point to our staging SDK ifneq ($(OUT_OF_TREE_BUILD),) LIBDIR = $(IDA)lib/$(TARGET_PROCESSOR_NAME)_$(SYSNAME)_$(COMPILER_NAME)_$(ADRSIZE)$(EXTRASUF) endif # HACK for mkdep to add dependencies for $(F)idapython$(O) ifdef __MKDEP__ OBJS += $(F)idapython$(O) endif # allmake.mak defines 'CP' as 'qcp.sh' which is an internal tool providing # support for the '-u' flag on OSX. However, since this makefile is part # of the public release of IDAPython, we cannot rely on it (we do not use # that flag in IDAPython anyway) ifdef __MAC__ CP = cp -f endif #---------------------------------------------------------------------- # the 'configs' target is in $(IDA)module.mak CONFIGS += idapython.cfg #---------------------------------------------------------------------- # the 'modules' target is in $(IDA)module.mak ifdef __EA64__ MODULE_NAME_STEM:=idapython3 else MODULE_NAME_STEM:=idapython3_ endif MODULE = $(call module_dll,$(MODULE_NAME_STEM)) MODULES += $(MODULE) #---------------------------------------------------------------------- ifdef __LINUX__ # we don't link to libpython anymore so allow to have undefined symbols NO_UNDEFS= endif #---------------------------------------------------------------------- # we explicitly added our module targets NO_DEFAULT_TARGETS = 1 DONT_ERASE_LIB = 1 # NOTE: all MODULES must be defined before including plugin.mak. include ../plugin.mak include ../pyplg.mak # NOTE: target-specific rules and dependencies that use variable # expansion to name the target (such as "$(MODULE): [...]") must # come after including plugin.mak #---------------------------------------------------------------------- PYTHON_OBJS += $(F)idapython$(O) $(MODULE): MODULE_OBJS += $(PYTHON_OBJS) $(MODULE): $(PYTHON_OBJS) $(IDAPYSWITCH_MODULE_DEP) ifdef __NT__ $(MODULE): OUTDLL = /DLL $(MODULE): LDFLAGS += /DEF:$(IDAPYTHON_IMPLIB_DEF) /IMPLIB:$(IDAPYTHON_IMPLIB_PATH) endif # TODO these should apply only to $(MODULE) DEFFILE = idapython.script INSTALL_NAME = @rpath/plugins/$(notdir $(MODULE)) ifdef __LINUX__ LDFLAGS_MOD = -Wl,-soname,$(notdir $(MODULE)) LDFLAGS_EXE = -lpython$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR) -Wl,--no-undefined endif PATCH_CONST=$(Q)$(PYTHON) tools/patch_constants.py -i $(1) -o $(2) #---------------------------------------------------------------------- # TODO move this below, but it might be necessary before the defines-* ifdef DO_IDAMAKE_SIMPLIFY QCHKAPI = @echo $(call qcolor,chkapi) && # QDUMPAPI = @echo $(call qcolor,dumpapi) && # QDEPLOY = @echo $(call qcolor,deploy) $$< && # QGENDOXYCFG = @echo $(call qcolor,gendoxycfg) $@ && # QGENHOOKS = @echo $(call qcolor,genhooks) $< && # QGENIDAAPI = @echo $(call qcolor,genidaapi) $< && # QGENSWIGHEADER = @echo $(call qcolor,genswigheader) $< && # QINJECT_PYDOC = @echo $(call qcolor,inject_pydoc) $$< && # QPATCH_CODEGEN = @echo $(call qcolor,patch_codegen) $$< && # QPATCH_H_CODEGEN = @echo $(call qcolor,patch_h_codegen) $$< && # QPATCH_PYTHON_CODEGEN = @echo $(call qcolor,patch_python_codegen) $$< && # QSWIG = @echo $(call qcolor,swig) $$< && # QUPDATE_SDK = @echo $(call qcolor,update_sdk) $< && # QSPLIT_HEXRAYS_TEMPLATES = @echo $(call qcolor,split_hexrays_templates) $< && # QGEN_EXAMPLES_INDEX = @echo $(call qcolor,gen_examples_index) $@ && # endif #---------------------------------------------------------------------- ST_SWIG=$(F)swig ST_PYW=$(F)pywraps ST_WRAP=$(F)wrappers ST_PARSED_HEADERS_NOXML=$(F)parsed_notifications ST_PARSED_HEADERS=$(ST_PARSED_HEADERS_NOXML)/xml ifeq ($(OUT_OF_TREE_BUILD),) ST_PARSED_HEADERS_CONFIG=$(ST_PARSED_HEADERS_NOXML)/doxy_gen_notifs.cfg endif # output directory for python scripts DEPLOY_PYDIR=$(R)python DEPLOY_INIT_PY=$(DEPLOY_PYDIR)/init.py DEPLOY_IDC_PY=$(DEPLOY_PYDIR)/idc.py DEPLOY_IDAUTILS_PY=$(DEPLOY_PYDIR)/idautils.py DEPLOY_IDAAPI_PY=$(DEPLOY_PYDIR)/idaapi.py DEPLOY_IDADEX_PY=$(DEPLOY_PYDIR)/idadex.py ifdef TESTABLE_BUILD DEPLOY_LUMINA_MODEL_PY=$(DEPLOY_PYDIR)/lumina_model.py endif ifeq ($(OUT_OF_TREE_BUILD),) TEST_IDC=test_idc IDAT_PATH?=$(R)/idat else IDAT_PATH?=$(IDA_INSTALL)/idat endif ifeq ($(OUT_OF_TREE_BUILD),) IDAT_CMD=TVHEADLESS=1 "$(IDAT_PATH)$(SUFF32)" else IDAT_CMD=TVHEADLESS=1 IDAPYTHON_DYNLOAD_BASE=$(R) "$(IDAT_PATH)$(SUFF32)" endif ifeq ($(LOCAL_LICENSE),1) IDAT_CMD := $(IDAT_CMD) -Olicense:keyfile endif ifdef LOG_FILE IDAT_CMD := $(IDAT_CMD) -L$(LOG_FILE) endif # envvar HAS_HEXRAYS must have been set by build.py if needed ifeq ($(OUT_OF_TREE_BUILD),) HAS_HEXRAYS=1 # force hexrays bindings endif # determine SDK_SOURCES ifeq ($(OUT_OF_TREE_BUILD),) include ../../etc/sdk/sdk_files.mak SDK_SOURCES=$(sort $(foreach v,$(SDK_FILES),$(if $(findstring include/,$(v)),$(addprefix $(IDA_INCLUDE)/,$(notdir $(v)))))) ifneq ($(HAS_HEXRAYS),) SDK_SOURCES+=$(IDA_INCLUDE)/hexrays.hpp endif SDK_SOURCES+=$(IDA_INCLUDE)/lumina.hpp else SDK_SOURCES=$(wildcard $(IDA_INCLUDE)/*.h) $(wildcard $(IDA_INCLUDE)/*.hpp) endif ST_SDK_TARGETS = $(SDK_SOURCES:$(IDA_INCLUDE)/%=$(ST_SDK)/%) _SWIGPY3FLAG := -DPY3=1 CC_DEFS += PY3=1 CC_DEFS += Py_LIMITED_API=0x03040000 # we should make sure we use the same version as SWiG DEPLOY_LIBDIR=$(DEPLOY_PYDIR)/lib-dynload ifdef __NT__ PYDLL_EXT = .pyd else PYDLL_EXT = .so endif ifneq ($(HAS_HEXRAYS),) WITH_HEXRAYS_DEF = WITH_HEXRAYS WITH_HEXRAYS_CHKAPI=--with-hexrays HEXRAYS_MODNAME=hexrays # Warning: adding an empty HEXRAYS_MODNAME will lead to idaapy trying to load # a module called ida_. MODULES_NAMES += $(HEXRAYS_MODNAME) endif ifeq ($(HAS_HEXRAYS),) NO_CMP_API := 1 endif #---------------------------------------------------------------------- MODULES_NAMES += allins MODULES_NAMES += auto MODULES_NAMES += bitrange MODULES_NAMES += bytes MODULES_NAMES += dbg MODULES_NAMES += diskio MODULES_NAMES += dirtree MODULES_NAMES += entry MODULES_NAMES += expr MODULES_NAMES += fixup MODULES_NAMES += fpro MODULES_NAMES += frame MODULES_NAMES += funcs MODULES_NAMES += gdl MODULES_NAMES += graph MODULES_NAMES += ida MODULES_NAMES += idaapi MODULES_NAMES += idc MODULES_NAMES += idd MODULES_NAMES += idp MODULES_NAMES += ieee MODULES_NAMES += kernwin MODULES_NAMES += libfuncs MODULES_NAMES += lines MODULES_NAMES += loader ifdef TESTABLE_BUILD MODULES_NAMES += lumina endif MODULES_NAMES += moves MODULES_NAMES += nalt MODULES_NAMES += name MODULES_NAMES += netnode MODULES_NAMES += offset MODULES_NAMES += pro MODULES_NAMES += problems MODULES_NAMES += range MODULES_NAMES += registry MODULES_NAMES += regfinder MODULES_NAMES += search MODULES_NAMES += segment MODULES_NAMES += segregs MODULES_NAMES += srclang MODULES_NAMES += strlist MODULES_NAMES += tryblks MODULES_NAMES += typeinf MODULES_NAMES += ua MODULES_NAMES += xref MODULES_NAMES += mergemod MODULES_NAMES += merge MODULES_NAMES += undo ALL_ST_WRAP_CPP = $(foreach mod,$(MODULES_NAMES),$(ST_WRAP)/$(mod).cpp) ALL_ST_WRAP_PY = $(foreach mod,$(MODULES_NAMES),$(ST_WRAP)/ida_$(mod).py) ALL_ST_WRAP_PY_FINAL = $(foreach mod,$(MODULES_NAMES),$(ST_WRAP)/ida_$(mod).py.final) DEPLOYED_MODULES = $(foreach mod,$(MODULES_NAMES),$(DEPLOY_LIBDIR)/_ida_$(mod)$(PYDLL_EXT)) IDAPYTHON_MODULES = $(foreach mod,$(MODULES_NAMES),$(DEPLOY_PYDIR)/ida_$(mod).py) PYTHON_BINARY_MODULES = $(foreach mod,$(MODULES_NAMES),$(DEPLOY_LIBDIR)/_ida_$(mod)$(PYDLL_EXT)) #---------------------------------------------------------------------- idapython_modules: $(IDAPYTHON_MODULES) deployed_modules: $(DEPLOYED_MODULES) ifdef __NT__ IDAPYTHON_IMPLIB_DEF=idapython_implib.def IDAPYTHON_IMPLIB_PATH=$(F)idapython.lib LINKIDAPYTHON = $(IDAPYTHON_IMPLIB_PATH) else LINKIDAPYTHON = $(MODULE) endif ifdef __NT__ # os and compiler specific flags _SWIGFLAGS = -D__NT__ -DWIN32 -D_USRDLL -I"$(PYTHON_ROOT)/include" CFLAGS += /bigobj $(_SWIGFLAGS) -I$(ST_SDK) else # unix/mac ifdef __LINUX__ PYTHON_LDFLAGS_RPATH_MODULE=-Wl,-rpath='$$ORIGIN/../../..' _SWIGFLAGS = -D__LINUX__ else ifdef __MAC__ PYTHON_LDFLAGS_RPATH_MODULE=-Wl,-rpath,@loader_path/../../.. _SWIGFLAGS = -D__MAC__ endif endif # Apparently that's not needed, but I don't understand why ATM, since doc says: # ...Then, only modules compiled with SWIG_TYPE_TABLE set to myprojectname # will share type information. So if your project has three modules, all three # should be compiled with -DSWIG_TYPE_TABLE=myprojectname, and then these # three modules will share type information. But any other project's # types will not interfere or clash with the types in your module. DEF_TYPE_TABLE = SWIG_TYPE_TABLE=idaapi SWIGFLAGS=$(_SWIGFLAGS) -Itools/typemaps-supplement $(SWIG_INCLUDES) $(addprefix -D,$(DEF_TYPE_TABLE)) -DMISSED_BC695 pyfiles: $(DEPLOY_IDAUTILS_PY) \ $(DEPLOY_IDC_PY) \ $(DEPLOY_INIT_PY) \ $(DEPLOY_IDAAPI_PY) \ $(DEPLOY_IDADEX_PY) \ $(DEPLOY_LUMINA_MODEL_PY) ifeq ($(OUT_OF_TREE_BUILD),) ifndef NDEBUG SRC_PYQT_BUNDLE:=$(PYQT5_DEBUG) else SRC_PYQT_BUNDLE:=$(PYQT5_RELEASE) endif DEST_PYQT_DIR:=$(R)python/PyQt5 $(DEST_PYQT_DIR): -$(Q)if [ ! -d "$(DEST_PYQT_DIR)" ] ; then mkdir -p 2>/dev/null $(DEST_PYQT_DIR) ; fi # PyQt5 DEST_PYQT_QTCORE:=$(DEST_PYQT_DIR)/QtCore$(PYDLL_EXT) $(DEST_PYQT_QTCORE): $(SRC_PYQT_BUNDLE) | $(DEST_PYQT_DIR) $(Q)$(TAR) -xf $(SRC_PYQT_BUNDLE) -C $(dir $(DEST_PYQT_DIR)) --strip 1 $(Q)touch $@ DEST_PYQT += $(DEST_PYQT_QTCORE) SIP_PYDLL_FNAME:=sip$(PYDLL_EXT) SIP_PYI_FNAME:=sip.pyi # sip for Python < 3.8 DEST_SIP34_DIR:=$(DEST_PYQT_DIR)/python_3.4 $(DEST_SIP34_DIR): -$(Q)if [ ! -d "$(DEST_SIP34_DIR)" ] ; then mkdir -p 2>/dev/null $(DEST_SIP34_DIR) ; fi DEST_SIP34_PYDLL:=$(DEST_SIP34_DIR)/$(SIP_PYDLL_FNAME) DEST_SIP34_PYI:=$(DEST_SIP34_DIR)/$(SIP_PYI_FNAME) $(DEST_SIP34_PYDLL): $(wildcard $(SIP34_TREE)/lib/python*/PyQt5/$(SIP_PYDLL_FNAME)) | $(DEST_SIP34_DIR) $(Q)$(CP) $? $@ $(DEST_SIP34_PYI): $(wildcard $(SIP34_TREE)/lib/python*/PyQt5/$(SIP_PYI_FNAME)) | $(DEST_SIP34_DIR) $(Q)$(CP) $? $@ DEST_SIP += $(DEST_SIP34_PYDLL) $(DEST_SIP34_PYI) # sip for Python [3.8, 3.9) DEST_SIP38_DIR:=$(DEST_PYQT_DIR)/python_3.8 $(DEST_SIP38_DIR): -$(Q)if [ ! -d "$(DEST_SIP38_DIR)" ] ; then mkdir -p 2>/dev/null $(DEST_SIP38_DIR) ; fi DEST_SIP38_PYDLL:=$(DEST_SIP38_DIR)/$(SIP_PYDLL_FNAME) DEST_SIP38_PYI:=$(DEST_SIP38_DIR)/$(SIP_PYI_FNAME) $(DEST_SIP38_PYDLL): $(wildcard $(SIP38_TREE)/lib/python*/PyQt5/$(SIP_PYDLL_FNAME)) | $(DEST_SIP38_DIR) $(Q)$(CP) $? $@ $(DEST_SIP38_PYI): $(wildcard $(SIP38_TREE)/lib/python*/PyQt5/$(SIP_PYI_FNAME)) | $(DEST_SIP38_DIR) $(Q)$(CP) $? $@ DEST_SIP += $(DEST_SIP38_PYDLL) $(DEST_SIP38_PYI) # sip for Python 3.9 DEST_SIP39_DIR:=$(DEST_PYQT_DIR)/python_3.9 $(DEST_SIP39_DIR): -$(Q)if [ ! -d "$(DEST_SIP39_DIR)" ] ; then mkdir -p 2>/dev/null $(DEST_SIP39_DIR) ; fi DEST_SIP39_PYDLL:=$(DEST_SIP39_DIR)/$(SIP_PYDLL_FNAME) DEST_SIP39_PYI:=$(DEST_SIP39_DIR)/$(SIP_PYI_FNAME) $(DEST_SIP39_PYDLL): $(wildcard $(SIP39_TREE)/lib/python*/PyQt5/$(SIP_PYDLL_FNAME)) | $(DEST_SIP39_DIR) $(Q)$(CP) $? $@ $(DEST_SIP39_PYI): $(wildcard $(SIP39_TREE)/lib/python*/PyQt5/$(SIP_PYI_FNAME)) | $(DEST_SIP39_DIR) $(Q)$(CP) $? $@ DEST_SIP += $(DEST_SIP39_PYDLL) $(DEST_SIP39_PYI) # sip for Python 3.10 DEST_SIP310_DIR:=$(DEST_PYQT_DIR)/python_3.10 $(DEST_SIP310_DIR): -$(Q)if [ ! -d "$(DEST_SIP310_DIR)" ] ; then mkdir -p 2>/dev/null $(DEST_SIP310_DIR) ; fi DEST_SIP310_PYDLL:=$(DEST_SIP310_DIR)/$(SIP_PYDLL_FNAME) DEST_SIP310_PYI:=$(DEST_SIP310_DIR)/$(SIP_PYI_FNAME) $(DEST_SIP310_PYDLL): $(wildcard $(SIP310_TREE)/lib/python*/PyQt5/$(SIP_PYDLL_FNAME)) | $(DEST_SIP310_DIR) $(Q)$(CP) $? $@ $(DEST_SIP310_PYI): $(wildcard $(SIP310_TREE)/lib/python*/PyQt5/$(SIP_PYI_FNAME)) | $(DEST_SIP310_DIR) $(Q)$(CP) $? $@ DEST_SIP += $(DEST_SIP310_PYDLL) $(DEST_SIP310_PYI) # sip for Python 3.11 DEST_SIP311_DIR:=$(DEST_PYQT_DIR)/python_3.11 $(DEST_SIP311_DIR): -$(Q)if [ ! -d "$(DEST_SIP311_DIR)" ] ; then mkdir -p 2>/dev/null $(DEST_SIP311_DIR) ; fi DEST_SIP311_PYDLL:=$(DEST_SIP311_DIR)/$(SIP_PYDLL_FNAME) DEST_SIP311_PYI:=$(DEST_SIP311_DIR)/$(SIP_PYI_FNAME) $(DEST_SIP311_PYDLL): $(wildcard $(SIP311_TREE)/lib/python*/PyQt5/$(SIP_PYDLL_FNAME)) | $(DEST_SIP311_DIR) $(Q)$(CP) $? $@ $(DEST_SIP311_PYI): $(wildcard $(SIP311_TREE)/lib/python*/PyQt5/$(SIP_PYI_FNAME)) | $(DEST_SIP311_DIR) $(Q)$(CP) $? $@ DEST_SIP += $(DEST_SIP311_PYDLL) $(DEST_SIP311_PYI) # sip for Python 3.12 DEST_SIP312_DIR:=$(DEST_PYQT_DIR)/python_3.12 $(DEST_SIP312_DIR): -$(Q)if [ ! -d "$(DEST_SIP312_DIR)" ] ; then mkdir -p 2>/dev/null $(DEST_SIP312_DIR) ; fi DEST_SIP312_PYDLL:=$(DEST_SIP312_DIR)/$(SIP_PYDLL_FNAME) DEST_SIP312_PYI:=$(DEST_SIP312_DIR)/$(SIP_PYI_FNAME) $(DEST_SIP312_PYDLL): $(wildcard $(SIP312_TREE)/lib/python*/PyQt5/$(SIP_PYDLL_FNAME)) | $(DEST_SIP312_DIR) $(Q)$(CP) $? $@ $(DEST_SIP312_PYI): $(wildcard $(SIP312_TREE)/lib/python*/PyQt5/$(SIP_PYI_FNAME)) | $(DEST_SIP312_DIR) $(Q)$(CP) $? $@ DEST_SIP += $(DEST_SIP312_PYDLL) $(DEST_SIP312_PYI) # sip for Python 3.13 DEST_SIP313_DIR:=$(DEST_PYQT_DIR)/python_3.13 $(DEST_SIP313_DIR): -$(Q)if [ ! -d "$(DEST_SIP313_DIR)" ] ; then mkdir -p 2>/dev/null $(DEST_SIP313_DIR) ; fi DEST_SIP313_PYDLL:=$(DEST_SIP313_DIR)/$(SIP_PYDLL_FNAME) DEST_SIP313_PYI:=$(DEST_SIP313_DIR)/$(SIP_PYI_FNAME) $(DEST_SIP313_PYDLL): $(wildcard $(SIP313_TREE)/lib/python*/PyQt5/$(SIP_PYDLL_FNAME)) | $(DEST_SIP313_DIR) $(Q)$(CP) $? $@ $(DEST_SIP313_PYI): $(wildcard $(SIP313_TREE)/lib/python*/PyQt5/$(SIP_PYI_FNAME)) | $(DEST_SIP313_DIR) $(Q)$(CP) $? $@ DEST_SIP += $(DEST_SIP313_PYDLL) $(DEST_SIP313_PYI) ifdef __LINUX__ ifdef __APPLE_SILICON__ DEST_SIP = $(DEST_SIP313_PYDLL) $(DEST_SIP313_PYI) endif endif DEST_PYQT5_SHIMS += $(DEST_PYQT_DIR)/__init__.py DEST_PYQT5_SHIMS += $(DEST_PYQT_DIR)/sip.py DEST_PYQT5_SHIMS += $(DEST_PYQT_DIR)/QtCore.py DEST_PYQT5_SHIMS += $(DEST_PYQT_DIR)/QtGui.py DEST_PYQT5_SHIMS += $(DEST_PYQT_DIR)/QtWidgets.py # # PySide6 # # For PySide6, we'll be producing the following tree structure, # for every Python version we support: # # python/PySide6-python3.13/ # ├── libpyside6.abi3.so.6.8 # ├── libshiboken6.abi3.so.6.8 # └── python3.13 # └── site-packages # ├── PySide6 # │   ├── __init__.py # │   ├── QtCore.abi3.so # │   ├── QtCore.pyi # │   ├── QtGui.abi3.so # │   ├── QtGui.pyi # │   ├── QtWidgets.abi3.so # │   └── QtWidgets.pyi # └── shiboken6 # ├── __init__.py # ├── Shiboken.abi3.so # └── Shiboken.pyi # define make-pyside6-rules DEST_PYSIDE6_DEPS += $(2)/libpyside6.abi3.so.6.8 DEST_PYSIDE6_DEPS += $(2)/libshiboken6.abi3.so.6.8 DEST_PYSIDE6_DEPS += $(2)/python3.$(1)/site-packages/shiboken6/__init__.py DEST_PYSIDE6_DEPS += $(2)/python3.$(1)/site-packages/shiboken6/Shiboken.abi3.so DEST_PYSIDE6_DEPS += $(2)/python3.$(1)/site-packages/shiboken6/Shiboken.pyi DEST_PYSIDE6_DEPS += $(2)/python3.$(1)/site-packages/PySide6/__init__.py DEST_PYSIDE6_DEPS += $(2)/python3.$(1)/site-packages/PySide6/QtCore.abi3.so DEST_PYSIDE6_DEPS += $(2)/python3.$(1)/site-packages/PySide6/QtCore.pyi DEST_PYSIDE6_DEPS += $(2)/python3.$(1)/site-packages/PySide6/QtGui.abi3.so DEST_PYSIDE6_DEPS += $(2)/python3.$(1)/site-packages/PySide6/QtGui.pyi DEST_PYSIDE6_DEPS += $(2)/python3.$(1)/site-packages/PySide6/QtWidgets.abi3.so DEST_PYSIDE6_DEPS += $(2)/python3.$(1)/site-packages/PySide6/QtWidgets.pyi DEST_PYSIDE6_PYTHON3$(1)_DIRS += $(2)/python3.$(1)/site-packages/PySide6 DEST_PYSIDE6_PYTHON3$(1)_DIRS += $(2)/python3.$(1)/site-packages/shiboken6 $(2)/python3.$(1)/site-packages/PySide6: -$(Q)if [ ! -d "$$@" ] ; then mkdir -p 2>/dev/null $$@ ; fi $(2)/python3.$(1)/site-packages/shiboken6: -$(Q)if [ ! -d "$$@" ] ; then mkdir -p 2>/dev/null $$@ ; fi $(2)/libpyside6.abi3.so.6.8: $(3)/libpyside6.abi3.so.6.8.0 | $$(DEST_PYSIDE6_PYTHON3$(1)_DIRS) $(Q)$(CP) $$? $$@ $(2)/libshiboken6.abi3.so.6.8: $(3)/libshiboken6.abi3.so.6.8.0 | $$(DEST_PYSIDE6_PYTHON3$(1)_DIRS) $(Q)$(CP) $$? $$@ $(2)/python3.13/site-packages/shiboken6/%: $(3)/python3.$(1)/site-packages/shiboken6/% | $$(DEST_PYSIDE6_PYTHON3$(1)_DIRS) $(Q)$(CP) $$? $$@ $(2)/python3.13/site-packages/PySide6/%: $(3)/python3.$(1)/site-packages/PySide6/% | $$(DEST_PYSIDE6_PYTHON3$(1)_DIRS) $(Q)$(CP) $$? $$@ endef $(eval $(call make-pyside6-rules,13,$(R)python/PySide6-python3.13,$(PYSIDE6_DIR)/PySide6-python3.13)) endif ifeq ($(QT_VERSION_MAJOR),6) QT_BINDINGS_DEPS += $(DEST_PYQT5_SHIMS) $(DEST_PYSIDE6_DEPS) $(DEST_PYQT_DIR)/%: PyQt5-shims/% | $(DEST_PYQT_DIR) $(CP) $? $@ else QT_BINDINGS_DEPS += $(DEST_PYQT) QT_BINDINGS_DEPS += $(DEST_SIP) endif qt_bindings: $(QT_BINDINGS_DEPS) GENHOOKS=tools/genhooks/ $(DEPLOY_INIT_PY): python/init.py tools/genidaapi.py $(IDAPYTHON_MODULES) $(QGENIDAAPI)$(PYTHON) tools/genidaapi.py -i $< -o $@ -m $(subst $(space),$(comma),$(MODULES_NAMES)) $(DEPLOY_IDC_PY): python/idc.py $(CP) $? $@ $(DEPLOY_IDAUTILS_PY): python/idautils.py $(CP) $? $@ $(DEPLOY_IDAAPI_PY): python/idaapi.py tools/genidaapi.py $(IDAPYTHON_MODULES) $(QGENIDAAPI)$(PYTHON) tools/genidaapi.py -i $< -o $@ -m $(subst $(space),$(comma),$(MODULES_NAMES)) $(DEPLOY_IDADEX_PY): python/idadex.py $(CP) $? $@ $(DEPLOY_LUMINA_MODEL_PY): python/lumina_model.py $(CP) $? $@ $(DEPLOY_PYDIR)/lib/%: precompiled/lib/% cp $< $@ $(Q)chmod +w $@ #---------------------------------------------------------------------- # Hooks generation # http://stackoverflow.com/questions/11032280/specify-doxygen-parameters-through-command-line $(ST_PARSED_HEADERS_CONFIG): $(GENHOOKS)doxy_gen_notifs.cfg.in $(ST_SDK_TARGETS) $(GENHOOKS)gendoxycfg.py $(QGENDOXYCFG)$(PYTHON) $(GENHOOKS)gendoxycfg.py -i $< -o $@ --includes $(subst $(space),$(comma),$(ST_SDK_TARGETS)) PARSED_HEADERS_MARKER=$(ST_PARSED_HEADERS)/headers_generated.marker $(PARSED_HEADERS_MARKER): $(ST_SDK_TARGETS) $(ST_PARSED_HEADERS_CONFIG) $(ST_SDK_TARGETS) ifeq ($(OUT_OF_TREE_BUILD),) $(Q)( cat $(ST_PARSED_HEADERS_CONFIG); echo "OUTPUT_DIRECTORY=$(ST_PARSED_HEADERS_NOXML)" ) | $(DOXYGEN_BIN) - >/dev/null else (cd $(F) && unzip ../../out_of_tree/parsed_notifications.zip) endif $(Q)touch $@ #---------------------------------------------------------------------- # Create directories in the first phase of makefile parsing. DIRLIST += $(DEPLOY_LIBDIR) DIRLIST += $(DEPLOY_PYDIR) DIRLIST += $(ST_PARSED_HEADERS) DIRLIST += $(ST_PYW) DIRLIST += $(ST_SDK) DIRLIST += $(ST_SWIG) DIRLIST += $(ST_WRAP) $(foreach d,$(sort $(DIRLIST)),$(if $(wildcard $(d)),,$(shell mkdir -p $(d)))) #---------------------------------------------------------------------- # obj/.../idasdk/*.h[pp] # NOTE: Because we have the following sequence in hexrays.hpp: # - definition of template "template struct ivl_tpl" # - instantiation of template into "typedef ivl_tpl uval_ivl_t;" # - subclassing of "uval_ivl_t": "struct ivl_t : public uval_ivl_t", # we are in trouble in our hexrays.i file, because by the time SWiG # processes "struct ivl_t", it won't have properly instantiated the # template, leading to the IDAPython proxy class "ivl_t" not subclassing # "uval_ivl_t". Therefore, we have to split the hexrays.hpp header file # into two: one that defines the template, and one that instantiates it. # This way, we can '%import "hexrays_templates.hpp"', then do the SWiG # template incantation, and finally '%include "hexrays_notemplates.hpp"' # to actually generate wrappers. ifeq ($(OUT_OF_TREE_BUILD),) $(ST_SDK)/%.h: $(IDA_INCLUDE)/%.h ../../etc/sdk/filter_src.pl tools/preprocess_sdk_header.py $(QUPDATE_SDK) perl ../../etc/sdk/filter_src.pl $< - | $(PYTHON) tools/preprocess_sdk_header.py --input - --output $@ --metadata $@.metadata $(ST_SDK)/%.hpp: $(IDA_INCLUDE)/%.hpp ../../etc/sdk/filter_src.pl tools/preprocess_sdk_header.py $(QUPDATE_SDK) perl ../../etc/sdk/filter_src.pl $< - | $(PYTHON) tools/preprocess_sdk_header.py --input - --output $@ --metadata $@.metadata else $(ST_SDK)/%.h: $(IDA_INCLUDE)/%.h tools/preprocess_sdk_header.py $(QUPDATE_SDK) $(PYTHON) tools/preprocess_sdk_header.py --input $< --output $@ --metadata $@.metadata $(ST_SDK)/%.hpp: $(IDA_INCLUDE)/%.hpp tools/preprocess_sdk_header.py $(QUPDATE_SDK) $(PYTHON) tools/preprocess_sdk_header.py --input $< --output $@ --metadata $@.metadata endif HEXRAYS_HPP_SPLIT_DIR:=$(ST_SDK) $(HEXRAYS_HPP_SPLIT_DIR)/hexrays_notemplates.hpp: $(ST_SDK)/hexrays.hpp tools/split_hexrays_templates.py $(QSPLIT_HEXRAYS_TEMPLATES)$(PYTHON) tools/split_hexrays_templates.py \ --input $< \ --out-templates $(HEXRAYS_HPP_SPLIT_DIR)/hexrays_templates.hpp \ --out-body=$(HEXRAYS_HPP_SPLIT_DIR)/hexrays_notemplates.hpp SWIGFLAGS += -I$(HEXRAYS_HPP_SPLIT_DIR) #---------------------------------------------------------------------- # obj/.../pywraps/* $(ST_PYW)/%.hpp: pywraps/%.hpp $(Q)$(CP) $^ $@ && chmod +rw $@ $(ST_PYW)/%.py: pywraps/%.py $(Q)$(CP) $^ $@ && chmod +rw $@ # These require special care, as they will have to be injected w/ hooks -- this # only happens if we are sitting in the hexrays source tree; when published to # the outside world, the pywraps must already contain the injected code. $(ST_PYW)/py_idp.hpp: pywraps/py_idp.hpp \ $(I)idp.hpp \ $(GENHOOKS)genhooks.py \ $(GENHOOKS)recipe_idphooks.py \ $(PARSED_HEADERS_MARKER) $(MAKEFILE_DEP) | $(SDK_SOURCES) $(QGENHOOKS)$(PYTHON) $(GENHOOKS)genhooks.py -i $< -o $@ \ -c IDP_Hooks \ -x $(ST_PARSED_HEADERS) \ -m hookgenIDP \ -q "processor_t::" $(ST_PYW)/py_idp_idbhooks.hpp: pywraps/py_idp_idbhooks.hpp \ $(I)idp.hpp \ $(GENHOOKS)recipe_idbhooks.py \ $(GENHOOKS)genhooks.py $(PARSED_HEADERS_MARKER) $(MAKEFILE_DEP) | $(SDK_SOURCES) $(QGENHOOKS)$(PYTHON) $(GENHOOKS)genhooks.py -i $< -o $@ \ -c IDB_Hooks \ -x $(ST_PARSED_HEADERS) \ -m hookgenIDB \ -q "idb_event::" $(ST_PYW)/py_dbg.hpp: pywraps/py_dbg.hpp \ $(I)dbg.hpp \ $(GENHOOKS)recipe_dbghooks.py \ $(GENHOOKS)genhooks.py $(PARSED_HEADERS_MARKER) $(MAKEFILE_DEP) | $(SDK_SOURCES) $(QGENHOOKS)$(PYTHON) $(GENHOOKS)genhooks.py -i $< -o $@ \ -c DBG_Hooks \ -x $(ST_PARSED_HEADERS) \ -m hookgenDBG \ -q "dbg_notification_t::" $(ST_PYW)/py_kernwin.hpp: pywraps/py_kernwin.hpp \ $(I)kernwin.hpp \ $(GENHOOKS)recipe_uihooks.py \ $(GENHOOKS)genhooks.py $(PARSED_HEADERS_MARKER) $(MAKEFILE_DEP) | $(SDK_SOURCES) $(QGENHOOKS)$(PYTHON) $(GENHOOKS)genhooks.py -i $< -o $@ \ -c UI_Hooks \ -x $(ST_PARSED_HEADERS) \ -q "ui_notification_t::" \ -m hookgenUI $(ST_PYW)/py_kernwin_viewhooks.hpp: pywraps/py_kernwin_viewhooks.hpp \ $(I)kernwin.hpp \ $(GENHOOKS)recipe_viewhooks.py \ $(GENHOOKS)genhooks.py $(PARSED_HEADERS_MARKER) $(MAKEFILE_DEP) | $(SDK_SOURCES) $(QGENHOOKS)$(PYTHON) $(GENHOOKS)genhooks.py -i $< -o $@ \ -c View_Hooks \ -x $(ST_PARSED_HEADERS) \ -q "view_notification_t::" \ -m hookgenVIEW $(ST_PYW)/py_hexrays_hooks.hpp: pywraps/py_hexrays_hooks.hpp \ $(HEXRAYS_HPP_SPLIT_DIR)/hexrays_notemplates.hpp \ $(GENHOOKS)recipe_hexrays.py \ $(GENHOOKS)genhooks.py $(PARSED_HEADERS_MARKER) $(MAKEFILE_DEP) | $(SDK_SOURCES) $(QGENHOOKS)$(PYTHON) $(GENHOOKS)genhooks.py -i $< -o $@ \ -c Hexrays_Hooks \ -x $(ST_PARSED_HEADERS) \ -q "hexrays_event_t::" \ -m hookgenHEXRAYS #---------------------------------------------------------------------- CFLAGS += $(PYTHON_CFLAGS) CC_DEFS += MISSED_BC695 CC_DEFS += $(DEF_TYPE_TABLE) CC_DEFS += $(WITH_HEXRAYS_DEF) CC_DEFS += USE_STANDARD_FILE_FUNCTIONS CC_DEFS += IDAVER_MAJOR=$(IDAVER_MAJOR) CC_DEFS += IDAVER_MINOR=$(IDAVER_MINOR) CC_DEFS += IDAVER_PATCH=$(IDAVER_PATCH) CC_DEFS += __EXPR_SRC CC_INCP += $(F) CC_INCP += $(ST_SWIG) CC_INCP += . ifdef __UNIX__ # suppress some warnings # see https://github.com/swig/swig/pull/801 # FIXME: remove these once swig is fixed CC_WNO += -Wno-shadow CC_WNO += -Wno-unused-parameter # FIXME: these should be fixed and removed CC_WNO += -Wno-attributes CC_WNO += -Wno-delete-non-virtual-dtor CC_WNO += -Wno-deprecated-declarations CC_WNO += -Wno-format-nonliteral CC_WNO += -Wno-write-strings ifdef __MAC__ # additional switches for clang CC_WNO += -Wno-deprecated-register endif endif # disable -pthread in CFLAGS PTHR_SWITCH = # disable -DNO_OBSOLETE_FUNCS in CFLAGS NO_OBSOLETE_FUNCS = #---------------------------------------------------------------------- ifdef TESTABLE_BUILD SWIGFLAGS+=-DTESTABLE_BUILD endif ST_SWIG_HEADER = $(ST_SWIG)/header.i $(ST_SWIG)/header.i: tools/deploy/header.i.in tools/genswigheader.py $(ST_SDK_TARGETS) $(QGENSWIGHEADER)$(PYTHON) tools/genswigheader.py -i $< -o $@ -m $(subst $(space),$(comma),$(MODULES_NAMES)) -s $(ST_SDK) ifdef __NT__ PATCH_DIRECTORS_SCRIPT = tools/patch_directors_cc.py endif find-pywraps-deps = $(wildcard pywraps/py_$(subst .i,,$(notdir $(1)))*.hpp) $(wildcard pywraps/py_$(subst .i,,$(notdir $(1)))*.py) find-patch-codegen-deps = $(wildcard tools/patch_codegen/*$(1)*.py) # Some .i files depend on some other .i files in order to be parseable by SWiG # (e.g., segregs.i imports range.i). Declare the list of such dependencies here # so they will be picked by the auto-generated rules. SWIG_IFACE_bytes=range SWIG_IFACE_dbg=idd SWIG_IFACE_frame=range SWIG_IFACE_funcs=range SWIG_IFACE_gdl=range SWIG_IFACE_graph=gdl SWIG_IFACE_hexrays=pro typeinf xref gdl SWIG_IFACE_idd=range SWIG_IFACE_idp=bitrange SWIG_IFACE_segment=range SWIG_IFACE_segregs=range SWIG_IFACE_typeinf=idp SWIG_IFACE_tryblks=range MODULE_LIFECYCLE_bytes=--lifecycle-aware MODULE_LIFECYCLE_hexrays=--lifecycle-aware MODULE_LIFECYCLE_idaapi=--lifecycle-aware MODULE_LIFECYCLE_kernwin=--lifecycle-aware define make-module-rules # Note: apparently make cannot work well when a given recipe generates multiple files # http://stackoverflow.com/questions/19822435/multiple-targets-from-one-recipe-and-parallel-execution # Consequently, rules such as this: # # $(ST_WRAP)/ida_$(1).py: $(ST_WRAP)/$(1).cpp # # i.e., that do nothing but rely on the generation of another file, # will not work in // execution. Thus, we will rely exclusively on # the presence of the generated .cpp file, and not other generated # files. # ../../bin/x86_linux_gcc/python/ida_$(1).py $(DEPLOY_PYDIR)/ida_$(1).py: $(ST_WRAP)/ida_$(1).py.final $(Q)$(CP) $$< $$@ # obj/x86_linux_gcc/wrappers/ida_X.py.final (note: dep. on .cpp. See note above.) $(ST_WRAP)/ida_$(1).py.final: $(ST_WRAP)/$(1).cpp $(wildcard tools/pypasses/*.py) $(wildcard tools/pypasses/*/*.py) $(wildcard apidoc/ida_$(1).py) $(PARSED_HEADERS_MARKER) $(call find-patch-codegen-deps,$(1)) $(QINJECT_PYDOC)$(PYTHON) tools/pypasses.py \ --input $(ST_WRAP)/ida_$(1).py \ --idapython-module-name ida_$(1) \ --doxygen-xml $(ST_PARSED_HEADERS) \ --cpp-wrapper $(ST_WRAP)/$(1).cpp \ --passes inject_doxygen,return_type_from_cpp_wrapper,pydoc_overrides,proto_overrides,argsify_for_dispatching_cpp,proto_fix_known_types \ --pydoc-overrides apidoc/ida_$(1).py \ --output $$@ \ --debug > $(ST_WRAP)/ida_$(1).pydoc_injection # obj/x86_linux_gcc/swig/X.i $(ST_SWIG)/$(1).i: $(addprefix $(F),$(call find-pywraps-deps,$(1))) swig/$(1).i $(ST_SWIG_HEADER) $(SWIG_IFACE_$(1):%=$(ST_SWIG)/%.i) $(ST_SWIG_HEADER) tools/deploy.py $(PARSED_HEADERS_MARKER) $(QDEPLOY)$(PYTHON) tools/deploy.py \ --pywraps $(ST_PYW) \ --template $$(subst $(F),,$$@) \ --output $$@ \ --module $$(subst .i,,$$(notdir $$@)) \ $(MODULE_LIFECYCLE_$(1)) \ --interface-dependencies=$(subst $(space),$(comma),$(SWIG_IFACE_$(1))) \ --xml-doc-directory $(ST_PARSED_HEADERS) # creating obj/x86_linux_gcc/wrappers/X.cpp and friends # 1. SWIG generates x.cpp.in1, x.h and x.py from swig/x.i # 2. patch_const.py generates x.cpp.in2 from x.cpp.in1 # 3. patch_codegen.py generates x.cpp from x.cpp.in2 # 4. patch_h_codegen.py patches x.h in place # 5. patch_python_codegen.py patches ida_x.py in place using helpers in tools/patch_codegen # 6. on windows, patch_directors_cc.py patches x.h in place again $(ST_WRAP)/$(1).cpp: $(ST_SWIG)/$(1).i tools/patch_codegen.py tools/patch_python_codegen.py $(PATCH_DIRECTORS_SCRIPT) $(PARSED_HEADERS_MARKER) tools/chkapi.py tools/wrapper_utils.py $(QSWIG)$(SWIG) $(addprefix -D,$(WITH_HEXRAYS_DEF)) -python $(_SWIGPY3FLAG) -threads -c++ -shadow \ -D__GNUC__ -DSWIG_PYTHON_LEGACY_BOOL=1 $(SWIGFLAGS) $(addprefix -D,$(EASIZE_DEF)) -I$(ST_SWIG) \ -outdir $(ST_WRAP) -o $$@.in1 -oh $(ST_WRAP)/$(1).h -I$(ST_SDK) -DIDAPYTHON_MODULE_$(1)=1 $$< $(call PATCH_CONST,$(ST_WRAP)/$(1).cpp.in1,$(ST_WRAP)/$(1).cpp.in2) $(QPATCH_CODEGEN)$(PYTHON) tools/patch_codegen.py \ --input $(ST_WRAP)/$(1).cpp.in2 \ --output $(ST_WRAP)/$(1).cpp \ --module $(1) \ --xml-doc-directory $(ST_PARSED_HEADERS) \ --patches tools/patch_codegen/$(1).py \ --batch-patches tools/patch_codegen/$(1)_batch.py $(QPATCH_H_CODEGEN)$(PYTHON) tools/patch_h_codegen.py \ --file $(ST_WRAP)/$(1).h \ --module $(1) \ --patches tools/patch_codegen/$(1)_h.py $(QPATCH_PYTHON_CODEGEN)$(PYTHON) tools/patch_python_codegen.py \ --file $(ST_WRAP)/ida_$(1).py \ --module $(1) \ --patches tools/patch_codegen/ida_$(1).py ifdef __NT__ $(PYTHON) $(PATCH_DIRECTORS_SCRIPT) --file $(ST_WRAP)/$(1).h endif # The copying of the .py will preserve attributes (including timestamps). # And, since we have patched $(1).cpp, it'll be more recent than ida_$(1).py, # and make would keep copying the .py file at each invocation. # To prevent that, let's make the source .py file more recent than .cpp. $(Q)touch $(ST_WRAP)/ida_$(1).py endef $(foreach mod,$(MODULES_NAMES),$(eval $(call make-module-rules,$(mod)))) # obj/x86_linux_gcc/X.o X_O = $(call objs,$(MODULES_NAMES)) vpath %.cpp $(ST_WRAP) ifdef __NT__ # remove warnings from generated code: # warning C4100: '': unreferenced formal parameter # error C4296: '<': expression is always false # warning C4647: behavior change: __is_pod(type) has different value in previous versions # warning C4700: uninitialized local variable 'c_result' used # warning C4706: assignment within conditional expression $(X_O): CFLAGS += /wd4100 /wd4296 /wd4647 /wd4700 /wd4706 ifndef NDEBUG # Use debug wrappers with the Python release dll $(X_O): CC_DEFS += SWIG_PYTHON_INTERPRETER_NO_DEBUG endif endif # disable -fno-rtti $(X_O): pywraps.hpp $(X_O): NORTTI = $(X_O): CC_DEFS += PLUGIN_SUBMODULE $(X_O): CC_DEFS += SWIG_DIRECTOR_NORTTI ifdef __CODE_CHECKER__ $(X_O): $(Q)touch $@ endif # obj/x86_linux_gcc/_ida_X.so _IDA_X_SO = $(addprefix $(F)_ida_,$(addsuffix $(PYDLL_EXT),$(MODULES_NAMES))) ifdef __NT__ $(_IDA_X_SO): STDLIBS += user32.lib endif # Note: On Windows, IDAPython's python.lib must come *after* python3x.lib # in the linking command line, otherwise Python will misdetect # IDAPython's python.dll as the main "python" DLL, and IDAPython # will fail to load with the following error: # "Module use of python.dll conflicts with this version of Python." # To achieve this, we add IDAPython's python.lib to STDLIBS, which # is at the end of the link command. # See Python's dynload_win.c:GetPythonImport() for more details. $(_IDA_X_SO): STDLIBS += $(LINKIDAPYTHON) $(_IDA_X_SO): LDFLAGS += $(PYTHON_LDFLAGS) $(PYTHON_LDFLAGS_RPATH_MODULE) $(OUTMAP)$(F)$(@F).map $(F)_ida_%$(PYDLL_EXT): $(F)%$(O) $(MODULE) $(IDAPYTHON_IMPLIB_DEF) $(IDAPYSWITCH_MODULE_DEP) $(call link_dll, $<, $(LINKIDA)) ifdef __NT__ $(Q)$(RM) $(@:$(PYDLL_EXT)=.exp) $(@:$(PYDLL_EXT)=.lib) endif # ../../bin/x64_linux_gcc/python/ida_32/_ida_X.so $(DEPLOY_LIBDIR)/_ida_%$(PYDLL_EXT): $(F)_ida_%$(PYDLL_EXT) $(Q)$(CP) $< $@ ifdef __LINUX__ ifneq (,$(POSTACTION_IDA_X_SO)) $(Q)$(POSTACTION_IDA_X_SO) $@ endif endif #---------------------------------------------------------------------- API_CONTENTS_BRIEF = api_contents$(EXTRASUF1).brief API_CONTENTS_FULL = api_contents$(EXTRASUF1).full ST_API_CONTENTS_BRIEF = $(F)$(API_CONTENTS_BRIEF) ST_API_CONTENTS_FULL = $(F)$(API_CONTENTS_FULL) ST_API_CONTENTS_BRIEF_SUCCESS = $(ST_API_CONTENTS_BRIEF).success ST_API_CONTENTS_FULL_SUCCESS = $(ST_API_CONTENTS_FULL).success .PRECIOUS: $(ST_API_CONTENTS_BRIEF) $(ST_API_CONTENTS_FULL) ifdef TESTABLE_BUILD DEFAULT_API_CONTENTS = $(API_CONTENTS_BRIEF) else DEFAULT_API_CONTENTS = $(API_CONTENTS_FULL) endif api_contents: $(DEFAULT_API_CONTENTS) define make-api-contents-rule $(1): $(3) ifeq ($(or $(__CODE_CHECKER__),$(NO_CMP_API),$(__ASAN__),$(IDAHOME),$(IDACLASS),$(IDAFREE)),) $(3): $(ALL_ST_WRAP_PY_FINAL) tools/py_scanner.py $(QDUMPAPI)$(PYTHON) tools/py_scanner.py $(4) --paths $(subst $(space),$(comma),$(ALL_ST_WRAP_PY_FINAL)) > $(2) ifeq ($(OUT_OF_TREE_BUILD),) $(Q)((diff -w $(1) $(2)) > /dev/null && touch $$@) || \ (echo "API CONTENTS CHANGED! update $(1) or fix the API" && \ echo "(New API: $(2)) ***" && \ (diff -U 1 -w $(1) $(2); true)) else $(Q)touch $$@ endif else $(3): $(ALL_ST_WRAP_PY_FINAL) tools/py_scanner.py $(Q)touch $$@ endif endef $(eval $(call make-api-contents-rule,$(API_CONTENTS_BRIEF),$(ST_API_CONTENTS_BRIEF),$(ST_API_CONTENTS_BRIEF_SUCCESS),)) $(eval $(call make-api-contents-rule,$(API_CONTENTS_FULL),$(ST_API_CONTENTS_FULL),$(ST_API_CONTENTS_FULL_SUCCESS),--dump-doc)) #------------------------------------------------------------------------- ST_API_CHECK_SUCCESS := $(F)api_check.success api_check: $(ST_API_CHECK_SUCCESS) $(ST_API_CHECK_SUCCESS): $(ALL_ST_WRAP_CPP) ifeq ($(or $(__CODE_CHECKER__),$(NO_CMP_API),$(__ASAN__),$(IDAHOME),$(IDACLASS),$(IDAFREE)),) $(QCHKAPI)$(PYTHON) tools/chkapi.py $(WITH_HEXRAYS_CHKAPI) -i $(subst $(space),$(comma),$(ALL_ST_WRAP_CPP)) -p $(subst $(space),$(comma),$(ALL_ST_WRAP_PY)) endif $(Q)touch $@ ifdef __EA64__ DUMPDOC_IS_64:=True else DUMPDOC_IS_64:=False endif #---------------------------------------------------------------------- DOCS_DEPS=tools/docs/hrdoc.py tools/docs/hrdoc.css DOCS_MODULES=$(foreach mod,$(MODULES_NAMES),ida_$(mod)) SORTED_DOCS_MODULES=$(sort $(DOCS_MODULES)) DOC_OUT_HTML?=docs/hr-html DOC_OUT_MD?=docs/hr-md docs_html: $(DOCS_DEPS) ifndef __NT__ $(IDAT_CMD) $(BATCH_SWITCH) -S"tools/docs/hrdoc.py -o $(DOC_OUT_HTML) -m $(subst $(space),$(comma),$(SORTED_DOCS_MODULES)),idc,idautils -s idc,idautils -x ida_allins" -t > /dev/null else $(R)ida -S"tools/docs/hrdoc.py -o $(DOC_OUT_HTML) -m $(subst $(space),$(comma),$(SORTED_DOCS_MODULES)),idc,idautils -s idc,idautils -x ida_allins" -t endif docs_md: $(DOCS_DEPS) ifndef __NT__ $(IDAT_CMD) $(BATCH_SWITCH) -S"tools/docs/hrdoc.py -o $(DOC_OUT_MD) -M -m $(subst $(space),$(comma),$(SORTED_DOCS_MODULES)),idc,idautils -s idc,idautils -x ida_allins" -t > /dev/null else $(R)ida -Stools/docs/hrdoc.py -t endif docs: docs_html docs_md @echo "copy MARKDOWN files from docs/hr-md ../../../../www/www.hex-rays.com/public_html/hex-rays/cgi-bin/themer/static/products/ida/support/idapython_docs_md/" @echo "copy HTML files from docs/hr-html ../../../../www/www.hex-rays.com/public_html/hex-rays/cgi-bin/themer/static/products/ida/support/idapython_docs/" @echo "" @read -p "Do you want to copy files to P4 repo? [y/N] " ans && ans=$${ans:-N} ; \ if [ $${ans} = y ] || [ $${ans} = Y ]; then \ echo "Starting to copy html & md files" ; \ ./copy_docs_to_p4.sh MARKDOWN docs/hr-md ../../../www/www.hex-rays.com/public_html/hex-rays/cgi-bin/themer/static/products/ida/support/idapython_docs_md/; \ ./copy_docs_to_p4.sh HTML docs/hr-html ../../../www/www.hex-rays.com/public_html/hex-rays/cgi-bin/themer/static/products/ida/support/idapython_docs/; \ else \ echo "NO file copied" ; \ fi @echo "\033[0;32mFiles prepared in P4, you need to manually submit them\033[0m" # the demo version of ida does not have the -B command line option ifeq ($(OUT_OF_TREE_BUILD),) ifndef IDAFREE BATCH_SWITCH=-B endif endif #---------------------------------------------------------------------- # Test that all functions that are present in ftable.cpp # are present in idc.py (and therefore made available by # the idapython). test_idc: $(TEST_IDC) $(TEST_IDC): $(F)idctest.log $(F)idctest.log: $(RS)idc/idc.idc | $(MODULE) pyfiles ifneq ($(wildcard ../../tests),) $(Q)$(RM) $(F)idctest.log $(Q)$(IDAT_CMD) $(BATCH_SWITCH) -S"test_idc.py $^" -t -L$(F)idctest.log >/dev/null || \ (echo "ERROR: The IDAPython IDC interface is incomplete. IDA log:" && cat $(F)idctest.log && false) endif #---------------------------------------------------------------------- PUBTREE_DIR=$(F)public_tree public_tree: all ifeq ($(OUT_OF_TREE_BUILD),) -$(Q)if [ ! -d "$(PUBTREE_DIR)/out_of_tree" ] ; then mkdir -p 2>/dev/null $(PUBTREE_DIR)/out_of_tree ; fi rsync -a --exclude=obj/ \ --exclude=precompiled/ \ --exclude=repl.py \ --exclude=test_idc.py \ --exclude=RELEASE.md \ --exclude=docs/hr-html/ \ --exclude=**/*~ \ . $(PUBTREE_DIR) (cd $(F) && zip -r ../../$(PUBTREE_DIR)/out_of_tree/parsed_notifications.zip parsed_notifications) endif #---------------------------------------------------------------------- IDAPYSWITCH_OBJS += $(F)idapyswitch$(O) ifdef __NT__ ifneq ($(OUT_OF_TREE_BUILD),) # SDK provides only MT libraries $(F)idapyswitch$(O): RUNTIME_LIBSW=/MT else ifndef NDEBUG $(F)idapyswitch$(O): CFLAGS := $(filter-out /U_DEBUG,$(CFLAGS)) endif endif endif $(R)idapyswitch$(B): $(QT_BINDINGS_DEPS) $(call dumb_target, pro compress, $(IDAPYSWITCH_OBJS)) #---------------------------------------------------------------------- TEST_PYWRAPS_OBJS += $(F)test_pywraps$(O) TEST_PYWRAPS_DEPS := pywraps.cpp pywraps.hpp extapi.cpp extapi.hpp $(F)test_pywraps$(O): $(PARSED_HEADERS_MARKER) $(TEST_PYWRAPS_DEPS) ifdef __NT__ ifneq ($(OUT_OF_TREE_BUILD),) # SDK provides only MT libraries $(F)test_pywraps$(O): RUNTIME_LIBSW=/MT endif endif ifdef __MAC__ LDFLAGS_EXE += -Wl,-rpath,@executable_path endif $(R)test_pywraps$(B): $(call dumb_target, json idc unicode pro, $(TEST_PYWRAPS_OBJS)) $(PYTHON_LDFLAGS) $(LDFLAGS_EXE) $(F)$(TEST_PYWRAPS_RESULT_FNAME).marker: $(R)test_pywraps$(B) $(Q)$(TEST_PYWRAPS_ENV) $(R)test_pywraps$(B) > $(F)$(TEST_PYWRAPS_RESULT_FNAME) ifeq ($(OUT_OF_TREE_BUILD),) $(Q)((diff -w $(TEST_PYWRAPS_RESULT_FNAME) $(F)$(TEST_PYWRAPS_RESULT_FNAME)) > /dev/null && touch $@) || \ (echo "$(TEST_PYWRAPS_RESULT_FNAME) changed" && \ (diff -U 1 -w $(TEST_PYWRAPS_RESULT_FNAME) $(F)$(TEST_PYWRAPS_RESULT_FNAME); true)) else $(Q)touch $@ endif ifdef __CODE_CHECKER__ test_pywraps: ; else test_pywraps: $(TEST_PYWRAPS) endif #---------------------------------------------------------------------- # the 'echo_modules' target must be called explicitly # Note: used by ida/build/pkgbin.py echo_modules: @echo $(MODULES_NAMES) #---------------------------------------------------------------------- clean:: rm -rf obj/ ifdef __CODE_CHECKER__ examples_index: ; examples: ; else EXAMPLES := $(wildcard examples/*/*.py examples/*/*/*.py examples/*/*/*/*.py) GEN_EXAMPLES_TOOL := tools/gen_examples_index.py GEN_EXAMPLES_CFG := tools/gen_examples_index.cfg EXAMPLES_INDEX_MD := examples/index.md EXAMPLES_README := examples/README.md ST_EXAMPLES_INDEX_MD = $(F)$(EXAMPLES_INDEX_MD) ST_EXAMPLES_INDEX_MD_SUCCESS = $(ST_EXAMPLES_INDEX_MD).success .PRECIOUS: $(ST_EXAMPLES_INDEX_MD) define make-examples-index-rules $(eval EXAMPLES_INDEX_CMD := $(PYTHON) $(GEN_EXAMPLES_TOOL) write \ -t $(4) \ -e examples \ -o $(2) \ ) $(1): $(3) $(3): $(GEN_EXAMPLES_TOOL) $(GEN_EXAMPLES_CFG) $(4) $(EXAMPLES) -$(Q)if [ ! -d "$(F)examples" ] ; then mkdir -p 2>/dev/null $(F)examples ; fi $(QGEN_EXAMPLES_INDEX)$(EXAMPLES_INDEX_CMD) \ || echo FAILED: $(EXAMPLES_INDEX_CMD) $(Q)diff -w $(1) $(2) > /dev/null && touch $$@ \ || (echo "EXAMPLES INDEX CHANGED! update $(1)" \ && echo "(New examples: $(2)) ***" \ && diff -U 1 -w $(1) $(2); true) endef $(eval $(call make-examples-index-rules,$(EXAMPLES_INDEX_MD),$(ST_EXAMPLES_INDEX_MD),$(ST_EXAMPLES_INDEX_MD_SUCCESS),tools/examples_index_template.md,md)) examples_index: $(EXAMPLES_INDEX_MD) EXAMPLE_FILES := $(addprefix $(R)python/,$(EXAMPLES) $(EXAMPLES_INDEX_MD) $(EXAMPLES_README)) examples: $(EXAMPLE_FILES) $(EXAMPLE_FILES): $(R)python/examples/%: examples/% $(Q)if [ ! -d $(dir $@) ]; then mkdir -p $(dir $@); fi $(Q)$(CP) $< $@ endif $(MODULE): LDFLAGS += $(PYTHON_LDFLAGS) $(LDFLAGS_MOD) # MAKEDEP dependency list ------------------ $(F)idapyswitch$(O): $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \ $(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)err.h \ $(I)exehdr.h $(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \ $(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \ $(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)lzfse.h \ $(I)lzvn_decode_base.h $(I)md5.h $(I)nalt.hpp \ $(I)name.hpp $(I)netnode.hpp $(I)network.hpp \ $(I)offset.hpp $(I)pro.h $(I)prodir.h $(I)range.hpp \ $(I)registry.hpp $(I)segment.hpp $(I)segregs.hpp \ $(I)ua.hpp $(I)xref.hpp ../../ldr/ar/aixar.hpp \ ../../ldr/ar/ar.hpp ../../ldr/ar/arcmn.cpp \ ../../ldr/mach-o/../ar/ar.hpp \ ../../ldr/mach-o/../idaldr.h \ ../../ldr/mach-o/apple_common.h \ ../../ldr/mach-o/base.cpp ../../ldr/mach-o/common.cpp \ ../../ldr/mach-o/common.h ../../ldr/mach-o/macho_node.h \ ../../ldr/mach-o/strtab_reader_t.h \ ../../ldr/mach-o/uncompress.cpp ../../ldr/pe/../idaldr.h \ ../../ldr/pe/common.cpp ../../ldr/pe/common.h \ ../../ldr/pe/pe.h ../../pro/registry.cpp idapyswitch.cpp \ idapyswitch_linux.cpp idapyswitch_mac.cpp \ idapyswitch_win.cpp $(F)idapython$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \ $(I)diskio.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \ $(I)funcs.hpp $(I)gdl.hpp $(I)graph.hpp $(I)ida.hpp \ $(I)ida_highlighter.hpp $(I)idd.hpp $(I)idp.hpp \ $(I)ieee.h $(I)kernwin.hpp $(I)lex.hpp \ $(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \ $(I)make_script_ns.hpp $(I)nalt.hpp $(I)name.hpp \ $(I)netnode.hpp $(I)parsejson.hpp $(I)pro.h \ $(I)range.hpp $(I)segment.hpp $(I)typeinf.hpp $(I)ua.hpp \ $(I)xref.hpp extapi.cpp \ extapi.hpp idapython.cpp pywraps.cpp pywraps.hpp $(F)test_pywraps$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \ $(I)err.h $(I)expr.hpp $(I)fpro.h $(I)funcs.hpp \ $(I)gdl.hpp $(I)graph.hpp $(I)ida.hpp $(I)idd.hpp \ $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp $(I)lex.hpp \ $(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \ $(I)name.hpp $(I)netnode.hpp $(I)parsejson.hpp $(I)pro.h \ $(I)range.hpp $(I)segment.hpp $(I)typeinf.hpp $(I)ua.hpp \ $(I)xref.hpp extapi.cpp extapi.hpp pywraps.cpp \ pywraps.hpp test_pywraps.cpp