cmake_minimum_required(VERSION 3.20)
project(ig5_native_decompiler LANGUAGES C CXX)
set(GHIDRA_SOURCE_ROOT "" CACHE PATH "Pinned upstream Ghidra source root")
set(_module "${GHIDRA_SOURCE_ROOT}/Ghidra/Features/Decompiler")
set(_cpp "${_module}/src/decompile/cpp")
if(NOT EXISTS "${_module}/buildNatives.gradle")
  message(FATAL_ERROR "GHIDRA_SOURCE_ROOT must contain the pinned decompiler sources")
endif()
file(READ "${_module}/buildNatives.gradle" _definitions)
string(REGEX REPLACE "//[^\n]*" "" _definitions "${_definitions}")
string(FIND "${_definitions}" "decompile(NativeExecutableSpec)" _decompile_begin)
string(FIND "${_definitions}" "sleigh(NativeExecutableSpec)" _sleigh_begin)
if(_decompile_begin LESS 0 OR _sleigh_begin LESS 0)
  message(FATAL_ERROR "Unsupported upstream native source declaration")
endif()
math(EXPR _length "${_sleigh_begin}-${_decompile_begin}")
string(SUBSTRING "${_definitions}" ${_decompile_begin} ${_length} _decompile)
string(SUBSTRING "${_definitions}" ${_sleigh_begin} -1 _sleigh)
function(ig5_source_list declaration output)
  string(REGEX MATCHALL "include \"[^\"]+\\.cc\"" _matches "${declaration}")
  set(_files "")
  foreach(_match IN LISTS _matches)
    string(REGEX REPLACE "include \"([^\"]+)\"" "\\1" _filename "${_match}")
    if(NOT EXISTS "${_cpp}/${_filename}")
      message(FATAL_ERROR "Missing upstream source: ${_filename}")
    endif()
    list(APPEND _files "${_cpp}/${_filename}")
  endforeach()
  set(${output} "${_files}" PARENT_SCOPE)
endfunction()
ig5_source_list("${_decompile}" _decompiler_sources)
ig5_source_list("${_sleigh}" _sleigh_sources)
# The Java-host communication architecture is excluded completely. This is
# SleighArchitecture with an IG5 LoadImage, not the normal decompile.exe shell.
list(FILTER _decompiler_sources EXCLUDE REGEX "/(ghidra_arch|inject_ghidra|ghidra_translate|loadimage_ghidra|typegrp_ghidra|database_ghidra|ghidra_context|cpool_ghidra|ghidra_process|comment_ghidra|string_ghidra|signature_ghidra)\\.cc$")
list(FILTER _sleigh_sources EXCLUDE REGEX "/(slgh_compile|slghparse|slghscan)\\.cc$")
set(_sources ${_decompiler_sources} ${_sleigh_sources} "${_cpp}/sleigh_arch.cc" "${_cpp}/inject_sleigh.cc" "${_cpp}/libdecomp.cc")
list(REMOVE_DUPLICATES _sources)
foreach(_source IN LISTS _sources)
  if(_source MATCHES "/(bfd_arch|loadimage_bfd|ghidra_process|consolemain|test)\\.cc$")
    message(FATAL_ERROR "Forbidden communication/console/BFD source in native kernel: ${_source}")
  endif()
endforeach()
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
file(GLOB _zlib_sources CONFIGURE_DEPENDS "${_module}/src/decompile/zlib/*.c")
add_library(ig5_decompiler_zlib STATIC ${_zlib_sources})
target_include_directories(ig5_decompiler_zlib PUBLIC "${_module}/src/decompile/zlib")
target_compile_definitions(ig5_decompiler_zlib PRIVATE NO_GZIP)
add_library(ig5_decompiler SHARED ig5_decompiler.cpp ${_sources})
target_include_directories(ig5_decompiler PRIVATE "${_cpp}")
target_compile_definitions(ig5_decompiler PRIVATE LOCAL_ZLIB IG5_DECOMPILER_BUILD)
target_link_libraries(ig5_decompiler PRIVATE ig5_decompiler_zlib)
foreach(_target ig5_decompiler ig5_decompiler_zlib)
  if(WIN32)
    target_compile_definitions(${_target} PRIVATE WINDOWS _WINDOWS WIN32 _WIN32 WIN64 _WIN64 _CRT_SECURE_NO_DEPRECATE _CRT_NONSTDC_NO_DEPRECATE)
    if(MSVC)
      target_compile_options(${_target} PRIVATE /W3 /utf-8 $<$<COMPILE_LANGUAGE:CXX>:/EHsc>)
      if(_target STREQUAL "ig5_decompiler_zlib")
        target_compile_definitions(${_target} PRIVATE ZLIB_WINAPI)
      endif()
    endif()
  elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR ANDROID)
    target_compile_definitions(${_target} PRIVATE LINUX _LINUX)
  endif()
endforeach()
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/upstream-sources.txt" "")
foreach(_source IN LISTS _sources)
  file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/upstream-sources.txt" "${_source}\n")
endforeach()
install(TARGETS ig5_decompiler RUNTIME DESTINATION . LIBRARY DESTINATION . ARCHIVE DESTINATION lib)
install(FILES ig5_decompiler.h DESTINATION include)
install(FILES "${CMAKE_CURRENT_LIST_DIR}/../NOTICE" DESTINATION .)
install(FILES "${GHIDRA_SOURCE_ROOT}/LICENSE" DESTINATION . RENAME Ghidra-LICENSE.txt)
install(FILES "${_module}/src/decompile/zlib/README.txt" DESTINATION . RENAME zlib-README.txt)
