game-music-emu: backport cmake / build system updates from master branch

From 2dec466f5a5df76014231bbfb15989a12684434f Mon Sep 17 00:00:00 2001
From: Ozkan Sezer <[EMAIL REDACTED]>
Date: Mon, 23 Oct 2023 17:12:23 +0300
Subject: [PATCH] backport cmake / build system updates from master branch

(cherry picked from commit 8387fede7aa9c111584fb5bbffc0d66364a7cc47)
(cherry picked from commit a53553adef6b9d54d302273f239d52286ef2adc0)
(cherry picked from commit 635661b6a51eea3bfd7e49c4cbfabbfee61b162a)
(cherry picked from commit 3a3d103cdaafade43d638579db541fef800dea57)
(cherry picked from commit 4bca4b40958fe65358c0847ec49d8711de53750a)
(cherry picked from commit cdf332f29c719a672920b869680a481a23ade83b)
(cherry picked from commit 2f5a378621f03afd1221491de34a7b16b4e538a1)
---
 Android.mk            |   5 +-
 CMakeLists.txt        |  45 +++++++++---------
 gme/CMakeLists.txt    | 107 +++++++++++++++++++++++++++++++-----------
 gme/blargg_endian.h   |  34 ++------------
 gme/blargg_source.h   |  15 ------
 gme/gme.cpp           |   6 ++-
 gme/gme.h             |   4 +-
 gme/libgme.pc.in      |   2 +-
 player/CMakeLists.txt |  17 +++----
 readme.txt            |   2 +-
 10 files changed, 129 insertions(+), 108 deletions(-)

diff --git a/Android.mk b/Android.mk
index ae6a6db..35c6064 100644
--- a/Android.mk
+++ b/Android.mk
@@ -13,9 +13,12 @@ LOCAL_CPP_FEATURES := exceptions
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/gme
 
 LOCAL_CFLAGS := -DVGM_YM2612_NUKED \
+	-DBLARGG_LITTLE_ENDIAN=1 \
 	-DBLARGG_BUILD_DLL \
 	-DLIBGME_VISIBILITY \
-	-fvisibility=hidden
+	-fwrapv \
+	-fvisibility=hidden \
+	-fvisibility-inlines-hidden
 
 LOCAL_CXXFLAGS := -std=c++11 \
 	-Wno-inconsistent-missing-override
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 55c6ca2..ba69f5a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,11 +1,12 @@
-cmake_minimum_required(VERSION 3.0...3.5)
 # CMake project definition file.
+cmake_minimum_required(VERSION 3.3...3.5)
 project(libgme)
 
-include(CheckCSourceCompiles)
-include(CheckCXXCompilerFlag)
 include(CMakePushCheckState)
+include(CheckCXXSourceCompiles)
+include(TestBigEndian)
 include(GNUInstallDirs)
+include(CTest)
 
 file(READ "gme/gme.h" GME_GME_H)
 string(REGEX MATCH "/\\* Game_Music_Emu ([0-9]+)\\.([0-9]+).([0-9]+) \\*/" RE_GME_VERSION "${GME_GME_H}")
@@ -30,6 +31,7 @@ option(USE_GME_SPC "Enable SNES SPC music emulation" ON)
 option(USE_GME_VGM "Enable Sega VGM/VGZ music emulation" ON)
 
 option(GME_SPC_ISOLATED_ECHO_BUFFER "Enable isolated echo buffer on SPC emulator to allow correct playing of \"dodgy\" SPC files made for various ROM hacks ran on ZSNES" OFF)
+option(GME_ZLIB "Enable GME to support compressed sound formats" ON)
 
 set(GME_YM2612_EMU "Nuked" CACHE STRING "Which YM2612 emulator to use: \"Nuked\" (LGPLv2.1+), \"MAME\" (GPLv2+), or \"GENS\" (LGPLv2.1+)")
 set(GME_YM2612_EMU_CHOICES "Nuked;MAME;GENS")
@@ -41,33 +43,30 @@ if(USE_GME_NSFE AND NOT USE_GME_NSF)
 endif()
 
 option(BUILD_SHARED_LIBS "Build shared library (set to OFF for static library)" ON)
+option(BUILD_FRAMEWORK "Build framework instead of dylib on macOS" OFF)
 
 option(ENABLE_UBSAN "Enable Undefined Behavior Sanitizer error-checking" OFF)
 
-option(BUILD_FRAMEWORK "Build framework instead of dylib (on macOS)" OFF)
 
-# Check for GCC/Clang "visibility" support.
-if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
-
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -W -Wextra")
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+set (CMAKE_CXX_STANDARD  11)
+set (CMAKE_CXX_STANDARD_REQUIRED ON)
+set (CMAKE_CXX_EXTENSIONS OFF)
 
-    # Assume we have visibility support on any compiler that supports C++11
-    add_definitions(-DLIBGME_VISIBILITY)
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden")
+test_big_endian(WORDS_BIGENDIAN)
 
-    # Try to protect against undefined behavior from signed integer overflow
-    # This has caused miscompilation of code already and there are other
-    # potential uses; see https://bitbucket.org/mpyne/game-music-emu/issues/18/
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fwrapv")
+if(MSVC)
+    add_compile_options(/W2)
+elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
+    add_compile_options(-Wall -W -Wextra)
+endif()
 
-    if(ENABLE_UBSAN)
-        # GCC needs -static-libubsan
-        if(NOT BUILD_SHARED_LIBS AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
-            set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -static-libubsan")
-        else()
-            set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined")
-        endif()
+# Check for GCC/Clang "visibility" support.
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" AND ENABLE_UBSAN)
+    # GCC needs -static-libubsan
+    if(NOT BUILD_SHARED_LIBS AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -static-libubsan")
+    else()
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined")
     endif()
 endif()
 
diff --git a/gme/CMakeLists.txt b/gme/CMakeLists.txt
index 7c3f052..1aae344 100644
--- a/gme/CMakeLists.txt
+++ b/gme/CMakeLists.txt
@@ -18,16 +18,15 @@ set(libgme_SRCS Blip_Buffer.cpp
 # libraries.  Ensure CMake looks only for static libs if we're doing a static
 # build.  See https://stackoverflow.com/a/44738756
 if(NOT BUILD_SHARED_LIBS)
-    if(MSVC)
-        set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
-    else()
-        set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
-    endif()
+  if(MSVC)
+    set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
+  else()
+    set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
+  endif()
 endif()
 
-option(GME_ZLIB "GME supports compressed sound formats" ON)
 if(GME_ZLIB)
-    find_package(ZLIB REQUIRED)
+    find_package(ZLIB QUIET)
 endif()
 
 # Ay_Apu is very popular around here
@@ -171,34 +170,88 @@ endif()
 # Add library to be compiled.
 add_library(gme ${libgme_SRCS})
 add_library(gme::gme ALIAS gme)
-target_include_directories(gme
-    PRIVATE "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>"  # For gme_types.h
-    INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>"
-    INTERFACE "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
-)
+
+set_property(TARGET gme PROPERTY C_VISIBILITY_PRESET "hidden")
+set_property(TARGET gme PROPERTY VISIBILITY_INLINES_HIDDEN TRUE)
+set_property(TARGET gme PROPERTY CXX_VISIBILITY_PRESET "hidden")
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
+    target_compile_definitions(gme PRIVATE LIBGME_VISIBILITY)
+endif()
 
 # On some platforms we may need to change headers or whatnot based on whether
 # we're building the library or merely using the library. The following is
 # only defined when building the library to allow us to tell which is which.
 set_property(TARGET gme PROPERTY DEFINE_SYMBOL BLARGG_BUILD_DLL)
 
-if(GME_ZLIB)
-    message(STATUS "ZLib library located, compressed file formats will be supported")
-    target_compile_definitions(gme PRIVATE HAVE_ZLIB_H)
-    target_link_libraries(gme ZLIB::ZLIB)
-    # Is not to be installed though
+target_compile_definitions(gme PRIVATE GEN_TYPES_H)
+if(WORDS_BIGENDIAN)
+    target_compile_definitions(gme PRIVATE BLARGG_BIG_ENDIAN=1)
 else()
-    message(STATUS "ZLib library not found, disabling support for compressed formats such as VGZ")
+    target_compile_definitions(gme PRIVATE BLARGG_LITTLE_ENDIAN=1)
 endif()
 
+# Try to protect against undefined behavior from signed integer overflow
+# This has caused miscompilation of code already and there are other
+# potential uses; see https://bitbucket.org/mpyne/game-music-emu/issues/18/
+target_compile_options(gme PRIVATE -fwrapv)
+
+target_include_directories(gme
+    PRIVATE "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>"  # For gen_types.h
+    INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>"
+    INTERFACE "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
+)
+
+## FIXME: Properly find the C++ library !!!
+set(PC_LIBS -lstdc++)
+
 if(NOT MSVC)
-    cmake_push_check_state()
-    set(CMAKE_REQUIRED_FLAGS "-Wl,-no-undefined")
-    check_c_source_compiles("int main() { return 0;}" COMPILER_SUPPORTS_WL_NO_UNDEFINED)
-    cmake_pop_check_state()
-    if(COMPILER_SUPPORTS_WL_NO_UNDEFINED)
+    # Link with -no-undefined, if available
+    if(APPLE)
+      set_property(TARGET gme APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-undefined,error")
+    else()
+      cmake_push_check_state()
+      set(CMAKE_REQUIRED_FLAGS "-Wl,-no-undefined")
+      check_cxx_source_compiles("int main(void) { return 0;}" LINKER_SUPPORTS_NO_UNDEFINED)
+      cmake_pop_check_state()
+      if(LINKER_SUPPORTS_NO_UNDEFINED)
         set_property(TARGET gme APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-no-undefined")
+      endif()
     endif()
+
+    # Link to libm, if necessary
+    check_cxx_source_compiles("
+        #include <math.h>
+        int main(int argc, char** argv) {
+            return (int) pow(argc, 2.5);
+        }" LIBM_NOT_NEEDED)
+    if(NOT LIBM_NOT_NEEDED)
+        cmake_push_check_state()
+        set(CMAKE_REQUIRED_LIBRARIES "-lm")
+        check_cxx_source_compiles("
+            #include <math.h>
+            int main(int argc, char** argv) {
+                return (int) pow(argc, 2.5);
+            }" HAVE_LIBM)
+        cmake_pop_check_state()
+        if(HAVE_LIBM)
+            target_link_libraries(gme PRIVATE -lm)
+            list(APPEND PC_LIBS -lm) # for libgme.pc
+        endif()
+    endif()
+endif()
+
+if(GME_ZLIB)
+  if(ZLIB_FOUND)
+      message(STATUS "ZLib library located, compressed file formats will be supported")
+      target_compile_definitions(gme PRIVATE HAVE_ZLIB_H)
+      target_link_libraries(gme PRIVATE ZLIB::ZLIB)
+      # Is not to be installed though
+      list(APPEND PC_LIBS -lz) # for libgme.pc
+  else()
+      message(STATUS "** ZLib library not found, disabling support for compressed formats such as VGZ")
+  endif()
+else()
+  message(STATUS "Zlib-Compressed formats excluded")
 endif()
 
 # Extract symbols from gme.exports
@@ -242,10 +295,10 @@ elseif(UNIX)
 
     cmake_push_check_state()
     set(CMAKE_REQUIRED_FLAGS "-Wl,-version-script='${generated_sym_file}'")
-    check_c_source_compiles("int main() { return 0;}" COMPILER_SUPPORTS_VERSION_SCRIPT)
+    check_cxx_source_compiles("int main() { return 0;}" LINKER_SUPPORTS_VERSION_SCRIPT)
     cmake_pop_check_state()
 
-    if(COMPILER_SUPPORTS_VERSION_SCRIPT)
+    if(LINKER_SUPPORTS_VERSION_SCRIPT)
         set_property(TARGET gme APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-version-script='${generated_sym_file}'")
         set_property(TARGET gme APPEND PROPERTY LINK_DEPENDS "${generated_sym_file}")
     endif()
@@ -278,8 +331,8 @@ install(TARGETS gme LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
 
 
 # Run during cmake phase, so this is available during make
-configure_file(gme_types.h.in gme_types.h @ONLY)
-
+configure_file(gme_types.h.in gen_types.h @ONLY)
+string(JOIN " " PC_LIBS ${PC_LIBS})
 configure_file(libgme.pc.in libgme.pc @ONLY)
 
 install(FILES ${EXPORTED_HEADERS} DESTINATION include/gme)
diff --git a/gme/blargg_endian.h b/gme/blargg_endian.h
index 46e58e2..fa5557a 100644
--- a/gme/blargg_endian.h
+++ b/gme/blargg_endian.h
@@ -19,36 +19,12 @@
 
 // BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only
 // one may be #defined to 1. Only needed if something actually depends on byte order.
-#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN)
-#ifdef __GLIBC__
-	// GCC handles this for us
-	#include <endian.h>
-	#if __BYTE_ORDER == __LITTLE_ENDIAN
-		#define BLARGG_LITTLE_ENDIAN 1
-	#elif __BYTE_ORDER == __BIG_ENDIAN
-		#define BLARGG_BIG_ENDIAN 1
-	#endif
-#else
-
-#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \
-		(defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234)
-	#define BLARGG_LITTLE_ENDIAN 1
-#endif
-
-#if defined (MSB_FIRST)     || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \
-	defined (__sparc__)     ||  BLARGG_CPU_POWERPC || \
-	(defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321)
-	#define BLARGG_BIG_ENDIAN 1
-#elif !defined (__mips__)
-	// No endian specified; assume little-endian, since it's most common
-	#define BLARGG_LITTLE_ENDIAN 1
+// BLARGG_BIG_ENDIAN or BLARGG_LITTLE_ENDIAN must be defined by the build system.
+#if !defined(BLARGG_BIG_ENDIAN) && !defined(BLARGG_LITTLE_ENDIAN)
+	#error Unspecified endianness.
 #endif
-#endif
-#endif
-
-#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN
-	#undef BLARGG_LITTLE_ENDIAN
-	#undef BLARGG_BIG_ENDIAN
+#if defined(BLARGG_BIG_ENDIAN) && defined(BLARGG_LITTLE_ENDIAN)
+	#error BLARGG_LITTLE_ENDIAN and BLARGG_BIG_ENDIAN are both defined.
 #endif
 
 inline void blargg_verify_byte_order()
diff --git a/gme/blargg_source.h b/gme/blargg_source.h
index deea918..d03b094 100644
--- a/gme/blargg_source.h
+++ b/gme/blargg_source.h
@@ -62,21 +62,6 @@
 #define byte byte_
 typedef unsigned char byte;
 
-/* Setup compiler defines useful for exporting required public API symbols in gme.cpp */
-#ifndef BLARGG_EXPORT
-    #if defined (_WIN32)
-        #if defined(BLARGG_BUILD_DLL)
-            #define BLARGG_EXPORT __declspec(dllexport)
-        #else
-            #define BLARGG_EXPORT /* Leave blank: friendly with both static and shared linking */
-        #endif
-    #elif defined (LIBGME_VISIBILITY) && defined(__cplusplus)
-        #define BLARGG_EXPORT __attribute__((visibility ("default")))
-    #else
-        #define BLARGG_EXPORT
-    #endif
-#endif
-
 /* deprecated */
 #define BLARGG_CHECK_ALLOC CHECK_ALLOC
 #define BLARGG_RETURN_ERR RETURN_ERR
diff --git a/gme/gme.cpp b/gme/gme.cpp
index 1c16c78..03446b0 100644
--- a/gme/gme.cpp
+++ b/gme/gme.cpp
@@ -2,7 +2,11 @@
 
 #include "Music_Emu.h"
 
-#include <gme_types.h>
+#ifdef GEN_TYPES_H
+#include "gen_types.h" /* same as gme_types.h but generated by build system */
+#else
+#include "gme_types.h"
+#endif
 #if !GME_DISABLE_STEREO_DEPTH
 #include "Effects_Buffer.h"
 #endif
diff --git a/gme/gme.h b/gme/gme.h
index 3594df2..9ac6a02 100644
--- a/gme/gme.h
+++ b/gme/gme.h
@@ -23,9 +23,9 @@ typedef struct Music_Emu Music_Emu;
         #if defined(BLARGG_BUILD_DLL)
             #define BLARGG_EXPORT __declspec(dllexport)
         #else
-            #define BLARGG_EXPORT /* Leave blank: friendly with both static and shared linking */
+            #define BLARGG_EXPORT /* Leave blank: friendly with both static and shared linking. */
         #endif
-    #elif defined (LIBGME_VISIBILITY) && defined(__cplusplus)
+    #elif defined (LIBGME_VISIBILITY)
         #define BLARGG_EXPORT __attribute__((visibility ("default")))
     #else
         #define BLARGG_EXPORT
diff --git a/gme/libgme.pc.in b/gme/libgme.pc.in
index f057ce1..0f379d7 100644
--- a/gme/libgme.pc.in
+++ b/gme/libgme.pc.in
@@ -13,4 +13,4 @@ URL: https://bitbucket.org/mpyne/game-music-emu/wiki/Home
 Version: @GME_VERSION@
 Cflags: -I${includedir}
 Libs: -L${libdir} -lgme
-Libs.private: -lstdc++ @PKG_CONFIG_ZLIB@
+Libs.private: @PC_LIBS@
diff --git a/player/CMakeLists.txt b/player/CMakeLists.txt
index c2d7138..f96c01e 100644
--- a/player/CMakeLists.txt
+++ b/player/CMakeLists.txt
@@ -7,16 +7,17 @@ set(player_SRCS Audio_Scope.cpp
                 player.cpp)
 
 if(SDL2_FOUND)
-    message(" ** SDL 2 library located, player demo is available to be built in the /player directory")
-
-    include_directories(${SDL2_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}
-        "${CMAKE_HOME_DIRECTORY}" "${CMAKE_HOME_DIRECTORY}/gme"
-        "${CMAKE_BINARY_DIR}/gme")
+    message(STATUS "SDL2 library located, player demo is available to be built in the /player directory")
 
     add_executable(gme_player ${player_SRCS})
-    target_link_libraries(gme_player ${SDL2_LIBRARIES} gme)
-
+    target_include_directories(gme_player PRIVATE
+        ${SDL2_INCLUDE_DIRS}
+        ${PROJECT_SOURCE_DIR}/gme
+    )
+    set_property(TARGET gme_player PROPERTY CXX_STANDARD_REQUIRED ON)
+    set_property(TARGET gme_player PROPERTY CXX_STANDARD 11)
+    target_link_libraries(gme_player PRIVATE ${SDL2_LIBRARIES} gme::gme)
     # Is not to be installed though
 else()
-    message("SDL library not found, disabling player demo build")
+    message(STATUS "** SDL library not found, disabling player demo build")
 endif()
diff --git a/readme.txt b/readme.txt
index 4dffbfb..4b8bb63 100644
--- a/readme.txt
+++ b/readme.txt
@@ -47,7 +47,7 @@ Getting Started
 Build a program consisting of demo/basics.c, demo/Wave_Writer.cpp, and
 all source files in gme/.
 
-Or, if you have CMake 2.6 or later, execute at a command prompt (from the
+Or, if you have CMake 3.3 or later, execute at a command prompt (from the
 extracted source directory):
 
     mkdir build