cmake_minimum_required(VERSION 3.4.0)
project (faust)

#######################################
# Versions
set (VERSION 2.5.6)

get_filename_component(ROOT ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
set (SRCDIR ${ROOT}/compiler)
set (BINDIR ${CMAKE_CURRENT_SOURCE_DIR}/bin)
set (LIBDIR ${CMAKE_CURRENT_SOURCE_DIR}/lib)

set (CMAKE_CXX_STANDARD 11)


#######################################
# Output options
option ( UNIVERSAL 	"Compiles and combines i386 and x86_64 architectures [MacOS]"	off )

#######################################
# Check output options
if (UNIVERSAL AND NOT APPLE)
	message(WARNING "UNIVERSAL option is only available on MacOS or iOS")
endif()

####################################
# source and headers files
file (GLOB SRC ${SRCDIR}/*.cpp ${SRCDIR}/*/*.cpp ${SRCDIR}/draw/*/*.cpp ${SRCDIR}/generator/fir/*.cpp)
file (GLOB HH  ${SRCDIR}/*.hh  ${SRCDIR}/*/*.hh  ${SRCDIR}/generator/fir/*.hh)

####################################
# include directories
set (FAUST_INC ${SRCDIR} ${SRCDIR}/boxes ${SRCDIR}/documentator ${SRCDIR}/draw ${SRCDIR}/errors ${SRCDIR}/evaluate ${SRCDIR}/extended ${SRCDIR}/generator ${SRCDIR}/generator/fir ${SRCDIR}/generator/interpreter ${SRCDIR}/normalize ${SRCDIR}/parallelize ${SRCDIR}/parser ${SRCDIR}/patternmatcher ${SRCDIR}/propagate ${SRCDIR}/signals ${SRCDIR}/tlib ${SRCDIR}/utils  ${SRCDIR}/draw/device ${SRCDIR}/draw/schema ${SRCDIR}/../architecture /usr/local/include)


####################################
function(backend NAME DIR TARGET)
	message(STATUS "In target ${TARGET}: include ${NAME} backend")
	target_compile_definitions (${TARGET} PRIVATE -D${NAME}_BUILD)
	if (NOT "${DIR}" STREQUAL "")
		file (GLOB BACKEND_SRC	${SRCDIR}/generator/${DIR}/*.cpp ${SRCDIR}/generator/${DIR}/*.hh)
		target_sources (${TARGET} PRIVATE ${BACKEND_SRC})
		target_include_directories (${TARGET} PRIVATE ${SRCDIR}/generator/${DIR})
	endif()
endfunction()

####################################
function (scan_backends TARGET FLAG)
	string (FIND "${ASMJS_BACKEND}" ${FLAG} POS)
	if (${POS} GREATER -1)
		backend (ASMJS asmjs ${TARGET})
	endif()
	string (FIND "${C_BACKEND}" ${FLAG} POS)
	if (${POS} GREATER -1)
		backend (C c ${TARGET})
	endif()
	string (FIND "${CPP_BACKEND}" ${FLAG} POS)
	if (${POS} GREATER -1)
		backend (CPP cpp ${TARGET})
	endif()
	string (FIND "${FIR_BACKEND}" ${FLAG} POS)
	if (${POS} GREATER -1)
		backend (FIR "" ${TARGET})
	endif()
	string (FIND "${INTERP_BACKEND}" ${FLAG} POS)
	if (${POS} GREATER -1)
		backend (INTERP interpreter ${TARGET})
	endif()
	string (FIND "${JAVA_BACKEND}" ${FLAG} POS)
	if (${POS} GREATER -1)
		backend (JAVA java ${TARGET})
	endif()
	string (FIND "${JS_BACKEND}" ${FLAG} POS)
	if (${POS} GREATER -1)
		backend (JS js ${TARGET})
	endif()
	string (FIND "${OLDCPP_BACKEND}" ${FLAG} POS)
	if (${POS} GREATER -1)
		backend (OCPP "" ${TARGET})
	endif()
	string (FIND "${RUST_BACKEND}" ${FLAG} POS)
	if (${POS} GREATER -1)
		backend (RUST rust ${TARGET})
	endif()
	string (FIND "${WASM_BACKEND}" ${FLAG} POS)
	if (${POS} GREATER -1)
		backend (WASM wasm ${TARGET})
	endif()
	string (FIND "${LLVM_BACKEND}" ${FLAG} POS)
	if (${POS} GREATER -1)
		backend (LLVM llvm ${TARGET})
		target_compile_definitions (${TARGET} PRIVATE -D${LLVM_VERSION})
		target_include_directories (${TARGET} PRIVATE ${SRCDIR}/generator/c ${SRCDIR}/generator/cpp  ${LLVM_INCLUDE_DIRS})
	endif()
endfunction()

####################################
# LLVM
if (LLVM_BACKEND )
	if (WIN32 AND NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
		set (LLVM_CONFIG llvm-config.exe)
		execute_process (COMMAND ${LLVM_CONFIG} --version OUTPUT_VARIABLE LLVM_VERSION)
		string ( STRIP ${LLVM_VERSION} LLVM_PACKAGE_VERSION )
		message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")

		execute_process (COMMAND ${LLVM_CONFIG} --includedir OUTPUT_VARIABLE LLVM_INCLUDE)
		string ( STRIP ${LLVM_INCLUDE} LLVM_INCLUDE_DIRS )
		execute_process (COMMAND ${LLVM_CONFIG} --ldflags OUTPUT_VARIABLE LLVM_LDFLAGS_TMP)
		string ( STRIP ${LLVM_LDFLAGS_TMP} LLVM_LD_FLAGS )
		execute_process (COMMAND ${LLVM_CONFIG}  --libs OUTPUT_VARIABLE LLVM_LIBS_TMP)
		string ( STRIP ${LLVM_LIBS_TMP} LLVM_LIBS )
	else()
		find_package(LLVM REQUIRED CONFIG)
		message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
		message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
		# Find the libraries that correspond to the LLVM components that we wish to use
		llvm_map_components_to_libnames(LLVM_LIBS all)
	endif()

	string (REGEX REPLACE "([0-9])\\.([0-9]).*" "LLVM_\\1\\2" LLVM_VERSION ${LLVM_PACKAGE_VERSION})

	# the declarations below are redundant but necessary to cope with different cmake behaviors on different platforms
	set_property(SOURCE ${SRCDIR}/generator/llvm/llvm_dsp_aux.cpp APPEND_STRING PROPERTY COMPILE_FLAGS   "-fno-rtti ${LLVM_DEFINITIONS}")
	set_property(SOURCE ${SRCDIR}/generator/llvm/llvm_dsp_aux.cpp APPEND_STRING PROPERTY CMAKE_CXX_FLAGS "-fno-rtti ${LLVM_DEFINITIONS}")
	set (FAUST_LIBS ${FAUST_LIBS} ${LLVM_LD_FLAGS} ${LLVM_LIBS} )
endif()

####################################
# platform dependent settings
if(APPLE)
	if (UNIVERSAL)
		message (STATUS "Compiles an universal binary")
		set (CMAKE_OSX_ARCHITECTURES "x86_64 i386")
	endif()
elseif(WIN32)
	if (NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
		set (FAUST_DEFINITIONS ${FAUST_DEFINITIONS} -DWIN32 -D__MINGW32__)
	endif()
	set (FAUST_LIBS ${FAUST_LIBS} Ws2_32.lib)
else()
	set (FAUST_LIBS -lpthread ${FAUST_LIBS})
endif()

####################################
# add backends src and headers
#set (SRC ${SRC} ${BACKEND_SRC})
#set (HH  ${HH} ${BACKEND_H})

####################################
# Add the different targets
add_executable(faust ${SRC} ${HH})
set_target_properties(faust  PROPERTIES 
	RUNTIME_OUTPUT_DIRECTORY_RELEASE ${BINDIR})

add_library(staticlib STATIC EXCLUDE_FROM_ALL ${SRC} ${HH})
set_target_properties(staticlib PROPERTIES ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${LIBDIR})

add_library(dynamiclib SHARED EXCLUDE_FROM_ALL ${SRC} ${HH})
if (WIN32)
	set_target_properties(dynamiclib PROPERTIES 
		ARCHIVE_OUTPUT_DIRECTORY_RELEASE  ${LIBDIR}
		RUNTIME_OUTPUT_DIRECTORY_RELEASE  ${LIBDIR})
	set_target_properties(staticlib  PROPERTIES OUTPUT_NAME libfaust)
	set_target_properties(dynamiclib PROPERTIES OUTPUT_NAME faust)
else()
	set_target_properties(dynamiclib staticlib PROPERTIES OUTPUT_NAME faust)
	set_target_properties(dynamiclib PROPERTIES LIBRARY_OUTPUT_DIRECTORY_RELEASE ${LIBDIR})
endif()
set_target_properties(dynamiclib  staticlib PROPERTIES COMPILE_FLAGS  -DFAUST_LIB)

foreach (TARGET faust staticlib dynamiclib)
	target_compile_definitions (${TARGET} PRIVATE ${FAUST_DEFINITIONS})
	target_include_directories (${TARGET} PRIVATE ${FAUST_INC} ${LLVM_INC})
	target_link_libraries (${TARGET} PRIVATE ${FAUST_LIBS})
endforeach()

scan_backends (faust COMPILER)
scan_backends (staticlib STATIC)
scan_backends (dynamiclib DYNAMIC)

####################################
if (NOT (${CMAKE_GENERATOR} STREQUAL Xcode OR ${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC))
	add_subdirectory (emcc)
else()
	message ("WARNING Targets asmjslib and wasmlib are not included with Xcode or Visual Studio")
endif()
