# CMake project file by Prakash Punnoor
CMAKE_MINIMUM_REQUIRED(VERSION 2.4)

SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMakeModules")
Project(Aften C)

SET(SO_MAJOR_VERSION "0")
SET(SO_MINOR_VERSION "0")
SET(SO_BUILD_VERSION "8")
SET(SO_VERSION "${SO_MAJOR_VERSION}.${SO_MINOR_VERSION}.${SO_BUILD_VERSION}")

IF(${Aften_SOURCE_DIR} MATCHES ${Aften_BINARY_DIR})
  MESSAGE("Please do an out-of-tree build:")
  MESSAGE("rm -f CMakeCache.txt; mkdir -p default; cd default; cmake ..; make")
  MESSAGE(FATAL_ERROR "in-tree-build detected")
ENDIF(${Aften_SOURCE_DIR} MATCHES ${Aften_BINARY_DIR})

INCLUDE(${CMAKE_ROOT}/Modules/TestBigEndian.cmake)
INCLUDE(${CMAKE_ROOT}/Modules/CheckCSourceCompiles.cmake)
INCLUDE(${CMAKE_MODULE_PATH}/ConfigHelper.cmake)
INCLUDE(${CMAKE_MODULE_PATH}/HeaderTests.cmake)
INCLUDE(${CMAKE_MODULE_PATH}/FlagsTests.cmake)
INCLUDE(${CMAKE_MODULE_PATH}/CompilerVisibility.cmake)
INCLUDE(${CMAKE_MODULE_PATH}/CompilerSIMD.cmake)
INCLUDE(${CMAKE_MODULE_PATH}/DetectCompiler.cmake)

OPTION(SHARED "build shared Aften library" OFF)
OPTION(DOUBLE "build Aften with doubles instead of floats" OFF)
IF(DOUBLE)
  ADD_DEFINE(CONFIG_DOUBLE)
ENDIF(DOUBLE)
OPTION(BINDINGS_CXX "build C++ bindings" OFF)
IF(BINDINGS_CXX)
  SET(SHARED ON CACHE BOOL "build shared Aften library" FORCE)
ENDIF(BINDINGS_CXX)

INCLUDE_DIRECTORIES(${Aften_BINARY_DIR}/)
INCLUDE_DIRECTORIES(${Aften_SOURCE_DIR}/)
INCLUDE_DIRECTORIES(${Aften_SOURCE_DIR}/libaften)
INCLUDE_DIRECTORIES(${Aften_SOURCE_DIR}/aften)
INCLUDE_DIRECTORIES(${Aften_SOURCE_DIR}/pcm)

SET(LIBAFTEN_SRCS libaften/a52enc.c
                  libaften/bitalloc.c
                  libaften/bitio.c
                  libaften/crc.c
                  libaften/dynrng.c
                  libaften/window.c
                  libaften/mdct.c
                  libaften/exponent.c
                  libaften/filter.c
                  libaften/util.c)

SET(LIBAFTEN_X86_SRCS libaften/x86/x86_cpu_caps.c)

SET(LIBAFTEN_X86_MMX_SRCS libaften/x86/x86_mmx_exponent.c)

SET(LIBAFTEN_X86_SSE_SRCS libaften/x86/x86_sse_mdct_dummy.c
                          libaften/x86/x86_sse_mdct_common_init.c
                          libaften/x86/x86_sse_window.c)

SET(LIBAFTEN_X86_SSE2_SRCS libaften/x86/x86_sse2_exponent.c)

SET(LIBAFTEN_X86_SSE3_SRCS libaften/x86/x86_sse3_mdct_dummy.c)

SET(LIBAFTEN_PPC_SRCS libaften/ppc/ppc_cpu_caps.c)
SET(LIBAFTEN_ALTIVEC_SRCS libaften/ppc/mdct_altivec.c)

SET(AFTEN_SRCS aften/aften.c aften/opts.c)

SET(PCM_SRCS pcm/byteio.c
             pcm/convert.c
             pcm/pcm.c
             pcm/raw.c
             pcm/wav.c)


IF(CMAKE_UNAME)
  EXEC_PROGRAM(uname ARGS -m OUTPUT_VARIABLE CMAKE_SYSTEM_MACHINE)
ELSE(CMAKE_UNAME)
  MESSAGE("Could not detect machine type")
  IF(CMAKE_SYSTEM MATCHES "Windows")
    MESSAGE(STATUS "Assuming i386 machine")
    SET(CMAKE_SYSTEM_MACHINE i386)
  ENDIF(CMAKE_SYSTEM MATCHES "Windows")
ENDIF(CMAKE_UNAME)

DETECT_COMPILER()

CHECK_64BITS()

IF(CMAKE_COMPILER_IS_GNUCC)
  SET(CMAKE_C_FLAGS_RELEASE "-funroll-loops -fomit-frame-pointer ${CMAKE_C_FLAGS_RELEASE}")
  SET(ADD_CFLAGS "-pedantic -Wall -Wpointer-arith -Wredundant-decls -Wformat -Wunused ${ADD_CFLAGS}")

  # gcc 2.9.5 doesn't know following
  CHECK_CFLAGS_APPEND(ADD_EXCLUSIVE_CFLAGS "-std=gnu99")
  CHECK_CFLAGS_APPEND(ADD_CFLAGS "-Wdisabled-optimization")
  CHECK_CFLAGS_APPEND(ADD_CFLAGS "-Wfloat-equal")
  CHECK_CFLAGS_APPEND(ADD_EXCLUSIVE_CFLAGS "-Wbad-function-cast")

  # gcc 3.0 doesn't know following
  CHECK_CFLAGS_APPEND(ADD_EXCLUSIVE_CFLAGS "-Wdeclaration-after-statement")
  CHECK_CFLAGS_APPEND(ADD_CFLAGS "-Wextra")
  CHECK_CFLAGS_APPEND(ADD_CFLAGS "-Wno-switch")

  # gcc 4.1 doesn't know following
  CHECK_CFLAGS_APPEND(ADD_CFLAGS "-Wstrict-overflow")
ENDIF(CMAKE_COMPILER_IS_GNUCC)

IF(CMAKE_COMPILER_IS_ICC)
  # icc ignores bogus options, so detection makes no sense
  SET(CMAKE_C_FLAGS_RELEASE "-O3 -funroll-loops -fomit-frame-pointer ${CMAKE_C_FLAGS_RELEASE}")
  SET(ADD_CFLAGS "-std=c99 -Wall ${ADD_CFLAGS}")
ENDIF(CMAKE_COMPILER_IS_ICC)

IF(MSVC)
  # msvc ignores bogus options, so detection makes no sense
  SET(CMAKE_C_FLAGS_RELEASE "/Ot /Oy /Oi /Ox ${CMAKE_C_FLAGS_RELEASE}")
  ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE)
ENDIF(MSVC)

IF(CMAKE_BUILD_TYPE MATCHES "")
  SET(CMAKE_BUILD_TYPE "Release")
ENDIF(CMAKE_BUILD_TYPE MATCHES "")

TEST_BIG_ENDIAN(CMAKE_WORDS_BIGENDIAN)
IF(CMAKE_WORDS_BIGENDIAN)
  ADD_DEFINE(WORDS_BIGENDIAN)
ENDIF(CMAKE_WORDS_BIGENDIAN)

IF(UNIX)
  SET(LIBM "m")

  TEST_COMPILER_VISIBILITY()

  IF(APPLE)
    ADD_DEFINE(SYS_DARWIN)
  ELSE(APPLE)
    CHECK_FUNCTION_DEFINE("#include <sys/sysinfo.h>" "get_nprocs" "()" HAVE_GET_NPROCS)

    IF(NOT HAVE_GET_NPROCS)
      MESSAGE(STATUS "Hardcoding 2 threads usage")
      ADD_DEFINE("NUM_THREADS 2")
    ENDIF(NOT HAVE_GET_NPROCS)
  ENDIF(APPLE)
ENDIF(UNIX)

# threads handling
FIND_PACKAGE(Threads)
IF(CMAKE_USE_WIN32_THREADS_INIT)
  ADD_DEFINE(HAVE_WINDOWS_THREADS)
  IF(MINGW)
    ADD_DEFINE(MINGW_ALIGN_STACK_HACK)
  ENDIF(MINGW)
ELSE(CMAKE_USE_WIN32_THREADS_INIT)

IF(CMAKE_USE_PTHREADS_INIT)
  ADD_DEFINE(HAVE_POSIX_THREADS)
  SET(ADD_LIBS ${ADD_LIBS} ${CMAKE_THREAD_LIBS_INIT})
ENDIF(CMAKE_USE_PTHREADS_INIT)
ENDIF(CMAKE_USE_WIN32_THREADS_INIT)

ADD_DEFINE("MAX_NUM_THREADS 32")

ADD_DEFINITIONS(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)

CHECK_INCLUDE_FILE_DEFINE(inttypes.h HAVE_INTTYPES_H)
CHECK_INCLUDE_FILE_DEFINE(byteswap.h HAVE_BYTESWAP_H)

# output SVN version to config.h
EXECUTE_PROCESS(COMMAND svn info --xml WORKING_DIRECTORY ${Aften_SOURCE_DIR}
OUTPUT_VARIABLE SVN_INFO ERROR_QUIET)
STRING(REGEX MATCH "<entry[^>]+" SVN_VERSION "${SVN_INFO}")
STRING(REGEX MATCH "revision=\"[0123456789]+\"" SVN_VERSION "${SVN_VERSION}")
STRING(REGEX MATCH "[0123456789]+" SVN_VERSION "${SVN_VERSION}")
IF(SVN_VERSION)
  ADD_DEFINE("SVN_VERSION \"${SVN_VERSION}\"")
ENDIF(SVN_VERSION)

# do SIMD stuff
IF(CMAKE_SYSTEM_MACHINE MATCHES "i.86" OR CMAKE_SYSTEM_MACHINE MATCHES "x86_64")
  CHECK_MMX()

  IF(HAVE_MMX)
    INCLUDE_DIRECTORIES(${Aften_SOURCE_DIR}/libaften/x86)
    SET(LIBAFTEN_SRCS ${LIBAFTEN_SRCS} ${LIBAFTEN_X86_SRCS})
    ADD_DEFINE(HAVE_CPU_CAPS_DETECTION)

    CHECK_SSE()
    SET(LIBAFTEN_SRCS ${LIBAFTEN_SRCS} ${LIBAFTEN_X86_MMX_SRCS})
      FOREACH(SRC ${LIBAFTEN_X86_MMX_SRCS})
        SET_SOURCE_FILES_PROPERTIES(${SRC} PROPERTIES COMPILE_FLAGS "${MMX_FLAGS} -DUSE_MMX")
      ENDFOREACH(SRC)
    ADD_DEFINE(HAVE_MMX)

    IF(HAVE_SSE)
      CHECK_SSE2()
      IF(NOT DOUBLE)
      SET(LIBAFTEN_SRCS ${LIBAFTEN_SRCS} ${LIBAFTEN_X86_SSE_SRCS})
      FOREACH(SRC ${LIBAFTEN_X86_SSE_SRCS})
        SET_SOURCE_FILES_PROPERTIES(${SRC} PROPERTIES COMPILE_FLAGS "${SSE_FLAGS} -DUSE_MMX -DUSE_SSE")
      ENDFOREACH(SRC)
      ENDIF(NOT DOUBLE)
      ADD_DEFINE(HAVE_SSE)

      CHECK_MM_MALLOC()
      IF(NOT HAVE_MM_MALLOC)
        CHECK_POSIX_MEMALIGN()
      ENDIF(NOT HAVE_MM_MALLOC)
    ENDIF(HAVE_SSE)

    IF(HAVE_SSE2)
      CHECK_SSE3()
      SET(LIBAFTEN_SRCS ${LIBAFTEN_SRCS} ${LIBAFTEN_X86_SSE2_SRCS})
      FOREACH(SRC ${LIBAFTEN_X86_SSE2_SRCS})
        SET_SOURCE_FILES_PROPERTIES(${SRC} PROPERTIES COMPILE_FLAGS "${SSE2_FLAGS} -DUSE_MMX -DUSE_SSE -DUSE_SSE2")
      ENDFOREACH(SRC)
      ADD_DEFINE(HAVE_SSE2)
    ENDIF(HAVE_SSE2)

    IF(HAVE_SSE3)
      IF(NOT DOUBLE)
      SET(LIBAFTEN_SRCS ${LIBAFTEN_SRCS} ${LIBAFTEN_X86_SSE3_SRCS})
      FOREACH(SRC ${LIBAFTEN_X86_SSE3_SRCS})
        SET_SOURCE_FILES_PROPERTIES(${SRC} PROPERTIES COMPILE_FLAGS "${SSE3_FLAGS} -DUSE_MMX -DUSE_SSE -DUSE_SSE2 -DUSE_SSE3")
      ENDFOREACH(SRC)
      ENDIF(NOT DOUBLE)
      ADD_DEFINE(HAVE_SSE3)

      CHECK_CASTSI128()
    ENDIF(HAVE_SSE3)
  ENDIF(HAVE_MMX)
ENDIF(CMAKE_SYSTEM_MACHINE MATCHES "i.86" OR CMAKE_SYSTEM_MACHINE MATCHES "x86_64")

IF(CMAKE_SYSTEM_MACHINE MATCHES "Power Macintosh" OR CMAKE_SYSTEM_MACHINE MATCHES "ppc")
  CHECK_ALTIVEC()

  IF(HAVE_ALTIVEC AND NOT DOUBLE)
    INCLUDE_DIRECTORIES(${Aften_SOURCE_DIR}/libaften/ppc)
    SET(LIBAFTEN_SRCS ${LIBAFTEN_SRCS} ${LIBAFTEN_PPC_SRCS})
    SET(LIBAFTEN_SRCS ${LIBAFTEN_SRCS} ${LIBAFTEN_ALTIVEC_SRCS})
    FOREACH(SRC ${LIBAFTEN_ALTIVEC_SRCS})
      SET_SOURCE_FILES_PROPERTIES(${SRC} PROPERTIES COMPILE_FLAGS "-maltivec")
    ENDFOREACH(SRC)
    ADD_DEFINE(HAVE_ALTIVEC)

  ENDIF(HAVE_ALTIVEC AND NOT DOUBLE)
ENDIF(CMAKE_SYSTEM_MACHINE MATCHES "Power Macintosh" OR CMAKE_SYSTEM_MACHINE MATCHES "ppc")


GENERATE_CONFIG_H()

SET(CMAKE_C_FLAGS "${ADD_CFLAGS} ${ADD_EXCLUSIVE_CFLAGS} ${CMAKE_C_FLAGS}")

IF(SHARED)
  ADD_LIBRARY(aften SHARED ${LIBAFTEN_SRCS})
  SET_TARGET_PROPERTIES(aften PROPERTIES VERSION ${SO_VERSION} SOVERSION ${SO_MAJOR_VERSION})
  SET_TARGET_PROPERTIES(aften PROPERTIES LINKER_LANGUAGE C)
  SET_TARGET_PROPERTIES(aften PROPERTIES DEFINE_SYMBOL AFTEN_BUILD_LIBRARY)
  TARGET_LINK_LIBRARIES(aften ${LIBM} ${ADD_LIBS})
  SET(INSTALL_TARGETS ${INSTALL_TARGETS} aften)
ENDIF(SHARED)

ADD_LIBRARY(aften_static STATIC ${LIBAFTEN_SRCS})
#SET_TARGET_PROPERTIES(aften_static PROPERTIES OUTPUT_NAME aften)
SET_TARGET_PROPERTIES(aften_static PROPERTIES LINKER_LANGUAGE C)
SET_TARGET_PROPERTIES(aften_static PROPERTIES COMPILE_FLAGS -DAFTEN_BUILD_LIBRARY)
TARGET_LINK_LIBRARIES(aften_static ${LIBM} ${ADD_LIBS})

# building a separate static lib for the pcm audio decoder
ADD_LIBRARY(aften_pcm STATIC ${PCM_SRCS})

ADD_EXECUTABLE(aften_exe ${AFTEN_SRCS})
SET_TARGET_PROPERTIES(aften_exe PROPERTIES OUTPUT_NAME aften)
SET_TARGET_PROPERTIES(aften_exe PROPERTIES LINKER_LANGUAGE C)
IF(WIN32)
  # When linking to static aften, dllimport mustn't be used
  SET_TARGET_PROPERTIES(aften_exe PROPERTIES COMPILE_FLAGS -DAFTEN_BUILD_LIBRARY)
ENDIF(WIN32)
TARGET_LINK_LIBRARIES(aften_exe aften_pcm aften_static)

ADD_EXECUTABLE(wavinfo util/wavinfo.c)
TARGET_LINK_LIBRARIES(wavinfo aften_pcm)

ADD_EXECUTABLE(wavrms util/wavrms.c)
TARGET_LINK_LIBRARIES(wavrms aften_pcm ${LIBM})

ADD_EXECUTABLE(wavfilter util/wavfilter.c libaften/filter.c)
TARGET_LINK_LIBRARIES(wavfilter aften_pcm ${LIBM})

IF(BINDINGS_CXX)
  MESSAGE("## WARNING: The C++ bindings are only lightly tested. Feed-back appreciated. ##")
  Project(Aften CXX)
  SET(CMAKE_CXX_FLAGS_RELEASE "${ADD_CFLAGS} ${CMAKE_C_FLAGS_RELEASE}")
  INCLUDE_DIRECTORIES(${Aften_SOURCE_DIR}/bindings)
  ADD_LIBRARY(aftenxx SHARED bindings/aftenxx.cxx)
  SET_TARGET_PROPERTIES(aftenxx PROPERTIES VERSION ${SO_VERSION} SOVERSION ${SO_MAJOR_VERSION})
  SET_TARGET_PROPERTIES(aftenxx PROPERTIES LINKER_LANGUAGE CXX)
  SET_TARGET_PROPERTIES(aftenxx PROPERTIES DEFINE_SYMBOL AFTENXX_BUILD_LIBRARY)
  TARGET_LINK_LIBRARIES(aftenxx aften)
  SET(INSTALL_TARGETS ${INSTALL_TARGETS} aftenxx)
  SET(INSTALL_HEADERS ${INSTALL_HEADERS} bindings/aftenxx.h)
ENDIF(BINDINGS_CXX)

INSTALL(TARGETS ${INSTALL_TARGETS} aften_exe wavinfo wavrms wavfilter
        RUNTIME DESTINATION bin
        LIBRARY DESTINATION lib
        ARCHIVE DESTINATION lib)
INSTALL(FILES ${INSTALL_HEADERS} libaften/aften.h libaften/aften-types.h DESTINATION include/aften)
