# CMakeLists.txt
# The root CMakeLists.txt of Yaramod-v4 project, script for cmake
#
# Author: Vojtěch Dvořák

cmake_minimum_required(VERSION 3.24)


project(yaramod-v4 VERSION 1.0.0)

include(FetchContent)
set(FETCHCONTENT_QUIET FALSE)
set(FETCHCONTENT_TRY_FIND_PACKAGE_MODE ALWAYS)

find_package(Doxygen)

# ----------------------------- Setup of variables ----------------------------

set(LIBRARY_NAME "yaramod-v4")

set(PYTHON_MODULE_NAME "yaramodv4")

option(BUILD_DOCS "Build library documentation" OFF)
option(BUILD_UNIT_TESTS "Build unit tests" ON)
option(BUILD_PYTHON_BINDINGS "Build bindings for python" ON)

# Build type (Debug or Release)
set(CMAKE_BUILD_TYPE Release)
    
set(CMAKE_CXX_FLAGS_DEBUG "-g -gdwarf-4 -pg")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS ON)

set(CMAKE_POSITION_INDEPENDENT_CODE ON)


# Paths of dependecies etc.
set(TREE_SITTER_YARA_DIR "${CMAKE_CURRENT_LIST_DIR}/tree-sitter-yara")


set(MODULE_DIR "${CMAKE_CURRENT_LIST_DIR}/modules")
set(UNIT_TEST_DIR "tests/unit")
set(PYTHON_BINDINGS_DIR "bindings/python")


# Source files of library
file(GLOB_RECURSE SRCS src/*.cpp)
file(GLOB_RECURSE PYTHON_SRCS ${PYTHON_BINDINGS_DIR}/*.cpp)


# --------------------- Cloning and compiling dependencies --------------------


FetchContent_Declare(
    tree-sitter
    GIT_REPOSITORY https://github.com/tree-sitter/tree-sitter.git
    GIT_TAG b268e412ad4848380166af153300464e5a1cf83f
    GIT_PROGRESS TRUE
)
FetchContent_MakeAvailable(tree-sitter)


# Check if there is tree-sitter yara
if(NOT EXISTS "${TREE_SITTER_YARA_DIR}")
    # Fetch the tree-sitter-yara parser (Avast step VPN ONLY!)
    FetchContent_Declare(
        tree-sitter-yara
        GIT_REPOSITORY https://git.int.avast.com/tis/tree-sitter-yara.git
        GIT_TAG 3ba611384f4bbb1146b308a793402c4891e8e21c
        GIT_PROGRESS TRUE
    )
    FetchContent_MakeAvailable(tree-sitter-yara)
    set(TREE_SITTER_YARA_DIR "${tree-sitter-yara_SOURCE_DIR}")
endif()


# Custom step for building parsing table in tree-sitter-yara
# Check if parser.c was generated or generate it
if(NOT EXISTS "${TREE_SITTER_YARA_DIR}/src/parser.c")
    message(WARNING "parser.c not found, generating...")
    execute_process(
        COMMAND ./init.sh
        WORKING_DIRECTORY "${TREE_SITTER_YARA_DIR}"
        RESULT_VARIABLE RET
    )
    if(RET AND NOT RET EQUAL "0")
        message(FATAL_ERROR "Generating of parser failed!")
    endif()

    execute_process(
        COMMAND ./node_modules/.bin/tree-sitter generate
        WORKING_DIRECTORY "${TREE_SITTER_YARA_DIR}"
        RESULT_VARIABLE RET
    )
    if(RET AND NOT RET EQUAL "0")
        message(FATAL_ERROR "Generating of parser failed!")
    endif()
else()
    message(STATUS "parser.c found")
endif()



# -------------------------- Main Library target ------------------------------
# Build yaramod-library

add_library(tree-sitter-lib ${tree-sitter_SOURCE_DIR}/lib/src/lib.c)
target_include_directories(tree-sitter-lib PUBLIC ${tree-sitter_SOURCE_DIR}/lib/include)

add_library(${LIBRARY_NAME} STATIC
    ${TREE_SITTER_YARA_DIR}/src/parser.c
    ${SRCS}
)
set_target_properties(${LIBRARY_NAME} PROPERTIES 
    COMPILE_FLAGS "-Wall -Wextra -pedantic")
target_include_directories(${LIBRARY_NAME} PUBLIC utils)
target_include_directories(${LIBRARY_NAME} PUBLIC lib/include)
target_link_libraries(${LIBRARY_NAME} PUBLIC tree-sitter-lib)

# Copying modules to binary dir
file(COPY "${MODULE_DIR}" DESTINATION ${CMAKE_CURRENT_BINARY_DIR})


# ----------------------------- Unit tests ------------------------------------
 

if(BUILD_UNIT_TESTS)
    add_subdirectory(${UNIT_TEST_DIR})
endif()


# ------------------------------ Examples -------------------------------------

add_executable(parsing examples/parsing.cpp)
target_link_libraries(parsing PRIVATE ${LIBRARY_NAME})


add_executable(reparsing examples/reparsing.cpp)
target_link_libraries(reparsing PRIVATE ${LIBRARY_NAME})


add_executable(o_visitor examples/observing_visitor.cpp)
target_link_libraries(o_visitor PRIVATE ${LIBRARY_NAME})



# -------------------------- Documentation ------------------------------------

if(DOXYGEN_FOUND AND BUILD_DOCS)
    add_custom_target(doc_yaramod
        COMMAND ${DOXYGEN_EXECUTABLE} "${CMAKE_CURRENT_LIST_DIR}/doc/Doxyfile"
    )
elseif(NOT DOXYGEN_FOUND)
    message("Doxygen not found! Documentation cannot be generated.")
endif()

# ----------------------------- Python bindings -------------------------------

if(BUILD_PYTHON_BINDINGS)
    add_subdirectory(${PYTHON_BINDINGS_DIR})
endif()

