# Top level CMakeLists.txt file for SyFi

# Require CMake 2.8
cmake_minimum_required(VERSION 2.8)

#------------------------------------------------------------------------------
# Set project name and version number

project(SYFI)

set(SYFILIB_MAJOR_VERSION "1")
set(SYFILIB_MINOR_VERSION "0")
set(SYFILIB_MICRO_VERSION "0")
set(SYFILIB_VERSION
  "${SYFILIB_MAJOR_VERSION}.${SYFILIB_MINOR_VERSION}.${SYFILIB_MICRO_VERSION}")
add_definitions(-DSYFILIB_VERSION="${SYFILIB_VERSION}")

#------------------------------------------------------------------------------
# General configuration

# Set CMake options, see `cmake --help-policy CMP000x`
if (COMMAND cmake_policy)
  cmake_policy(SET CMP0003 NEW)
  cmake_policy(SET CMP0004 OLD)
endif()

# Set location of our FindFoo.cmake modules
set(CMAKE_MODULE_PATH 
  ${CMAKE_SOURCE_DIR}/cmake/modules
  ${CMAKE_MODULE_PATH})

# Make sure CMake uses the correct syfi-config.cmake for tests and demos
#set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${CMAKE_CURRENT_BINARY_DIR}/syfi)

#------------------------------------------------------------------------------
# Configurable options for how we want to build

option(BUILD_SHARED_LIBS "Build SyFi with shared libraries." ON)
option(CMAKE_USE_RELATIVE_PATHS "Use relative paths in makefiles and projects." OFF)
option(SYFI_WITH_LIBRARY_VERSION "Build with library version information." ON)
option(SYFI_ENABLE_DOCS "Enable documentation." OFF)
option(SYFI_ENABLE_TESTING "Enable testing." OFF)

#------------------------------------------------------------------------------
# Compiler flags

# Default build type (can be overridden by user)
if (NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING
    "Choose the type of build, options are: Debug Developer MinSizeRel Release RelWithDebInfo." FORCE)
endif()

# Check for some compiler flags
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-pipe HAVE_PIPE)
if (HAVE_PIPE)
  set(SYFI_CXX_DEVELOPER_FLAGS "-pipe ${SYFI_CXX_DEVELOPER_FLAGS}")
endif()

check_cxx_compiler_flag("-Wall -Werror" HAVE_PEDANTIC)
if (HAVE_PEDANTIC)
  set(SYFI_CXX_DEVELOPER_FLAGS "-Wall -Werror ${SYFI_CXX_DEVELOPER_FLAGS}")
endif()

check_cxx_compiler_flag(-std=c++98 HAVE_STD)
if (HAVE_STD)
  set(SYFI_CXX_DEVELOPER_FLAGS "-std=c++98 ${SYFI_CXX_DEVELOPER_FLAGS}")
endif()

check_cxx_compiler_flag(-g HAVE_DEBUG)
if (HAVE_DEBUG)
  set(SYFI_CXX_DEVELOPER_FLAGS "-g ${SYFI_CXX_DEVELOPER_FLAGS}")
endif()

check_cxx_compiler_flag(-O2 HAVE_O2_OPTIMISATION)
if (HAVE_O2_OPTIMISATION)
  set(SYFI_CXX_DEVELOPER_FLAGS "-O2 ${SYFI_CXX_DEVELOPER_FLAGS}")
endif()

# Set 'Developer' build type flags
set(CMAKE_CXX_FLAGS_DEVELOPER "${SYFI_CXX_DEVELOPER_FLAGS}" CACHE STRING
  "Flags used by the compiler during development." FORCE)

# Add debug definitions
if (CMAKE_BUILD_TYPE STREQUAL "Developer" OR CMAKE_BUILD_TYPE STREQUAL "Debug")
  list(APPEND SYFI_CXX_DEFINITIONS "-DDEBUG")
endif()

#------------------------------------------------------------------------------
# Run tests to find required packages

find_package(GiNaC REQUIRED)
find_package(PythonInterp REQUIRED)
find_package(PythonLibs REQUIRED)
find_package(NumPy REQUIRED)
find_package(SWIG REQUIRED)
include(UseSWIG)

#------------------------------------------------------------------------------
# Set include directories and libs of required packages

set(SYFI_INCLUDE_DIRECTORIES
  ${GINAC_INCLUDE_DIRS}
  )

set(SYFI_TARGET_LINK_LIBRARIES
  ${GINAC_LIBRARIES}
  )

#------------------------------------------------------------------------------
# Set compiler flags and include directories

# Add compiler include directories
include_directories(
  ${SYFI_SOURCE_DIR}/syfi
  ${SYFI_BINARY_DIR}/syfi
  ${SYFI_SOURCE_DIR}/syfi/swig
  ${SYFI_BINARY_DIR}/syfi/swig
  ${SYFI_INCLUDE_DIRECTORIES}
  )

# Add CXX defintions
add_definitions(${SYFI_CXX_DEFINITIONS})

# Add flags
set(CMAKE_CXX_FLAGS
  ${CMAKE_CXX_FLAGS}
  ${SYFI_CXX_FLAGS}
  )

#------------------------------------------------------------------------------
# Set SyFi install sub-directories

set(SYFI_BIN_DIR "bin" CACHE PATH "Binary installation directory.")
set(SYFI_LIB_DIR "lib" CACHE PATH "Library installation directory.")
set(SYFI_INCLUDE_DIR "include" CACHE PATH "C/C++ header installation directory.")
set(SYFI_PKGCONFIG_DIR "lib/pkgconfig" CACHE PATH "pkg-config file installation directory.")
set(SYFI_SHARE_DIR "share/syfi" CACHE PATH "Shared data installation directory.")
set(SYFI_MAN_DIR "share/man" CACHE PATH "Manual page installation directory.")

# Extract Python version info for use to determine where to install Python files
execute_process(
  COMMAND ${PYTHON_EXECUTABLE} -c "import platform; print platform.python_version()"
  OUTPUT_VARIABLE PYTHON_VERSION
  OUTPUT_STRIP_TRAILING_WHITESPACE
  )
string(SUBSTRING "${PYTHON_VERSION}" 0 1 PYTHON_VERSION_MAJOR)
string(SUBSTRING "${PYTHON_VERSION}" 2 1 PYTHON_VERSION_MINOR)
string(SUBSTRING "${PYTHON_VERSION}" 4 1 PYTHON_VERSION_PATCH)

# We install Python files to lib/pythonX.Y/site-packages by default
set(SYFI_PYTHON_MODULE_DIR "lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages"
  CACHE PATH "Python module installation directory")
set(SYFI_PYTHON_EXT_DIR "lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages"
  CACHE PATH "Python extension module installation directory")

#------------------------------------------------------------------------------
# Installation of sfc

install(DIRECTORY ${CMAKE_SOURCE_DIR}/site-packages/sfc
  DESTINATION ${SYFI_PYTHON_MODULE_DIR}
  USE_SOURCE_PERMISSIONS
  COMPONENT RuntimeExecutables)

install(FILES ${CMAKE_SOURCE_DIR}/scripts/sfc
  DESTINATION ${SYFI_BIN_DIR}
  PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE
  COMPONENT RuntimeExecutables)

#------------------------------------------------------------------------------
# Installation of SyFi manual pages

install(DIRECTORY ${SYFI_SOURCE_DIR}/doc/man/
  DESTINATION ${SYFI_MAN_DIR}
  USE_SOURCE_PERMISSIONS
  COMPONENT RuntimeExecutables)

#------------------------------------------------------------------------------
# SyFi library

# Add source directory
add_subdirectory(syfi)

#------------------------------------------------------------------------------
# Generate and install helper file syfi.conf

# FIXME: not cross-platform compatible
# Create and install syfi.conf file
configure_file(${CMAKE_SOURCE_DIR}/cmake/templates/syfi.conf.in
  ${CMAKE_BINARY_DIR}/syfi.conf @ONLY)
install(FILES ${CMAKE_BINARY_DIR}/syfi.conf
  DESTINATION ${SYFI_SHARE_DIR}
  COMPONENT Development)

#------------------------------------------------------------------------------
# Add demos and install demo source files

# Copy demo files to build directory
file(COPY demo DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

# Add target "demo" for building the demos
add_custom_target(demo
  COMMAND ${PYTHON_EXECUTABLE} makeall.py
  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/demo")

# Add target "demo_clean" for cleaning the demos
add_custom_target(demo_clean
  COMMAND ${PYTHON_EXECUTABLE} cleanall.py
  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/demo")

# Install the demo source files
install(DIRECTORY demo DESTINATION ${SYFI_SHARE_DIR})

#------------------------------------------------------------------------------
# Install demo files

install(DIRECTORY demo DESTINATION ${SYFI_SHARE_DIR})

#------------------------------------------------------------------------------
# Add tests

if (SYFI_ENABLE_TESTING)
  enable_testing()
  add_subdirectory(tests)
endif()

#------------------------------------------------------------------------------
# Generate pkg-config file and install it

# Convert include dirs to -I<incdir> form
foreach(_inc_dir ${SYFI_INCLUDE_DIRECTORIES})
  set(PKG_INCLUDES "-I${_inc_dir} ${PKG_INCLUDES}")
endforeach()

# Convert compiler flags and definitions into space separated strings
string(REPLACE ";" " " PKG_CXXFLAGS "${CMAKE_CXX_FLAGS}")
string(REPLACE ";" " " PKG_DEFINITIONS "${SYFI_CXX_DEFINITIONS}")

# Convert libraries to -L<libdir> -l<lib> form
foreach(_lib ${SYFI_TARGET_LINK_LIBRARIES})
  string(REGEX REPLACE "(.?:?/[^ ]*)/lib([^ ]*)\\.(a|so|dylib|dll)" "-L\\1 -l\\2"
    _linkflags
    "${_lib}"
    )

  # Only add libraries that matches the form -L<libdir> -l<lib>
  if ("${_linkflags}" MATCHES "-L.+ -l.+")
    set(PKG_LINKFLAGS "${_linkflags} ${PKG_LINKFLAGS}")
  endif()
endforeach()

# Remove duplicated link flags
separate_arguments(PKG_LINKFLAGS)
list(REMOVE_DUPLICATES PKG_LINKFLAGS)
string(REPLACE ";" " " PKG_LINKFLAGS "${PKG_LINKFLAGS}")

# Add additional link flags
#set(PKG_LINK_FLAGS "${PKG_LINKFLAGS} ${SYFI_LINK_FLAGS}")

# Configure and install pkg-config file
configure_file(${SYFI_SOURCE_DIR}/cmake/templates/syfi.pc.in ${CMAKE_BINARY_DIR}/syfi.pc @ONLY)
install(FILES ${CMAKE_BINARY_DIR}/syfi.pc
  DESTINATION ${SYFI_PKGCONFIG_DIR}
  COMPONENT Development
  )

#------------------------------------------------------------------------------
# Add "make uninstall" target

configure_file(
  "${CMAKE_SOURCE_DIR}/cmake/templates/cmake_uninstall.cmake.in"
  "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
  IMMEDIATE @ONLY)

add_custom_target(uninstall
  "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
