# Top-level CMakeLists.txt file for the KDAB State Machine Editor Library.
cmake_minimum_required(VERSION 2.8.12) # because of ALIAS targets
if(POLICY CMP0053)
  cmake_policy(SET CMP0053 NEW)
endif()
if(POLICY CMP0063)
  cmake_policy(SET CMP0063 NEW)
endif()

project(kdstatemachineeditor CXX C)

# Version setup
set(KDSME_VERSION_MAJOR "1")
set(KDSME_VERSION_MINOR "2")
set(KDSME_VERSION_PATCH "5")
set(KDSME_VERSION "${KDSME_VERSION_MAJOR}.${KDSME_VERSION_MINOR}.${KDSME_VERSION_PATCH}")
set(KDSME_VERSION_STRING "${KDSME_VERSION}")
set(KDSME_SOVERSION "1.2.5")
set(PROJECT_VERSION_STRING "${KDSME_VERSION_STRING}")

set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/ ${CMAKE_MODULE_PATH})
set(CMAKE_AUTOMOC ON)

if(NOT DEFINED CMAKE_MACOSX_RPATH)
  set(CMAKE_MACOSX_RPATH TRUE)
endif()

if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
endif()

if(WIN32)
  # Needed for qmake-integration because qmake's QT modules import mechanism does assume
  # debug libraries at windows always have a d suffix.
  set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "debug library postfix, usually d on windows")
endif()

include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
include(CheckIncludeFiles)
include(CMakePackageConfigHelpers)
include(CTest)
include(GenerateExportHeader)
include(GNUInstallDirs)
include(ExternalProject)
include(MacroLogFeature)
include(ECMAddTests)
include(ECMGeneratePriFile)

find_package(Qt5 5.3 CONFIG REQUIRED Quick Test Widgets)
find_package(Qt5 5.3 CONFIG REQUIRED QuickWidgets)
include(QtInstallPaths) #to set QT_INSTALL_FOO variables

find_package(Qt5RemoteObjects 5.4 CONFIG QUIET)
set_package_properties(Qt5RemoteObjects PROPERTIES
  TYPE OPTIONAL
  DESCRIPTION "Qt Remote Objects module"
  PURPOSE "Needed for the QStateMachine/QtSCXML adapter and remote debugging capabilities"
)
if (Qt5RemoteObjects_FOUND)
    string(REPLACE "." ";" VERSION_LIST ${Qt5RemoteObjects_VERSION})
    list(GET VERSION_LIST 0 Qt5RemoteObjects_VERSION_MAJOR)
    list(GET VERSION_LIST 1 Qt5RemoteObjects_VERSION_MINOR)
    list(GET VERSION_LIST 2 Qt5RemoteObjects_VERSION_PATCH)
endif()

find_package(Qt5Scxml 5.8 CONFIG QUIET)
set_package_properties(Qt5Scxml PROPERTIES
  TYPE OPTIONAL
  DESCRIPTION "Qt SCXML module"
  PURPOSE "Needed for the Qt SCXML adapter (adapter itself depends on Qt5RemoteObjects)"
)

find_package(Qt5 5.3 CONFIG OPTIONAL_COMPONENTS XmlPatterns)
set_package_properties(Qt5XmlPatterns PROPERTIES
  TYPE OPTIONAL
  DESCRIPTION "Qt5 XmlPatterns library"
  PURPOSE "Required for unit tests dealing with XML input/output"
)

option(DEPLOY_DEPENDENCIES "Install Qt5 and graphviz" ON)

option(BUILD_DOCS "Build KDStateMachineEditor documentation" ON)

if(NOT CMAKE_CROSSCOMPILING)
  option(BUILD_EXAMPLES "Build examples directory" ON)
endif()

# Don't require lots of include_directories(${CMAKE_CURRENT_SOURCE_DIR}) etc.
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Automatically include the current dirs in the INTERFACE_INCLUDE_DIRS of targets.
set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
set(CMAKE_AUTOMOC TRUE)

set(BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR})
set(LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING "Library install destination.")
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}/${CMAKE_PROJECT_NAME})
set(XDG_DATA_INSTALL_DIR ${CMAKE_INSTALL_DATAROOTDIR}/${CMAKE_PROJECT_NAME})
set(QCH_INSTALL_DIR ${CMAKE_INSTALL_DOCDIR} CACHE STRING "Install location of Qt Assistant help files.")

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${BIN_INSTALL_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${LIB_INSTALL_DIR})

set(INSTALL_TARGETS_DEFAULT_ARGS
  RUNTIME DESTINATION ${BIN_INSTALL_DIR}
  LIBRARY DESTINATION ${LIB_INSTALL_DIR}
  ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT Devel
  BUNDLE DESTINATION "/Applications/Qt5"
)

# search for Graphviz
set(GRAPHVIZ_MIN_VERSION "2.20")
find_package(Graphviz)
set_package_properties(Graphviz PROPERTIES
    TYPE RECOMMENDED
    DESCRIPTION "Graph visualization software"
    PURPOSE "Needed for automatic layout of state charts"
    URL "http://www.graphviz.org/"
)

if(GRAPHVIZ_FOUND)
    set(WITH_INTERNAL_GRAPHVIZ_DEFAULT OFF)
elseif (NOT CMAKE_SYSTEM_NAME STREQUAL QNX)
    message(STATUS "Auto-enabling internal Graphviz build, since no installed version is available")
    set(WITH_INTERNAL_GRAPHVIZ_DEFAULT ON)
endif()

option(WITH_INTERNAL_GRAPHVIZ "Enable build of external project Graphviz" ${WITH_INTERNAL_GRAPHVIZ_DEFAULT})
add_feature_info("Internal build of Graphviz" WITH_INTERNAL_GRAPHVIZ "enable with WITH_INTERNAL_GRAPHVIZ=ON")

if(WITH_INTERNAL_GRAPHVIZ)
    # CMake is really awful here...
    set(install_dir ${CMAKE_CURRENT_BINARY_DIR}/graphviz-install)
    set(staticdotlayoutplugin_library "${install_dir}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}gvplugin_dot_layout${CMAKE_STATIC_LIBRARY_SUFFIX}")
    set(link_libraries "dotgen;common;xdot;gvc;cgraph;cdt;pathplan;ortho;pack;label;ingraphs")
    set(link_libraries_absolute)
    foreach(link_library ${link_libraries})
        list(APPEND link_libraries_absolute ${install_dir}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${link_library}${CMAKE_STATIC_LIBRARY_SUFFIX})
    endforeach()
    ExternalProject_Add(GraphvizExternalProject
        GIT_REPOSITORY "https://github.com/krf/graphviz.git"
        GIT_TAG "9f64e9807d76747dc53db88fcca1fd999c48ec4b"
        CMAKE_ARGS
            -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
            -DCMAKE_INSTALL_PREFIX=${install_dir}
        BUILD_COMMAND "" # skip, make install is enough
        INSTALL_DIR ${install_dir}
        INSTALL_COMMAND
            ${CMAKE_COMMAND} --build . --target install

        # Note: BUILD_BYPRODUCTS only available since CMake 3.2
        # Needed to make ExternalProject_Add in combination with the Ninja generator work
        # Also see: https://cmake.org/pipermail/cmake/2015-April/060234.html
        BUILD_BYPRODUCTS ${staticdotlayoutplugin_library} ${link_libraries_absolute}
    )
    ExternalProject_Get_Property(GraphvizExternalProject source_dir)
    ExternalProject_Get_Property(GraphvizExternalProject binary_dir)

    # work-around: https://cmake.org/Bug/view.php?id=15052
    set(include_dir "${install_dir}/include")
    file(MAKE_DIRECTORY ${include_dir})

    add_library(GraphvizStaticDotLayoutPlugin IMPORTED STATIC)
    set_target_properties(GraphvizStaticDotLayoutPlugin PROPERTIES
        IMPORTED_LOCATION "${staticdotlayoutplugin_library}"
        INTERFACE_COMPILE_DEFINITIONS "CGRAPH_EXPORTS;GVC_EXPORTS;WITH_CGRAPH" # Fix export macro madness in Graphviz
        INTERFACE_INCLUDE_DIRECTORIES ${include_dir}
        INTERFACE_LINK_LIBRARIES "${link_libraries_absolute}"
    )
    add_dependencies(GraphvizStaticDotLayoutPlugin GraphvizExternalProject)
    set(GRAPHVIZ_FOUND TRUE)
    set(GRAPHVIZ_MAJOR_VERSION 2)
    set(GRAPHVIZ_MINOR_VERSION 38)
    set(GRAPHVIZ_PATCH_VERSION 0)
endif()

#
# Compiler & linker settings
#
function(append_if condition value)
  if (${condition})
    foreach(variable ${ARGN})
      set(${variable} "${${variable}} ${value}" PARENT_SCOPE)
    endforeach(variable)
  endif()
endfunction()

macro(add_flag_if_supported flag name)
  check_c_compiler_flag("-Werror ${flag}" "C_SUPPORTS_${name}")
  append_if("C_SUPPORTS_${name}" "${flag}" CMAKE_C_FLAGS)
  check_cxx_compiler_flag("-Werror ${flag}" "CXX_SUPPORTS_${name}")
  append_if("CXX_SUPPORTS_${name}" "${flag}" CMAKE_CXX_FLAGS)
endmacro()

set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
if(CMAKE_COMPILER_IS_GNUCXX OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
  add_flag_if_supported(-Wunused-but-set-variable UNUSED_BUT_SET)
  add_flag_if_supported(-Wlogical-op LOGICAL_OP)
  add_flag_if_supported(-Wsizeof-pointer-memaccess POINTER_MEMACCESS)
  add_flag_if_supported(-Wreorder REORDER)
  add_flag_if_supported(-Wformat-security FORMAT_SECURITY)

  check_cxx_compiler_flag(-std=gnu++0x HAVE_GXX_GNUXX11)
  check_cxx_compiler_flag(-std=c++0x HAVE_GXX_CXX11)
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -Wextra -Woverloaded-virtual -Winit-self -Wmissing-include-dirs -Wunused -Wno-div-by-zero -Wundef -Wpointer-arith -Wmissing-noreturn -Werror=return-type -Wswitch")
  if(HAVE_GXX_GNUXX11) # QNX needs gnu++0x rather than c++0x for compiling QML V4 private headers
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x")
  elseif(HAVE_GXX_CXX11)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
  endif()
  if(MINGW)
    # mingw will error out on the crazy casts in probe.cpp without this
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")
  endif()
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments -Wdocumentation")
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Qunused-arguments")
endif()
add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050400)
if(MSVC)
  add_definitions(-D_SCL_SECURE_NO_WARNINGS)
endif()

# linker flags
if(CMAKE_SYSTEM_NAME MATCHES Linux OR CMAKE_SYSTEM_NAME STREQUAL GNU)
  if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
    set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--fatal-warnings -Wl,--no-undefined -lc ${CMAKE_SHARED_LINKER_FLAGS}")
    set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--fatal-warnings -Wl,--no-undefined -lc ${CMAKE_MODULE_LINKER_FLAGS}")
  endif()
endif()

if(NOT CMAKE_CROSSCOMPILING)
  enable_testing()
endif()

set(TEST_DATA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/data)

add_subdirectory(src)

if(BUILD_EXAMPLES)
  add_subdirectory(examples)
endif()

if(BUILD_DOCS)
  add_subdirectory(docs)
endif()

set(CONFIG_DIR "KDSME")
write_basic_package_version_file(
  "${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_DIR}/KDSMEConfigVersion.cmake"
  VERSION ${KDSME_VERSION}
  COMPATIBILITY AnyNewerVersion
)
configure_file(cmake/KDSMEConfig.cmake
  "${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_DIR}/KDSMEConfig.cmake"
  COPYONLY
)

set(CMAKECONFIG_INSTALL_DIR ${LIB_INSTALL_DIR}/cmake/${CONFIG_DIR})
install(EXPORT KDSME_TARGETS
  NAMESPACE
    KDSME::
  FILE
    KDSMETargets.cmake
  DESTINATION
    ${CMAKECONFIG_INSTALL_DIR}
)
install(
  FILES
    cmake/KDSMEConfig.cmake
    cmake/KDSMEFindDependencyMacro.cmake
    "${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_DIR}/KDSMEConfigVersion.cmake"
  DESTINATION
    ${CMAKECONFIG_INSTALL_DIR}
  COMPONENT
    Devel
)

feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)

set(LICENSE_FILE "LICENSE.LGPL.txt")
set(README_FILE "ReadMe.txt")

#CPACK
set(CPACK_PACKAGE_VERSION_MAJOR "${KDSME_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${KDSME_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${KDSME_VERSION_PATCH}")
set(CPACK_PACKAGE_VERSION "${KDSME_VERSION}")
set(CPACK_PACKAGE_VENDOR "KDAB")
set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/${README_FILE}")
if(WIN32)
  set(CPACK_GENERATOR "NSIS")
  set(CPACK_PACKAGE_INSTALL_DIRECTORY "KDStateMachineEditor")
  set(CPACK_PACKAGE_FILE_NAME "KDStateMachineEditor-${KDSME_VERSION}")
  set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/${LICENSE_FILE}")
  set(CPACK_NSIS_EXECUTABLES_DIRECTORY "${BIN_INSTALL_DIR}")
  set(CPACK_NSIS_URL_INFO_ABOUT "http://www.kdab.com/")
  set(CPACK_NSIS_MENU_LINKS
    "${LICENSE_FILE}" "License"
    "${README_FILE}" "Readme"
   )
endif()
include(CPack)
