CMake: Simplify overriding of options / settings

Outer projects can just set() the option / setting before calling add_subdirectory() on Dawn.

Also provide a build directory for Dawn's third_party dependencies. Allows the outer project to specify a third_party directory that's out of the dawn tree.

Change-Id: I04c5f12b362ee9c9488b7b78a6aa5fa6f55dec98
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/64743
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 67d2386..a8eaf33 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -47,6 +47,30 @@
 # Configuration options
 ################################################################################
 
+# option_if_not_defined(name description default)
+# Behaves like:
+#   option(name description default)
+# If a variable is not already defined with the given name, otherwise the
+# function does nothing.
+# Simplifies customization by projects that use Dawn as a dependency.
+function (option_if_not_defined name description default)
+    if(NOT DEFINED ${name})
+        option(${name} ${description} ${default})
+    endif()
+endfunction()
+
+# set_if_not_defined(name value description)
+# Behaves like:
+#   set(${name} ${value} CACHE STRING ${description})
+# If a variable is not already defined with the given name, otherwise the
+# function does nothing.
+# Simplifies customization by projects that use Dawn as a dependency.
+function (set_if_not_defined name value description)
+    if(NOT DEFINED ${name})
+        set(${name} ${value} CACHE STRING ${description})
+    endif()
+endfunction()
+
 # Default values for the backend-enabling options
 set(ENABLE_D3D12 OFF)
 set(ENABLE_METAL OFF)
@@ -81,30 +105,30 @@
     set(BUILD_EXAMPLE ON)
 endif()
 
-option(DAWN_ENABLE_D3D12 "Enable compilation of the D3D12 backend" ${ENABLE_D3D12})
-option(DAWN_ENABLE_METAL "Enable compilation of the Metal backend" ${ENABLE_METAL})
-option(DAWN_ENABLE_NULL "Enable compilation of the Null backend" ON)
-option(DAWN_ENABLE_DESKTOP_GL "Enable compilation of the OpenGL backend" ${ENABLE_DESKTOP_GL})
-option(DAWN_ENABLE_OPENGLES "Enable compilation of the OpenGL ES backend" ${ENABLE_OPENGLES})
-option(DAWN_ENABLE_VULKAN "Enable compilation of the Vulkan backend" ${ENABLE_VULKAN})
-option(DAWN_ALWAYS_ASSERT "Enable assertions on all build types" OFF)
-option(DAWN_USE_X11 "Enable support for X11 surface" ${USE_X11})
+option_if_not_defined(DAWN_ENABLE_D3D12 "Enable compilation of the D3D12 backend" ${ENABLE_D3D12})
+option_if_not_defined(DAWN_ENABLE_METAL "Enable compilation of the Metal backend" ${ENABLE_METAL})
+option_if_not_defined(DAWN_ENABLE_NULL "Enable compilation of the Null backend" ON)
+option_if_not_defined(DAWN_ENABLE_DESKTOP_GL "Enable compilation of the OpenGL backend" ${ENABLE_DESKTOP_GL})
+option_if_not_defined(DAWN_ENABLE_OPENGLES "Enable compilation of the OpenGL ES backend" ${ENABLE_OPENGLES})
+option_if_not_defined(DAWN_ENABLE_VULKAN "Enable compilation of the Vulkan backend" ${ENABLE_VULKAN})
+option_if_not_defined(DAWN_ALWAYS_ASSERT "Enable assertions on all build types" OFF)
+option_if_not_defined(DAWN_USE_X11 "Enable support for X11 surface" ${USE_X11})
 
-option(DAWN_BUILD_EXAMPLES "Enables building Dawn's exmaples" ${BUILD_EXAMPLE})
+option_if_not_defined(DAWN_BUILD_EXAMPLES "Enables building Dawn's exmaples" ${BUILD_EXAMPLE})
 
-set(DAWN_THIRD_PARTY_DIR "${Dawn_SOURCE_DIR}/third_party" CACHE STRING "Directory in which to find third-party dependencies.")
+set_if_not_defined(DAWN_THIRD_PARTY_DIR "${Dawn_SOURCE_DIR}/third_party" "Directory in which to find third-party dependencies.")
 
 # Recommended setting for compability with future abseil releases.
 set(ABSL_PROPAGATE_CXX_STD ON)
-set(DAWN_ABSEIL_DIR "${DAWN_THIRD_PARTY_DIR}/abseil-cpp" CACHE STRING "Directory in which to find Abseil")
 
-set(DAWN_GLFW_DIR "${DAWN_THIRD_PARTY_DIR}/glfw" CACHE STRING "Directory in which to find GLFW")
-set(DAWN_GLM_DIR "${DAWN_THIRD_PARTY_DIR}/glm" CACHE STRING "Directory in which to find GLM")
-set(DAWN_JINJA2_DIR "${DAWN_THIRD_PARTY_DIR}/jinja2" CACHE STRING "Directory in which to find Jinja2")
-set(DAWN_SPIRV_CROSS_DIR "${DAWN_THIRD_PARTY_DIR}/vulkan-deps/spirv-cross/src" CACHE STRING "Directory in which to find SPIRV-Cross")
-set(DAWN_SPIRV_HEADERS_DIR "${DAWN_THIRD_PARTY_DIR}/vulkan-deps/spirv-headers/src" CACHE STRING "Directory in which to find SPIRV-Headers")
-set(DAWN_SPIRV_TOOLS_DIR "${DAWN_THIRD_PARTY_DIR}/vulkan-deps/spirv-tools/src" CACHE STRING "Directory in which to find SPIRV-Tools")
-set(DAWN_TINT_DIR "${DAWN_THIRD_PARTY_DIR}/tint" CACHE STRING "Directory in which to find Tint")
+set_if_not_defined(DAWN_ABSEIL_DIR "${DAWN_THIRD_PARTY_DIR}/abseil-cpp" "Directory in which to find Abseil")
+set_if_not_defined(DAWN_GLFW_DIR "${DAWN_THIRD_PARTY_DIR}/glfw" "Directory in which to find GLFW")
+set_if_not_defined(DAWN_GLM_DIR "${DAWN_THIRD_PARTY_DIR}/glm" "Directory in which to find GLM")
+set_if_not_defined(DAWN_JINJA2_DIR "${DAWN_THIRD_PARTY_DIR}/jinja2" "Directory in which to find Jinja2")
+set_if_not_defined(DAWN_SPIRV_CROSS_DIR "${DAWN_THIRD_PARTY_DIR}/vulkan-deps/spirv-cross/src" "Directory in which to find SPIRV-Cross")
+set_if_not_defined(DAWN_SPIRV_HEADERS_DIR "${DAWN_THIRD_PARTY_DIR}/vulkan-deps/spirv-headers/src" "Directory in which to find SPIRV-Headers")
+set_if_not_defined(DAWN_SPIRV_TOOLS_DIR "${DAWN_THIRD_PARTY_DIR}/vulkan-deps/spirv-tools/src" "Directory in which to find SPIRV-Tools")
+set_if_not_defined(DAWN_TINT_DIR "${DAWN_THIRD_PARTY_DIR}/tint" "Directory in which to find Tint")
 
 # Much of the backend code is shared among desktop OpenGL and OpenGL ES
 if (${DAWN_ENABLE_DESKTOP_GL} OR ${DAWN_ENABLE_OPENGLES})
diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt
index c8d20b6..8c4f961 100644
--- a/third_party/CMakeLists.txt
+++ b/third_party/CMakeLists.txt
@@ -18,7 +18,7 @@
     set(SPIRV_CROSS_SKIP_INSTALL ON CACHE BOOL "" FORCE)
 
     message(STATUS "Dawn: using spirv-cross at ${DAWN_SPIRV_CROSS_DIR}")
-    add_subdirectory(${DAWN_SPIRV_CROSS_DIR})
+    add_subdirectory(${DAWN_SPIRV_CROSS_DIR} "${CMAKE_BINARY_DIR}/third_party/spirv-cross")
 endif()
 
 if (NOT TARGET SPIRV-Headers)
@@ -26,7 +26,7 @@
     set(SPIRV_HEADERS_SKIP_INSTALL ON CACHE BOOL "" FORCE)
 
     message(STATUS "Dawn: using SPIRV-Headers at ${DAWN_SPIRV_HEADERS_DIR}")
-    add_subdirectory(${DAWN_SPIRV_HEADERS_DIR})
+    add_subdirectory(${DAWN_SPIRV_HEADERS_DIR} "${CMAKE_BINARY_DIR}/third_party/spirv-headers")
 endif()
 
 if (NOT TARGET SPIRV-Tools)
@@ -35,7 +35,7 @@
     set(SKIP_SPIRV_TOOLS_INSTALL ON CACHE BOOL "" FORCE)
 
     message(STATUS "Dawn: using SPIRV-Tools at ${DAWN_SPIRV_TOOLS_DIR}")
-    add_subdirectory(${DAWN_SPIRV_TOOLS_DIR})
+    add_subdirectory(${DAWN_SPIRV_TOOLS_DIR} "${CMAKE_BINARY_DIR}/third_party/spirv-tools")
 endif()
 
 if (NOT TARGET glfw)
@@ -44,24 +44,24 @@
     set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
 
     message(STATUS "Dawn: using GLFW at ${DAWN_GLFW_DIR}")
-    add_subdirectory(${DAWN_GLFW_DIR})
+    add_subdirectory(${DAWN_GLFW_DIR} "${CMAKE_BINARY_DIR}/third_party/glfw")
 endif()
 
 if (DAWN_BUILD_EXAMPLES)
     if (NOT TARGET glm)
         message(STATUS "Dawn: using GLM at ${DAWN_GLM_DIR}")
-        add_subdirectory(${DAWN_GLM_DIR})
+        add_subdirectory(${DAWN_GLM_DIR} "${CMAKE_BINARY_DIR}/third_party/glm")
     endif()
 endif()
 
 if (NOT TARGET libtint)
     message(STATUS "Dawn: using Tint at ${DAWN_TINT_DIR}")
-    add_subdirectory(${DAWN_TINT_DIR})
+    add_subdirectory(${DAWN_TINT_DIR} "${CMAKE_BINARY_DIR}/third_party/tint")
 endif()
 
 if (NOT TARGET libabsl)
     message(STATUS "Dawn: using Abseil at ${DAWN_ABSEIL_DIR}")
-    add_subdirectory(${DAWN_ABSEIL_DIR})
+    add_subdirectory(${DAWN_ABSEIL_DIR} "${CMAKE_BINARY_DIR}/third_party/abseil")
 endif()
 
 # Header-only library for khrplatform.h