From 9fd06955ddb4e58314b3a122348d3721b47d496e Mon Sep 17 00:00:00 2001
From: Dudemanguy <random342@airmail.cc>
Date: Thu, 23 Feb 2023 10:00:21 -0600
Subject: [PATCH] dependencies: add custom atomic dependency

Almost exactly the same as how the dl dependency works. On certain
systems (like BSDs that use clang), stdatomic is provided by compiler-rt
and doesn't need a separate library explictly linked. On a typical
GNU/LINUX system, atomic is a separate library that must be explictly
found and linked against. So just add a builtin and system method for
these two use cases.
---
 docs/markdown/Dependencies.md               | 10 ++++++++
 docs/markdown/snippets/atomic-dependency.md |  9 +++++++
 mesonbuild/dependencies/__init__.py         |  1 +
 mesonbuild/dependencies/misc.py             | 28 +++++++++++++++++++++
 4 files changed, 48 insertions(+)
 create mode 100644 docs/markdown/snippets/atomic-dependency.md

diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md
index 93f75d5a916b..2e255b209822 100644
--- a/docs/markdown/Dependencies.md
+++ b/docs/markdown/Dependencies.md
@@ -317,6 +317,16 @@ dep = dependency('appleframeworks', modules : 'foundation')
 
 These dependencies can never be found for non-OSX hosts.
 
+## atomic (stdatomic)
+
+*(added 1.7.0)*
+
+Provides access to the atomic operations library. This first attempts
+to look for a valid atomic external library before trying to fallback
+to what is provided by the C runtime libraries.
+
+`method` may be `auto`, `builtin` or `system`.
+
 ## Blocks
 
 Enable support for Clang's blocks extension.
diff --git a/docs/markdown/snippets/atomic-dependency.md b/docs/markdown/snippets/atomic-dependency.md
new file mode 100644
index 000000000000..2eef5e0b1cb0
--- /dev/null
+++ b/docs/markdown/snippets/atomic-dependency.md
@@ -0,0 +1,9 @@
+## New custom dependency for atomic
+
+```
+dependency('atomic')
+```
+
+checks for the availability of the atomic operation library. First, it looks
+for the atomic library. If that is not found, then it will try to use what is
+provided by the libc.
diff --git a/mesonbuild/dependencies/__init__.py b/mesonbuild/dependencies/__init__.py
index a3eb6623f02c..95e606975a5e 100644
--- a/mesonbuild/dependencies/__init__.py
+++ b/mesonbuild/dependencies/__init__.py
@@ -220,6 +220,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.
     'shaderc': 'misc',
     'iconv': 'misc',
     'intl': 'misc',
+    'atomic': 'misc',
     'dl': 'misc',
     'openssl': 'misc',
     'libcrypto': 'misc',
diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py
index 4815e1c18cd9..7bfe198e0179 100644
--- a/mesonbuild/dependencies/misc.py
+++ b/mesonbuild/dependencies/misc.py
@@ -51,6 +51,27 @@ def netcdf_factory(env: 'Environment',
 packages['netcdf'] = netcdf_factory
 
 
+class AtomicBuiltinDependency(BuiltinDependency):
+    def __init__(self, name: str, env: Environment, kwargs: T.Dict[str, T.Any]):
+        super().__init__(name, env, kwargs)
+        self.feature_since = ('1.7.0', "consider checking for `atomic_flag_clear` with and without `find_library('atomic')`")
+
+        if self.clib_compiler.has_function('atomic_flag_clear', '#include <stdatomic.h>', env)[0]:
+            self.is_found = True
+
+
+class AtomicSystemDependency(SystemDependency):
+    def __init__(self, name: str, env: Environment, kwargs: T.Dict[str, T.Any]):
+        super().__init__(name, env, kwargs)
+        self.feature_since = ('1.7.0', "consider checking for `atomic_flag_clear` with and without `find_library('atomic')`")
+
+        h = self.clib_compiler.has_header('stdatomic.h', '', env)
+        self.link_args = self.clib_compiler.find_library('atomic', env, [], self.libtype)
+
+        if h[0] and self.link_args:
+            self.is_found = True
+
+
 class DlBuiltinDependency(BuiltinDependency):
     def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
         super().__init__(name, env, kwargs)
@@ -564,6 +585,13 @@ def shaderc_factory(env: 'Environment',
 packages['shaderc'] = shaderc_factory
 
 
+packages['atomic'] = atomic_factory = DependencyFactory(
+    'atomic',
+    [DependencyMethods.SYSTEM, DependencyMethods.BUILTIN],
+    system_class=AtomicSystemDependency,
+    builtin_class=AtomicBuiltinDependency,
+)
+
 packages['cups'] = cups_factory = DependencyFactory(
     'cups',
     [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK, DependencyMethods.CMAKE],