project(terraphast C CXX)

cmake_minimum_required(VERSION 3.0.2)
cmake_policy(SET CMP0054 NEW)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")

Option(DEV_ENVIRONMENT "Development environment (extended debugging)" OFF)

#####################################################################
# decide which components need to be built: by default, build everything,
# unless some components were explicitely disabled from the parent project
#####################################################################
Option(TERRAPHAST_USE_GMP "Use GMP" ON)
Option(TERRAPHAST_BUILD_CLIB "Build the C library" ON)
Option(TERRAPHAST_BUILD_APPS "Build the tools" ON)
Option(TERRAPHAST_BUILD_TESTS "Build the tests" ON)
Option(TERRAPHAST_ARCH_NATIVE "Use -march=native compiler flag" ON)

#####################################################################
# build library
#####################################################################
add_library(terraces
		lib/advanced.cpp
		lib/bigint.cpp
		lib/bipartitions.cpp
		lib/bipartitions.hpp
		lib/bitmatrix.cpp
		lib/bits.hpp
		lib/bitvector.hpp
		lib/clamped_uint.cpp
		lib/constraints.cpp
		lib/constraints_impl.hpp
		lib/errors.cpp
		lib/io_utils.hpp
		lib/multitree.cpp
		lib/multitree.hpp
		lib/multitree_impl.hpp
		lib/multitree_iterator.cpp
		lib/multitree_iterator.hpp
		lib/nodes.cpp
		lib/parser.cpp
		lib/ranked_bitvector.hpp
		lib/rooting.cpp
		lib/simple.cpp
		lib/small_bipartition.hpp
		lib/stack_allocator.hpp
		lib/subtree_extraction.cpp
		lib/subtree_extraction_impl.hpp
		lib/supertree_enumerator.hpp
		lib/supertree_helpers.cpp
		lib/supertree_helpers.hpp
		lib/supertree_variants.hpp
		lib/supertree_variants_debug.hpp
		lib/supertree_variants_multitree.hpp
		lib/trees.cpp
		lib/trees_impl.hpp
		lib/union_find.cpp
		lib/union_find.hpp
		lib/union_find_debug.hpp
		lib/utils.hpp
		lib/validation.cpp
		lib/validation.hpp
		# For QtCreator/CLion/... to show the files
		include/terraces/advanced.hpp
		include/terraces/bigint.hpp
		include/terraces/bitmatrix.hpp
		include/terraces/clamped_uint.hpp
		include/terraces/constraints.hpp
		include/terraces/definitions.hpp
		include/terraces/errors.hpp
		include/terraces/parser.hpp
		include/terraces/rooting.hpp
		include/terraces/simple.hpp
		include/terraces/subtree_extraction.hpp
		include/terraces/trees.hpp
)
target_include_directories(terraces
		PUBLIC include
		PRIVATE lib
)

if(TERRAPHAST_USE_GMP)
	find_package(GMP)
	if(GMP_FOUND)
		message(STATUS "GMP libraries found")
		target_link_libraries(terraces gmpxx gmp)
		target_compile_definitions(terraces PUBLIC USE_GMP)
	else()
		message(FATAL_ERROR "GMP libraries not found! Disable them using -DTERRAPHAST_USE_GMP=OFF")
	endif()
endif()

set(terraces_targets terraces)

if(TERRAPHAST_BUILD_CLIB)
	add_library(terraces_c
			c_lib/terraces.cpp
			c_include/terraces/terraces.h
	)
	target_include_directories(terraces_c PUBLIC c_include)
	target_link_libraries(terraces_c terraces)
	if (NOT TERRAPHAST_USE_GMP)
		message(FATAL_ERROR "The C library requires the GMP libraries to build! Enable them using -DTERRAPHAST_USE_GMP=ON")
	endif()

	set(terraces_targets ${terraces_targets} terraces_c)
endif()

#####################################################################
# internal compiler flags
#####################################################################
if(DEV_ENVIRONMENT AND CMAKE_BUILD_TYPE STREQUAL "Debug")
	target_compile_definitions(terraces PUBLIC _GLIBCXX_DEBUG) # PUBLIC to maintain ABI compatibility
	if(TERRAPHAST_BUILD_CLIB)
		target_compile_definitions(terraces_c PRIVATE _GLIBCXX_DEBUG) # PRIVATE since no stdlib objects are used
	endif()
endif()

#####################################################################
# build tools
#####################################################################
if(TERRAPHAST_BUILD_APPS)
	add_executable(app "app/app.cpp")
	add_executable(validated_run "tools/validated_run.cpp")
	add_executable(verbose_run "tools/verbose_run.cpp")
	add_executable(isomorphic "tools/isomorphic.cpp")
	add_executable(reroot "tools/reroot.cpp")
	add_executable(subtree "tools/subtree.cpp")
	add_executable(tree_gen "tools/tree_gen.cpp")
	add_executable(site_gen "tools/site_gen.cpp")
	add_executable(nwk_to_dot "tools/nwk_to_dot.cpp")
	target_link_libraries(validated_run terraces)
	target_link_libraries(verbose_run terraces)
	target_link_libraries(isomorphic terraces)
	target_link_libraries(reroot terraces)
	target_link_libraries(subtree terraces)
	target_link_libraries(tree_gen terraces)
	target_link_libraries(site_gen terraces)
	target_link_libraries(nwk_to_dot terraces)
	target_link_libraries(app terraces)

	set(terraces_targets ${terraces_targets} app validated_run verbose_run isomorphic reroot subtree tree_gen site_gen nwk_to_dot)
endif()

#####################################################################
# build tests
#####################################################################
if(TERRAPHAST_BUILD_TESTS)
	add_library(Catch INTERFACE)
	target_include_directories(Catch INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/catch)

	add_executable(unittests
		test/main.cc
		test/advanced.cpp
		test/bipartitions.cpp
		test/bitmatrix.cpp
		test/bits.cpp
		test/bitvector.cpp
		test/clamped_uint.cpp
		test/constraints.cpp
		test/compile_test.cpp
		test/fast_set.cpp
		test/integration.cpp
		test/multitree_iterator.cpp
		test/parser.cpp
		test/rooting.cpp
		test/small_bipartition.cpp
		test/stack_allocator.cpp
		test/subtree_extraction.cpp
		test/supertree.cpp
		test/trees.cpp
		test/union_find.cpp
		test/util.cpp
		test/validation.cpp
		test/simple.cpp
		test/limited.cpp
	)
	target_link_libraries(unittests terraces Catch)
	if(TERRAPHAST_BUILD_CLIB)
		target_sources(unittests PRIVATE
			test/c_api.cpp
		)
		target_link_libraries(unittests terraces_c)
	endif()
	add_test(NAME unittests COMMAND unittests)
	enable_testing()

	set(terraces_targets ${terraces_targets} unittests)
endif()

set_target_properties(${terraces_targets} PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED ON)

#####################################################################
# set platform-specific options, include platform-specific files
#####################################################################
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
	set(TERRAPHAST_PLATFORM_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/lib/cl")
	set(TERRAPHAST_COMPILE_FLAGS -Oi -W4)

	# Most of our files only compile with disabled language extensions for VC++
	# Unfortunately, Catch uses some windows-specific features, so we have to
	# enable these extensions for the Catch main method (more specific: not disable them)
	file(GLOB ALL_SOURCES lib/*.cpp c_lib/*.cpp test/*.cpp tools/*.cpp app/*.cpp)
	set_source_files_properties(${ALL_SOURCES} PROPERTIES COMPILE_FLAGS "-Za")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
	set(TERRAPHAST_PLATFORM_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/lib/intel")
	set(TERRAPHAST_COMPILE_FLAGS -Wall -Wextra -Wconversion -Wsign-conversion -Werror)
	if(TERRAPHAST_ARCH_NATIVE)
		set(TERRAPHAST_COMPILE_FLAGS -march=native ${TERRAPHAST_COMPILE_FLAGS})
	endif()
else()
	set(TERRAPHAST_PLATFORM_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/lib/gcc_clang")
	set(TERRAPHAST_COMPILE_FLAGS -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Werror)
	if(TERRAPHAST_ARCH_NATIVE)
		set(TERRAPHAST_COMPILE_FLAGS -march=native ${TERRAPHAST_COMPILE_FLAGS})
	endif()
endif()

target_include_directories(terraces PUBLIC "${TERRAPHAST_PLATFORM_INCLUDE}")
if(TERRAPHAST_BUILD_TESTS)
	target_include_directories(unittests PRIVATE "${TERRAPHAST_PLATFORM_INCLUDE}")
endif()
target_compile_options(terraces PRIVATE "${TERRAPHAST_COMPILE_FLAGS}")
if(TERRAPHAST_BUILD_CLIB)
	target_compile_options(terraces_c PRIVATE "${TERRAPHAST_COMPILE_FLAGS}")
endif()

#####################################################################
# setup clang-tidy
#####################################################################
find_program(CLANG_TIDY_PATH NAMES "clang-tidy")
if(NOT CLANG_TIDY_PATH)
	message(STATUS "clang-tidy not found.")
else()
	message(STATUS "clang-tidy found: ${CLANG_TIDY_PATH}")
	set(CLANG_TIDY_COMMANDLINE "${CLANG_TIDY_PATH}" "-checks=llvm-namespace-comment -fix")
endif()

#set_target_properties(terraces terraces_c app validated_run verbose_run isomorphic reroot subtree tree_gen site_gen nwk_to_dot unittests PROPERTIES CXX_CLANG_TIDY "${CLANG_TIDY_COMMANDLINE}")
