
################################################################################
# see Ghidra/Features/Decompiler/build.gradle in Ghidra source

set(DECOMPILER_SOURCE_BASE_CXX
		# xml.cc				// generated by yacc task
		space.cc
		float.cc
		address.cc
		pcoderaw.cc
		translate.cc
		opcodes.cc
		globalcontext.cc
		capability.cc
		architecture.cc
		options.cc
		graph.cc
		cover.cc
		block.cc
		cast.cc
		typeop.cc
		database.cc
		cpool.cc
		comment.cc
		fspec.cc
		action.cc
		loadimage.cc
		# grammar.cc	 // doesn't seem to be used
		varnode.cc
		op.cc
		type.cc
		variable.cc
		varmap.cc
		jumptable.cc
		emulate.cc
		emulateutil.cc
		flow.cc
		userop.cc
		funcdata.cc
		funcdata_block.cc
		funcdata_varnode.cc
		funcdata_op.cc
		pcodeinject.cc
		heritage.cc
		prefersplit.cc
		rangeutil.cc
		ruleaction.cc
		subflow.cc
		blockaction.cc
		merge.cc
		double.cc
		coreaction.cc
		condexe.cc
		override.cc
		dynamic.cc
		crc32.cc
		prettyprint.cc
		printlanguage.cc
		printc.cc
		printjava.cc
		memstate.cc
		opbehavior.cc
		paramid.cc
		transform.cc
		string_ghidra.cc
		stringmanage.cc
		# callgraph.cc			// uncomment for debug
		# ifacedecomp.cc		// uncomment for debug
		# ifaceterm.cc			// uncomment for debug
		# interface.cc			// uncomment for debug
		)

set(DECOMPILER_SOURCE_BASE_YACC
		xml.y)

set(DECOMPILER_SOURCE_LIBDECOMP_CXX
		libdecomp.cc)

# Source specific to Ghidra
set(DECOMPILER_SOURCE_GHIDRA_CXX
		ghidra_process.cc
		ghidra_arch.cc
		loadimage_ghidra.cc
		typegrp_ghidra.cc
		database_ghidra.cc
		ghidra_context.cc
		cpool_ghidra.cc
		comment_ghidra.cc
		inject_ghidra.cc
		ghidra_translate.cc)

set(DECOMPILER_SOURCE_SLEIGH_CXX
		sleigh_arch.cc
		sleigh.cc
		inject_sleigh.cc
		filemanage.cc
		semantics.cc
		slghsymbol.cc
		context.cc
		sleighbase.cc
		slghpatexpress.cc
		slghpattern.cc
		pcodecompile.cc)

set(DECOMPILER_SOURCE_SLEIGH_YACC
		pcodeparse.y
		grammar.y)

set(DECOMPILER_SOURCE_CONSOLE_CXX
		consolemain.cc
		interface.cc
		ifacedecomp.cc
		ifaceterm.cc
		callgraph.cc
		raw_arch.cc)

set(SLEIGH_COMPILER_SOURCE_CXX
		slgh_compile.cc
		slgh_compile.hh)

set(SLEIGH_COMPILER_SOURCE_YACC
		slghparse.y)

set(SLEIGH_COMPILER_SOURCE_FLEX
		slghscan.l)

set(DECOMPILER_SOURCE_DIR ghidra/Ghidra/Features/Decompiler/src/decompile/cpp)

################################################################################

function(prepend_src_dir list_name)
	set(tmp)
	foreach(r ${${list_name}})
		list(APPEND tmp "${DECOMPILER_SOURCE_DIR}/${r}")
	endforeach()
	set(${list_name} "${tmp}" PARENT_SCOPE)
endfunction()

prepend_src_dir(DECOMPILER_SOURCE_BASE_CXX)
prepend_src_dir(DECOMPILER_SOURCE_LIBDECOMP_CXX)
prepend_src_dir(DECOMPILER_SOURCE_GHIDRA_CXX)
prepend_src_dir(DECOMPILER_SOURCE_SLEIGH_CXX)
prepend_src_dir(DECOMPILER_SOURCE_CONSOLE_CXX)
prepend_src_dir(SLEIGH_COMPILER_SOURCE_CXX)
set(SOURCE "${DECOMPILER_SOURCE_BASE_CXX}")

if(GENERATE_PARSERS)
	find_package(BISON REQUIRED)
	file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bison")
	find_package(FLEX REQUIRED)
	file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/flex")

	# build yacc files and append the output files to OUT_VAR
	macro(build_bison OUT_VAR)
		foreach(yacc_file ${ARGN})
			get_filename_component(yacc_name "${yacc_file}" NAME_WE)
			if("${yacc_name}" STREQUAL "slghparse")
				set(yacc_prefix yy)
			else()
				set(yacc_prefix "${yacc_name}")
			endif()
			if(BISON_VERSION VERSION_LESS 2.6)
				set(BISON_COMPILE_FLAGS "--name-prefix=${yacc_prefix}")
			else()
				set(BISON_COMPILE_FLAGS "-Dapi.prefix={${yacc_prefix}}")
			endif()
			BISON_TARGET(${yacc_name}
					"${CMAKE_CURRENT_SOURCE_DIR}/${DECOMPILER_SOURCE_DIR}/${yacc_file}"
					"${CMAKE_CURRENT_BINARY_DIR}/bison/${yacc_name}.cpp"
					COMPILE_FLAGS ${BISON_COMPILE_FLAGS})
			list(APPEND ${OUT_VAR} "${BISON_${yacc_name}_OUTPUTS}")
		endforeach()
	endmacro()

	build_bison(SOURCE ${DECOMPILER_SOURCE_BASE_YACC})
	build_bison(DECOMPILER_SOURCE_SLEIGH_CXX ${DECOMPILER_SOURCE_SLEIGH_YACC})
	build_bison(SLEIGH_COMPILER_SOURCE_CXX ${SLEIGH_COMPILER_SOURCE_YACC})

	FLEX_TARGET(slghscan "${DECOMPILER_SOURCE_DIR}/${SLEIGH_COMPILER_SOURCE_FLEX}" "${CMAKE_CURRENT_BINARY_DIR}/flex/slghscan.cpp")
	list(APPEND SLEIGH_COMPILER_SOURCE_CXX "${CMAKE_CURRENT_BINARY_DIR}/flex/slghscan.cpp")
	file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/flex/slghparse.tab.hh" "#include \"../bison/slghparse.hpp\"")
else()
	list(APPEND SOURCE
		"${DECOMPILER_SOURCE_DIR}/xml.hh"
		"${DECOMPILER_SOURCE_DIR}/xml.cc")
	list(APPEND DECOMPILER_SOURCE_SLEIGH_CXX
		"${DECOMPILER_SOURCE_DIR}/pcodeparse.hh"
		"${DECOMPILER_SOURCE_DIR}/pcodeparse.cc"
		"${DECOMPILER_SOURCE_DIR}/grammar.hh"
		"${DECOMPILER_SOURCE_DIR}/grammar.cc")
	list(APPEND SLEIGH_COMPILER_SOURCE_CXX
		"${DECOMPILER_SOURCE_DIR}/slghparse.hh"
		"${DECOMPILER_SOURCE_DIR}/slghparse.cc"
		"${DECOMPILER_SOURCE_DIR}/slghscan.cc")
endif()

add_library(ghidra_decompiler_base STATIC ${SOURCE})
target_include_directories(ghidra_decompiler_base PUBLIC "${DECOMPILER_SOURCE_DIR}")
set_target_properties(ghidra_decompiler_base PROPERTIES POSITION_INDEPENDENT_CODE ON)

add_library(ghidra_libdecomp STATIC ${DECOMPILER_SOURCE_LIBDECOMP_CXX})
set_target_properties(ghidra_libdecomp PROPERTIES POSITION_INDEPENDENT_CODE ON)

add_library(ghidra_decompiler_sleigh STATIC ${DECOMPILER_SOURCE_SLEIGH_CXX})
target_include_directories(ghidra_decompiler_sleigh PUBLIC "${DECOMPILER_SOURCE_DIR}")
set_target_properties(ghidra_decompiler_sleigh PROPERTIES POSITION_INDEPENDENT_CODE ON)

# "decompile" executable as used by Ghidra
if(BUILD_DECOMPILE_EXECUTABLE)
	add_executable(ghidra_decompiler_exec ${DECOMPILER_SOURCE_GHIDRA_CXX})
	target_link_libraries(ghidra_decompiler_exec ghidra_decompiler_base)
	set_target_properties(ghidra_decompiler_exec PROPERTIES OUTPUT_NAME decompile)
endif()

if(BUILD_DECOMPILE_CLI_EXECUTABLE)
	add_executable(ghidra_decompiler_cli ${DECOMPILER_SOURCE_CONSOLE_CXX})
	target_link_libraries(ghidra_decompiler_cli ghidra_decompiler_base ghidra_libdecomp ghidra_decompiler_sleigh)
	set_target_properties(ghidra_decompiler_cli PROPERTIES OUTPUT_NAME decompile_cli)
endif()

add_executable(sleighc ${SLEIGH_COMPILER_SOURCE_CXX})
target_link_libraries(sleighc ghidra_decompiler_sleigh ghidra_decompiler_base)
target_include_directories(sleighc PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/flex")

if(BUILD_SLASPECS)
	file(GLOB_RECURSE SLASPEC_FILES "ghidra/Ghidra/Processors/*.slaspec")
	file(GLOB_RECURSE CPEC_FILES "ghidra/Ghidra/Processors/*.cspec")
	file(GLOB_RECURSE LDEFS_FILES "ghidra/Ghidra/Processors/*.ldefs")
	file(GLOB_RECURSE PSPEC_FILES "ghidra/Ghidra/Processors/*.pspec")
	set(SLAFILES "")
	set(SLEIGH_BASE "${CMAKE_CURRENT_BINARY_DIR}/sleigh")
	file(MAKE_DIRECTORY "${SLEIGH_BASE}")
	foreach(slaspec ${SLASPEC_FILES})
		get_filename_component(sleigh_name "${slaspec}" NAME_WE)
		get_filename_component(sleigh_dir "${slaspec}" DIRECTORY)
		set(sla_file "${SLEIGH_BASE}/${sleigh_name}.sla")
		add_custom_command(OUTPUT "${sla_file}"
				COMMAND sleighc "${slaspec}" "${sla_file}"
				MAIN_DEPENDENCY "${slaspec}"
				WORKING_DIRECTORY "${sleigh_dir}")
		list(APPEND SLAFILES "${sla_file}")
	endforeach()
	add_custom_target(sla ALL DEPENDS ${SLAFILES})
	set(SLEIGH_INSTALL_DEST "${RADARE2_INSTALL_PLUGDIR}/r2ghidra_sleigh")
	install(FILES ${SLAFILES} ${CPEC_FILES} ${LDEFS_FILES} ${PSPEC_FILES} DESTINATION "${SLEIGH_INSTALL_DEST}")
	if(IS_ABSOLUTE "${SLEIGH_INSTALL_DEST}")
		set(SLEIGHHOME_DEFAULT "${SLEIGH_INSTALL_DEST}")
	else()
		set(SLEIGHHOME_DEFAULT "${CMAKE_INSTALL_PREFIX}/${SLEIGH_INSTALL_DEST}")
	endif()
else()
	unset(SLEIGHHOME_DEFAULT)
endif()
set(SLEIGHHOME_DEFAULT "${SLEIGHHOME_DEFAULT}" PARENT_SCOPE)
