SDL_mixer: Update wikiheaders.pl and PrivateSdlFunctions.cmake

From 1fbcf34b53a720e51c67ecbbe92498dc55c14022 Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Thu, 8 Jan 2026 22:27:50 +0100
Subject: [PATCH] Update wikiheaders.pl and PrivateSdlFunctions.cmake

---
 build-scripts/wikiheaders.pl    |  54 +++++---
 cmake/PrivateSdlFunctions.cmake | 232 +++++++++++++++++---------------
 2 files changed, 160 insertions(+), 126 deletions(-)

diff --git a/build-scripts/wikiheaders.pl b/build-scripts/wikiheaders.pl
index f4673fe02..2092912bc 100755
--- a/build-scripts/wikiheaders.pl
+++ b/build-scripts/wikiheaders.pl
@@ -37,6 +37,11 @@
 my $versionmajorregex = '\A\#define\s+SDL_MAJOR_VERSION\s+(\d+)\Z';
 my $versionminorregex = '\A\#define\s+SDL_MINOR_VERSION\s+(\d+)\Z';
 my $versionmicroregex = '\A\#define\s+SDL_MICRO_VERSION\s+(\d+)\Z';
+my $wikidocsectionsym = 'SDL_WIKI_DOCUMENTATION_SECTION';
+my $forceinlinesym = 'SDL_FORCE_INLINE';
+my $deprecatedsym = 'SDL_DEPRECATED';
+my $declspecsym = '(?:SDLMAIN_|SDL_)?DECLSPEC';
+my $callconvsym = 'SDLCALL';
 my $mainincludefname = 'SDL.h';
 my $selectheaderregex = '\ASDL.*?\.h\Z';
 my $projecturl = 'https://libsdl.org/';
@@ -147,6 +152,12 @@
             $envvardesc = $val, next if $key eq 'envvardesc';
             $envvarsymregex = $val, next if $key eq 'envvarsymregex';
             $envvarsymreplace = $val, next if $key eq 'envvarsymreplace';
+            $wikidocsectionsym = $val, next if $key eq 'wikidocsectionsym';
+            $forceinlinesym = $val, next if $key eq 'forceinlinesym';
+            $deprecatedsym = $val, next if $key eq 'deprecatedsym';
+            $declspecsym = $val, next if $key eq 'declspecsym';
+            $callconvsym = $val, next if $key eq 'callconvsym';
+
         }
     }
     close(OPTIONS);
@@ -750,6 +761,7 @@ sub print_undocumented_section {
     }
 }
 
+# !!! FIXME: generalize this for other libraries to use.
 sub strip_fn_declaration_metadata {
     my $decl = shift;
     $decl =~ s/SDL_(PRINTF|SCANF)_FORMAT_STRING\s*//;  # don't want this metadata as part of the documentation.
@@ -1153,7 +1165,7 @@ sub generate_envvar_wiki_page {
         } elsif ($ignoring_lines) {
             push @contents, $_;
             next;
-        } elsif (/\A\s*\#\s*ifndef\s+SDL_WIKI_DOCUMENTATION_SECTION\s*\Z/) {
+        } elsif (/\A\s*\#\s*ifndef\s+$wikidocsectionsym\s*\Z/) {
             $ignoring_lines = 1;
             push @contents, $_;
             next;
@@ -1162,13 +1174,13 @@ sub generate_envvar_wiki_page {
             #print("CATEGORY FOR '$dent' CHANGED TO " . (defined($current_wiki_category) ? "'$current_wiki_category'" : '(undef)') . "\n");
             push @contents, $_;
             next;
-        } elsif (/\A\s*extern\s+(SDL_DEPRECATED\s+|)(SDLMAIN_|SDL_)?DECLSPEC/) {  # a function declaration without a doxygen comment?
+        } elsif (/\A\s*extern\s+(?:$deprecatedsym\s+|)$declspecsym/) {  # a function declaration without a doxygen comment?
             $symtype = 1;   # function declaration
             @templines = ();
             $decl = $_;
             $str = '';
             $has_doxygen = 0;
-        } elsif (/\A\s*SDL_FORCE_INLINE/) {  # a (forced-inline) function declaration without a doxygen comment?
+        } elsif (/\A\s*$forceinlinesym/) {  # a (forced-inline) function declaration without a doxygen comment?
             $symtype = 1;   # function declaration
             @templines = ();
             $decl = $_;
@@ -1235,9 +1247,9 @@ sub generate_envvar_wiki_page {
                 $lineno++ if defined $decl;
                 $decl = '' if not defined $decl;
                 chomp($decl);
-                if ($decl =~ /\A\s*extern\s+(SDL_DEPRECATED\s+|)(SDLMAIN_|SDL_)?DECLSPEC/) {
+                if ($decl =~ /\A\s*extern\s+(?:$deprecatedsym\s+|)$declspecsym/) {
                     $symtype = 1;   # function declaration
-                } elsif ($decl =~ /\A\s*SDL_FORCE_INLINE/) {
+                } elsif ($decl =~ /\A\s*$forceinlinesym/) {
                     $symtype = 1;   # (forced-inline) function declaration
                 } elsif ($decl =~ /\A\s*\#\s*define\s+/) {
                     $symtype = 2;   # macro
@@ -1274,7 +1286,7 @@ sub generate_envvar_wiki_page {
             }
             $headercategorydocs{$current_wiki_category} = $sym;
         } elsif ($symtype == 1) {  # a function
-            my $is_forced_inline = ($decl =~ /\A\s*SDL_FORCE_INLINE/);
+            my $is_forced_inline = ($decl =~ /\A\s*$forceinlinesym/);
 
             if ($is_forced_inline) {
                 if (not $decl =~ /\)\s*(\{.*|)\s*\Z/) {
@@ -1311,14 +1323,14 @@ sub generate_envvar_wiki_page {
 
             my $paramsstr = undef;
 
-            if (!$is_forced_inline && $decl =~ /\A\s*extern\s+(SDL_DEPRECATED\s+|)(SDLMAIN_|SDL_)?DECLSPEC\w*\s+(const\s+|)(unsigned\s+|)(.*?)([\*\s]+)(\*?)\s*SDLCALL\s+(.*?)\s*\((.*?)\);/) {
-                $sym = $8;
-                $rettype = "$3$4$5$6";
-                $paramsstr = $9;
-             } elsif ($is_forced_inline && $decl =~ /\A\s*SDL_FORCE_INLINE\s+(SDL_DEPRECATED\s+|)(const\s+|)(unsigned\s+|)(.*?)([\*\s]+)(.*?)\s*\((.*?)\);/) {
+            if (!$is_forced_inline && $decl =~ /\A\s*extern\s+(?:$deprecatedsym\s+|)$declspecsym\w*\s+(const\s+|)(unsigned\s+|)(.*?)([\*\s]+)(\*?)\s*$callconvsym\s+(.*?)\s*\((.*?)\);/) {
                 $sym = $6;
-                $rettype = "$2$3$4$5";
+                $rettype = "$1$2$3$4$5";
                 $paramsstr = $7;
+             } elsif ($is_forced_inline && $decl =~ /\A\s*$forceinlinesym\s+(?:$deprecatedsym\s+|)(const\s+|)(unsigned\s+|)(.*?)([\*\s]+)(.*?)\s*\((.*?)\);/) {
+                $sym = $5;
+                $rettype = "$1$2$3$4";
+                $paramsstr = $6;
              } else {
                 #print "Found doxygen but no function sig:\n$str\n\n";
                 foreach (@templines) {
@@ -1384,7 +1396,7 @@ sub generate_envvar_wiki_page {
 
                         $decl = $_;
                         $temp = $decl;
-                        $temp =~ s/\Aextern\s+(SDL_DEPRECATED\s+|)(SDLMAIN_|SDL_)?DECLSPEC\w*\s+(.*?)\s+(\*?)SDLCALL\s+/$3$4 /;
+                        $temp =~ s/\Aextern\s+(?:$deprecatedsym\s+|)$declspecsym\w*\s+(.*?)\s+(\*?)$callconvsym\s+/$1$2 /;
                         $shrink_length = length($decl) - length($temp);
                         $decl = $temp;
                     } else {
@@ -2259,10 +2271,10 @@ sub generate_envvar_wiki_page {
 
                 $desc =~ s/[\s\n]+\Z//ms;
 
-                if (0) {  # !!! FIXME: disabled because it's not currently suitable for general use, but for manually inspecting the output, it can be useful.
-                    if (($desc =~ /\A[A-Z]/) && (not $desc =~ /\ASDL_/)) {
-                        print STDERR "WARNING: $sym\'s '\\param $arg' text starts with a capital letter: '$desc'. Fixing.\n";
-                        $desc = lcfirst($desc);
+                if (0) {
+                    if (($desc =~ /\A[a-z]/) && (not $desc =~ /$apiprefixregex/)) {
+                        print STDERR "WARNING: $sym\'s '\\param $arg' text starts with a lowercase letter: '$desc'. Fixing.\n";
+                        $desc = ucfirst($desc);
                     }
                 }
 
@@ -2306,8 +2318,8 @@ sub generate_envvar_wiki_page {
                 }
                 $desc =~ s/[\s\n]+\Z//ms;
 
-                if (0) {  # !!! FIXME: disabled because it's not currently suitable for general use, but for manually inspecting the output, it can be useful.
-                    if (($desc =~ /\A[A-Z]/) && (not $desc =~ /\ASDL_/)) {
+                if (0) {
+                    if (($desc =~ /\A[A-Z]/) && (not $desc =~ /$apiprefixregex/)) {
                         print STDERR "WARNING: $sym\'s '\\returns' text starts with a capital letter: '$desc'. Fixing.\n";
                         $desc = lcfirst($desc);
                     }
@@ -2451,7 +2463,7 @@ sub generate_envvar_wiki_page {
                 } else {
                     die("Unexpected symbol type $symtype!");
                 }
-                my $str = "This $symtypename is available since SDL 3.0.0.";
+                my $str = "This $symtypename is available since $projectshortname 3.0.0.";
                 $sections{'Version'} = wordwrap(wikify($wikitype, $str)) . "\n";
             }
         }
@@ -2916,7 +2928,7 @@ sub generate_envvar_wiki_page {
         $str .= ".\\\" Please report issues in this manpage's content at:\n";
         $str .= ".\\\"   $bugreporturl\n";
         $str .= ".\\\" Please report issues in the generation of this manpage from the wiki at:\n";
-        $str .= ".\\\"   https://github.com/libsdl-org/SDL/issues/new?title=Misgenerated%20manpage%20for%20$sym\n";
+        $str .= ".\\\"   https://github.com/libsdl-org/SDL/issues/new?title=Misgenerated%20manpage%20for%20$sym\n";  # !!! FIXME: if this becomes a problem for other projects, we'll generalize this.
         $str .= ".\\\" $projectshortname can be found at $projecturl\n";
 
         # Define a .URL macro. The "www.tmac" thing decides if we're using GNU roff (which has a .URL macro already), and if so, overrides the macro we just created.
diff --git a/cmake/PrivateSdlFunctions.cmake b/cmake/PrivateSdlFunctions.cmake
index 47e6f4e4f..0f3eb4060 100644
--- a/cmake/PrivateSdlFunctions.cmake
+++ b/cmake/PrivateSdlFunctions.cmake
@@ -3,6 +3,9 @@
 include(CheckCCompilerFlag)
 include(CheckCSourceCompiles)
 include(CMakePushCheckState)
+if(NOT CMAKE_VERSION VERSION_LESS "3.18")
+  include(CheckLinkerFlag)
+endif()
 
 macro(sdl_calculate_derived_version_variables MAJOR MINOR MICRO)
     set(SO_VERSION_MAJOR "0")
@@ -111,114 +114,122 @@ endfunction()
 
 function(target_get_dynamic_library DEST TARGET)
     set(result)
-    get_actual_target(TARGET)
-    if(WIN32)
-        # Use the target dll of the import library
-        set(props_to_check IMPORTED_IMPLIB)
-        if(CMAKE_BUILD_TYPE)
-            list(APPEND props_to_check IMPORTED_IMPLIB_${CMAKE_BUILD_TYPE})
-        endif()
-        list(APPEND props_to_check IMPORTED_LOCATION)
-        if(CMAKE_BUILD_TYPE)
-            list(APPEND props_to_check IMPORTED_LOCATION_${CMAKE_BUILD_TYPE})
+    if(DEFINED ${DEST})
+        if(NOT EXISTS "${${DEST}}")
+            message(FATAL_ERROR "${DEST}=${${DEST}} does not exist")
         endif()
-        foreach (config_type ${CMAKE_CONFIGURATION_TYPES} RELEASE DEBUG RELWITHDEBINFO MINSIZEREL)
-            list(APPEND props_to_check IMPORTED_IMPLIB_${config_type})
-            list(APPEND props_to_check IMPORTED_LOCATION_${config_type})
-        endforeach()
+        get_filename_component(filename ${${DEST}} NAME)
+        set(${DEST} ${filename} PARENT_SCOPE)
+    else()
+        get_actual_target(TARGET)
+        if(WIN32)
+            # Use the target dll of the import library
+            set(props_to_check IMPORTED_IMPLIB)
+            if(CMAKE_BUILD_TYPE)
+                list(APPEND props_to_check IMPORTED_IMPLIB_${CMAKE_BUILD_TYPE})
+            endif()
+            list(APPEND props_to_check IMPORTED_LOCATION)
+            if(CMAKE_BUILD_TYPE)
+                list(APPEND props_to_check IMPORTED_LOCATION_${CMAKE_BUILD_TYPE})
+            endif()
+            foreach (config_type ${CMAKE_CONFIGURATION_TYPES} RELEASE DEBUG RELWITHDEBINFO MINSIZEREL)
+                list(APPEND props_to_check IMPORTED_IMPLIB_${config_type})
+                list(APPEND props_to_check IMPORTED_LOCATION_${config_type})
+            endforeach()
 
-        foreach(prop_to_check ${props_to_check})
-            if(NOT result)
-                get_target_property(propvalue "${TARGET}" ${prop_to_check})
-                if(propvalue AND EXISTS "${propvalue}")
-                    win32_implib_identify_dll(result "${propvalue}" NOTFATAL)
+            foreach(prop_to_check ${props_to_check})
+                if(NOT result)
+                    get_target_property(propvalue "${TARGET}" ${prop_to_check})
+                    if(propvalue AND EXISTS "${propvalue}")
+                        win32_implib_identify_dll(result "${propvalue}" NOTFATAL)
+                    endif()
                 endif()
-            endif()
-        endforeach()
-    else()
-        # 1. find the target library a file might be symbolic linking to
-        # 2. find all other files in the same folder that symolic link to it
-        # 3. sort all these files, and select the 1st item on Linux, and last on Macos
-        set(location_properties IMPORTED_LOCATION)
-        if(CMAKE_BUILD_TYPE)
-            list(APPEND location_properties IMPORTED_LOCATION_${CMAKE_BUILD_TYPE})
-        endif()
-        foreach (config_type ${CMAKE_CONFIGURATION_TYPES} RELEASE DEBUG RELWITHDEBINFO MINSIZEREL)
-            list(APPEND location_properties IMPORTED_LOCATION_${config_type})
-        endforeach()
-        if(APPLE)
-            set(valid_shared_library_regex "\\.[0-9]+\\.dylib$")
+            endforeach()
         else()
-            set(valid_shared_library_regex "\\.so\\.([0-9.]+)?[0-9]")
-        endif()
-        foreach(location_property ${location_properties})
-            if(NOT result)
-                get_target_property(library_path "${TARGET}" ${location_property})
-                message(DEBUG "get_target_property(${TARGET} ${location_propert}) -> ${library_path}")
-                if(EXISTS "${library_path}")
-                    get_filename_component(library_path "${library_path}" ABSOLUTE)
-                    while (IS_SYMLINK "${library_path}")
-                        read_absolute_symlink(library_path "${library_path}")
-                    endwhile()
-                    message(DEBUG "${TARGET} -> ${library_path}")
-                    get_filename_component(libdir "${library_path}" DIRECTORY)
-                    file(GLOB subfiles "${libdir}/*")
-                    set(similar_files "${library_path}")
-                    foreach(subfile ${subfiles})
-                        if(IS_SYMLINK "${subfile}")
-                            read_absolute_symlink(subfile_target "${subfile}")
-                            while(IS_SYMLINK "${subfile_target}")
-                                read_absolute_symlink(subfile_target "${subfile_target}")
-                            endwhile()
-                            get_filename_component(subfile_target "${subfile_target}" ABSOLUTE)
-                            if(subfile_target STREQUAL library_path AND subfile MATCHES "${valid_shared_library_regex}")
-                                list(APPEND similar_files "${subfile}")
+            # 1. find the target library a file might be symbolic linking to
+            # 2. find all other files in the same folder that symolic link to it
+            # 3. sort all these files, and select the 1st item on Linux, and last on Macos
+            set(location_properties IMPORTED_LOCATION)
+            if(CMAKE_BUILD_TYPE)
+                list(APPEND location_properties IMPORTED_LOCATION_${CMAKE_BUILD_TYPE})
+            endif()
+            foreach (config_type ${CMAKE_CONFIGURATION_TYPES} RELEASE DEBUG RELWITHDEBINFO MINSIZEREL)
+                list(APPEND location_properties IMPORTED_LOCATION_${config_type})
+            endforeach()
+            if(APPLE)
+                set(valid_shared_library_regex "\\.[0-9]+\\.dylib$")
+            else()
+                set(valid_shared_library_regex "\\.so\\.([0-9.]+)?[0-9]")
+            endif()
+            foreach(location_property ${location_properties})
+                if(NOT result)
+                    get_target_property(library_path "${TARGET}" ${location_property})
+                    message(DEBUG "get_target_property(${TARGET} ${location_propert}) -> ${library_path}")
+                    if(EXISTS "${library_path}")
+                        get_filename_component(library_path "${library_path}" ABSOLUTE)
+                        while (IS_SYMLINK "${library_path}")
+                            read_absolute_symlink(library_path "${library_path}")
+                        endwhile()
+                        message(DEBUG "${TARGET} -> ${library_path}")
+                        get_filename_component(libdir "${library_path}" DIRECTORY)
+                        file(GLOB subfiles "${libdir}/*")
+                        set(similar_files "${library_path}")
+                        foreach(subfile ${subfiles})
+                            if(IS_SYMLINK "${subfile}")
+                                read_absolute_symlink(subfile_target "${subfile}")
+                                while(IS_SYMLINK "${subfile_target}")
+                                    read_absolute_symlink(subfile_target "${subfile_target}")
+                                endwhile()
+                                get_filename_component(subfile_target "${subfile_target}" ABSOLUTE)
+                                if(subfile_target STREQUAL library_path AND subfile MATCHES "${valid_shared_library_regex}")
+                                    list(APPEND similar_files "${subfile}")
+                                endif()
                             endif()
+                        endforeach()
+                        list(SORT similar_files)
+                        message(DEBUG "files that are similar to \"${library_path}\"=${similar_files}")
+                        if(APPLE)
+                            list(REVERSE similar_files)
                         endif()
-                    endforeach()
-                    list(SORT similar_files)
-                    message(DEBUG "files that are similar to \"${library_path}\"=${similar_files}")
-                    if(APPLE)
-                        list(REVERSE similar_files)
+                        list(GET similar_files 0 item)
+                        get_filename_component(result "${item}" NAME)
                     endif()
-                    list(GET similar_files 0 item)
-                    get_filename_component(result "${item}" NAME)
                 endif()
-            endif()
-        endforeach()
-    endif()
-    if(result)
-        string(TOLOWER "${result}" result_lower)
-        if(WIN32 OR OS2)
-            if(NOT result_lower MATCHES ".*dll")
-                message(FATAL_ERROR "\"${result}\" is not a .dll library")
-            endif()
-        elseif(APPLE)
-            if(NOT result_lower MATCHES ".*dylib.*")
-                message(FATAL_ERROR "\"${result}\" is not a .dylib shared library")
+            endforeach()
+        endif()
+        if(result)
+            string(TOLOWER "${result}" result_lower)
+            if(WIN32 OR OS2)
+                if(NOT result_lower MATCHES ".*dll")
+                    message(FATAL_ERROR "\"${result}\" is not a .dll library")
+                endif()
+            elseif(APPLE)
+                if(NOT result_lower MATCHES ".*dylib.*")
+                    message(FATAL_ERROR "\"${result}\" is not a .dylib shared library")
+                endif()
+            else()
+                if(NOT result_lower MATCHES ".*so.*")
+                    message(FATAL_ERROR "\"${result}\" is not a .so shared library")
+                endif()
             endif()
         else()
-            if(NOT result_lower MATCHES ".*so.*")
-                message(FATAL_ERROR "\"${result}\" is not a .so shared library")
+            get_target_property(target_type ${TARGET} TYPE)
+            if(target_type MATCHES "SHARED_LIBRARY|MODULE_LIBRARY")
+                # OK
+            elseif(target_type MATCHES "STATIC_LIBRARY|OBJECT_LIBRARY|INTERFACE_LIBRARY|EXECUTABLE")
+                message(SEND_ERROR "${TARGET} is not a shared library, but has type=${target_type}")
+            else()
+                message(WARNING "Unable to extract dynamic library from target=${TARGET}, type=${target_type}.")
+            endif()
+            # TARGET_SONAME_FILE is not allowed for DLL target platforms.
+            if(WIN32)
+              set(result "$<TARGET_FILE_NAME:${TARGET}>")
+            else()
+              set(result "$<TARGET_SONAME_FILE_NAME:${TARGET}>")
             endif()
         endif()
-    else()
-        get_target_property(target_type ${TARGET} TYPE)
-        if(target_type MATCHES "SHARED_LIBRARY|MODULE_LIBRARY")
-            # OK
-        elseif(target_type MATCHES "STATIC_LIBRARY|OBJECT_LIBRARY|INTERFACE_LIBRARY|EXECUTABLE")
-            message(SEND_ERROR "${TARGET} is not a shared library, but has type=${target_type}")
-        else()
-            message(WARNING "Unable to extract dynamic library from target=${TARGET}, type=${target_type}.")
-        endif()
-        # TARGET_SONAME_FILE is not allowed for DLL target platforms.
-        if(WIN32)
-          set(result "$<TARGET_FILE_NAME:${TARGET}>")
-        else()
-          set(result "$<TARGET_SONAME_FILE_NAME:${TARGET}>")
-        endif()
+        set(${DEST} ${result} PARENT_SCOPE)
     endif()
-    set(${DEST} ${result} PARENT_SCOPE)
 endfunction()
 
 function(sdl_check_project_in_subfolder relative_subfolder name vendored_option)
@@ -233,11 +244,14 @@ function(sdl_check_project_in_subfolder relative_subfolder name vendored_option)
 endfunction()
 
 macro(sdl_check_linker_flag flag var)
-    # FIXME: Use CheckLinkerFlag module once cmake minimum version >= 3.18
-    cmake_push_check_state(RESET)
-    set(CMAKE_REQUIRED_LINK_OPTIONS "${flag}")
-    check_c_source_compiles("int main() { return 0; }" ${var} FAIL_REGEX "(unsupported|syntax error|unrecognized option)")
-    cmake_pop_check_state()
+    if(NOT CMAKE_VERSION VERSION_LESS "3.18")
+        check_linker_flag(C "${flag}" "${var}")
+    else()
+        cmake_push_check_state(RESET)
+        set(CMAKE_REQUIRED_LINK_OPTIONS "${flag}")
+        check_c_source_compiles("int main() { return 0; }" ${var} FAIL_REGEX "(unsupported|syntax error|unrecognized option)")
+        cmake_pop_check_state()
+    endif()
 endmacro()
 
 function(SDL_detect_linker)
@@ -275,7 +289,6 @@ endfunction()
 function(sdl_target_link_options_no_undefined TARGET)
     if(NOT MSVC AND NOT CMAKE_SYSTEM_NAME MATCHES ".*OpenBSD.*")
         if(CMAKE_C_COMPILER_ID MATCHES "AppleClang")
-            target_link_options(${TARGET} PRIVATE "-Wl,-undefined,error")
         else()
             sdl_check_linker_flag("-Wl,--no-undefined" HAVE_WL_NO_UNDEFINED)
             if(HAVE_WL_NO_UNDEFINED AND NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") AND WIN32))
@@ -302,7 +315,7 @@ function(sdl_add_warning_options TARGET)
     if(MSVC)
         target_compile_options(${TARGET} PRIVATE /W2)
     else()
-        target_compile_options(${TARGET} PRIVATE -Wall)
+        target_compile_options(${TARGET} PRIVATE -Wall -Wextra -Wno-unused-parameter)
     endif()
     if(ARGS_WARNING_AS_ERROR)
         if(MSVC)
@@ -310,14 +323,23 @@ function(sdl_add_warning_options TARGET)
         else()
             target_compile_options(${TARGET} PRIVATE -Werror)
         endif()
+        get_property(target_type TARGET ${TARGET} PROPERTY TYPE)
+        if(NOT (APPLE OR MSVC))
+            if(target_type MATCHES "SHARED_LIBRARY|MODULE_LIBRARY")
+                sdl_check_linker_flag("-Wl,-fatal-warnings" HAVE_WL_FATAL_WARNINGS)
+                if(HAVE_WL_FATAL_WARNINGS)
+                    target_link_options(${TARGET} PRIVATE "-Wl,-fatal-warnings")
+                endif()
+            endif()
+        endif()
     endif()
 endfunction()
 
 function(sdl_no_deprecated_errors TARGET)
     check_c_compiler_flag(-Wno-error=deprecated-declarations HAVE_WNO_ERROR_DEPRECATED_DECLARATIONS)
-        if(HAVE_WNO_ERROR_DEPRECATED_DECLARATIONS)
-    target_compile_options(${TARGET} PRIVATE "-Wno-error=deprecated-declarations")
-endif()
+    if(HAVE_WNO_ERROR_DEPRECATED_DECLARATIONS)
+        target_compile_options(${TARGET} PRIVATE "-Wno-error=deprecated-declarations")
+    endif()
 endfunction()
 
 function(sdl_get_git_revision_hash VARNAME)