Adding CMake support for Windows, Mac, Linux and Android Co-Authored-By: evpobr

Signed-off-by: Jean-Marc Valin <jmvalin@jmvalin.ca>
diff --git a/.gitignore b/.gitignore
index eccd0a2..31e2901 100644
--- a/.gitignore
+++ b/.gitignore
@@ -83,3 +83,7 @@
 src/Debug
 src/Release
 src/x64
+/*[Bb]uild*/
+.vs/
+.vscode/
+CMakeSettings.json
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..18b1e8d
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,363 @@
+cmake_minimum_required(VERSION 3.1)
+
+include(opus_functions.cmake)
+
+get_library_version(OPUS_LIBRARY_VERSION OPUS_LIBRARY_VERSION_MAJOR)
+message(STATUS "Opus library version: ${OPUS_LIBRARY_VERSION}")
+
+get_package_version(PACKAGE_VERSION)
+message(STATUS "Opus package version: ${PACKAGE_VERSION}")
+
+string(REGEX
+       REPLACE "^([0-9]+.[0-9]+\\.?([0-9]+)?).*"
+               "\\1"
+               PROJECT_VERSION
+               ${PACKAGE_VERSION})
+message(STATUS "Opus project version: ${PROJECT_VERSION}")
+
+project(Opus LANGUAGES C VERSION ${PROJECT_VERSION})
+
+option(OPUS_FIXED_POINT
+       "Compile as fixed-point (for machines without a fast enough FPU)" OFF)
+option(OPUS_ENABLE_FLOAT_API
+       "Compile with the floating point API (for machines with float library"
+       ON)
+option(OPUS_INSTALL_PKG_CONFIG_MODULE "Install PkgConfig module" ON)
+option(OPUS_INSTALL_CMAKE_CONFIG_MODULE "Install CMake package config module"
+       ON)
+
+include(opus_config.cmake)
+include(opus_sources.cmake)
+include(GNUInstallDirs)
+include(CMakeDependentOption)
+include(FeatureSummary)
+
+if(OPUS_CPU_X86 OR OPUS_CPU_X64)
+  cmake_dependent_option(OPUS_X86_MAY_HAVE_SSE
+                         "Does runtime check for SSE1 support"
+                         ON
+                         "SSE1_SUPPORTED"
+                         OFF)
+  cmake_dependent_option(OPUS_X86_MAY_HAVE_SSE2
+                         "Does runtime check for SSE2 support"
+                         ON
+                         "SSE2_SUPPORTED"
+                         OFF)
+  cmake_dependent_option(OPUS_X86_MAY_HAVE_SSE4_1
+                         "Does runtime check for SSE4.1 support"
+                         ON
+                         "SSE4_1_SUPPORTED"
+                         OFF)
+  cmake_dependent_option(OPUS_X86_MAY_HAVE_AVX
+                         "Does runtime check for AVX support"
+                         ON
+                         "AVX_SUPPORTED"
+                         OFF)
+
+  if(OPUS_CPU_X64) # Assume 64 bit has SSE2 support
+    cmake_dependent_option(OPUS_X86_PRESUME_SSE
+                           "Assume target CPU has SSE1 support"
+                           ON
+                           "OPUS_X86_MAY_HAVE_SSE"
+                           OFF)
+    cmake_dependent_option(OPUS_X86_PRESUME_SSE2
+                           "Assume target CPU has SSE2 support"
+                           ON
+                           "OPUS_X86_MAY_HAVE_SSE2"
+                           OFF)
+  else()
+    cmake_dependent_option(OPUS_X86_PRESUME_SSE
+                           "Assume target CPU has SSE1 support"
+                           OFF
+                           "OPUS_X86_MAY_HAVE_SSE"
+                           OFF)
+    cmake_dependent_option(OPUS_X86_PRESUME_SSE2
+                           "Assume target CPU has SSE2 support"
+                           OFF
+                           "OPUS_X86_MAY_HAVE_SSE2"
+                           OFF)
+  endif()
+  cmake_dependent_option(OPUS_X86_PRESUME_SSE4_1
+                         "Assume target CPU has SSE4.1 support"
+                         OFF
+                         "OPUS_X86_MAY_HAVE_SSE4_1"
+                         OFF)
+  cmake_dependent_option(OPUS_X86_PRESUME_AVX
+                         "Assume target CPU has AVX support"
+                         OFF
+                         "OPUS_X86_MAY_HAVE_AVX"
+                         OFF)
+endif()
+
+set_package_properties(Git
+                       PROPERTIES
+                       TYPE
+                       REQUIRED
+                       DESCRIPTION
+                       "fast, scalable, distributed revision control system"
+                       URL
+                       "https://git-scm.com/"
+                       PURPOSE
+                       "required to set up package version")
+
+add_feature_info(
+  FIXED_POINT OPUS_FIXED_POINT
+  "compile as fixed-point (for machines without a fast enough FPU)")
+add_feature_info(
+  FLOAT_API OPUS_ENABLE_FLOAT_API
+  "compile with the floating point API (for machines with float library)")
+
+add_feature_info(INSTALL_PKG_CONFIG_MODULE OPUS_INSTALL_PKG_CONFIG_MODULE
+                 "install PkgConfig module")
+add_feature_info(INSTALL_CMAKE_CONFIG_MODULE OPUS_INSTALL_CMAKE_CONFIG_MODULE
+                 "install CMake package config module")
+
+if(OPUS_CPU_X86 OR OPUS_CPU_X64)
+  add_feature_info(X86_MAY_HAVE_SSE OPUS_X86_MAY_HAVE_SSE
+                   "does runtime check for SSE1 support")
+  add_feature_info(X86_MAY_HAVE_SSE2 OPUS_X86_MAY_HAVE_SSE2
+                   "does runtime check for SSE2 support")
+  add_feature_info(X86_MAY_HAVE_SSE4_1 OPUS_X86_MAY_HAVE_SSE4_1
+                   "does runtime check for SSE4_1 support")
+  add_feature_info(X86_MAY_HAVE_AVX OPUS_X86_MAY_HAVE_AVX
+                   "does runtime check for AVX support")
+  add_feature_info(X86_PRESUME_SSE OPUS_X86_PRESUME_SSE
+                   "assume target CPU has SSE1 support")
+  add_feature_info(X86_PRESUME_SSE2 OPUS_X86_PRESUME_SSE2
+                   "assume target CPU has SSE2 support")
+  add_feature_info(X86_PRESUME_SSE4_1 OPUS_X86_PRESUME_SSE4_1
+                   "assume target CPU has SSE4_1 support")
+  add_feature_info(X86_PRESUME_AVX OPUS_X86_PRESUME_AVX
+                   "assume target CPU has AVX support")
+endif()
+
+feature_summary(WHAT ALL)
+
+add_library(opus ${opus_sources} ${opus_sources_float})
+
+set(Opus_PUBLIC_HEADER
+    ${CMAKE_CURRENT_SOURCE_DIR}/include/opus.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_custom.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_defines.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_multistream.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_projection.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_types.h)
+
+set_target_properties(opus
+                      PROPERTIES SOVERSION
+                                 ${OPUS_LIBRARY_VERSION_MAJOR}
+                                 VERSION
+                                 ${OPUS_LIBRARY_VERSION}
+                                 PUBLIC_HEADER
+                                 "${Opus_PUBLIC_HEADER}")
+
+target_include_directories(
+  opus
+  PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+         $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
+          ${CMAKE_CURRENT_SOURCE_DIR}
+          celt
+          silk)
+
+target_link_libraries(opus PRIVATE ${OPUS_REQUIRED_LIBRARIES})
+
+target_compile_definitions(opus PRIVATE CUSTOM_MODES OPUS_BUILD)
+
+if(BUILD_SHARED_LIBS)
+  if(WIN32)
+    target_compile_definitions(opus PRIVATE DLL_EXPORT)
+  else()
+    include(CheckCCompilerFlag)
+    check_c_compiler_flag(-fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY)
+    if(COMPILER_HAS_HIDDEN_VISIBILITY)
+      set_target_properties(opus PROPERTIES C_VISIBILITY_PRESET hidden)
+    endif()
+  endif()
+endif()
+
+add_sources_group(opus silk ${silk_sources})
+add_sources_group(opus celt ${celt_sources})
+
+if(OPUS_FIXED_POINT)
+  add_sources_group(opus silk ${silk_sources_fixed})
+  target_include_directories(opus PRIVATE silk/fixed)
+  target_compile_definitions(opus PRIVATE FIXED_POINT=1)
+else()
+  add_sources_group(opus silk ${silk_sources_float})
+  target_include_directories(opus PRIVATE silk/float)
+endif()
+
+if(NOT OPUS_ENABLE_FLOAT_API)
+  target_compile_definitions(opus PRIVATE DISABLE_FLOAT_API)
+endif()
+
+if(OPUS_X86_MAY_HAVE_SSE
+   OR OPUS_X86_MAY_HAVE_SSE2
+   OR OPUS_X86_MAY_HAVE_SSE4_1
+   OR OPUS_X86_MAY_HAVE_AVX)
+  target_compile_definitions(opus PRIVATE OPUS_HAVE_RTCD)
+endif()
+
+if(OPUS_X86_MAY_HAVE_SSE)
+  add_sources_group(opus celt ${celt_sources_sse})
+  target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_SSE)
+endif()
+if(OPUS_X86_PRESUME_SSE)
+  target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_SSE)
+endif()
+
+if(OPUS_X86_MAY_HAVE_SSE2)
+  add_sources_group(opus celt ${celt_sources_sse2})
+  target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_SSE2)
+endif()
+if(OPUS_X86_PRESUME_SSE2)
+  target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_SSE2)
+endif()
+
+if(OPUS_X86_MAY_HAVE_SSE)
+  add_sources_group(opus celt ${celt_sources_sse4_1})
+  add_sources_group(opus silk ${silk_sources_sse4_1})
+  if(OPUS_FIXED_POINT)
+    add_sources_group(opus silk ${silk_sources_fixed_sse4_1})
+  endif()
+  target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_SSE4_1)
+endif()
+if(OPUS_X86_PRESUME_SSE4_1)
+  target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_SSE4_1)
+endif()
+
+if(CMAKE_SYSTEM_PROCESSOR MATCHES "(armv7-a)")
+  add_sources_group(opus celt ${celt_sources_arm})
+endif()
+
+if(COMPILER_SUPPORT_NEON AND OPUS_USE_NEON)
+
+  if(OPUS_MAY_HAVE_NEON)
+    if(RUNTIME_CPU_CAPABILITY_DETECTION)
+      message(STATUS "OPUS_MAY_HAVE_NEON enabling runtime detection")
+      target_compile_definitions(opus PRIVATE OPUS_HAVE_RTCD)
+    else()
+      message(ERROR "Runtime cpu capability detection needed for MAY_HAVE_NEON")
+    endif()
+    # Do runtime check for NEON
+    target_compile_definitions(opus
+                               PRIVATE
+                               OPUS_ARM_MAY_HAVE_NEON
+                               OPUS_ARM_MAY_HAVE_NEON_INTR)
+  endif()
+
+  add_sources_group(opus celt ${celt_sources_arm_neon_intr})
+  add_sources_group(opus silk ${silk_sources_arm_neon_intr})
+
+  # silk arm neon depends on main_Fix.h
+  target_include_directories(opus PRIVATE silk/fixed)
+
+  if(OPUS_FIXED_POINT)
+    add_sources_group(opus silk ${silk_sources_fixed_arm_neon_intr})
+  endif()
+
+  if(OPUS_PRESUME_NEON)
+    target_compile_definitions(opus
+                               PRIVATE
+                               OPUS_ARM_PRESUME_NEON
+                               OPUS_ARM_PRESUME_NEON_INTR)
+  endif()
+endif()
+
+install(TARGETS opus
+        EXPORT OpusTargets
+        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+        PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/opus)
+
+if(OPUS_INSTALL_PKG_CONFIG_MODULE)
+  set(prefix ${CMAKE_INSTALL_PREFIX})
+  set(exec_prefix ${CMAKE_INSTALL_PREFIX})
+  set(libdir ${CMAKE_INSTALL_FULL_LIBDIR})
+  set(includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR})
+  set(VERSION ${OPUS_LIBRARY_VERSION})
+  set(VERSION ${OPUS_LIBRARY_VERSION})
+  if(HAVE_LIBM)
+    set(LIBM "-lm")
+  endif()
+  configure_file(opus.pc.in opus.pc)
+  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/opus.pc
+          DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+endif()
+
+if(OPUS_INSTALL_CMAKE_CONFIG_MODULE)
+  set(CMAKE_INSTALL_PACKAGEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
+  install(EXPORT OpusTargets
+          NAMESPACE Opus::
+          DESTINATION ${CMAKE_INSTALL_PACKAGEDIR})
+
+  include(CMakePackageConfigHelpers)
+
+  set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
+  configure_package_config_file(OpusConfig.cmake.in
+                                OpusConfig.cmake
+                                INSTALL_DESTINATION
+                                ${CMAKE_INSTALL_PACKAGEDIR}
+                                PATH_VARS
+                                INCLUDE_INSTALL_DIR
+                                INSTALL_PREFIX
+                                ${CMAKE_INSTALL_PREFIX})
+  write_basic_package_version_file(OpusConfigVersion.cmake
+                                   VERSION ${PROJECT_VERSION}
+                                   COMPATIBILITY SameMajorVersion)
+  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/OpusConfig.cmake
+                ${CMAKE_CURRENT_BINARY_DIR}/OpusConfigVersion.cmake
+          DESTINATION ${CMAKE_INSTALL_PACKAGEDIR})
+endif()
+
+if(BUILD_PROGRAMS)
+  # demo
+  add_executable(opus_demo ${opus_demo_sources})
+  target_include_directories(opus_demo PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+  target_link_libraries(opus_demo PRIVATE opus)
+
+  # compare
+  add_executable(opus_compare ${opus_compare_sources})
+  target_include_directories(opus_compare PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+  target_link_libraries(opus_compare PRIVATE opus)
+endif()
+
+if(BUILD_TESTING)
+  enable_testing()
+
+  # tests
+  add_executable(test_opus_decode ${test_opus_decode_sources})
+  target_include_directories(test_opus_decode
+                             PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+  target_link_libraries(test_opus_decode PRIVATE opus)
+  if(OPUS_FIXED_POINT)
+    target_compile_definitions(test_opus_decode PRIVATE DISABLE_FLOAT_API)
+  endif()
+  add_test(test_opus_decode test_opus_decode)
+
+  add_executable(test_opus_padding ${test_opus_padding_sources})
+  target_include_directories(test_opus_padding
+                             PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+  target_link_libraries(test_opus_padding PRIVATE opus)
+  add_test(test_opus_padding test_opus_padding)
+
+  if(NOT BUILD_SHARED_LIBS)
+    # disable tests that depends on private API when building shared lib
+    add_executable(test_opus_api ${test_opus_api_sources})
+    target_include_directories(test_opus_api
+                               PRIVATE ${CMAKE_CURRENT_BINARY_DIR} celt)
+    target_link_libraries(test_opus_api PRIVATE opus)
+    if(OPUS_FIXED_POINT)
+      target_compile_definitions(test_opus_api PRIVATE DISABLE_FLOAT_API)
+    endif()
+    add_test(test_opus_api test_opus_api)
+
+    add_executable(test_opus_encode ${test_opus_encode_sources})
+    target_include_directories(test_opus_encode
+                               PRIVATE ${CMAKE_CURRENT_BINARY_DIR} celt)
+    target_link_libraries(test_opus_encode PRIVATE opus)
+    add_test(test_opus_encode test_opus_encode)
+  endif()
+endif()
diff --git a/Makefile.am b/Makefile.am
index 9c09dec..4e3f183 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -210,6 +210,12 @@
              opus.m4 \
              Makefile.mips \
              Makefile.unix \
+             CMakeLists.txt \
+             config.h.cmake.in \
+             opus_config.cmake \
+             opus_functions.cmake \
+             opus_sources.cmake \
+             OpusConfig.cmake.in \
              tests/run_vectors.sh \
              celt/arm/arm2gnu.pl \
              celt/arm/celt_pitch_xcorr_arm.s \
diff --git a/OpusConfig.cmake.in b/OpusConfig.cmake.in
new file mode 100644
index 0000000..1577174
--- /dev/null
+++ b/OpusConfig.cmake.in
@@ -0,0 +1,19 @@
+set(OPUS_VERSION @PROJECT_VERSION@)
+set(OPUS_VERSION_STRING @PROJECT_VERSION@)
+set(OPUS_VERSION_MAJOR @PROJECT_VERSION_MAJOR@)
+set(OPUS_VERSION_MINOR @PROJECT_VERSION_MINOR@)
+set(OPUS_VERSION_PATCH @PROJECT_VERSION_PATCH@)
+
+@PACKAGE_INIT@
+
+set_and_check(OPUS_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
+set_and_check(OPUS_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@")
+
+include(${CMAKE_CURRENT_LIST_DIR}/OpusTargets.cmake)
+
+set(OPUS_LIBRARY Opus::opus)
+set(OPUS_LIBRARIES Opus::opus)
+
+check_required_components(Opus)
+
+set(OPUS_FOUND 1)
diff --git a/celt_sources.mk b/celt_sources.mk
index b619dae..c9dab06 100644
--- a/celt_sources.mk
+++ b/celt_sources.mk
@@ -1,4 +1,5 @@
-CELT_SOURCES = celt/bands.c \
+CELT_SOURCES = \
+celt/bands.c \
 celt/celt.c \
 celt/celt_encoder.c \
 celt/celt_decoder.c \
diff --git a/config.h.cmake.in b/config.h.cmake.in
new file mode 100644
index 0000000..5550842
--- /dev/null
+++ b/config.h.cmake.in
@@ -0,0 +1 @@
+#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@"
\ No newline at end of file
diff --git a/opus_config.cmake b/opus_config.cmake
new file mode 100644
index 0000000..e41d6b0
--- /dev/null
+++ b/opus_config.cmake
@@ -0,0 +1,58 @@
+include(opus_functions.cmake)
+
+configure_file(config.h.cmake.in config.h @ONLY)
+add_definitions(-DHAVE_CONFIG_H)
+
+option(FIXED_POINT "Use fixed-point code (for devices with less powerful FPU)"
+       OFF)
+option(USE_ALLOCA "Use alloca for stack arrays (on non-C99 compilers)" OFF)
+option(BUILD_PROGRAMS "Build programs" OFF)
+
+set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+set_property(GLOBAL PROPERTY C_STANDARD 99)
+
+if(MSVC)
+  add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+endif()
+
+# It is strongly recommended to uncomment one of these VAR_ARRAYS: Use C99
+# variable-length arrays for stack allocation USE_ALLOCA: Use alloca() for stack
+# allocation If none is defined, then the fallback is a non-threadsafe global
+# array
+if(USE_ALLOCA OR MSVC)
+  add_definitions(-DUSE_ALLOCA)
+else()
+  add_definitions(-DVAR_ARRAYS)
+endif()
+
+include(CheckLibraryExists)
+check_library_exists(m floor "" HAVE_LIBM)
+if(HAVE_LIBM)
+  list(APPEND OPUS_REQUIRED_LIBRARIES m)
+endif()
+
+if(CMAKE_SYSTEM_PROCESSOR MATCHES "(i[0-9]86|x86|X86|amd64|AMD64|x86_64)")
+  if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+    set(OPUS_CPU_X64 1)
+  else()
+    set(OPUS_CPU_X86 1)
+  endif()
+elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
+  set(OPUS_CPU_ARM 1)
+endif()
+
+opus_supports_cpu_detection(RUNTIME_CPU_CAPABILITY_DETECTION)
+
+if(OPUS_CPU_X86 OR OPUS_CPU_X64)
+  opus_detect_sse(COMPILER_SUPPORT_SIMD)
+elseif(OPUS_CPU_ARM)
+  opus_detect_neon(COMPILER_SUPPORT_NEON)
+  if(COMPILER_SUPPORT_NEON)
+    option(OPUS_USE_NEON "Option to turn off SSE" ON)
+    option(OPUS_MAY_SUPPORT_NEON "Does runtime check for neon support" ON)
+    option(OPUS_PRESUME_NEON "Assume target CPU has NEON support" OFF)
+    if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
+      set(OPUS_PRESUME_NEON ON)
+    endif()
+  endif()
+endif()
diff --git a/opus_functions.cmake b/opus_functions.cmake
new file mode 100644
index 0000000..fe309c2
--- /dev/null
+++ b/opus_functions.cmake
@@ -0,0 +1,262 @@
+#[[Cmake helper function to parse source files from make files
+this is to avoid breaking existing make and auto make support
+but still have the option to use CMake with only lists at one place]]
+
+cmake_minimum_required(VERSION 3.1)
+
+function(get_library_version OPUS_LIBRARY_VERSION OPUS_LIBRARY_VERSION_MAJOR)
+  file(STRINGS configure.ac opus_lt_current_string
+       LIMIT_COUNT 1
+       REGEX "OPUS_LT_CURRENT=")
+  string(REGEX MATCH
+               "OPUS_LT_CURRENT=([0-9]*)"
+               _
+               ${opus_lt_current_string})
+  set(OPUS_LT_CURRENT ${CMAKE_MATCH_1})
+
+  file(STRINGS configure.ac opus_lt_revision_string
+       LIMIT_COUNT 1
+       REGEX "OPUS_LT_REVISION=")
+  string(REGEX MATCH
+               "OPUS_LT_REVISION=([0-9]*)"
+               _
+               ${opus_lt_revision_string})
+  set(OPUS_LT_REVISION ${CMAKE_MATCH_1})
+
+  file(STRINGS configure.ac opus_lt_age_string
+       LIMIT_COUNT 1
+       REGEX "OPUS_LT_AGE=")
+  string(REGEX MATCH
+               "OPUS_LT_AGE=([0-9]*)"
+               _
+               ${opus_lt_age_string})
+  set(OPUS_LT_AGE ${CMAKE_MATCH_1})
+
+  math(EXPR OPUS_LIBRARY_VERSION_MAJOR "${OPUS_LT_CURRENT} - ${OPUS_LT_AGE}")
+  set(OPUS_LIBRARY_VERSION_MINOR ${OPUS_LT_AGE})
+  set(OPUS_LIBRARY_VERSION_PATCH ${OPUS_LT_REVISION})
+  set(
+    OPUS_LIBRARY_VERSION
+    "${OPUS_LIBRARY_VERSION_MAJOR}.${OPUS_LIBRARY_VERSION_MINOR}.${OPUS_LIBRARY_VERSION_PATCH}"
+    PARENT_SCOPE)
+  set(OPUS_LIBRARY_VERSION_MAJOR ${OPUS_LIBRARY_VERSION_MAJOR} PARENT_SCOPE)
+endfunction()
+
+function(get_package_version PACKAGE_VERSION)
+  find_package(Git)
+  if(GIT_FOUND)
+    execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --match "v*"
+                    OUTPUT_VARIABLE OPUS_PACKAGE_VERSION)
+    if(OPUS_PACKAGE_VERSION)
+      string(STRIP ${OPUS_PACKAGE_VERSION}, OPUS_PACKAGE_VERSION)
+      string(REPLACE \n
+                     ""
+                     OPUS_PACKAGE_VERSION
+                     ${OPUS_PACKAGE_VERSION})
+      string(REPLACE ,
+                     ""
+                     OPUS_PACKAGE_VERSION
+                     ${OPUS_PACKAGE_VERSION})
+
+      string(SUBSTRING ${OPUS_PACKAGE_VERSION}
+                       1
+                       -1
+                       OPUS_PACKAGE_VERSION)
+      set(PACKAGE_VERSION ${OPUS_PACKAGE_VERSION} PARENT_SCOPE)
+      return()
+    endif()
+  endif()
+
+  if(EXISTS "${CMAKE_SOURCE_DIR}/package_version")
+    # Not a git repo, lets' try to parse it from package_version file if exists
+    file(STRINGS package_version opus_package_version_string
+         LIMIT_COUNT 1
+         REGEX "PACKAGE_VERSION=")
+    string(REPLACE "PACKAGE_VERSION="
+                   ""
+                   opus_package_version_string
+                   ${opus_package_version_string})
+    string(REPLACE "\""
+                   ""
+                   opus_package_version_string
+                   ${opus_package_version_string})
+    set(PACKAGE_VERSION ${opus_package_version_string} PARENT_SCOPE)
+    return()
+  endif()
+
+  # if all else fails set to 0
+  set(PACKAGE_VERSION 0 PARENT_SCOPE)
+endfunction()
+
+function(check_and_set_flag NAME FLAG)
+  include(CheckCCompilerFlag)
+  check_c_compiler_flag(${FLAG} ${NAME}_SUPPORTED)
+  if(${NAME}_SUPPORTED)
+    add_definitions(${FLAG})
+  endif()
+endfunction()
+
+function(check_flag NAME FLAG)
+  include(CheckCCompilerFlag)
+  check_c_compiler_flag(${FLAG} ${NAME}_SUPPORTED)
+endfunction()
+
+include(CheckIncludeFile)
+# function to check if compiler supports SSE, SSE2, SSE4.1 and AVX if target
+# systems may not have SSE support then use OPUS_MAY_HAVE_SSE option if target
+# system is guaranteed to have SSE support then OPUS_PRESUME_SSE can be used to
+# skip SSE runtime check
+function(opus_detect_sse COMPILER_SUPPORT_SIMD)
+  message(STATUS "Check SIMD support by compiler")
+  check_include_file(xmmintrin.h HAVE_XMMINTRIN_H) # SSE1
+  if(HAVE_XMMINTRIN_H)
+    if(MSVC)
+      # different arch options for 32 and 64 bit target for MSVC
+      if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+        check_flag(SSE1 /arch:SSE)
+      else()
+        set(SSE1_SUPPORTED 1 PARENT_SCOPE)
+      endif()
+    else()
+      check_and_set_flag(SSE1 -msse)
+    endif()
+  else()
+    set(SSE1_SUPPORTED 0 PARENT_SCOPE)
+  endif()
+
+  check_include_file(emmintrin.h HAVE_EMMINTRIN_H) # SSE2
+  if(HAVE_EMMINTRIN_H)
+    if(MSVC)
+      if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+        check_flag(SSE2 /arch:SSE2)
+      else()
+        set(SSE2_SUPPORTED 1 PARENT_SCOPE)
+      endif()
+    else()
+      check_and_set_flag(SSE2 -msse2)
+    endif()
+  else()
+    set(SSE2_SUPPORTED 0 PARENT_SCOPE)
+  endif()
+
+  check_include_file(smmintrin.h HAVE_SMMINTRIN_H) # SSE4.1
+  if(HAVE_SMMINTRIN_H)
+    if(MSVC)
+      if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+        check_flag(SSE4_1 /arch:SSE2) # SSE2 and above
+      else()
+        set(SSE4_1_SUPPORTED 1 PARENT_SCOPE)
+      endif()
+    else()
+      check_and_set_flag(SSE4_1 -msse4.1)
+    endif()
+  else()
+    set(SSE4_1_SUPPORTED 0 PARENT_SCOPE)
+  endif()
+
+  check_include_file(immintrin.h HAVE_IMMINTRIN_H) # AVX
+  if(HAVE_IMMINTRIN_H)
+    if(MSVC)
+      check_flag(AVX /arch:AVX)
+    else()
+      check_and_set_flag(AVX -mavx)
+    endif()
+  else()
+    set(AVX_SUPPORTED 0 PARENT_SCOPE)
+  endif()
+
+  if(MSVC) # To avoid warning D9025 of overriding compiler options
+    if(AVX_SUPPORTED) # on 64 bit and 32 bits
+      add_definitions(/arch:AVX)
+    elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) # if AVX not supported then set SSE flag
+      if(SSE4_1_SUPPORTED OR SSE2_SUPPORTED)
+        add_definitions(/arch:SSE2)
+      elseif(SSE1_SUPPORTED)
+        add_definitions(/arch:SSE)
+      endif()
+    endif()
+  endif()
+
+  if(SSE1_SUPPORTED OR SSE2_SUPPORTED OR SSE4_1_SUPPORTED OR AVX_SUPPORTED)
+    set(COMPILER_SUPPORT_SIMD 1 PARENT_SCOPE)
+  else()
+    message(STATUS "No SIMD support in compiler")
+  endif()
+endfunction()
+
+function(opus_detect_neon COMPILER_SUPPORT_NEON)
+  if(CMAKE_SYSTEM_PROCESSOR MATCHES "(armv7-a|aarch64)")
+    message(STATUS "Check NEON support by compiler")
+    check_include_file(arm_neon.h HAVE_ARM_NEON_H)
+    if(HAVE_ARM_NEON_H)
+      set(COMPILER_SUPPORT_NEON ${HAVE_ARM_NEON_H} PARENT_SCOPE)
+    endif()
+  endif()
+endfunction()
+
+function(opus_supports_cpu_detection RUNTIME_CPU_CAPABILITY_DETECTION)
+  if(MSVC)
+    check_include_file(intrin.h HAVE_INTRIN_H)
+  else()
+    check_include_file(cpuid.h HAVE_CPUID_H)
+  endif()
+  if(HAVE_INTRIN_H OR HAVE_CPUID_H)
+    set(RUNTIME_CPU_CAPABILITY_DETECTION 1 PARENT_SCOPE)
+  else()
+    set(RUNTIME_CPU_CAPABILITY_DETECTION 0 PARENT_SCOPE)
+  endif()
+endfunction()
+
+function(add_sources_group target group)
+  target_sources(${target} PRIVATE ${ARGN})
+  source_group(${group} FILES ${ARGN})
+endfunction()
+
+function(get_opus_sources SOURCE_GROUP MAKE_FILE SOURCES)
+  # read file, each item in list is one group
+  file(STRINGS ${MAKE_FILE} opus_sources)
+
+  # add wildcard for regex match
+  string(CONCAT SOURCE_GROUP ${SOURCE_GROUP} ".*$")
+
+  # find group
+  foreach(val IN LISTS opus_sources)
+    if(val MATCHES ${SOURCE_GROUP})
+      list(LENGTH val list_length)
+      if(${list_length} EQUAL 1)
+        # for tests split by '=' and clean up the rest into a list
+        string(FIND ${val} "=" index)
+        math(EXPR index "${index} + 1")
+        string(SUBSTRING ${val}
+                         ${index}
+                         -1
+                         sources)
+        string(REPLACE " "
+                       ";"
+                       sources
+                       ${sources})
+      else()
+        # discard the group
+        list(REMOVE_AT val 0)
+        set(sources ${val})
+      endif()
+      break()
+    endif()
+  endforeach()
+
+  list(LENGTH sources list_length)
+  if(${list_length} LESS 1)
+    message(
+      FATAL_ERROR
+        "No files parsed succesfully from ${SOURCE_GROUP} in ${MAKE_FILE}")
+  endif()
+
+  # remove trailing whitespaces
+  set(list_var "")
+  foreach(source ${sources})
+    string(STRIP "${source}" source)
+    list(APPEND list_var "${source}")
+  endforeach()
+
+  set(${SOURCES} ${list_var} PARENT_SCOPE)
+endfunction()
diff --git a/opus_sources.cmake b/opus_sources.cmake
new file mode 100644
index 0000000..ecdf398
--- /dev/null
+++ b/opus_sources.cmake
@@ -0,0 +1,37 @@
+include(opus_functions.cmake)
+
+get_opus_sources(SILK_SOURCES silk_sources.mk silk_sources)
+get_opus_sources(SILK_SOURCES_FLOAT silk_sources.mk silk_sources_float)
+get_opus_sources(SILK_SOURCES_FIXED silk_sources.mk silk_sources_fixed)
+get_opus_sources(SILK_SOURCES_SSE4_1 silk_sources.mk silk_sources_sse4_1)
+get_opus_sources(SILK_SOURCES_FIXED_SSE4_1 silk_sources.mk
+                 silk_sources_fixed_sse4_1)
+get_opus_sources(SILK_SOURCES_ARM_NEON_INTR silk_sources.mk
+                 silk_sources_arm_neon_intr)
+get_opus_sources(SILK_SOURCES_FIXED_ARM_NEON_INTR silk_sources.mk
+                 silk_sources_fixed_arm_neon_intr)
+
+get_opus_sources(OPUS_SOURCES opus_sources.mk opus_sources)
+get_opus_sources(OPUS_SOURCES_FLOAT opus_sources.mk opus_sources_float)
+
+get_opus_sources(CELT_SOURCES celt_sources.mk celt_sources)
+get_opus_sources(CELT_SOURCES_SSE celt_sources.mk celt_sources_sse)
+get_opus_sources(CELT_SOURCES_SSE2 celt_sources.mk celt_sources_sse2)
+get_opus_sources(CELT_SOURCES_SSE4_1 celt_sources.mk celt_sources_sse4_1)
+get_opus_sources(CELT_SOURCES_ARM celt_sources.mk celt_sources_arm)
+get_opus_sources(CELT_SOURCES_ARM_ASM celt_sources.mk celt_sources_arm_asm)
+get_opus_sources(CELT_AM_SOURCES_ARM_ASM celt_sources.mk
+                 celt_am_sources_arm_asm)
+get_opus_sources(CELT_SOURCES_ARM_NEON_INTR celt_sources.mk
+                 celt_sources_arm_neon_intr)
+get_opus_sources(CELT_SOURCES_ARM_NE10 celt_sources.mk celt_sources_arm_ne10)
+
+get_opus_sources(opus_custom_demo_SOURCES Makefile.am opus_demo_sources)
+get_opus_sources(opus_compare_SOURCES Makefile.am opus_compare_sources)
+get_opus_sources(tests_test_opus_api_SOURCES Makefile.am test_opus_api_sources)
+get_opus_sources(tests_test_opus_encode_SOURCES Makefile.am
+                 test_opus_encode_sources)
+get_opus_sources(tests_test_opus_decode_SOURCES Makefile.am
+                 test_opus_decode_sources)
+get_opus_sources(tests_test_opus_padding_SOURCES Makefile.am
+                 test_opus_padding_sources)
diff --git a/opus_sources.mk b/opus_sources.mk
index b0763f9..44153b5 100644
--- a/opus_sources.mk
+++ b/opus_sources.mk
@@ -1,4 +1,5 @@
-OPUS_SOURCES = src/opus.c \
+OPUS_SOURCES = \
+src/opus.c \
 src/opus_decoder.c \
 src/opus_encoder.c \
 src/opus_multistream.c \
diff --git a/silk_sources.mk b/silk_sources.mk
index 67c8a4f..d2666e6 100644
--- a/silk_sources.mk
+++ b/silk_sources.mk
@@ -77,7 +77,8 @@
 silk/stereo_quant_pred.c \
 silk/LPC_fit.c
 
-SILK_SOURCES_SSE4_1 = silk/x86/NSQ_sse4_1.c \
+SILK_SOURCES_SSE4_1 =  \
+silk/x86/NSQ_sse4_1.c \
 silk/x86/NSQ_del_dec_sse4_1.c \
 silk/x86/x86_silk_map.c \
 silk/x86/VAD_sse4_1.c \
@@ -115,7 +116,8 @@
 silk/fixed/schur64_FIX.c \
 silk/fixed/schur_FIX.c
 
-SILK_SOURCES_FIXED_SSE4_1 = silk/fixed/x86/vector_ops_FIX_sse4_1.c \
+SILK_SOURCES_FIXED_SSE4_1 = \
+silk/fixed/x86/vector_ops_FIX_sse4_1.c \
 silk/fixed/x86/burg_modified_FIX_sse4_1.c
 
 SILK_SOURCES_FIXED_ARM_NEON_INTR = \