# root

# 2.8.3 includes a patch for detecting gdk-pixbuf
cmake_minimum_required(VERSION 2.8.3)

# this policy warning is due to lib command lines arg output from llvm-config
if(COMMAND cmake_policy)
    cmake_policy(SET CMP0003 NEW)
    cmake_policy(SET CMP0011 NEW)
endif(COMMAND cmake_policy)

project (crack)

set(CRACK_VERSION "1.7")
set(CRACKLANG_API_VERSION "16.0.0")
set(NATRUN_API_VERSION "6.0.1")
set(DEBUG_API_VERSION "4.0.0")

set(LLVM_MIN_VERSION       "3003000")
set(LLVM_MIN_VERSION_TEXT  "3.3")

set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules )

set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

include(CheckIncludeFiles)
include(CheckFunctionExists)
include(MacroOptionalFindPackage)
include(MacroLogFeature)

MESSAGE( STATUS "PROJECT_SOURCE_DIR: " ${PROJECT_SOURCE_DIR} )
MESSAGE( STATUS "CMAKE_MODULE_PATH: " ${CMAKE_MODULE_PATH} )

MESSAGE( STATUS "CMAKE_SYSTEM_PROCESSOR: " ${CMAKE_SYSTEM_PROCESSOR} )

Find_Package(LLVM REQUIRED)
IF(NOT LLVM_CONFIG_EXECUTABLE)
  MESSAGE(FATAL_ERROR "LLVM not found. Please install ${LLVM_MIN_VERSION_TEXT} "
                      "or greater, or set LLVM_DIR environment variable"
         )
ENDIF (NOT LLVM_CONFIG_EXECUTABLE)

IF( LLVM_VERSION LESS ${LLVM_MIN_VERSION} )
  MESSAGE(FATAL_ERROR "LLVM version ${LLVM_STRING_VERSION} is too old,"
                      " please install ${LLVM_MIN_VERSION_TEXT} or greater!"
         )
ENDIF( LLVM_VERSION LESS ${LLVM_MIN_VERSION} )
MESSAGE( STATUS "LLVM_COMPILE_FLAGS: " ${LLVM_COMPILE_FLAGS} )

find_package(Iconv REQUIRED)

include_directories(${PROJECT_SOURCE_DIR}
                    ${PROJECT_BINARY_DIR}
                    ${LLVM_INCLUDE_DIR}
                    ${ICONV_INCLUDE_DIRS}
                   )

add_definitions(-DLLVM_VERSION=${LLVM_VERSION})
add_definitions("-DCRACKLIB=\"${CMAKE_INSTALL_PREFIX}/lib/crack-${CRACK_VERSION}\"")

# share this is autoconf
file(STRINGS sourceModules.txt CRACK_SRC_FILES)
#MESSAGE( STATUS "modules: " ${CRACK_SRC_FILES})
file(STRINGS runtimeModules.txt RUNTIME_SRC_FILES)

# debug tools
set(DEBUG_SRC_FILES debug/DebugTools.cc util/md5.c util/SourceDigest.cc
    util/Hasher.cc
    )

# these are llvm specific compile flags, needed only for source files that
# include llvm headers
set_source_files_properties(${CRACK_SRC_FILES}
                            PROPERTIES COMPILE_FLAGS ${LLVM_COMPILE_FLAGS}
                           )
set_source_files_properties(crack_main.cc
                            PROPERTIES COMPILE_FLAGS ${LLVM_COMPILE_FLAGS}
                           )

# libCrackLang
add_library(libcrack SHARED ${CRACK_SRC_FILES})
set_target_properties(libcrack
                      PROPERTIES
                      OUTPUT_NAME CrackLang
                      SOVERSION ${CRACKLANG_API_VERSION}
                      LINK_FLAGS ${LLVM_LDFLAGS}
                      COMPILE_DEFINITIONS_DEBUG _DEBUG
                      )

target_link_libraries( libcrack
                       ${LLVM_LIBS} pthread dl libcrackdebug
                     )

# libCrackNativeRuntime
add_library(libcrackextstub SHARED ext/Stub.cc)
set_target_properties(libcrackextstub
                      PROPERTIES
                      OUTPUT_NAME CrackNativeRuntime
                      SOVERSION ${NATRUN_API_VERSION}
                      LINK_FLAGS ${LLVM_LDFLAGS}
                      COMPILE_DEFINITIONS_DEBUG _DEBUG
                      )
target_link_libraries(libcrackextstub
                      ${LLVM_LIBS}
                     )

# libCrackDebugTools
add_library(libcrackdebug SHARED ${DEBUG_SRC_FILES})
set_target_properties(libcrackdebug
                      PROPERTIES
                      OUTPUT_NAME CrackDebugTools
                      SOVERSION ${DEBUG_API_VERSION}
                      LINK_FLAGS ${LLVM_LDFLAGS}
                      COMPILE_DEFINITIONS_DEBUG _DEBUG
                      )
target_link_libraries(libcrackdebug
                      ${LLVM_LIBS}
                     )

# platform specific config, per autoconf
set(CMAKE_CONFIG_H_IN "${PROJECT_SOURCE_DIR}/config_cmake.h.in")
set(CMAKE_CONFIG_H_OUT "${PROJECT_SOURCE_DIR}/config.h")

# read autoheader generated config.h.in and cmakeify it
file(READ config.h.in CONFIG_H_STR)
string(REGEX REPLACE "#undef ([_a-zA-Z]+)" "#cmakedefine \\1 @\\1@"
             CONFIG_H_STR ${CONFIG_H_STR}
      )
file(WRITE config_cmake.h.in "/* Autogenerated by CMAKE from config.h.in */\n"
           ${CONFIG_H_STR}
    )

# define the variables it will be expecting to substitute
set(SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
set(VERSION "\"${CRACK_VERSION}\"")

check_include_files(malloc.h HAVE_MALLOC_H)
check_include_files(strings.h HAVE_STRINGS_H)
check_include_files(string.h HAVE_STRING_H)
check_include_files(memory.h HAVE_MEMORY_H)
check_include_files(stdint.h HAVE_STDINT_H)
check_include_files(stdlib.h HAVE_STDLIB_H)
check_include_files(sys/stat.h HAVE_SYS_STAT_H)
check_include_files(sys/types.h HAVE_SYS_TYPES_H)
check_include_files(unistd.h HAVE_UNISTD_H)

check_function_exists(ppoll HAVE_PPOLL)

# do the sub
configure_file(${CMAKE_CONFIG_H_IN} ${CMAKE_CONFIG_H_OUT})

# test extension. we set this up to mirror the autoconf
# build
add_library(testext SHARED test/testext.cc)
set_target_properties(testext
                      PROPERTIES
                      OUTPUT_NAME testext
                      LINK_FLAGS ${LLVM_LDFLAGS}
                      PREFIX ""
                      )
target_link_libraries(testext
                      libcrack)

# runtime extension
add_library( crack-runtime SHARED ${RUNTIME_SRC_FILES} )
set_target_properties(crack-runtime
                      PROPERTIES
                      OUTPUT_NAME runtime
                      LIBRARY_OUTPUT_DIRECTORY lib/crack
                      LINK_FLAGS ${LLVM_LDFLAGS}
                      PREFIX ""
                      )
target_link_libraries(crack-runtime
                      libcrack pthread libcrackdebug ${ICONV_LIBRARIES})


add_executable(crack crack_main.cc)
set_target_properties(crack
                      PROPERTIES LINK_FLAGS ${LLVM_LDFLAGS}
                      VERSION ${CRACK_VERSION}
                     )

target_link_libraries( crack
                       libcrack pthread
                     )

add_custom_command(TARGET crack POST_BUILD COMMAND
                          ${CMAKE_COMMAND} -E create_symlink crack crackc
                  )

# install targets
install(TARGETS crack libcrack libcrackextstub libcrackdebug
        RUNTIME DESTINATION bin
        LIBRARY DESTINATION lib
        ARCHIVE DESTINATION lib
       )

install(FILES ${CMAKE_CURRENT_BINARY_DIR}/crackc DESTINATION bin)

# runtime
install(TARGETS crack-runtime
         LIBRARY DESTINATION "lib/crack-${CRACK_VERSION}/crack"
        )

# manual
if (EXISTS doc/Manual.html)
    install(FILES doc/Manual.html DESTINATION share/doc/crack)
endif (EXISTS doc/Manual.html)

# header files
install(DIRECTORY compiler/ DESTINATION
                  "include/crack-${CRACK_VERSION}/crack/compiler"
                   FILES_MATCHING PATTERN "*.h"
        )
install(DIRECTORY ext/ DESTINATION "include/crack-${CRACK_VERSION}/crack/ext"
                  FILES_MATCHING PATTERN "*.h"
        )
install(DIRECTORY ext/ DESTINATION "include/crack-${CRACK_VERSION}/crack/debug"
                  FILES_MATCHING PATTERN "*.h"
       )

# install library modules
install(DIRECTORY lib/crack DESTINATION "lib/crack-${CRACK_VERSION}"
        FILES_MATCHING PATTERN "*.crk")

add_custom_target(check env CRACK_LIB_PATH=${CMAKE_CURRENT_BINARY_DIR}/lib
                            BUILD_ROOT=${CMAKE_CURRENT_BINARY_DIR}
                            SOURCES_ROOT=${CMAKE_CURRENT_SOURCE_DIR}
                                         ${CMAKE_CURRENT_SOURCE_DIR}/test/screen
                 )

add_custom_target(checkc env CRACK_LIB_PATH=${CMAKE_CURRENT_BINARY_DIR}/lib
                             BUILD_ROOT=${CMAKE_CURRENT_BINARY_DIR}
                             SOURCES_ROOT=${CMAKE_CURRENT_SOURCE_DIR}
                                          ${CMAKE_CURRENT_SOURCE_DIR}/test/screen -n
                 )

add_subdirectory(opt)

macro_display_feature_log()
