diff --git a/libvmaf/meson.build b/libvmaf/meson.build index cf20cecbd..71ab6f986 100644 --- a/libvmaf/meson.build +++ b/libvmaf/meson.build @@ -29,21 +29,38 @@ elif host_machine.system() == 'darwin' endif # Header checks -stdatomic_dependency = [] -if not cc.check_header('stdatomic.h') - if cc.get_id() == 'msvc' - # we have a custom replacement for MSVC - stdatomic_dependency = declare_dependency( - include_directories : include_directories('src/compat/msvc'), - ) - elif cc.compiles('''int main() { int v = 0; return __atomic_fetch_add(&v, 1, __ATOMIC_SEQ_CST); }''', - name : 'GCC-style atomics', args : test_args) - stdatomic_dependency = declare_dependency( - include_directories : include_directories('src/compat/gcc'), - ) +if cc.has_header('stdatomic.h', args: test_args) + if cc.check_header('stdatomic.h', args: test_args) + stdatomic_dependency = declare_dependency(compile_args: '-DHAVE_STDATOMIC_H') + elif cc.get_id() == 'msvc' + # If stdatomic.h exists but isn't usable under MSVC it may be because recent (VS2022) MSVC + # has added support for lock-free atomics where (sizeof(T) <= sizeof(intptr_t)) + # Note that __STDC_NO_ATOMICS__ remains defined due to lack of locking atomics + test_args += '/experimental:c11atomics' + + if not cc.check_header('stdatomic.h', args: test_args) + error('stdatomic.h exists but could not be made usable under MSVC with /experimental:c11atomics') + endif + + add_project_arguments('/experimental:c11atomics', language: 'c') + stdatomic_dependency = declare_dependency(compile_args: '-DHAVE_STDATOMIC_H') else - error('Atomics not supported') + error('stdatomic.h was found but is not usable for some reason; check whether the compiler needs extension flags') endif +elif cc.get_id() == 'msvc' + # we have a custom replacement for MSVC before /experimental:c11atomics was added + stdatomic_dependency = declare_dependency( + compile_args : '-DHAVE_STDATOMIC_H', + include_directories : include_directories('src/compat/msvc'), + ) +elif cc.compiles('''int main() { int v = 0; return __atomic_fetch_add(&v, 1, __ATOMIC_SEQ_CST); }''', + name : 'GCC-style atomics', args : test_args) + stdatomic_dependency = declare_dependency( + compile_args : '-DHAVE_STDATOMIC_H', + include_directories : include_directories('src/compat/gcc'), + ) +else + error('Atomics not supported') endif subdir('include') diff --git a/libvmaf/src/compat/msvc/stdatomic.h b/libvmaf/src/compat/msvc/stdatomic.h index 979ee2ba8..17613686d 100644 --- a/libvmaf/src/compat/msvc/stdatomic.h +++ b/libvmaf/src/compat/msvc/stdatomic.h @@ -27,20 +27,29 @@ #ifndef MSCVER_STDATOMIC_H_ #define MSCVER_STDATOMIC_H_ -#if !defined(__cplusplus) && defined(_MSC_VER) +#ifdef __cplusplus +#error "This compatibility header should not be used with C++ files (C++ has its own )" +#endif + +#ifndef _MSC_VER +#error "This compatibility header should only be used with MSVC (clang-cl might work)" +#endif + +#ifndef __STDC_NO_ATOMICS__ +#error "This compatibility header should only be used with MSVC versions that don't implement " +#endif #pragma warning(push) #pragma warning(disable:4067) /* newline for __has_include_next */ #if defined(__clang__) && __has_include_next() + /* ??? This should not happen unless system exists but for some reason the Meson test for it failed. */ /* use the clang stdatomic.h with clang-cl*/ # include_next -#else /* ! stdatomic.h */ +#else /* ! clang && stdatomic.h */ #include -#include "common/attributes.h" - typedef volatile LONG __declspec(align(32)) atomic_int; typedef volatile ULONG __declspec(align(32)) atomic_uint; @@ -65,6 +74,4 @@ typedef enum { #pragma warning(pop) -#endif /* !defined(__cplusplus) && defined(_MSC_VER) */ - #endif /* MSCVER_STDATOMIC_H_ */ diff --git a/libvmaf/src/feature/feature_extractor.h b/libvmaf/src/feature/feature_extractor.h index 574436e76..4baf26989 100644 --- a/libvmaf/src/feature/feature_extractor.h +++ b/libvmaf/src/feature/feature_extractor.h @@ -19,7 +19,11 @@ #ifndef __VMAF_FEATURE_EXTRACTOR_H__ #define __VMAF_FEATURE_EXTRACTOR_H__ +#ifdef HAVE_STDATOMIC_H #include +#else +#error "Meson target is missing stdatomic_depedency" +#endif #include #include diff --git a/libvmaf/src/framesync.h b/libvmaf/src/framesync.h index 08e9a543a..aa8e1d483 100644 --- a/libvmaf/src/framesync.h +++ b/libvmaf/src/framesync.h @@ -20,7 +20,11 @@ #define __VMAF_FRAME_SYNC_H__ #include +#ifdef HAVE_STDATOMIC_H #include +#else +#error "Meson target is missing stdatomic_depedency" +#endif #include #include #include "libvmaf/libvmaf.h" diff --git a/libvmaf/src/ref.h b/libvmaf/src/ref.h index 66cd93956..291ef29e8 100644 --- a/libvmaf/src/ref.h +++ b/libvmaf/src/ref.h @@ -19,7 +19,11 @@ #ifndef __VMAF_SRC_REF_H__ #define __VMAF_SRC_REF_H__ +#ifdef HAVE_STDATOMIC_H #include +#else +#error "Meson target is missing stdatomic_depedency" +#endif typedef struct VmafRef { atomic_int cnt; diff --git a/libvmaf/test/meson.build b/libvmaf/test/meson.build index e8d943e98..53574709f 100644 --- a/libvmaf/test/meson.build +++ b/libvmaf/test/meson.build @@ -26,7 +26,7 @@ test_feature_collector = executable('test_feature_collector', ['test.c', 'test_feature_collector.c', '../src/log.c', '../src/predict.c', '../src/svm.cpp', '../src/metadata_handler.c'], include_directories : [libvmaf_inc, test_inc, include_directories('../src/feature/'), include_directories('../src')], link_with : get_option('default_library') == 'both' ? libvmaf.get_static_lib() : libvmaf, - dependencies: cuda_dependency + dependencies: [stdatomic_dependency, cuda_dependency] ) test_log = executable('test_log', @@ -46,7 +46,7 @@ test_model = executable('test_model', link_with : get_option('default_library') == 'both' ? libvmaf.get_static_lib() : libvmaf, c_args : [vmaf_cflags_common, '-DJSON_MODEL_PATH="'+join_paths(meson.project_source_root(), '../model/')+'"'], cpp_args : vmaf_cflags_common, - dependencies : [thread_lib, cuda_dependency], + dependencies : [stdatomic_dependency, thread_lib, cuda_dependency], ) test_predict = executable('test_predict', @@ -57,7 +57,7 @@ test_predict = executable('test_predict', link_with : get_option('default_library') == 'both' ? libvmaf.get_static_lib() : libvmaf, c_args : vmaf_cflags_common, cpp_args : vmaf_cflags_common, - dependencies : [thread_lib, cuda_dependency], + dependencies : [stdatomic_dependency, thread_lib, cuda_dependency], ) test_feature_extractor = executable('test_feature_extractor', @@ -88,6 +88,7 @@ test_cpu = executable('test_cpu', test_ref = executable('test_ref', ['test.c', 'test_ref.c', '../src/ref.c'], include_directories : [libvmaf_inc, test_inc, include_directories('../src/')], + dependencies: stdatomic_dependency ) test_feature = executable('test_feature', @@ -99,14 +100,14 @@ test_ciede = executable('test_ciede', ['test.c', 'test_ciede.c'], include_directories : [libvmaf_inc, test_inc, include_directories('../src/')], link_with : get_option('default_library') == 'both' ? libvmaf.get_static_lib() : libvmaf, - dependencies: cuda_dependency + dependencies: [stdatomic_dependency, cuda_dependency] ) test_cambi = executable('test_cambi', ['test.c', 'test_cambi.c', '../src/picture.c', '../src/mem.c', '../src/ref.c'], include_directories : [libvmaf_inc, test_inc, include_directories('../src/')], link_with : get_option('default_library') == 'both' ? libvmaf.get_static_lib() : libvmaf, - dependencies: cuda_dependency + dependencies: [stdatomic_dependency, cuda_dependency] ) test_luminance_tools = executable('test_luminance_tools', @@ -126,6 +127,7 @@ test_psnr = executable('test_psnr', ['test.c', 'test_psnr.c', '../src/picture.c'], include_directories : [libvmaf_inc, test_inc, include_directories('../src/')], link_with : get_option('default_library') == 'both' ? libvmaf.get_static_lib() : libvmaf, + dependencies : stdatomic_dependency ) test_framesync = executable('test_framesync', @@ -134,7 +136,7 @@ test_framesync = executable('test_framesync', link_with : get_option('default_library') == 'both' ? libvmaf.get_static_lib() : libvmaf, c_args : vmaf_cflags_common, cpp_args : vmaf_cflags_common, - dependencies : thread_lib, + dependencies : [stdatomic_dependency, thread_lib], ) if get_option('enable_cuda')