diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml
index aff830284f069dc3250f7013fba6eb60e98c7f97..0ca4ddeaa44cb53f9de9d2f7d817d663bdc44e69 100644
--- a/debian/gitlab-ci.yml
+++ b/debian/gitlab-ci.yml
@@ -49,12 +49,23 @@ ubsan:
                 clang-tools \
                 ${NULL+}
 
+            rm -fr builddir
+            meson \
+                -Db_lundef=false \
+                -Db_sanitize=address,undefined \
+                --werror \
+                builddir
+            ninja -C builddir
+            meson test -C builddir -v
+
             export CC=clang
+            export CXX=clang++
 
             rm -fr builddir
             meson \
                 -Db_lundef=false \
                 -Db_sanitize=address,undefined \
+                --werror \
                 builddir
             ninja -C builddir scan-build
             meson test -C builddir -v
diff --git a/debian/rules b/debian/rules
index 9e30a9ef675c0a9099c270fcb9f53adcf840319e..41b2ae0ba5113562bd8a2c849c26858ee6746351 100755
--- a/debian/rules
+++ b/debian/rules
@@ -11,6 +11,12 @@ ifeq ($(shell dpkg --compare-versions `c++ -dumpversion || echo 0` ge 4.8 || ech
 export CXX = g++-4.8
 endif
 
+meson_options =
+
+ifeq ($(DEB_DISTRIBUTION),UNRELEASED)
+meson_options += --werror
+endif
+
 gtk_doc_has_cflags := $(shell \
 	if gtkdoc-scangobj --help 2>&1 | grep '[-]-cflags' >/dev/null; then \
 		echo true; \
@@ -42,7 +48,7 @@ override_dh_auto_configure:
 		-Dgtk_doc=$(gtk_doc_has_cflags) \
 		-Dintrospection=false \
 		-Dmultiarch_tuple=$(DEB_HOST_MULTIARCH) \
-		$(NULL)
+		$(meson_options)
 
 override_dh_auto_build:
 	ninja -C builddir
diff --git a/helpers/check-vulkan.cpp b/helpers/check-vulkan.cpp
index 32e49c3dbb53a9859445f58b88e3160e5f950a9d..af5d3d8b4496fb816870792c875aca3f5910e2e7 100644
--- a/helpers/check-vulkan.cpp
+++ b/helpers/check-vulkan.cpp
@@ -783,50 +783,50 @@ private:
         }
     }
 
-    SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) {
+    SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice dev) {
         SwapChainSupportDetails details;
 
-        vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
+        vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, surface, &details.capabilities);
 
         uint32_t formatCount;
-        vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
+        vkGetPhysicalDeviceSurfaceFormatsKHR(dev, surface, &formatCount, nullptr);
 
         if (formatCount != 0) {
             details.formats.resize(formatCount);
-            vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
+            vkGetPhysicalDeviceSurfaceFormatsKHR(dev, surface, &formatCount, details.formats.data());
         }
 
         uint32_t presentModeCount;
-        vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
+        vkGetPhysicalDeviceSurfacePresentModesKHR(dev, surface, &presentModeCount, nullptr);
 
         if (presentModeCount != 0) {
             details.presentModes.resize(presentModeCount);
-            vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
+            vkGetPhysicalDeviceSurfacePresentModesKHR(dev, surface, &presentModeCount, details.presentModes.data());
         }
 
         return details;
     }
 
-    bool isDeviceSuitable(VkPhysicalDevice device) {
-        QueueFamilyIndices indices = findQueueFamilies(device);
+    bool isDeviceSuitable(VkPhysicalDevice dev) {
+        QueueFamilyIndices indices = findQueueFamilies(dev);
 
-        bool extensionsSupported = checkDeviceExtensionSupport(device);
+        bool extensionsSupported = checkDeviceExtensionSupport(dev);
 
         bool swapChainAdequate = false;
         if (extensionsSupported) {
-            SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);
+            SwapChainSupportDetails swapChainSupport = querySwapChainSupport(dev);
             swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
         }
 
         return indices.isComplete() && extensionsSupported && swapChainAdequate;
     }
 
-    bool checkDeviceExtensionSupport(VkPhysicalDevice device) {
+    bool checkDeviceExtensionSupport(VkPhysicalDevice dev) {
         uint32_t extensionCount;
-        vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
+        vkEnumerateDeviceExtensionProperties(dev, nullptr, &extensionCount, nullptr);
 
         std::vector<VkExtensionProperties> availableExtensions(extensionCount);
-        vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
+        vkEnumerateDeviceExtensionProperties(dev, nullptr, &extensionCount, availableExtensions.data());
 
         std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
 
@@ -837,16 +837,16 @@ private:
         return requiredExtensions.empty();
     }
 
-    QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
+    QueueFamilyIndices findQueueFamilies(VkPhysicalDevice dev) {
         QueueFamilyIndices indices;
         indices.hasGraphicsFamily = false;
         indices.hasPresentFamily = false;
 
         uint32_t queueFamilyCount = 0;
-        vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
+        vkGetPhysicalDeviceQueueFamilyProperties(dev, &queueFamilyCount, nullptr);
 
         std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
-        vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
+        vkGetPhysicalDeviceQueueFamilyProperties(dev, &queueFamilyCount, queueFamilies.data());
 
         int i = 0;
         for (const auto& queueFamily : queueFamilies) {
@@ -856,7 +856,7 @@ private:
             }
 
             VkBool32 presentSupport = false;
-            vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
+            vkGetPhysicalDeviceSurfaceSupportKHR(dev, i, surface, &presentSupport);
 
             if (queueFamily.queueCount > 0 && presentSupport) {
                 indices.presentFamily = i;
diff --git a/helpers/meson.build b/helpers/meson.build
index f0f475a59f6ea2885145506460e9d605ef84bb5d..80b6a218268d11ad1e6122d14db42a65c87b2317 100644
--- a/helpers/meson.build
+++ b/helpers/meson.build
@@ -24,6 +24,7 @@
 executable(
   multiarch + '-true',
   'true.c',
+  include_directories : project_include_dirs,
   install : true,
   install_dir : pkglibexecdir,
   # Deliberately no RPATH/RUNPATH here: it's unnecessary because this
@@ -46,6 +47,7 @@ executable(
   multiarch + '-inspect-library',
   'inspect-library.c',
   dependencies : [libdl],
+  include_directories : project_include_dirs,
   install : true,
   install_dir : pkglibexecdir,
   # Deliberately no RPATH/RUNPATH here: we want to determine whether
@@ -56,6 +58,7 @@ executable(
   multiarch + '-check-vulkan',
   'check-vulkan.cpp',
   dependencies : [vulkan, xcb],
+  include_directories : project_include_dirs,
   install : true,
   install_dir : join_paths(
     get_option('libexecdir'),
diff --git a/meson.build b/meson.build
index acc59c3f82b29e028c9d2c7c9ab8d466edeb0e8c..e688948affe120414abb7590cfe5eb36bcbfff6b 100644
--- a/meson.build
+++ b/meson.build
@@ -21,9 +21,15 @@
 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
-project('steam-runtime-tools', 'c', 
-        version : '0.20191024.0',
-        default_options: ['cpp_std=c++11'])
+project(
+  'steam-runtime-tools', 'c',
+  version : '0.20191024.0',
+  default_options: [
+    'c_std=c99',
+    'cpp_std=c++11',
+    'warning_level=2',
+  ],
+)
 add_languages('cpp')
 
 api_major = '0'
@@ -49,31 +55,24 @@ endif
 
 glslang_validator = find_program('glslangValidator', required : true)
 
-warning_cflags = [
+warning_flags = [
     '-Wall',
     '-Wextra',
     '-Warray-bounds',
     '-Wcast-align',
-    '-Wdeclaration-after-statement',
     '-Wdouble-promotion',
     '-Wduplicated-branches',
     '-Wduplicated-cond',
     '-Wformat-nonliteral',
     '-Wformat-security',
     '-Wformat=2',
-    '-Wimplicit-function-declaration',
     '-Winit-self',
-    '-Winline',
-    '-Wjump-misses-init',
     '-Wlogical-op',
     '-Wmissing-declarations',
     '-Wmissing-format-attribute',
     '-Wmissing-include-dirs',
     '-Wmissing-noreturn',
-    '-Wmissing-prototypes',
-    '-Wnested-externs',
     '-Wnull-dereference',
-    '-Wold-style-definition',
     '-Wpacked',
     '-Wpointer-arith',
     '-Wredundant-decls',
@@ -81,27 +80,46 @@ warning_cflags = [
     '-Wreturn-type',
     '-Wshadow',
     '-Wstrict-aliasing',
-    '-Wstrict-prototypes',
     '-Wswitch-default',
     '-Wswitch-enum',
     '-Wundef',
     '-Wunused-but-set-variable',
     '-Wwrite-strings',
 ]
-no_warning_cflags = [
-    'declaration-after-statement',
+warning_cflags = warning_flags + [
+    '-Wimplicit-function-declaration',
+    '-Wjump-misses-init',
+    '-Wmissing-prototypes',
+    '-Wnested-externs',
+    '-Wold-style-definition',
+    '-Wstrict-prototypes',
+]
+warning_cxxflags = warning_flags + [
+]
+
+no_warning_flags = [
+    'inline',
     'missing-field-initializers',
+    'pedantic',
     'sign-compare',
     'unused-local-typedefs',
     'unused-parameter',
 ]
+no_warning_cflags = no_warning_flags + [
+    'declaration-after-statement',
+]
+no_warning_cxxflags = no_warning_flags + [
+]
 
 c_compiler = meson.get_compiler('c')
+cpp_compiler = meson.get_compiler('cpp')
 supported_warning_cflags = c_compiler.get_supported_arguments(warning_cflags)
 add_project_arguments(supported_warning_cflags, language : 'c')
+supported_warning_cxxflags = cpp_compiler.get_supported_arguments(warning_cxxflags)
+add_project_arguments(supported_warning_cxxflags, language : 'cpp')
 
-add_project_arguments(
-  c_compiler.get_supported_arguments(
+add_project_link_arguments(
+  c_compiler.get_supported_link_arguments(
     '-Wl,-z,origin',
     # Generate RPATH in preference to RUNPATH, even if RUNPATH is the
     # linker's default. We want RPATH here, because it's used recursively
@@ -121,18 +139,31 @@ foreach flag : no_warning_cflags
   add_project_arguments(supported_no_warning_cflags, language : 'c')
 endforeach
 
+foreach flag : no_warning_cxxflags
+  supported_no_warning_cxxflags = cpp_compiler.get_supported_arguments([
+    '-Wno-error=' + flag,
+    '-Wno-' + flag,
+  ])
+  add_project_arguments(supported_no_warning_cxxflags, language : 'cpp')
+endforeach
+
 conf_data = configuration_data()
+conf_data.set('_GNU_SOURCE', '1')
 conf_data.set_quoted('VERSION', meson.project_version())
 
 configure_file(
-  output : 'config.h',
+  output : '_steam-runtime-tools-config.h',
   configuration : conf_data,
 )
 
-add_project_arguments(['-std=c99'], language : 'c')
-add_project_arguments(['-D_GNU_SOURCE'], language : 'c')
-add_project_arguments(['-include', 'config.h'], language : 'c')
-add_project_arguments(['-include', 'config.h'], language : 'cpp')
+add_project_arguments(
+  ['-include', '_steam-runtime-tools-config.h'],
+  language : 'c',
+)
+add_project_arguments(
+  ['-include', '_steam-runtime-tools-config.h'],
+  language : 'cpp',
+)
 
 glib = dependency(
   'glib-2.0',
diff --git a/tests/meson.build b/tests/meson.build
index 784f33db5cbd11fc3bc1c65e9417ac43053b7af4..bfd2354aad47e817a0329ca2dd32450bdfaad826 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -65,6 +65,7 @@ install_subdir('sysroots', install_dir : tests_dir)
 executable(
   'mock-true',
   join_paths('..', 'helpers', 'true.c'),
+  include_directories : project_include_dirs,
   install : get_option('installed_tests'),
   install_dir : tests_dir,
 )
@@ -77,6 +78,7 @@ foreach test_name : tests
       '-D_SRT_MULTIARCH="' + multiarch + '"',
     ],
     dependencies : [glib, gobject, libsteamrt_dep, json_glib],
+    include_directories : project_include_dirs,
     install : get_option('installed_tests'),
     install_dir : tests_dir,
   )
@@ -146,6 +148,7 @@ executable(
 executable(
   'mock-good-wflinfo',
   'mock-good-wflinfo.c',
+  include_directories : project_include_dirs,
   install: true,
   install_dir: tests_dir
 )
@@ -153,6 +156,7 @@ executable(
 executable(
   'mock-hanging-wflinfo',
   'mock-hanging-wflinfo.c',
+  include_directories : project_include_dirs,
   install: true,
   install_dir: tests_dir
 )
@@ -160,6 +164,7 @@ executable(
 executable(
   'mock-bad-wflinfo',
   'mock-bad-wflinfo.c',
+  include_directories : project_include_dirs,
   install: true,
   install_dir: tests_dir
 )
@@ -167,6 +172,7 @@ executable(
 executable(
   'mock-software-wflinfo',
   'mock-software-wflinfo.c',
+  include_directories : project_include_dirs,
   install: true,
   install_dir: tests_dir
 )
@@ -174,6 +180,7 @@ executable(
 executable(
   'mock-good-vulkaninfo',
   'mock-good-vulkaninfo.c',
+  include_directories : project_include_dirs,
   install: true,
   install_dir: tests_dir
 )
@@ -181,6 +188,7 @@ executable(
 executable(
   'mock-bad-vulkaninfo',
   'mock-bad-vulkaninfo.c',
+  include_directories : project_include_dirs,
   install: true,
   install_dir: tests_dir
 )
@@ -188,6 +196,7 @@ executable(
 executable(
   'mock-good-check-vulkan',
   join_paths('..', 'helpers', 'true.c'),
+  include_directories : project_include_dirs,
   install: true,
   install_dir: tests_dir
 )
@@ -195,6 +204,7 @@ executable(
 executable(
   'mock-bad-check-vulkan',
   'mock-bad-check-vulkan.c',
+  include_directories : project_include_dirs,
   install: true,
   install_dir: tests_dir
 )
@@ -202,6 +212,7 @@ executable(
 executable(
   'mock-mixed-vulkaninfo',
   'mock-good-vulkaninfo.c',
+  include_directories : project_include_dirs,
   install: true,
   install_dir: tests_dir
 )
@@ -209,6 +220,7 @@ executable(
 executable(
   'mock-mixed-check-vulkan',
   'mock-bad-check-vulkan.c',
+  include_directories : project_include_dirs,
   install: true,
   install_dir: tests_dir
 )