#===============================================================================
# file: CMakeLists.txt
# created: Jun 08, 2017
#
# CMake file for sortmerna/src/sortmerna
#===============================================================================

cmake_minimum_required(VERSION 3.21)
project(sortmerna CXX)
set(CMAKE_CXX_STANDARD 17)

find_package(Threads REQUIRED)

# indexed_bzip2 / rapidgzip (header-only, seekable parallel gzip decompression)
if(NOT DEFINED INDEXED_BZIP2_HOME)
	set(INDEXED_BZIP2_HOME ${CMAKE_SOURCE_DIR}/3rdparty/indexed_bzip2/src CACHE PATH "Path to indexed_bzip2/src")
endif()
if(NOT TARGET rapidgzip::rapidgzip)
	add_subdirectory(${INDEXED_BZIP2_HOME} ${CMAKE_BINARY_DIR}/indexed_bzip2_src EXCLUDE_FROM_ALL)
endif()

# parasail: SIMD-accelerated pairwise sequence alignment (replaces SSW)
if(DEFINED CACHE{PARASAIL_DIST})
	find_library(PARASAIL_LIB parasail
		PATHS ${PARASAIL_DIST}/lib ${PARASAIL_DIST}/lib64
		NO_DEFAULT_PATH
	)
	find_path(PARASAIL_INCLUDE_DIR parasail.h
		PATHS ${PARASAIL_DIST}/include
		NO_DEFAULT_PATH
	)
else()
	find_library(PARASAIL_LIB parasail)
	find_path(PARASAIL_INCLUDE_DIR parasail.h)
endif()
if(PARASAIL_LIB AND PARASAIL_INCLUDE_DIR)
	message("parasail found: lib=${PARASAIL_LIB} include=${PARASAIL_INCLUDE_DIR}")
else()
	message(FATAL_ERROR "parasail not found. Build it first: python setup.py parasail")
endif()

#include(FindZLIB)
if (DEFINED CACHE{ZLIB_ROOT})
	message("searching ZLIB in ${ZLIB_ROOT}")
else()
	message("searching ZLIB in default locations")
endif()
find_package(ZLIB MODULE REQUIRED) # prevent CONFIG search mode

if(ZLIB_FOUND)
	get_target_property(lib ZLIB::ZLIB LOCATION)
	message("ZLIB::ZLIB LOCATION: ${lib}")
	get_target_property(lib ZLIB::ZLIB LOCATION_DEBUG)
	message("ZLIB::ZLIB LOCATION_DEBUG: ${lib}")
endif(ZLIB_FOUND)

# cmake has no FindRocksDB module, but RocksDB build provides cmake config,
# whence using CONFIG search.
# defines RocksDB::rocksdb (static) and RocksDB::rocksdb-shared targets. Note that
# these names can only be found by reading the package configuration files.
if (DEFINED CACHE{ROCKSDB_DIST})
	find_package(RocksDB CONFIG REQUIRED
	  PATHS ${ROCKSDB_DIST}
	  NO_DEFAULT_PATH
	)
else()
	message("searching RocksDB in default locations")
	list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules/")
	message("CMAKE_MODULE_PATH: ${CMAKE_MODULE_PATH}")
  	find_package(RocksDB REQUIRED)
endif()

if(RocksDB_FOUND)
	message("RocksDB found")
	if(ROCKSDB_USE_STATIC_LIBS)
		message("Using Static RocksDB lib")
		get_target_property(lib RocksDB::rocksdb LOCATION)
		message("RocksDB::rocksdb LOCATION: ${lib}")
		get_target_property(lib RocksDB::rocksdb LOCATION_DEBUG)
		message("RocksDB::rocksdb LOCATION_DEBUG: ${lib}")
		# use ROCKSDB_LIB variable for potential switching between rocksdb and rocksb-shared
		set(ROCKSDB_LIB RocksDB::rocksdb)
	else()
		message("Using Shared RocksDB lib")
		get_target_property(lib RocksDB::rocksdb-shared LOCATION)
		message("RocksDB::rocksdb-shared LOCATION: ${lib}")
		get_target_property(lib RocksDB::rocksdb-shared LOCATION_DEBUG)
		message("RocksDB::rocksdb-shared LOCATION_DEBUG: ${lib}")
	    set(ROCKSDB_LIB RocksDB::rocksdb-shared)
	endif()
	get_property(trans_deps TARGET ${ROCKSDB_LIB} PROPERTY INTERFACE_LINK_LIBRARIES)
	message("${ROCKSDB_LIB} transitive link dependencies: ${trans_deps}")
else()
	message("RocksDB not found")
endif(RocksDB_FOUND)

# src/smr_api bundles the static dependencies into a self-contained
# libsmr_api.a, and needs their paths. RocksDB::rocksdb and ZLIB::ZLIB are
# IMPORTED targets, which are scoped to the directory that created them, so
# resolve them to plain paths here and publish those to the parent (top level)
# scope - src/smr_api is added after this directory and inherits them. Both
# point at a prebuilt dist and are the same for every configuration.
# PARASAIL_LIB needs no publishing: find_library made it a cache entry.
if(RocksDB_FOUND)
	get_target_property(SMR_ROCKSDB_ARCHIVE ${ROCKSDB_LIB} LOCATION)
	set(SMR_ROCKSDB_ARCHIVE "${SMR_ROCKSDB_ARCHIVE}" PARENT_SCOPE)
endif()
if(ZLIB_FOUND)
	get_target_property(SMR_ZLIB_ARCHIVE ZLIB::ZLIB LOCATION)
	set(SMR_ZLIB_ARCHIVE "${SMR_ZLIB_ARCHIVE}" PARENT_SCOPE)
endif()

# fix RocksDBTargets.cmake, which makes both static and shared libraries always dependent on libz.so
if(ZLIB_LIBRARY_RELEASE)
	# modify the dependent libraries of the RocksDB::rocksdb target
	set_target_properties(RocksDB::rocksdb PROPERTIES
		INTERFACE_LINK_LIBRARIES "${ZLIB_LIBRARY_RELEASE};Threads::Threads"
	)
endif()

if(RocksDB_FOUND)
get_property(trans_deps TARGET RocksDB::rocksdb PROPERTY INTERFACE_LINK_LIBRARIES)
message("rocksdb transitive link dependencies AFTER modification: ${trans_deps}")
endif(RocksDB_FOUND)
#include(FindRapidJson)
 # prevent CONFIG search mode
#find_package(RapidJson MODULE REQUIRED)

# set additional compile flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wextra -Wall -Xlinker -v") # -Xlinker -v / --verbose (linked libraries info)   '-Wl,-Map,mapfile.txt'  '-Wl,-v'
#set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -v -da -Q") # for segfault
#                                                    |  |   |_show which function is causing the crash.
#                                                    |  |_dumps the RTL to a file after each stage
#                                                    |_show how the program was invoked
#set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -v -da -Q -O0") # for segfault
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-compare -Wshadow -Wno-unused-parameter -Wno-unused-variable -Woverloaded-virtual -Wnon-virtual-dtor -Wno-missing-field-initializers -Wno-strict-aliasing")

#set(MY_OPTS -g -Wall) # using quotes "-g -Wall" throws error
#target_compile_options(smr_objs PUBLIC ${MY_OPTS})
#target_compile_options(smr_objs PUBLIC "$<$<CONFIG:DEBUG>:${MY_OPTS}>")
#target_compile_options(smr_objs PUBLIC "$<$<CONFIG:RELEASE>:${MY_OPTS}>")
#set_target_properties(smr_objs PROPERTIES COMPILE_OPTIONS ${MY_OPTS})

set(SMR_SRCS
	alignment.cpp
	bitvector.cpp
	#callbacks.cpp
	cmd.cpp
	izlib.cpp
	index.cpp
	indexdb.cpp
	kseq_load.cpp
	kvdb.cpp
	options.cpp
	output.cpp
	summary.cpp
	paralleltraversal.cpp
	processor.cpp
	read.cpp
	readfeed.cpp
	readstats.cpp
	references.cpp
	refstats.cpp
	restart.cpp
	traverse_bursttrie.cpp
	util.cpp
	otumap.cpp
	report.cpp
	report_fx_base.cpp
	report_fastx.cpp
	report_fx_other.cpp
	report_blast.cpp
	report_denovo.cpp
	report_biom.cpp
	report_sam.cpp
	smr_log.cpp
)

# SMR Objects - build a separate library to use with Tests
add_library(smr_objs OBJECT ${SMR_SRCS})
target_link_libraries(smr_objs
	PUBLIC
		alp
		${ROCKSDB_LIB}
		ZLIB::ZLIB
		rapidgzip::rapidgzip
		${PARASAIL_LIB}
		#RapidJSON::RapidJSON
)
target_include_directories(smr_objs
	PUBLIC
		${CMAKE_SOURCE_DIR}/include
		${CMAKE_SOURCE_DIR}/3rdparty/bbhash
		${PARASAIL_INCLUDE_DIR}
)

get_property(trans_deps TARGET smr_objs PROPERTY INTERFACE_LINK_LIBRARIES)
message("SMR Objects transitive link dependencies: ${trans_deps}")

get_target_property(COMPILE_OPT smr_objs COMPILE_OPTIONS)
get_target_property(COMPILE_FLG smr_objs COMPILE_FLAGS)
message("SMR Objects COMPILE_OPT: ${COMPILE_OPT}  COMPILE_FLG: ${COMPILE_FLG}")

# SMR
add_executable(sortmerna main.cpp)
target_include_directories(sortmerna
	PRIVATE
		${CMAKE_SOURCE_DIR}/include
)
#get_property(rocksdb_trans_deps TARGET RocksDB::rocksdb PROPERTY INTERFACE_LINK_LIBRARIES)
#message("rocksdb_trans_deps: ${rocksdb_trans_deps}")
target_link_libraries(sortmerna
	build_version
	smr_objs
	alp # this is a transitive dependency of smr_objs but the linking fails without it. Why?
	${ROCKSDB_LIB}
	${CMAKE_DL_LIBS}
	# the following are all transitive dependencies of smr_objs i.e. no need to link:
	# RapidJSON::RapidJSON ZLIB::ZLIB Threads::Threads (rockdb deps)
)

if(PORTABLE)
	target_link_options(sortmerna PRIVATE -static)
endif(PORTABLE)
