CMake: Enable building with BUILD_SHARED_LIBS=1 (#3490)

Rename the `${SPIRV_TOOLS}` target to `${SPIRV_TOOLS}-static` and alias `${SPIRV_TOOLS}` to either `${SPIRV_TOOLS}-static` or `${SPIRV_TOOLS}-shared` depending on `BUILD_SHARED_LIBS`.

Re-point all internal uses of `${SPIRV_TOOLS}` to `${SPIRV_TOOLS}-static`.

`${SPIRV_TOOLS}-static` is explicitly renamed to just `${SPIRV_TOOLS}` to ensure the name does not change from current behavior.

Build the `SPIRV-Tools-*` libraries as static, as this is what they always were.

Force the external targets `gmock` and `effcee` to be built statically. These either do not support being built as shared libraries, or require special flags.

Issue: #3482
diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt
index 5b34159..f5009fd 100644
--- a/external/CMakeLists.txt
+++ b/external/CMakeLists.txt
@@ -13,6 +13,19 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# Utility functions for pushing & popping variables.
+function(push_variable var val)
+    set("${var}_SAVE_STACK" "${${var}}" "${${var}_SAVE_STACK}" PARENT_SCOPE)
+    set(${var} ${val} PARENT_SCOPE)
+endfunction()
+function(pop_variable var)
+    set(save_stack "${${var}_SAVE_STACK}")
+    list(GET save_stack 0 val)
+    list(REMOVE_AT save_stack 0)
+    set("${var}_SAVE_STACK" "${save_stack}" PARENT_SCOPE)
+    set(${var} ${val} PARENT_SCOPE)
+endfunction()
+
 if (DEFINED SPIRV-Headers_SOURCE_DIR)
   # This allows flexible position of the SPIRV-Headers repo.
   set(SPIRV_HEADER_DIR ${SPIRV-Headers_SOURCE_DIR})
@@ -61,7 +74,11 @@
           "Use shared (DLL) run-time lib even when Google Test is built as static lib."
           ON)
       endif()
+      # gtest requires special defines for building as a shared 
+      # library, simply always build as static.
+      push_variable(BUILD_SHARED_LIBS 0) 
       add_subdirectory(${GMOCK_DIR} EXCLUDE_FROM_ALL)
+      pop_variable(BUILD_SHARED_LIBS) 
     endif()
   endif()
   if (TARGET gmock)
@@ -108,7 +125,9 @@
       if (NOT TARGET effcee)
         set(EFFCEE_BUILD_TESTING OFF CACHE BOOL "Do not build Effcee test suite")
       endif()
+      push_variable(BUILD_SHARED_LIBS 0) # effcee does not export any symbols for building as a DLL. Always build as static.
       add_subdirectory(effcee EXCLUDE_FROM_ALL)
+      pop_variable(BUILD_SHARED_LIBS)
       set_property(TARGET effcee PROPERTY FOLDER Effcee)
       # Turn off warnings for effcee and re2
       set_property(TARGET effcee APPEND PROPERTY COMPILE_OPTIONS -w)
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index 708ca84..5a11320 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -345,18 +345,21 @@
 
 spvtools_pch(SPIRV_SOURCES pch_source)
 
-add_library(${SPIRV_TOOLS} ${SPIRV_SOURCES})
-spvtools_default_compile_options(${SPIRV_TOOLS})
-target_include_directories(${SPIRV_TOOLS}
+add_library(${SPIRV_TOOLS}-static STATIC ${SPIRV_SOURCES})
+spvtools_default_compile_options(${SPIRV_TOOLS}-static)
+target_include_directories(${SPIRV_TOOLS}-static
   PUBLIC
     $<BUILD_INTERFACE:${spirv-tools_SOURCE_DIR}/include>
     $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
   PRIVATE ${spirv-tools_BINARY_DIR}
   PRIVATE ${SPIRV_HEADER_INCLUDE_DIR}
   )
-set_property(TARGET ${SPIRV_TOOLS} PROPERTY FOLDER "SPIRV-Tools libraries")
-spvtools_check_symbol_exports(${SPIRV_TOOLS})
-add_dependencies( ${SPIRV_TOOLS} core_tables enum_string_mapping extinst_tables )
+set_property(TARGET ${SPIRV_TOOLS}-static PROPERTY FOLDER "SPIRV-Tools libraries")
+spvtools_check_symbol_exports(${SPIRV_TOOLS}-static)
+add_dependencies(${SPIRV_TOOLS}-static core_tables enum_string_mapping extinst_tables)
+
+# The static target does not have the '-static' suffix.
+set_target_properties(${SPIRV_TOOLS}-static PROPERTIES OUTPUT_NAME "${SPIRV_TOOLS}")
 
 add_library(${SPIRV_TOOLS}-shared SHARED ${SPIRV_SOURCES})
 spvtools_default_compile_options(${SPIRV_TOOLS}-shared)
@@ -374,18 +377,26 @@
   PRIVATE SPIRV_TOOLS_IMPLEMENTATION
   PUBLIC SPIRV_TOOLS_SHAREDLIB
 )
-add_dependencies( ${SPIRV_TOOLS}-shared core_tables enum_string_mapping extinst_tables )
+add_dependencies(${SPIRV_TOOLS}-shared core_tables enum_string_mapping extinst_tables)
+
+# Create the "${SPIRV_TOOLS}" target as an alias to either "${SPIRV_TOOLS}-static"
+# or "${SPIRV_TOOLS}-shared" depending on the value of BUILD_SHARED_LIBS.
+if(BUILD_SHARED_LIBS)
+    add_library(${SPIRV_TOOLS} ALIAS ${SPIRV_TOOLS}-shared)
+else()
+    add_library(${SPIRV_TOOLS} ALIAS ${SPIRV_TOOLS}-static)
+endif()
 
 if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
   find_library(LIBRT rt)
   if(LIBRT)
-    target_link_libraries(${SPIRV_TOOLS} ${LIBRT})
+    target_link_libraries(${SPIRV_TOOLS}-static ${LIBRT})
     target_link_libraries(${SPIRV_TOOLS}-shared ${LIBRT})
   endif()
 endif()
 
 if(ENABLE_SPIRV_TOOLS_INSTALL)
-  install(TARGETS ${SPIRV_TOOLS} ${SPIRV_TOOLS}-shared EXPORT ${SPIRV_TOOLS}Targets
+  install(TARGETS ${SPIRV_TOOLS}-static ${SPIRV_TOOLS}-shared EXPORT ${SPIRV_TOOLS}Targets
     RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
     LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
     ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
diff --git a/source/fuzz/CMakeLists.txt b/source/fuzz/CMakeLists.txt
index c413614..16075c8 100644
--- a/source/fuzz/CMakeLists.txt
+++ b/source/fuzz/CMakeLists.txt
@@ -319,7 +319,7 @@
 
   # The fuzzer reuses a lot of functionality from the SPIRV-Tools library.
   target_link_libraries(SPIRV-Tools-fuzz
-        PUBLIC ${SPIRV_TOOLS}
+        PUBLIC ${SPIRV_TOOLS}-static
         PUBLIC SPIRV-Tools-opt
         PUBLIC protobuf::libprotobuf)
 
diff --git a/source/link/CMakeLists.txt b/source/link/CMakeLists.txt
index d308319..bb058ea 100644
--- a/source/link/CMakeLists.txt
+++ b/source/link/CMakeLists.txt
@@ -11,7 +11,7 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-add_library(SPIRV-Tools-link
+add_library(SPIRV-Tools-link STATIC
   linker.cpp
 )
 
diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt
index 0047c34..090aeac 100644
--- a/source/opt/CMakeLists.txt
+++ b/source/opt/CMakeLists.txt
@@ -233,7 +233,7 @@
 
 spvtools_pch(SPIRV_TOOLS_OPT_SOURCES pch_source_opt)
 
-add_library(SPIRV-Tools-opt ${SPIRV_TOOLS_OPT_SOURCES})
+add_library(SPIRV-Tools-opt STATIC ${SPIRV_TOOLS_OPT_SOURCES})
 
 spvtools_default_compile_options(SPIRV-Tools-opt)
 target_include_directories(SPIRV-Tools-opt
@@ -245,7 +245,7 @@
 )
 # We need the assembling and disassembling functionalities in the main library.
 target_link_libraries(SPIRV-Tools-opt
-  PUBLIC ${SPIRV_TOOLS})
+  PUBLIC ${SPIRV_TOOLS}-static)
 
 set_property(TARGET SPIRV-Tools-opt PROPERTY FOLDER "SPIRV-Tools libraries")
 spvtools_check_symbol_exports(SPIRV-Tools-opt)
diff --git a/source/reduce/CMakeLists.txt b/source/reduce/CMakeLists.txt
index d945bd2..865510b 100644
--- a/source/reduce/CMakeLists.txt
+++ b/source/reduce/CMakeLists.txt
@@ -77,7 +77,7 @@
 
 spvtools_pch(SPIRV_TOOLS_REDUCE_SOURCES pch_source_reduce)
 
-add_library(SPIRV-Tools-reduce ${SPIRV_TOOLS_REDUCE_SOURCES})
+add_library(SPIRV-Tools-reduce STATIC ${SPIRV_TOOLS_REDUCE_SOURCES})
 
 spvtools_default_compile_options(SPIRV-Tools-reduce)
 target_include_directories(SPIRV-Tools-reduce
@@ -89,7 +89,7 @@
 )
 # The reducer reuses a lot of functionality from the SPIRV-Tools library.
 target_link_libraries(SPIRV-Tools-reduce
-  PUBLIC ${SPIRV_TOOLS}
+  PUBLIC ${SPIRV_TOOLS}-static
   PUBLIC SPIRV-Tools-opt)
 
 set_property(TARGET SPIRV-Tools-reduce PROPERTY FOLDER "SPIRV-Tools libraries")
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 70999f9..5dd4036 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -159,12 +159,12 @@
 add_spvtools_unittest(
   TARGET spirv_unit_tests
   SRCS ${TEST_SOURCES}
-  LIBS ${SPIRV_TOOLS})
+  LIBS ${SPIRV_TOOLS}-static)
 
 add_spvtools_unittest(
   TARGET c_interface
   SRCS c_interface_test.cpp
-  LIBS ${SPIRV_TOOLS})
+  LIBS ${SPIRV_TOOLS}-static)
 
 add_spvtools_unittest(
   TARGET c_interface_shared
@@ -181,7 +181,7 @@
 add_spvtools_unittest(
   TARGET timer
   SRCS timer_test.cpp
-  LIBS ${SPIRV_TOOLS})
+  LIBS ${SPIRV_TOOLS}-static)
 endif()
 
 
diff --git a/test/val/CMakeLists.txt b/test/val/CMakeLists.txt
index 23d7a19..c458a2f 100644
--- a/test/val/CMakeLists.txt
+++ b/test/val/CMakeLists.txt
@@ -41,21 +41,21 @@
        val_extension_spv_khr_terminate_invocation.cpp
        val_ext_inst_test.cpp
        ${VAL_TEST_COMMON_SRCS}
-  LIBS ${SPIRV_TOOLS}
+  LIBS ${SPIRV_TOOLS}-static
   PCH_FILE pch_test_val
 )
 
 add_spvtools_unittest(TARGET val_capability
   SRCS
        val_capability_test.cpp
-  LIBS ${SPIRV_TOOLS}
+  LIBS ${SPIRV_TOOLS}-static
   PCH_FILE pch_test_val
 )
 
 add_spvtools_unittest(TARGET val_limits
   SRCS val_limits_test.cpp
        ${VAL_TEST_COMMON_SRCS}
-  LIBS ${SPIRV_TOOLS}
+  LIBS ${SPIRV_TOOLS}-static
   PCH_FILE pch_test_val
 )
 
@@ -76,7 +76,7 @@
        val_opencl_test.cpp
        val_primitives_test.cpp
        ${VAL_TEST_COMMON_SRCS}
-  LIBS ${SPIRV_TOOLS}
+  LIBS ${SPIRV_TOOLS}-static
   PCH_FILE pch_test_val
 )
 
@@ -91,6 +91,6 @@
        val_version_test.cpp
        val_webgpu_test.cpp
        ${VAL_TEST_COMMON_SRCS}
-  LIBS ${SPIRV_TOOLS}
+  LIBS ${SPIRV_TOOLS}-static
   PCH_FILE pch_test_val
 )
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index b3a4cc1..67d606a 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -40,19 +40,19 @@
 endfunction()
 
 if (NOT ${SPIRV_SKIP_EXECUTABLES})
-  add_spvtools_tool(TARGET spirv-as SRCS as/as.cpp LIBS ${SPIRV_TOOLS})
-  add_spvtools_tool(TARGET spirv-dis SRCS dis/dis.cpp LIBS ${SPIRV_TOOLS})
-  add_spvtools_tool(TARGET spirv-val SRCS val/val.cpp util/cli_consumer.cpp LIBS ${SPIRV_TOOLS})
-  add_spvtools_tool(TARGET spirv-opt SRCS opt/opt.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS})
+  add_spvtools_tool(TARGET spirv-as SRCS as/as.cpp LIBS ${SPIRV_TOOLS}-static)
+  add_spvtools_tool(TARGET spirv-dis SRCS dis/dis.cpp LIBS ${SPIRV_TOOLS}-static)
+  add_spvtools_tool(TARGET spirv-val SRCS val/val.cpp util/cli_consumer.cpp LIBS ${SPIRV_TOOLS}-static)
+  add_spvtools_tool(TARGET spirv-opt SRCS opt/opt.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS}-static)
   if (NOT DEFINED IOS_PLATFORM) # iOS does not allow std::system calls which spirv-reduce requires
-    add_spvtools_tool(TARGET spirv-reduce SRCS reduce/reduce.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-reduce ${SPIRV_TOOLS})
+    add_spvtools_tool(TARGET spirv-reduce SRCS reduce/reduce.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-reduce ${SPIRV_TOOLS}-static)
   endif()
-  add_spvtools_tool(TARGET spirv-link SRCS link/linker.cpp LIBS SPIRV-Tools-link ${SPIRV_TOOLS})
+  add_spvtools_tool(TARGET spirv-link SRCS link/linker.cpp LIBS SPIRV-Tools-link ${SPIRV_TOOLS}-static)
   add_spvtools_tool(TARGET spirv-cfg
                     SRCS cfg/cfg.cpp
                          cfg/bin_to_dot.h
                          cfg/bin_to_dot.cpp
-                    LIBS ${SPIRV_TOOLS})
+                    LIBS ${SPIRV_TOOLS}-static)
   target_include_directories(spirv-cfg PRIVATE ${spirv-tools_SOURCE_DIR}
                                                ${SPIRV_HEADER_INCLUDE_DIR})
   set(SPIRV_INSTALL_TARGETS spirv-as spirv-dis spirv-val spirv-opt
@@ -62,7 +62,7 @@
   endif()
 
   if(SPIRV_BUILD_FUZZER)
-    add_spvtools_tool(TARGET spirv-fuzz SRCS fuzz/fuzz.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-fuzz ${SPIRV_TOOLS})
+    add_spvtools_tool(TARGET spirv-fuzz SRCS fuzz/fuzz.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-fuzz ${SPIRV_TOOLS}-static)
     set(SPIRV_INSTALL_TARGETS ${SPIRV_INSTALL_TARGETS} spirv-fuzz)
   endif(SPIRV_BUILD_FUZZER)