# CMake build file list for OpenAL cmake_minimum_required(VERSION 3.13...3.31) enable_testing() if(APPLE) # The workaround for try_compile failing with code signing # since cmake-3.18.2, not required set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES ${CMAKE_TRY_COMPILE_PLATFORM_VARIABLES} "CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED" "CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED") set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED NO) set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED NO) endif() if(CMAKE_SYSTEM_NAME STREQUAL "iOS") # Fix compile failure with armv7 deployment target >= 11.0, xcode clang # will report: # error: invalid iOS deployment version '--target=armv7-apple-ios13.6', # iOS 10 is the maximum deployment target for 32-bit targets # If CMAKE_OSX_DEPLOYMENT_TARGET is not defined, cmake will choose latest # deployment target if("${CMAKE_OSX_ARCHITECTURES}" MATCHES ".*armv7.*") if(NOT DEFINED CMAKE_OSX_DEPLOYMENT_TARGET OR NOT CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS "11.0") message(STATUS "Forcing iOS deployment target to 10.0 for armv7") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.0" CACHE STRING "Minimum OS X deployment version" FORCE) endif() endif() elseif(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") set(ALSOFT_UWP TRUE) endif() project(OpenAL VERSION 1.24.3 LANGUAGES C CXX) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) endif() if(NOT CMAKE_DEBUG_POSTFIX) set(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Library postfix for debug builds. Normally left blank." FORCE) endif() set(ALSOFT_STD_VERSION_PROPS # Require C++20. CXX_STANDARD 20 CXX_STANDARD_REQUIRED TRUE # Prefer C17, but support earlier when necessary. C_STANDARD 17) set(CMAKE_MODULE_PATH "${OpenAL_SOURCE_DIR}/cmake") include(CheckFunctionExists) include(CheckLibraryExists) include(CheckIncludeFile) include(CheckIncludeFiles) include(CheckSymbolExists) include(CheckCCompilerFlag) include(CheckCXXCompilerFlag) include(CheckCSourceCompiles) include(CheckCXXSourceCompiles) include(CheckCXXSymbolExists) include(CheckLinkerFlag) include(CheckStructHasMember) include(CMakePackageConfigHelpers) include(GNUInstallDirs) find_package(PkgConfig) find_package(SDL3 QUIET) option(ALSOFT_DLOPEN "Check for the dlopen API for loading optional libs" ON) option(ALSOFT_WERROR "Treat compile warnings as errors" OFF) option(ALSOFT_UTILS "Build utility programs" ON) option(ALSOFT_NO_CONFIG_UTIL "Disable building the alsoft-config utility" OFF) option(ALSOFT_EXAMPLES "Build example programs" ON) option(ALSOFT_TESTS "Build test programs" OFF) option(ALSOFT_INSTALL "Install main library" ON) option(ALSOFT_INSTALL_CONFIG "Install alsoft.conf sample configuration file" ON) option(ALSOFT_INSTALL_HRTF_DATA "Install HRTF data files" ON) option(ALSOFT_INSTALL_AMBDEC_PRESETS "Install AmbDec preset files" ON) option(ALSOFT_INSTALL_EXAMPLES "Install example programs (alplay, alstream, ...)" ON) option(ALSOFT_INSTALL_UTILS "Install utility programs (openal-info, alsoft-config, ...)" ON) option(ALSOFT_UPDATE_BUILD_VERSION "Update git build version info" ON) option(ALSOFT_EAX "Enable legacy EAX extensions" ${WIN32}) option(ALSOFT_SEARCH_INSTALL_DATADIR "Search the installation data directory" OFF) if(ALSOFT_SEARCH_INSTALL_DATADIR) set(ALSOFT_INSTALL_DATADIR ${CMAKE_INSTALL_FULL_DATADIR}) endif() if(DEFINED SHARE_INSTALL_DIR) message(WARNING "SHARE_INSTALL_DIR is deprecated. Use the variables provided by the GNUInstallDirs module instead") set(CMAKE_INSTALL_DATADIR "${SHARE_INSTALL_DIR}") endif() if(DEFINED LIB_SUFFIX) message(WARNING "LIB_SUFFIX is deprecated. Use the variables provided by the GNUInstallDirs module instead") endif() if(DEFINED ALSOFT_CONFIG) message(WARNING "ALSOFT_CONFIG is deprecated. Use ALSOFT_INSTALL_CONFIG instead") endif() if(DEFINED ALSOFT_HRTF_DEFS) message(WARNING "ALSOFT_HRTF_DEFS is deprecated. Use ALSOFT_INSTALL_HRTF_DATA instead") endif() if(DEFINED ALSOFT_AMBDEC_PRESETS) message(WARNING "ALSOFT_AMBDEC_PRESETS is deprecated. Use ALSOFT_INSTALL_AMBDEC_PRESETS instead") endif() if(MSVC) option(FORCE_STATIC_VCRT "Force /MT for static VC runtimes" OFF) if(FORCE_STATIC_VCRT) foreach(flag_var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) if(${flag_var} MATCHES "/MD") string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") endif() endforeach(flag_var) endif() endif() if(WIN32 AND MINGW AND CMAKE_SIZEOF_VOID_P MATCHES "4") # HACK: 32-bit MinGW defines __STDCPP_DEFAULT_NEW_ALIGNMENT__ to 16, while # its default operator new relies on the system/Windows malloc that only # guarantees 8-byte alignment, leading to structs that need 16-byte # alignment being misaligned. This switch overrides that to assume only # 8-byte alignment from the default operator new. add_compile_options("$<$:-faligned-new=8>") endif() # Setting ALSOFT_STL_HARDENING=None disables/minimizes STL hardening, doing # only checks required by the standard (or can't be disabled at all). Should # really only be used where maximum performance is critical and the extra # safety can be sacrificed. # # ALSOFT_STL_HARDENING=Default enables some STL hardening, checking for more # significant issues that can also be done "fast", that's easier to optimize # away when unneeded and/or not become a bottleneck. This is generally # considered fine for production use, hence being the default here. # # ALSOFT_STL_HARDENING=Debug enables even more STL hardening, which has a much # higher runtime cost for less benefit. It's not intended for production use. set(ALSOFT_STL_HARDENING "Default" CACHE STRING "Specifies the level of C++ STL hardening. None, Default, Debug") set(HARDENING_LEVEL "None") check_cxx_symbol_exists(__GLIBCXX__ "version" HAVE_LIBSTDCXX) check_cxx_symbol_exists(_LIBCPP_VERSION "version" HAVE_LIBCXX) check_cxx_symbol_exists(_MSVC_STL_UPDATE "version" HAVE_MSSTL) if(HAVE_LIBSTDCXX) if(ALSOFT_STL_HARDENING STREQUAL "Debug") add_compile_definitions("_GLIBCXX_DEBUG=1") set(HARDENING_LEVEL "Debug") elseif(ALSOFT_STL_HARDENING STREQUAL "None") # TODO: Not sure how to fully disable STL hardening with libstdc++, # aside from not defining anything and using the compiler's default. # _GLIBCXX_NO_ASSERTIONS can explicitly disable the hardening # assertions, but not all STL debugging functionality. add_compile_definitions("_GLIBCXX_NO_ASSERTIONS=1") set(HARDENING_LEVEL "None") else() if(NOT (ALSOFT_STL_HARDENING STREQUAL "Default")) message(NOTICE "Unsupported STL hardening option \"${ALSOFT_STL_HARDENING}\", using Default") endif() add_compile_definitions("_GLIBCXX_ASSERTIONS=1") set(HARDENING_LEVEL "Default") endif() elseif(HAVE_LIBCXX) if(ALSOFT_STL_HARDENING STREQUAL "Debug") add_compile_definitions("_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG") set(HARDENING_LEVEL "Debug") elseif(ALSOFT_STL_HARDENING STREQUAL "None") add_compile_definitions("_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE") set(HARDENING_LEVEL "None") else() if(NOT (ALSOFT_STL_HARDENING STREQUAL "Default")) message(NOTICE "Unsupported STL hardening option \"${ALSOFT_STL_HARDENING}\", using Default") endif() add_compile_definitions("_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST") set(HARDENING_LEVEL "Default") endif() elseif(HAVE_MSSTL) if(ALSOFT_STL_HARDENING STREQUAL "Debug") # TODO: Is there anything more reasonable for heavier debugging (non- # production use) checks, where performance is not so important? add_compile_definitions("_MSVC_STL_HARDENING=1") set(HARDENING_LEVEL "Default") elseif(ALSOFT_STL_HARDENING STREQUAL "None") add_compile_definitions("_MSVC_STL_HARDENING=0") set(HARDENING_LEVEL "None") else() if(NOT (ALSOFT_STL_HARDENING STREQUAL "Default")) message(NOTICE "Unsupported STL hardening option \"${ALSOFT_STL_HARDENING}\", using Default") endif() add_compile_definitions("_MSVC_STL_HARDENING=1") set(HARDENING_LEVEL "Default") endif() endif() # Work out whether C++20 modules are supported. Currently only works with CMake # 3.28+ and the Ninja or VS 17 2022 generator, along with GCC 15+, Clang 17+, # or MSVC 14.34+. Unfortunately CMake doesn't provide any check to tell whether # it supports modules with the given generator and compiler, so we have to do a # check ourselves (which is far less inclusive and more pessimistic than what # it can actually do, especially as CMake continues to update and improve). option(ALSOFT_ENABLE_MODULES "Enable use of C++20 modules when supported" ON) set(HAVE_CXXMODULES FALSE) if(ALSOFT_ENABLE_MODULES) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.28 AND (CMAKE_GENERATOR STREQUAL "Ninja" OR CMAKE_GENERATOR STREQUAL "Visual Studio 17 2022")) if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 17.0) OR (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15.0) OR (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 14.34)) message(STATUS "C++20 modules enabled using ${CMAKE_CXX_COMPILER_ID} compiler v${CMAKE_CXX_COMPILER_VERSION} (CMake ${CMAKE_VERSION}, ${CMAKE_GENERATOR} generator)") set(HAVE_CXXMODULES TRUE) else() message(NOTICE "C++20 modules not supported with ${CMAKE_CXX_COMPILER_ID} compiler v${CMAKE_CXX_COMPILER_VERSION}") endif() else() message(NOTICE "C++20 modules not supported with ${CMAKE_GENERATOR} on CMake ${CMAKE_VERSION}") endif() endif() add_subdirectory(fmt-11.2.0 EXCLUDE_FROM_ALL) set(CPP_DEFS ) # C pre-processor, not C++ set(INC_PATHS ) set(C_FLAGS ) set(LINKER_FLAGS ) set(LINKER_FLAGS_DEBUG ) set(LINKER_FLAGS_RELEASE ) set(EXTRA_LIBS ) if(WIN32) set(CPP_DEFS ${CPP_DEFS} _WIN32 NOMINMAX WIN32_LEAN_AND_MEAN) if(MINGW) set(CPP_DEFS ${CPP_DEFS} __USE_MINGW_ANSI_STDIO) endif() option(ALSOFT_BUILD_ROUTER "Build the router (EXPERIMENTAL; creates OpenAL32.dll and soft_oal.dll)" OFF) if(MINGW) option(ALSOFT_BUILD_IMPORT_LIB "Build an import .lib using dlltool (requires sed)" ON) endif() if(NOT ALSOFT_UWP) # Some systems may need NTDDI_VERSION defined to NTDDI_VISTA or later check_c_source_compiles("#define INITGUID #include #include int main() { SHGetKnownFolderPath(&FOLDERID_RoamingAppData, KF_FLAG_DONT_UNEXPAND, NULL, NULL); return 0; }" HAVE_SHGETKNOWNFOLDERPATH_NO_NTDDI) if(NOT HAVE_SHGETKNOWNFOLDERPATH_NO_NTDDI) set(CPP_DEFS ${CPP_DEFS} NTDDI_VERSION=NTDDI_VISTA) endif() endif() elseif(APPLE) option(ALSOFT_OSX_FRAMEWORK "Build as macOS framework" OFF) endif() # QNX's gcc do not uses /usr/include and /usr/lib paths by default if("${CMAKE_C_PLATFORM_ID}" STREQUAL "QNX") set(INC_PATHS ${INC_PATHS} /usr/include) set(LINKER_FLAGS ${LINKER_FLAGS} -L/usr/lib) endif() # When the library is built for static linking, apps should define # AL_LIBTYPE_STATIC when including the AL headers. if(NOT LIBTYPE) set(LIBTYPE SHARED) endif() set(EXPORT_DECL "") # Some systems may need libatomic for atomic functions to work set(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) set(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES} atomic) check_cxx_source_compiles("#include std::atomic foo{0}; int main() { return foo.fetch_add(2); }" HAVE_LIBATOMIC) if(NOT HAVE_LIBATOMIC) set(CMAKE_REQUIRED_LIBRARIES "${OLD_REQUIRED_LIBRARIES}") else() set(EXTRA_LIBS atomic ${EXTRA_LIBS}) endif() unset(OLD_REQUIRED_LIBRARIES) if(ANDROID) # Include liblog for Android logging check_library_exists(log __android_log_print "" HAVE_LIBLOG) if(HAVE_LIBLOG) set(EXTRA_LIBS log ${EXTRA_LIBS}) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} log) endif() endif() if(MSVC) # NOTE: _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR is temporary. When building on # VS 2022 17.10 or newer, but using an older runtime, mutexes can crash # when locked. Ideally the runtime should be updated on the system, but # until the update becomes more widespread, this helps avoid some pain # points. set(CPP_DEFS ${CPP_DEFS} _CRT_SECURE_NO_WARNINGS _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR) check_cxx_compiler_flag(/permissive- HAVE_PERMISSIVE_SWITCH) if(HAVE_PERMISSIVE_SWITCH) set(C_FLAGS ${C_FLAGS} $<$:/permissive->) endif() # C4127 - conditional expression is constant # C4324 - structure was padded due to alignment specifier set(C_FLAGS ${C_FLAGS} /W4 /wd4127 /wd4324 /utf-8 $<$:/EHsc>) if(NOT DXSDK_DIR) string(REGEX REPLACE "\\\\" "/" DXSDK_DIR "$ENV{DXSDK_DIR}") else() string(REGEX REPLACE "\\\\" "/" DXSDK_DIR "${DXSDK_DIR}") endif() if(DXSDK_DIR) message(STATUS "Using DirectX SDK directory: ${DXSDK_DIR}") endif() else() # FIXME: Should include -Winline, but GCC tries inlining too much with # fmtlib due to all the constexpr functions and template classes, spamming # a bunch of warnings that we can't do anything about. Until something like # feeble_inline gets implemented and used, or inline is ignored by default, # we'll have to ignore inline warning. # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93008 set(C_FLAGS ${C_FLAGS} -Wunused -Wall -Wextra -Wshadow -Wconversion -Wcast-align -Wpedantic $<$:-Wold-style-cast -Wnon-virtual-dtor -Woverloaded-virtual>) check_cxx_compiler_flag(-Wno-interference-size HAVE_WNO_INTERFERENCE_SIZE) if(HAVE_WNO_INTERFERENCE_SIZE) set(C_FLAGS ${C_FLAGS} $<$:-Wno-interference-size>) endif() if(ALSOFT_WERROR) set(C_FLAGS ${C_FLAGS} -Werror) else() set(C_FLAGS ${C_FLAGS} -Werror=undef) endif() # NOTE: This essentially provides the equivalent of the C++26 feature to # initialize all local variables with a non-0 bit pattern. Until C++26 is # adopted, the [[gnu::uninitialized]] attribute will avoid the auto- # initialization where necessary. check_c_compiler_flag(-ftrivial-auto-var-init=pattern HAVE_FTRIVIAL_AUTO_VAR_INIT) if(HAVE_FTRIVIAL_AUTO_VAR_INIT) set(C_FLAGS ${C_FLAGS} -ftrivial-auto-var-init=pattern) endif() check_c_compiler_flag(-fno-math-errno HAVE_FNO_MATH_ERRNO) if(HAVE_FNO_MATH_ERRNO) set(C_FLAGS ${C_FLAGS} -fno-math-errno) endif() option(ALSOFT_STATIC_LIBGCC "Force -static-libgcc for static GCC runtimes" OFF) if(ALSOFT_STATIC_LIBGCC) set(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} -static-libgcc) check_cxx_source_compiles("int main() { }" HAVE_STATIC_LIBGCC_SWITCH) set(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES}) unset(OLD_REQUIRED_LIBRARIES) if(NOT HAVE_STATIC_LIBGCC_SWITCH) message(FATAL_ERROR "Cannot static link libgcc") endif() set(LINKER_FLAGS ${LINKER_FLAGS} -static-libgcc) endif() option(ALSOFT_STATIC_STDCXX "Static link libstdc++" OFF) if(ALSOFT_STATIC_STDCXX) set(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} "-static-libstdc++") check_cxx_source_compiles("int main() { }" HAVE_STATIC_LIBSTDCXX_SWITCH) set(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES}) unset(OLD_REQUIRED_LIBRARIES) if(NOT HAVE_STATIC_LIBSTDCXX_SWITCH) message(FATAL_ERROR "Cannot static link libstdc++") endif() set(LINKER_FLAGS ${LINKER_FLAGS} "-static-libstdc++") endif() if(WIN32) option(ALSOFT_STATIC_WINPTHREAD "Static link libwinpthread" OFF) if(ALSOFT_STATIC_WINPTHREAD) set(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} "-Wl,--push-state,-Bstatic,-lstdc++,-lwinpthread,--pop-state") check_cxx_source_compiles("int main() { }" HAVE_STATIC_LIBWINPTHREAD_SWITCH) set(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES}) unset(OLD_REQUIRED_LIBRARIES) if(NOT HAVE_STATIC_LIBWINPTHREAD_SWITCH) message(FATAL_ERROR "Cannot static link libwinpthread") endif() set(LINKER_FLAGS ${LINKER_FLAGS} "-Wl,--push-state,-Bstatic,-lstdc++,-lwinpthread,--pop-state") endif() endif() endif() # Set visibility/export options if available if(NOT LIBTYPE STREQUAL "STATIC") if(WIN32) set(EXPORT_DECL "__declspec(dllexport)") else() set(OLD_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") # Yes GCC, really don't accept visibility modes you don't support set(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS} -Wattributes -Werror") check_c_source_compiles("int foo() __attribute__((visibility(\"protected\"))); int main() {return 0;}" HAVE_GCC_PROTECTED_VISIBILITY) if(HAVE_GCC_PROTECTED_VISIBILITY) set(EXPORT_DECL "__attribute__((visibility(\"protected\")))") else() check_c_source_compiles("int foo() __attribute__((visibility(\"default\"))); int main() {return 0;}" HAVE_GCC_DEFAULT_VISIBILITY) if(HAVE_GCC_DEFAULT_VISIBILITY) set(EXPORT_DECL "__attribute__((visibility(\"default\")))") endif() endif() if(HAVE_GCC_PROTECTED_VISIBILITY OR HAVE_GCC_DEFAULT_VISIBILITY) set(CMAKE_C_VISIBILITY_PRESET hidden) set(CMAKE_CXX_VISIBILITY_PRESET hidden) endif() set(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS}") endif() endif() set(SSE2_SWITCH "") if(NOT MSVC) set(OLD_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) # Yes GCC, really don't accept command line options you don't support set(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS} -Werror") check_c_compiler_flag(-msse2 HAVE_MSSE2_SWITCH) if(HAVE_MSSE2_SWITCH) set(SSE2_SWITCH "-msse2") endif() set(CMAKE_REQUIRED_FLAGS ${OLD_REQUIRED_FLAGS}) unset(OLD_REQUIRED_FLAGS) endif() check_include_file(xmmintrin.h HAVE_XMMINTRIN_H) check_include_file(emmintrin.h HAVE_EMMINTRIN_H) check_include_file(pmmintrin.h HAVE_PMMINTRIN_H) check_include_file(smmintrin.h HAVE_SMMINTRIN_H) check_include_file(arm_neon.h HAVE_ARM_NEON_H) set(HAVE_SSE 0) set(HAVE_SSE2 0) set(HAVE_SSE3 0) set(HAVE_SSE4_1 0) set(HAVE_NEON 0) # Check for SSE support option(ALSOFT_CPUEXT_SSE "Enable SSE support" ON) option(ALSOFT_REQUIRE_SSE "Require SSE support" OFF) if(ALSOFT_CPUEXT_SSE AND HAVE_XMMINTRIN_H) set(HAVE_SSE 1) endif() if(ALSOFT_REQUIRE_SSE AND NOT HAVE_SSE) message(FATAL_ERROR "Failed to enable required SSE CPU extensions") endif() option(ALSOFT_CPUEXT_SSE2 "Enable SSE2 support" ON) option(ALSOFT_REQUIRE_SSE2 "Require SSE2 support" OFF) if(ALSOFT_CPUEXT_SSE2 AND HAVE_SSE AND HAVE_EMMINTRIN_H) set(HAVE_SSE2 1) endif() if(ALSOFT_REQUIRE_SSE2 AND NOT HAVE_SSE2) message(FATAL_ERROR "Failed to enable required SSE2 CPU extensions") endif() option(ALSOFT_CPUEXT_SSE3 "Enable SSE3 support" ON) option(ALSOFT_REQUIRE_SSE3 "Require SSE3 support" OFF) if(ALSOFT_CPUEXT_SSE3 AND HAVE_SSE2 AND HAVE_PMMINTRIN_H) set(HAVE_SSE3 1) endif() if(ALSOFT_REQUIRE_SSE3 AND NOT HAVE_SSE3) message(FATAL_ERROR "Failed to enable required SSE3 CPU extensions") endif() option(ALSOFT_CPUEXT_SSE4_1 "Enable SSE4.1 support" ON) option(ALSOFT_REQUIRE_SSE4_1 "Require SSE4.1 support" OFF) if(ALSOFT_CPUEXT_SSE4_1 AND HAVE_SSE3 AND HAVE_SMMINTRIN_H) set(HAVE_SSE4_1 1) endif() if(ALSOFT_REQUIRE_SSE4_1 AND NOT HAVE_SSE4_1) message(FATAL_ERROR "Failed to enable required SSE4.1 CPU extensions") endif() # Check for ARM Neon support option(ALSOFT_CPUEXT_NEON "Enable ARM NEON support" ON) option(ALSOFT_REQUIRE_NEON "Require ARM NEON support" OFF) if(ALSOFT_CPUEXT_NEON AND HAVE_ARM_NEON_H) check_c_source_compiles("#include int main() { int32x4_t ret4 = vdupq_n_s32(0); return vgetq_lane_s32(ret4, 0); }" HAVE_NEON_INTRINSICS) if(HAVE_NEON_INTRINSICS) set(HAVE_NEON 1) endif() endif() if(ALSOFT_REQUIRE_NEON AND NOT HAVE_NEON) message(FATAL_ERROR "Failed to enable required ARM NEON CPU extensions") endif() set(ALSOFT_FORCE_ALIGN ) set(SSE_FLAGS ) set(FPMATH_SET "0") if(CMAKE_SIZEOF_VOID_P MATCHES "4" AND HAVE_SSE2) option(ALSOFT_ENABLE_SSE2_CODEGEN "Enable SSE2 code generation instead of x87 for 32-bit targets." TRUE) if(ALSOFT_ENABLE_SSE2_CODEGEN) if(MSVC) check_c_compiler_flag("/arch:SSE2" HAVE_ARCH_SSE2) if(HAVE_ARCH_SSE2) set(SSE_FLAGS ${SSE_FLAGS} "/arch:SSE2") set(C_FLAGS ${C_FLAGS} ${SSE_FLAGS}) set(FPMATH_SET 2) endif() elseif(SSE2_SWITCH) check_c_compiler_flag("${SSE2_SWITCH} -mfpmath=sse" HAVE_MFPMATH_SSE_2) if(HAVE_MFPMATH_SSE_2) set(SSE_FLAGS ${SSE_FLAGS} ${SSE2_SWITCH} -mfpmath=sse) set(C_FLAGS ${C_FLAGS} ${SSE_FLAGS}) set(FPMATH_SET 2) endif() # SSE depends on a 16-byte aligned stack, and by default, GCC # assumes the stack is suitably aligned. Older Linux code or other # OSs don't guarantee this on 32-bit, so externally-callable # functions need to ensure an aligned stack. set(EXPORT_DECL "${EXPORT_DECL}__attribute__((force_align_arg_pointer))") set(ALSOFT_FORCE_ALIGN "__attribute__((force_align_arg_pointer))") endif() endif() endif() if(HAVE_SSE2) set(OLD_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) foreach(flag_var ${SSE_FLAGS}) set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${flag_var}") endforeach() check_c_source_compiles("#include int main() {_mm_pause(); return 0;}" HAVE_SSE_INTRINSICS) set(CMAKE_REQUIRED_FLAGS ${OLD_REQUIRED_FLAGS}) endif() check_include_file(cpuid.h HAVE_CPUID_H) check_include_file(intrin.h HAVE_INTRIN_H) check_include_file(guiddef.h HAVE_GUIDDEF_H) # Some systems need libm for some math functions to work set(MATH_LIB ) check_library_exists(m pow "" HAVE_LIBM) if(HAVE_LIBM) set(MATH_LIB ${MATH_LIB} m) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} m) endif() # Some systems need to link with -lrt for clock_gettime as used by the common # eaxmple functions. set(RT_LIB ) check_library_exists(rt clock_gettime "" HAVE_LIBRT) if(HAVE_LIBRT) set(RT_LIB rt) endif() # Check for the dlopen API (for dynamically loading backend libs) if(ALSOFT_DLOPEN) check_include_file(dlfcn.h HAVE_DLFCN_H) check_library_exists(dl dlopen "" HAVE_LIBDL) if(HAVE_LIBDL) set(EXTRA_LIBS dl ${EXTRA_LIBS}) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} dl) endif() endif() # Check for a cpuid intrinsic if(HAVE_CPUID_H) check_c_source_compiles("#include int main() { unsigned int eax, ebx, ecx, edx; return __get_cpuid(0, &eax, &ebx, &ecx, &edx); }" HAVE_GCC_GET_CPUID) endif() if(HAVE_INTRIN_H) check_c_source_compiles("#include int main() { int regs[4]; __cpuid(regs, 0); return regs[0]; }" HAVE_CPUID_INTRINSIC) endif() check_symbol_exists(proc_pidpath libproc.h HAVE_PROC_PIDPATH) if(NOT WIN32) # We need pthreads outside of Windows, for semaphores. It's also used to # set the priority and name of threads, when possible. check_include_file(pthread.h HAVE_PTHREAD_H) if(NOT HAVE_PTHREAD_H) message(FATAL_ERROR "PThreads is required for non-Windows builds!") endif() check_c_compiler_flag(-pthread HAVE_PTHREAD) if(HAVE_PTHREAD) set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -pthread") set(C_FLAGS ${C_FLAGS} -pthread) set(LINKER_FLAGS ${LINKER_FLAGS} -pthread) endif() check_symbol_exists(pthread_setschedparam pthread.h HAVE_PTHREAD_SETSCHEDPARAM) # Some systems need pthread_np.h to get pthread_setname_np check_include_files("pthread.h;pthread_np.h" HAVE_PTHREAD_NP_H) if(HAVE_PTHREAD_NP_H) check_symbol_exists(pthread_setname_np "pthread.h;pthread_np.h" HAVE_PTHREAD_SETNAME_NP) if(NOT HAVE_PTHREAD_SETNAME_NP) check_symbol_exists(pthread_set_name_np "pthread.h;pthread_np.h" HAVE_PTHREAD_SET_NAME_NP) endif() else() check_symbol_exists(pthread_setname_np pthread.h HAVE_PTHREAD_SETNAME_NP) if(NOT HAVE_PTHREAD_SETNAME_NP) check_symbol_exists(pthread_set_name_np pthread.h HAVE_PTHREAD_SET_NAME_NP) endif() endif() endif() # Common sources used by both the OpenAL implementation library, the OpenAL # router, and certain tools and examples. set(COMMON_OBJS common/albit.h common/alcomplex.cpp common/alcomplex.h common/almalloc.h common/alnumeric.h common/alstring.cpp common/alstring.h common/althrd_setname.cpp common/althrd_setname.h common/althreads.h common/atomic.h common/comptr.h common/dynload.cpp common/dynload.h common/expected.hpp common/filesystem.cpp common/filesystem.h common/flexarray.h common/intrusive_ptr.h common/opthelpers.h common/pffft.cpp common/pffft.h common/phase_shifter.h common/polyphase_resampler.cpp common/polyphase_resampler.h common/pragmadefs.h common/ringbuffer.h common/strutils.cpp common/strutils.hpp common/vecmat.h common/vector.h gsl/include/gsl/algorithm gsl/include/gsl/assert gsl/include/gsl/byte gsl/include/gsl/gsl gsl/include/gsl/narrow gsl/include/gsl/pointers gsl/include/gsl/span gsl/include/gsl/span_ext gsl/include/gsl/util gsl/include/gsl/zstring ) # Core library routines set(CORE_OBJS core/ambdec.cpp core/ambdec.h core/ambidefs.cpp core/ambidefs.h core/async_event.h core/bformatdec.cpp core/bformatdec.h core/bs2b.cpp core/bs2b.h core/bsinc_defs.h core/bsinc_tables.cpp core/bsinc_tables.h core/bufferline.h core/buffer_storage.cpp core/buffer_storage.h core/context.cpp core/context.h core/converter.cpp core/converter.h core/cpu_caps.cpp core/cpu_caps.h core/cubic_defs.h core/cubic_tables.cpp core/cubic_tables.h core/devformat.cpp core/devformat.h core/device.cpp core/device.h core/effects/base.h core/effectslot.cpp core/effectslot.h core/except.cpp core/except.h core/filters/biquad.h core/filters/biquad.cpp core/filters/nfc.cpp core/filters/nfc.h core/filters/splitter.cpp core/filters/splitter.h core/fmt_traits.h core/fpu_ctrl.cpp core/fpu_ctrl.h core/front_stablizer.h core/helpers.cpp core/helpers.h core/hrtf.cpp core/hrtf.h core/hrtf_loader.cpp core/hrtf_loader.hpp core/hrtf_resource.cpp core/hrtf_resource.hpp core/logging.cpp core/logging.h core/mastering.cpp core/mastering.h core/mixer.cpp core/mixer.h core/resampler_limits.h core/storage_formats.cpp core/storage_formats.h core/uhjfilter.cpp core/uhjfilter.h core/uiddefs.cpp core/voice.cpp core/voice.h core/voice_change.h) set(HAVE_RTKIT 0) if(NOT WIN32) option(ALSOFT_RTKIT "Enable RTKit support" ON) option(ALSOFT_REQUIRE_RTKIT "Require RTKit/D-Bus support" FALSE) if(ALSOFT_RTKIT) find_package(DBus1 QUIET) if(NOT DBus1_FOUND AND PkgConfig_FOUND) pkg_check_modules(DBUS dbus-1) endif() if(DBus1_FOUND OR DBUS_FOUND) set(HAVE_RTKIT 1) set(CORE_OBJS ${CORE_OBJS} core/dbus_wrap.cpp core/dbus_wrap.h core/rtkit.cpp core/rtkit.h) if(NOT DBus1_FOUND) set(INC_PATHS ${INC_PATHS} ${DBUS_INCLUDE_DIRS}) set(CPP_DEFS ${CPP_DEFS} ${DBUS_CFLAGS_OTHER}) if(NOT HAVE_DLFCN_H) set(EXTRA_LIBS ${EXTRA_LIBS} ${DBUS_LINK_LIBRARIES}) endif() elseif(HAVE_DLFCN_H) set(INC_PATHS ${INC_PATHS} ${DBus1_INCLUDE_DIRS}) set(CPP_DEFS ${CPP_DEFS} ${DBus1_DEFINITIONS}) else() set(EXTRA_LIBS ${EXTRA_LIBS} ${DBus1_LIBRARIES}) endif() else() set(MISSING_VARS "") if(NOT DBus1_INCLUDE_DIRS) set(MISSING_VARS "${MISSING_VARS} DBus1_INCLUDE_DIRS") endif() if(NOT DBus1_LIBRARIES) set(MISSING_VARS "${MISSING_VARS} DBus1_LIBRARIES") endif() message(STATUS "Could NOT find DBus1 (missing:${MISSING_VARS})") unset(MISSING_VARS) endif() endif() endif() if(ALSOFT_REQUIRE_RTKIT AND NOT HAVE_RTKIT) message(FATAL_ERROR "Failed to enable required RTKit support") endif() # Default mixers, always available set(CORE_OBJS ${CORE_OBJS} core/mixer/defs.h core/mixer/hrtfbase.h core/mixer/hrtfdefs.h core/mixer/mixer_c.cpp) # AL and related routines set(OPENAL_OBJS al/auxeffectslot.cpp al/auxeffectslot.h al/buffer.cpp al/buffer.h al/debug.cpp al/debug.h al/direct_defs.h al/effect.cpp al/effect.h al/effects/autowah.cpp al/effects/chorus.cpp al/effects/compressor.cpp al/effects/convolution.cpp al/effects/dedicated.cpp al/effects/distortion.cpp al/effects/echo.cpp al/effects/effects.cpp al/effects/effects.h al/effects/equalizer.cpp al/effects/fshifter.cpp al/effects/modulator.cpp al/effects/null.cpp al/effects/pshifter.cpp al/effects/reverb.cpp al/effects/vmorpher.cpp al/error.cpp al/event.cpp al/event.h al/extension.cpp al/filter.cpp al/filter.h al/listener.cpp al/listener.h al/source.cpp al/source.h al/state.cpp) # ALC and related routines set(ALC_OBJS alc/alc.cpp alc/alu.cpp alc/alu.h alc/alconfig.cpp alc/alconfig.h alc/context.cpp alc/context.h alc/device.cpp alc/device.h alc/effects/base.h alc/effects/autowah.cpp alc/effects/chorus.cpp alc/effects/compressor.cpp alc/effects/convolution.cpp alc/effects/dedicated.cpp alc/effects/distortion.cpp alc/effects/echo.cpp alc/effects/equalizer.cpp alc/effects/fshifter.cpp alc/effects/modulator.cpp alc/effects/null.cpp alc/effects/pshifter.cpp alc/effects/reverb.cpp alc/effects/vmorpher.cpp alc/events.cpp alc/events.h alc/export_list.h alc/inprogext.h alc/panning.cpp) if(ALSOFT_EAX) set(OPENAL_OBJS ${OPENAL_OBJS} al/eax.cpp al/eax/api.cpp al/eax/api.h al/eax/call.cpp al/eax/call.h al/eax/effect.h al/eax/exception.cpp al/eax/exception.h al/eax/fx_slot_index.cpp al/eax/fx_slot_index.h al/eax/fx_slots.cpp al/eax/fx_slots.h al/eax/globals.h al/eax/utils.cpp al/eax/utils.h al/eax/x_ram.h ) endif() # Include SIMD mixers set(CPU_EXTS "Default") if(HAVE_SSE) set(CORE_OBJS ${CORE_OBJS} core/mixer/mixer_sse.cpp) set(CPU_EXTS "${CPU_EXTS}, SSE") endif() if(HAVE_SSE2) set(CORE_OBJS ${CORE_OBJS} core/mixer/mixer_sse2.cpp) set(CPU_EXTS "${CPU_EXTS}, SSE2") endif() if(HAVE_SSE3) set(CORE_OBJS ${CORE_OBJS} core/mixer/mixer_sse3.cpp) set(CPU_EXTS "${CPU_EXTS}, SSE3") endif() if(HAVE_SSE4_1) set(CORE_OBJS ${CORE_OBJS} core/mixer/mixer_sse41.cpp) set(CPU_EXTS "${CPU_EXTS}, SSE4.1") endif() if(HAVE_NEON) set(CORE_OBJS ${CORE_OBJS} core/mixer/mixer_neon.cpp) set(CPU_EXTS "${CPU_EXTS}, Neon") endif() set(HAVE_ALSA 0) set(HAVE_OSS 0) set(HAVE_PIPEWIRE 0) set(HAVE_SOLARIS 0) set(HAVE_SNDIO 0) set(HAVE_WASAPI 0) set(HAVE_DSOUND 0) set(HAVE_WINMM 0) set(HAVE_PORTAUDIO 0) set(HAVE_PULSEAUDIO 0) set(HAVE_COREAUDIO 0) set(HAVE_OPENSL 0) set(HAVE_OBOE 0) set(HAVE_WAVE 0) set(HAVE_SDL2 0) set(HAVE_SDL3 0) if(WIN32 OR HAVE_DLFCN_H) set(IS_LINKED "") macro(ADD_BACKEND_LIBS _LIBS) endmacro() else() set(IS_LINKED " (linked)") macro(ADD_BACKEND_LIBS _LIBS) set(EXTRA_LIBS ${_LIBS} ${EXTRA_LIBS}) endmacro() endif() set(BACKENDS "") set(ALC_OBJS ${ALC_OBJS} alc/backends/base.cpp alc/backends/base.h # Default backends, always available alc/backends/loopback.cpp alc/backends/loopback.h alc/backends/null.cpp alc/backends/null.h ) # Check PipeWire backend option(ALSOFT_BACKEND_PIPEWIRE "Enable PipeWire backend" ON) option(ALSOFT_REQUIRE_PIPEWIRE "Require PipeWire backend" OFF) if(ALSOFT_BACKEND_PIPEWIRE AND PkgConfig_FOUND) pkg_check_modules(PIPEWIRE libpipewire-0.3>=0.3.23) if(PIPEWIRE_FOUND) set(HAVE_PIPEWIRE 1) set(BACKENDS "${BACKENDS} PipeWire${IS_LINKED},") set(ALC_OBJS ${ALC_OBJS} alc/backends/pipewire.cpp alc/backends/pipewire.h) add_backend_libs(${PIPEWIRE_LIBRARIES}) set(INC_PATHS ${INC_PATHS} ${PIPEWIRE_INCLUDE_DIRS}) endif() endif() if(ALSOFT_REQUIRE_PIPEWIRE AND NOT HAVE_PIPEWIRE) message(FATAL_ERROR "Failed to enable required PipeWire backend") endif() # Check PulseAudio backend option(ALSOFT_BACKEND_PULSEAUDIO "Enable PulseAudio backend" ON) option(ALSOFT_REQUIRE_PULSEAUDIO "Require PulseAudio backend" OFF) if(ALSOFT_BACKEND_PULSEAUDIO) find_package(PulseAudio) if(PULSEAUDIO_FOUND) set(HAVE_PULSEAUDIO 1) set(BACKENDS "${BACKENDS} PulseAudio${IS_LINKED},") set(ALC_OBJS ${ALC_OBJS} alc/backends/pulseaudio.cpp alc/backends/pulseaudio.h) add_backend_libs(${PULSEAUDIO_LIBRARY}) set(INC_PATHS ${INC_PATHS} ${PULSEAUDIO_INCLUDE_DIR}) endif() endif() if(ALSOFT_REQUIRE_PULSEAUDIO AND NOT HAVE_PULSEAUDIO) message(FATAL_ERROR "Failed to enable required PulseAudio backend") endif() if(NOT WIN32) # Check ALSA backend option(ALSOFT_BACKEND_ALSA "Enable ALSA backend" ON) option(ALSOFT_REQUIRE_ALSA "Require ALSA backend" OFF) if(ALSOFT_BACKEND_ALSA) find_package(ALSA) if(ALSA_FOUND) set(HAVE_ALSA 1) set(BACKENDS "${BACKENDS} ALSA${IS_LINKED},") set(ALC_OBJS ${ALC_OBJS} alc/backends/alsa.cpp alc/backends/alsa.h) add_backend_libs(${ALSA_LIBRARIES}) set(INC_PATHS ${INC_PATHS} ${ALSA_INCLUDE_DIRS}) endif() endif() # Check OSS backend option(ALSOFT_BACKEND_OSS "Enable OSS backend" ON) option(ALSOFT_REQUIRE_OSS "Require OSS backend" OFF) if(ALSOFT_BACKEND_OSS) find_package(OSS) if(OSS_FOUND) set(HAVE_OSS 1) set(BACKENDS "${BACKENDS} OSS,") set(ALC_OBJS ${ALC_OBJS} alc/backends/oss.cpp alc/backends/oss.h) if(OSS_LIBRARIES) set(EXTRA_LIBS ${OSS_LIBRARIES} ${EXTRA_LIBS}) endif() set(INC_PATHS ${INC_PATHS} ${OSS_INCLUDE_DIRS}) endif() endif() # Check Solaris backend option(ALSOFT_BACKEND_SOLARIS "Enable Solaris backend" ON) option(ALSOFT_REQUIRE_SOLARIS "Require Solaris backend" OFF) if(ALSOFT_BACKEND_SOLARIS) find_package(AudioIO) if(AUDIOIO_FOUND) set(HAVE_SOLARIS 1) set(BACKENDS "${BACKENDS} Solaris,") set(ALC_OBJS ${ALC_OBJS} alc/backends/solaris.cpp alc/backends/solaris.h) set(INC_PATHS ${INC_PATHS} ${AUDIOIO_INCLUDE_DIRS}) endif() endif() # Check SndIO backend (disabled by default on non-BSDs) if(BSD) option(ALSOFT_BACKEND_SNDIO "Enable SndIO backend" ON) else() option(ALSOFT_BACKEND_SNDIO "Enable SndIO backend" OFF) endif() option(ALSOFT_REQUIRE_SNDIO "Require SndIO backend" OFF) if(ALSOFT_BACKEND_SNDIO) find_package(SndIO) if(SNDIO_FOUND) set(HAVE_SNDIO 1) set(BACKENDS "${BACKENDS} SndIO (linked),") set(ALC_OBJS ${ALC_OBJS} alc/backends/sndio.cpp alc/backends/sndio.hpp) set(EXTRA_LIBS ${SNDIO_LIBRARIES} ${EXTRA_LIBS}) set(INC_PATHS ${INC_PATHS} ${SNDIO_INCLUDE_DIRS}) endif() endif() endif() if(ALSOFT_REQUIRE_ALSA AND NOT HAVE_ALSA) message(FATAL_ERROR "Failed to enable required ALSA backend") endif() if(ALSOFT_REQUIRE_OSS AND NOT HAVE_OSS) message(FATAL_ERROR "Failed to enable required OSS backend") endif() if(ALSOFT_REQUIRE_SOLARIS AND NOT HAVE_SOLARIS) message(FATAL_ERROR "Failed to enable required Solaris backend") endif() if(ALSOFT_REQUIRE_SNDIO AND NOT HAVE_SNDIO) message(FATAL_ERROR "Failed to enable required SndIO backend") endif() # Check Windows-only backends if(WIN32) # Check for WASAPI backend option(ALSOFT_BACKEND_WASAPI "Enable WASAPI backend" ON) option(ALSOFT_REQUIRE_WASAPI "Require WASAPI backend" OFF) if(ALSOFT_BACKEND_WASAPI) check_include_file(mmdeviceapi.h HAVE_MMDEVICEAPI_H) if(HAVE_MMDEVICEAPI_H) set(HAVE_WASAPI 1) set(BACKENDS "${BACKENDS} WASAPI,") set(ALC_OBJS ${ALC_OBJS} alc/backends/wasapi.cpp alc/backends/wasapi.h) if(NOT ALSOFT_UWP) set(EXTRA_LIBS avrt ${EXTRA_LIBS}) endif() endif() endif() if (NOT ALSOFT_UWP) # Check DSound backend option(ALSOFT_BACKEND_DSOUND "Enable DirectSound backend" ON) option(ALSOFT_REQUIRE_DSOUND "Require DirectSound backend" OFF) if(ALSOFT_BACKEND_DSOUND) check_include_file(dsound.h HAVE_DSOUND_H) if(DXSDK_DIR) find_path(DSOUND_INCLUDE_DIR NAMES "dsound.h" PATHS "${DXSDK_DIR}" PATH_SUFFIXES include DOC "The DirectSound include directory") endif() if(HAVE_DSOUND_H OR DSOUND_INCLUDE_DIR) set(HAVE_DSOUND 1) set(BACKENDS "${BACKENDS} DirectSound,") set(ALC_OBJS ${ALC_OBJS} alc/backends/dsound.cpp alc/backends/dsound.h) if(NOT HAVE_DSOUND_H) set(INC_PATHS ${INC_PATHS} ${DSOUND_INCLUDE_DIR}) endif() endif() endif() # Check MMSystem backend option(ALSOFT_BACKEND_WINMM "Enable Windows Multimedia backend" ON) option(ALSOFT_REQUIRE_WINMM "Require Windows Multimedia backend" OFF) if(ALSOFT_BACKEND_WINMM) set(HAVE_WINMM 1) set(BACKENDS "${BACKENDS} WinMM,") set(ALC_OBJS ${ALC_OBJS} alc/backends/winmm.cpp alc/backends/winmm.h) # There doesn't seem to be good way to search for winmm.lib for MSVC. # find_library doesn't find it without being told to look in a specific # place in the WindowsSDK, but it links anyway. If there ends up being # Windows targets without this, another means to detect it is needed. set(EXTRA_LIBS winmm ${EXTRA_LIBS}) endif() endif() endif() if(ALSOFT_REQUIRE_WASAPI AND NOT HAVE_WASAPI) message(FATAL_ERROR "Failed to enable required WASAPI backend") endif() if(ALSOFT_REQUIRE_DSOUND AND NOT HAVE_DSOUND) message(FATAL_ERROR "Failed to enable required DSound backend") endif() if(ALSOFT_REQUIRE_WINMM AND NOT HAVE_WINMM) message(FATAL_ERROR "Failed to enable required WinMM backend") endif() # Check JACK backend option(ALSOFT_BACKEND_JACK "Enable JACK backend" ON) option(ALSOFT_REQUIRE_JACK "Require JACK backend" OFF) if(ALSOFT_BACKEND_JACK) find_package(JACK) if(JACK_FOUND) set(HAVE_JACK 1) set(BACKENDS "${BACKENDS} JACK${IS_LINKED},") set(ALC_OBJS ${ALC_OBJS} alc/backends/jack.cpp alc/backends/jack.h) add_backend_libs(${JACK_LIBRARIES}) set(INC_PATHS ${INC_PATHS} ${JACK_INCLUDE_DIRS}) endif() endif() if(ALSOFT_REQUIRE_JACK AND NOT HAVE_JACK) message(FATAL_ERROR "Failed to enable required JACK backend") endif() # Check CoreAudio backend option(ALSOFT_BACKEND_COREAUDIO "Enable CoreAudio backend" ON) option(ALSOFT_REQUIRE_COREAUDIO "Require CoreAudio backend" OFF) if(ALSOFT_BACKEND_COREAUDIO) find_library(COREAUDIO_FRAMEWORK NAMES CoreAudio) find_path(AUDIOUNIT_INCLUDE_DIR NAMES AudioUnit/AudioUnit.h) if(COREAUDIO_FRAMEWORK AND AUDIOUNIT_INCLUDE_DIR) set(HAVE_COREAUDIO 1) set(ALC_OBJS ${ALC_OBJS} alc/backends/coreaudio.cpp alc/backends/coreaudio.h) set(BACKENDS "${BACKENDS} CoreAudio,") set(EXTRA_LIBS -Wl,-framework,CoreAudio ${EXTRA_LIBS}) if(CMAKE_SYSTEM_NAME MATCHES "^(iOS|tvOS)$") find_library(COREFOUNDATION_FRAMEWORK NAMES CoreFoundation) if(COREFOUNDATION_FRAMEWORK) set(EXTRA_LIBS -Wl,-framework,CoreFoundation ${EXTRA_LIBS}) endif() else() set(EXTRA_LIBS -Wl,-framework,AudioUnit,-framework,ApplicationServices ${EXTRA_LIBS}) endif() # Some versions of OSX may need the AudioToolbox framework. Add it if # it's found. find_library(AUDIOTOOLBOX_LIBRARY NAMES AudioToolbox) if(AUDIOTOOLBOX_LIBRARY) set(EXTRA_LIBS -Wl,-framework,AudioToolbox ${EXTRA_LIBS}) endif() set(INC_PATHS ${INC_PATHS} ${AUDIOUNIT_INCLUDE_DIR}) endif() endif() if(ALSOFT_REQUIRE_COREAUDIO AND NOT HAVE_COREAUDIO) message(FATAL_ERROR "Failed to enable required CoreAudio backend") endif() # Check for Oboe (Android) backend option(ALSOFT_BACKEND_OBOE "Enable Oboe backend" ON) option(ALSOFT_REQUIRE_OBOE "Require Oboe backend" OFF) if(ALSOFT_BACKEND_OBOE) set(OBOE_TARGET ) if(ANDROID) set(OBOE_SOURCE "" CACHE STRING "Source directory for Oboe.") if(OBOE_SOURCE) add_subdirectory(${OBOE_SOURCE} ./oboe EXCLUDE_FROM_ALL) set(OBOE_TARGET oboe) else() find_package(oboe CONFIG) if(NOT TARGET oboe::oboe) find_package(Oboe) endif() if(TARGET oboe::oboe) set(OBOE_TARGET "oboe::oboe") endif() endif() endif() if(OBOE_TARGET) set(HAVE_OBOE 1) set(ALC_OBJS ${ALC_OBJS} alc/backends/oboe.cpp alc/backends/oboe.h) set(BACKENDS "${BACKENDS} Oboe,") set(EXTRA_LIBS ${OBOE_TARGET} ${EXTRA_LIBS}) endif() endif() if(ALSOFT_REQUIRE_OBOE AND NOT HAVE_OBOE) message(FATAL_ERROR "Failed to enable required Oboe backend") endif() # Check for OpenSL (Android) backend option(ALSOFT_BACKEND_OPENSL "Enable OpenSL backend" ON) option(ALSOFT_REQUIRE_OPENSL "Require OpenSL backend" OFF) if(ALSOFT_BACKEND_OPENSL) find_package(OpenSL) if(OPENSL_FOUND) set(HAVE_OPENSL 1) set(ALC_OBJS ${ALC_OBJS} alc/backends/opensl.cpp alc/backends/opensl.h) set(BACKENDS "${BACKENDS} OpenSL${IS_LINKED},") add_backend_libs(${OPENSL_LIBRARIES}) set(INC_PATHS ${INC_PATHS} ${OPENSL_INCLUDE_DIRS}) endif() endif() if(ALSOFT_REQUIRE_OPENSL AND NOT HAVE_OPENSL) message(FATAL_ERROR "Failed to enable required OpenSL backend") endif() # Check PortAudio backend option(ALSOFT_BACKEND_PORTAUDIO "Enable PortAudio backend" ON) option(ALSOFT_REQUIRE_PORTAUDIO "Require PortAudio backend" OFF) if(ALSOFT_BACKEND_PORTAUDIO) find_package(PortAudio) if(PORTAUDIO_FOUND) set(HAVE_PORTAUDIO 1) set(BACKENDS "${BACKENDS} PortAudio${IS_LINKED},") set(ALC_OBJS ${ALC_OBJS} alc/backends/portaudio.cpp alc/backends/portaudio.hpp) add_backend_libs(${PORTAUDIO_LIBRARIES}) set(INC_PATHS ${INC_PATHS} ${PORTAUDIO_INCLUDE_DIRS}) endif() endif() if(ALSOFT_REQUIRE_PORTAUDIO AND NOT HAVE_PORTAUDIO) message(FATAL_ERROR "Failed to enable required PortAudio backend") endif() # Check for SDL2 or SDL3 backend # Off by default, since it adds a runtime dependency. Additionally, both SDL2 # and SDL3 can't be enabled simultaneously. option(ALSOFT_BACKEND_SDL3 "Enable SDL3 backend" OFF) option(ALSOFT_REQUIRE_SDL3 "Require SDL3 backend" OFF) if(ALSOFT_BACKEND_SDL3) if(SDL3_FOUND) set(HAVE_SDL3 1) set(ALC_OBJS ${ALC_OBJS} alc/backends/sdl3.cpp alc/backends/sdl3.h) set(BACKENDS "${BACKENDS} SDL3,") set(EXTRA_LIBS ${EXTRA_LIBS} SDL3::SDL3) else() message(STATUS "Could NOT find SDL3") endif() endif() if(ALSOFT_REQUIRE_SDL3 AND NOT HAVE_SDL3) message(FATAL_ERROR "Failed to enable required SDL3 backend") endif() option(ALSOFT_BACKEND_SDL2 "Enable SDL2 backend" OFF) option(ALSOFT_REQUIRE_SDL2 "Require SDL2 backend" OFF) if(ALSOFT_BACKEND_SDL2 AND NOT HAVE_SDL3) find_package(SDL2) if(SDL2_FOUND) set(HAVE_SDL2 1) set(ALC_OBJS ${ALC_OBJS} alc/backends/sdl2.cpp alc/backends/sdl2.h) set(BACKENDS "${BACKENDS} SDL2,") set(EXTRA_LIBS ${EXTRA_LIBS} SDL2::SDL2) else() message(STATUS "Could NOT find SDL2") endif() endif() if(ALSOFT_REQUIRE_SDL2 AND NOT HAVE_SDL2) message(FATAL_ERROR "Failed to enable required SDL2 backend") endif() # Optionally enable the Wave Writer backend option(ALSOFT_BACKEND_WAVE "Enable Wave Writer backend" ON) if(ALSOFT_BACKEND_WAVE) set(HAVE_WAVE 1) set(ALC_OBJS ${ALC_OBJS} alc/backends/wave.cpp alc/backends/wave.h) set(BACKENDS "${BACKENDS} WaveFile,") endif() # This is always available set(BACKENDS "${BACKENDS} Null") # Get the known version info to create version.h set(LIB_VERSION_NUM ${OpenAL_VERSION_MAJOR},${OpenAL_VERSION_MINOR},${OpenAL_VERSION_PATCH},0) find_package(Git) if(ALSOFT_UPDATE_BUILD_VERSION AND GIT_FOUND AND EXISTS "${OpenAL_SOURCE_DIR}/.git") set(GIT_DIR "${OpenAL_SOURCE_DIR}/.git") # Check if this is a submodule, if it is then find the .git directory if(NOT IS_DIRECTORY "${OpenAL_SOURCE_DIR}/.git") file(READ ${GIT_DIR} submodule) string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE ${submodule}) string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE) get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) endif() # Get the current working branch and its latest abbreviated commit hash add_custom_command(OUTPUT "${OpenAL_BINARY_DIR}/version_witness.txt" BYPRODUCTS "${OpenAL_BINARY_DIR}/version.h" COMMAND ${CMAKE_COMMAND} -D GIT_EXECUTABLE=${GIT_EXECUTABLE} -D LIB_VERSION=${OpenAL_VERSION} -D LIB_VERSION_NUM=${LIB_VERSION_NUM} -D SRC=${OpenAL_SOURCE_DIR}/version.h.in -D DST=${OpenAL_BINARY_DIR}/version.h -P ${OpenAL_SOURCE_DIR}/version.cmake COMMAND ${CMAKE_COMMAND} -E touch "${OpenAL_BINARY_DIR}/version_witness.txt" WORKING_DIRECTORY "${OpenAL_SOURCE_DIR}" MAIN_DEPENDENCY "${OpenAL_SOURCE_DIR}/version.h.in" DEPENDS "${GIT_DIR}/index" "${OpenAL_SOURCE_DIR}/version.cmake" VERBATIM ) add_custom_target(alsoft.build_version DEPENDS "${OpenAL_BINARY_DIR}/version_witness.txt") else() set(GIT_BRANCH "") set(GIT_COMMIT_HASH "") configure_file( "${OpenAL_SOURCE_DIR}/version.h.in" "${OpenAL_BINARY_DIR}/version.h") endif() option(ALSOFT_EMBED_HRTF_DATA "Embed the HRTF data files (increases library footprint)" ON) if(ALSOFT_EMBED_HRTF_DATA) macro(make_hrtf_header FILENAME VARNAME) set(infile "${OpenAL_SOURCE_DIR}/hrtf/${FILENAME}") set(outfile "${OpenAL_BINARY_DIR}/${VARNAME}.txt") add_custom_command(OUTPUT "${outfile}" COMMAND ${CMAKE_COMMAND} -D "INPUT_FILE=${infile}" -D "OUTPUT_FILE=${outfile}" -P "${CMAKE_MODULE_PATH}/bin2h.script.cmake" WORKING_DIRECTORY "${OpenAL_SOURCE_DIR}" DEPENDS "${infile}" "${CMAKE_MODULE_PATH}/bin2h.script.cmake" VERBATIM ) set(ALC_OBJS ${ALC_OBJS} "${outfile}") endmacro() make_hrtf_header("Default HRTF.mhr" "default_hrtf") endif() # Set a 16KB page size for Android if(ANDROID) set(CPP_DEFS ${CPP_DEFS} __BIONIC_NO_PAGE_SIZE_MACRO) check_linker_flag(C "-Wl,-z,max-page-size=16384" HAS_MAX_PAGE_SIZE_16384) if(HAS_MAX_PAGE_SIZE_16384) set(LINKER_FLAGS ${LINKER_FLAGS} "-Wl,-z,max-page-size=16384") endif() endif() if(ALSOFT_UTILS) find_package(MySOFA) if(NOT ALSOFT_NO_CONFIG_UTIL) find_package(Qt6Widgets QUIET) if(NOT Qt6Widgets_FOUND) message(STATUS "Could NOT find Qt6Widgets") endif() endif() endif() if(ALSOFT_UTILS OR ALSOFT_EXAMPLES) find_package(SndFile) endif() if(ALSOFT_EXAMPLES AND SDL3_FOUND) find_package(FFmpeg COMPONENTS AVFORMAT AVCODEC AVUTIL SWSCALE SWRESAMPLE) endif() if(NOT WIN32) set(LIBNAME "openal") else() set(LIBNAME "OpenAL32") endif() # Needed for openal.pc.in set(prefix ${CMAKE_INSTALL_PREFIX}) set(exec_prefix "\${prefix}") set(libdir "${CMAKE_INSTALL_FULL_LIBDIR}") set(bindir "${CMAKE_INSTALL_FULL_BINDIR}") set(includedir "${CMAKE_INSTALL_FULL_INCLUDEDIR}") set(PACKAGE_VERSION "${OpenAL_VERSION}") set(PKG_CONFIG_CFLAGS ) set(PKG_CONFIG_PRIVATE_LIBS ) if(LIBTYPE STREQUAL "STATIC") set(PKG_CONFIG_CFLAGS -DAL_LIBTYPE_STATIC) foreach(FLAG ${LINKER_FLAGS} ${EXTRA_LIBS} ${MATH_LIB}) # If this is already a linker flag, or is a full path+file, add it # as-is. If it's an SDL2 or SDL3 target, add the link flag for it. # Otherwise, it's a name intended to be dressed as -lname. if(FLAG MATCHES "^-.*" OR EXISTS "${FLAG}") set(PKG_CONFIG_PRIVATE_LIBS "${PKG_CONFIG_PRIVATE_LIBS} ${FLAG}") elseif(FLAG MATCHES "^SDL2::SDL2") set(PKG_CONFIG_PRIVATE_LIBS "${PKG_CONFIG_PRIVATE_LIBS} -lSDL2") elseif(FLAG MATCHES "^SDL3::SDL3") set(PKG_CONFIG_PRIVATE_LIBS "${PKG_CONFIG_PRIVATE_LIBS} -lSDL3") else() set(PKG_CONFIG_PRIVATE_LIBS "${PKG_CONFIG_PRIVATE_LIBS} -l${FLAG}") endif() endforeach() endif() # End configuration configure_file( "${OpenAL_SOURCE_DIR}/config.h.in" "${OpenAL_BINARY_DIR}/config.h") configure_file( "${OpenAL_SOURCE_DIR}/config_backends.h.in" "${OpenAL_BINARY_DIR}/config_backends.h") configure_file( "${OpenAL_SOURCE_DIR}/config_simd.h.in" "${OpenAL_BINARY_DIR}/config_simd.h") configure_file( "${OpenAL_SOURCE_DIR}/openal.pc.in" "${OpenAL_BINARY_DIR}/openal.pc" @ONLY) set(MODULES_OBJS ) if(HAVE_CXXMODULES) set(MODULES_OBJS modules/alc.cppm modules/al.cppm modules/alstd.cppm modules/efx.cppm modules/alext.cppm modules/openal.cppm) # For importing while building the examples and utilities (functions are # set to be imported from the shared library, or as free functions with # static library builds). add_library(openal.modules OBJECT EXCLUDE_FROM_ALL) target_sources(openal.modules PUBLIC FILE_SET CXX_MODULES FILES ${MODULES_OBJS}) target_include_directories(openal.modules PRIVATE ${OpenAL_SOURCE_DIR}/include) target_compile_definitions(openal.modules PRIVATE ${CPP_DEFS}) target_compile_options(openal.modules PRIVATE ${C_FLAGS}) set_target_properties(openal.modules PROPERTIES ${ALSOFT_STD_VERSION_PROPS} POSITION_INDEPENDENT_CODE TRUE) set(MODULES_TARGET openal.modules) # For importing while building the library (functions are set to be # exported from the shared library). add_library(alsoft.modules OBJECT EXCLUDE_FROM_ALL) target_sources(alsoft.modules PUBLIC FILE_SET CXX_MODULES FILES ${MODULES_OBJS}) target_compile_definitions(alsoft.modules PRIVATE AL_ALEXT_PROTOTYPES "ALC_API=${EXPORT_DECL}" "AL_API=${EXPORT_DECL}" ${CPP_DEFS}) target_compile_options(alsoft.modules PRIVATE ${C_FLAGS}) set_target_properties(alsoft.modules PROPERTIES ${ALSOFT_STD_VERSION_PROPS} POSITION_INDEPENDENT_CODE TRUE) else() set(MODULES_TARGET ) endif() add_library(alsoft.common STATIC EXCLUDE_FROM_ALL ${COMMON_OBJS}) target_include_directories(alsoft.common PRIVATE ${OpenAL_SOURCE_DIR}/include PUBLIC ${OpenAL_BINARY_DIR} ${OpenAL_SOURCE_DIR}/common ${OpenAL_SOURCE_DIR}/gsl/include) target_compile_definitions(alsoft.common PRIVATE ${CPP_DEFS}) target_compile_options(alsoft.common PRIVATE ${C_FLAGS}) target_link_libraries(alsoft.common PRIVATE alsoft::fmt) set_target_properties(alsoft.common PROPERTIES ${ALSOFT_STD_VERSION_PROPS} POSITION_INDEPENDENT_CODE TRUE) if(HAVE_CXXMODULES) set(MODULES_OBJS ${MODULES_OBJS} alsoft-modules/gsl.cppm) target_sources(alsoft.common PUBLIC FILE_SET CXX_MODULES FILES alsoft-modules/gsl.cppm) endif() unset(HAS_ROUTER) set(IMPL_TARGET OpenAL) # Either OpenAL or soft_oal. set(NEED_ANALYZE_SOURCE_FILES "") foreach(obj ${CORE_OBJS} ${OPENAL_OBJS} ${ALC_OBJS} ${COMMON_OBJS} ${MODULES_OBJS}) # CMake 3.20+ can use cmake_path(COMPARE ...), or CMake 3.24+ can use # PATH_EQUAL. if(NOT obj STREQUAL "${CMAKE_BINARY_DIR}/default_hrtf.txt") list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/${obj}") endif() endforeach() # Build main library if(LIBTYPE STREQUAL "STATIC") if(TARGET openal.modules) target_compile_definitions(openal.modules PUBLIC AL_LIBTYPE_STATIC) endif() add_library(${IMPL_TARGET} STATIC ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS} ${CORE_OBJS}) target_compile_definitions(${IMPL_TARGET} PUBLIC AL_LIBTYPE_STATIC) target_include_directories(${IMPL_TARGET} PRIVATE ${OpenAL_SOURCE_DIR}/gsl/include) target_link_libraries(${IMPL_TARGET} PRIVATE ${LINKER_FLAGS} ${EXTRA_LIBS} ${MATH_LIB} $) if(WIN32) # This option is for static linking OpenAL Soft into another project # that already defines the IDs. It is up to that project to ensure all # required IDs are defined. option(ALSOFT_NO_UID_DEFS "Do not define GUIDs, IIDs, CLSIDs, or PropertyKeys" OFF) if(ALSOFT_NO_UID_DEFS) target_compile_definitions(${IMPL_TARGET} PRIVATE AL_NO_UID_DEFS) endif() endif() else() set(RC_CONFIG resources/openal32.rc) if(WIN32 AND ALSOFT_BUILD_ROUTER) if(HAVE_CXXMODULES) add_library(alsoft.router-modules OBJECT EXCLUDE_FROM_ALL) target_sources(alsoft.router-modules PUBLIC FILE_SET CXX_MODULES FILES alsoft-modules/router.cppm) target_compile_definitions(alsoft.router-modules PRIVATE AL_ALEXT_PROTOTYPES "ALC_API=${EXPORT_DECL}" "AL_API=${EXPORT_DECL}" ${CPP_DEFS}) target_compile_options(alsoft.router-modules PRIVATE ${C_FLAGS}) target_link_libraries(alsoft.router-modules PRIVATE alsoft::fmt alsoft.modules) set_target_properties(alsoft.router-modules PROPERTIES ${ALSOFT_STD_VERSION_PROPS} POSITION_INDEPENDENT_CODE TRUE) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/alsoft-modules/router.cppm") endif() add_library(OpenAL SHARED resources/router.rc router/router.cpp router/router.h router/alc.cpp router/al.cpp ) target_compile_definitions(OpenAL PRIVATE AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES "ALC_API=${EXPORT_DECL}" "AL_API=${EXPORT_DECL}" ${CPP_DEFS}) target_compile_options(OpenAL PRIVATE ${C_FLAGS}) target_link_libraries(OpenAL PRIVATE alsoft.common ${LINKER_FLAGS} alsoft::fmt $<$:alsoft.modules alsoft.router-modules>) target_include_directories(OpenAL PUBLIC $ $ PRIVATE ${OpenAL_SOURCE_DIR}/common ${OpenAL_BINARY_DIR} ) set_target_properties(OpenAL PROPERTIES ${ALSOFT_STD_VERSION_PROPS} PREFIX "" OUTPUT_NAME ${LIBNAME}) if(TARGET alsoft.build_version) add_dependencies(OpenAL alsoft.build_version) endif() set(HAS_ROUTER 1) set(LIBNAME "soft_oal") set(IMPL_TARGET soft_oal) set(RC_CONFIG resources/soft_oal.rc) endif() # !important: for osx framework public header works, the headers must be in # the project set(TARGET_PUBLIC_HEADERS include/AL/al.h include/AL/alc.h include/AL/alext.h include/AL/efx.h include/AL/efx-presets.h) add_library(${IMPL_TARGET} SHARED ${OPENAL_OBJS} ${ALC_OBJS} ${CORE_OBJS} ${RC_CONFIG} ${TARGET_PUBLIC_HEADERS}) if(WIN32) set_target_properties(${IMPL_TARGET} PROPERTIES PREFIX "") endif() target_link_libraries(${IMPL_TARGET} PRIVATE alsoft.common ${LINKER_FLAGS} ${EXTRA_LIBS} ${MATH_LIB} alsoft::fmt) if(ALSOFT_UWP) find_package(cppwinrt CONFIG) if (TARGET Microsoft::CppWinRT) target_link_libraries(${IMPL_TARGET} PRIVATE Microsoft::CppWinRT) else() set(ALSOFT_CPPWINRT_VERSION "2.0.230706.1" CACHE STRING "The soft-oal default cppwinrt version") find_program(NUGET_EXE NAMES nuget) if(NOT NUGET_EXE) message("NUGET.EXE not found.") message(FATAL_ERROR "Please install this executable, and run CMake again.") endif() execute_process(COMMAND ${NUGET_EXE} install "Microsoft.Windows.CppWinRT" -Version ${ALSOFT_CPPWINRT_VERSION} -ExcludeVersion -OutputDirectory "${CMAKE_BINARY_DIR}/packages") set_target_properties(${IMPL_TARGET} PROPERTIES VS_PROJECT_IMPORT ${CMAKE_BINARY_DIR}/packages/Microsoft.Windows.CppWinRT/build/native/Microsoft.Windows.CppWinRT.props ) target_link_libraries(${IMPL_TARGET} PRIVATE ${CMAKE_BINARY_DIR}/packages/Microsoft.Windows.CppWinRT/build/native/Microsoft.Windows.CppWinRT.targets) endif() endif() if(NOT WIN32 AND NOT APPLE) # FIXME: This doesn't put a dependency on the version script. Changing # the version script will not cause a relink as it should. target_link_options(${IMPL_TARGET} PRIVATE "-Wl,--version-script=${OpenAL_SOURCE_DIR}/libopenal.version") endif() if(APPLE AND ALSOFT_OSX_FRAMEWORK) # Sets framework name to soft_oal to avoid ambiguity with the system OpenAL.framework set(LIBNAME "soft_oal") if(GIT_FOUND) execute_process(COMMAND ${GIT_EXECUTABLE} rev-list --count HEAD TIMEOUT 5 OUTPUT_VARIABLE BUNDLE_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) else() set(BUNDLE_VERSION 1) endif() # Build: Fix rpath in iOS shared libraries # If this flag is not set, the final dylib binary ld path will be # /User/xxx/*/soft_oal.framework/soft_oal, which can't be loaded by iOS devices. # See also: https://github.com/libjpeg-turbo/libjpeg-turbo/commit/c80ddef7a4ce21ace9e3ca0fd190d320cc8cdaeb if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG) set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,") endif() set_target_properties(${IMPL_TARGET} PROPERTIES FRAMEWORK TRUE FRAMEWORK_VERSION C MACOSX_FRAMEWORK_NAME "${IMPL_TARGET}" MACOSX_FRAMEWORK_IDENTIFIER "org.openal-soft.openal" MACOSX_FRAMEWORK_SHORT_VERSION_STRING "${OpenAL_VERSION}" MACOSX_FRAMEWORK_BUNDLE_VERSION "${BUNDLE_VERSION}" XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "" XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO" XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO" PUBLIC_HEADER "${TARGET_PUBLIC_HEADERS}" MACOSX_RPATH TRUE) endif() endif() target_include_directories(${IMPL_TARGET} PUBLIC $ INTERFACE $ $ $ PRIVATE ${INC_PATHS} ${OpenAL_BINARY_DIR} ${OpenAL_SOURCE_DIR} ${OpenAL_SOURCE_DIR}/common ) set_target_properties(${IMPL_TARGET} PROPERTIES ${ALSOFT_STD_VERSION_PROPS} OUTPUT_NAME ${LIBNAME} VERSION ${OpenAL_VERSION} SOVERSION ${OpenAL_VERSION_MAJOR} ) target_compile_definitions(${IMPL_TARGET} PRIVATE AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES "ALC_API=${EXPORT_DECL}" "AL_API=${EXPORT_DECL}" ${CPP_DEFS}) target_compile_options(${IMPL_TARGET} PRIVATE ${C_FLAGS}) if(TARGET alsoft.build_version) add_dependencies(${IMPL_TARGET} alsoft.build_version) endif() if(WIN32 AND MINGW AND ALSOFT_BUILD_IMPORT_LIB AND NOT LIBTYPE STREQUAL "STATIC") find_program(SED_EXECUTABLE NAMES sed DOC "sed executable") if(NOT SED_EXECUTABLE OR NOT CMAKE_DLLTOOL) message(STATUS "") if(NOT SED_EXECUTABLE) message(STATUS "WARNING: Cannot find sed, disabling .def/.lib generation") endif() if(NOT CMAKE_DLLTOOL) message(STATUS "WARNING: Cannot find dlltool, disabling .def/.lib generation") endif() else() target_link_options(OpenAL PRIVATE "-Wl,--output-def,${PROJECT_BINARY_DIR}/OpenAL32.def") add_custom_command(TARGET OpenAL POST_BUILD COMMAND "${SED_EXECUTABLE}" -i -e "s/ @[^ ]*//" OpenAL32.def COMMAND "${CMAKE_DLLTOOL}" -d OpenAL32.def -l OpenAL32.lib -D OpenAL32.dll # Technically OpenAL32.def was created by the build, but cmake # doesn't recognize it due to -Wl,--output-def,OpenAL32.def being # manually specified. But declaring the file here allows it to be # properly cleaned, e.g. during make clean. BYPRODUCTS OpenAL32.def OpenAL32.lib COMMENT "Stripping ordinals from OpenAL32.def and generating OpenAL32.lib..." VERBATIM ) endif() endif() message(STATUS "") message(STATUS "STL hardening level: ${HARDENING_LEVEL}") if(HAS_ROUTER) message(STATUS "") message(STATUS "Building DLL router") endif() message(STATUS "") message(STATUS "Building OpenAL with support for the following backends:") message(STATUS " ${BACKENDS}") message(STATUS "") message(STATUS "Building with support for CPU extensions:") message(STATUS " ${CPU_EXTS}") message(STATUS "") if(FPMATH_SET) message(STATUS "Building with SSE${FPMATH_SET} codegen") message(STATUS "") endif() if(ALSOFT_UWP) message(STATUS "Building with UWP support") message(STATUS "") endif() if(ALSOFT_EAX) message(STATUS "Building with legacy EAX extension support") message(STATUS "") endif() if(ALSOFT_EMBED_HRTF_DATA) message(STATUS "Embedding HRTF datasets") message(STATUS "") endif() # An alias for sub-project builds add_library(OpenAL::OpenAL ALIAS OpenAL) # Install main library if(ALSOFT_INSTALL) configure_package_config_file(OpenALConfig.cmake.in OpenALConfig.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/OpenAL) install(TARGETS OpenAL EXPORT OpenAL FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ${CMAKE_INSTALL_INCLUDEDIR}/AL) export(TARGETS OpenAL NAMESPACE OpenAL:: FILE OpenALTargets.cmake) install(EXPORT OpenAL DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/OpenAL NAMESPACE OpenAL:: FILE OpenALTargets.cmake) install(DIRECTORY include/AL DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(FILES "${OpenAL_BINARY_DIR}/openal.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") install(FILES "${OpenAL_BINARY_DIR}/OpenALConfig.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/OpenAL") if(TARGET soft_oal) install(TARGETS soft_oal) endif() message(STATUS "Installing library and headers") else() message(STATUS "NOT installing library and headers") endif() if(ALSOFT_INSTALL_CONFIG) install(FILES alsoftrc.sample DESTINATION ${CMAKE_INSTALL_DATADIR}/openal) message(STATUS "Installing sample configuration") endif() if(ALSOFT_INSTALL_HRTF_DATA) install(DIRECTORY hrtf DESTINATION ${CMAKE_INSTALL_DATADIR}/openal) message(STATUS "Installing HRTF data files") endif() if(ALSOFT_INSTALL_AMBDEC_PRESETS) install(DIRECTORY presets DESTINATION ${CMAKE_INSTALL_DATADIR}/openal) message(STATUS "Installing AmbDec presets") endif() message(STATUS "") set(UNICODE_FLAG ) if(MINGW) set(UNICODE_FLAG ${UNICODE_FLAG} -municode) endif() set(EXTRA_INSTALLS ) if(ALSOFT_UTILS) add_executable(openal-info utils/openal-info.c) target_include_directories(openal-info PRIVATE ${OpenAL_BINARY_DIR} ${OpenAL_SOURCE_DIR}/common) target_compile_options(openal-info PRIVATE ${C_FLAGS}) target_link_libraries(openal-info PRIVATE ${LINKER_FLAGS} OpenAL ${UNICODE_FLAG}) set_target_properties(openal-info PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/utils/openal-info.c") if(ALSOFT_INSTALL_EXAMPLES) set(EXTRA_INSTALLS ${EXTRA_INSTALLS} openal-info) endif() if(SNDFILE_FOUND) add_executable(uhjdecoder utils/uhjdecoder.cpp) target_compile_definitions(uhjdecoder PRIVATE ${CPP_DEFS}) target_include_directories(uhjdecoder PRIVATE ${OpenAL_BINARY_DIR} ${OpenAL_SOURCE_DIR}/common) target_compile_options(uhjdecoder PRIVATE ${C_FLAGS}) target_link_libraries(uhjdecoder PUBLIC alsoft.common PRIVATE ${LINKER_FLAGS} SndFile::SndFile ${UNICODE_FLAG} alsoft::fmt) set_target_properties(uhjdecoder PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/utils/uhjdecoder.cpp") add_executable(uhjencoder utils/uhjencoder.cpp) target_compile_definitions(uhjencoder PRIVATE ${CPP_DEFS}) target_include_directories(uhjencoder PRIVATE ${OpenAL_BINARY_DIR} ${OpenAL_SOURCE_DIR}/common) target_compile_options(uhjencoder PRIVATE ${C_FLAGS}) target_link_libraries(uhjencoder PUBLIC alsoft.common PRIVATE ${LINKER_FLAGS} SndFile::SndFile ${UNICODE_FLAG} alsoft::fmt) set_target_properties(uhjencoder PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/utils/uhjencoder.cpp") endif() if(MYSOFA_FOUND) set(SOFA_SUPPORT_SRCS utils/sofa-support.cpp utils/sofa-support.h) add_library(alsoft.sofa-support STATIC EXCLUDE_FROM_ALL ${SOFA_SUPPORT_SRCS}) target_compile_definitions(alsoft.sofa-support PRIVATE ${CPP_DEFS}) target_include_directories(alsoft.sofa-support PUBLIC ${OpenAL_SOURCE_DIR}/common) target_compile_options(alsoft.sofa-support PRIVATE ${C_FLAGS}) target_link_libraries(alsoft.sofa-support PUBLIC alsoft.common MySOFA::MySOFA PRIVATE ${LINKER_FLAGS} alsoft::fmt) set_target_properties(alsoft.sofa-support PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/utils/sofa-support.cpp" "${CMAKE_SOURCE_DIR}/utils/sofa-support.h") set(MAKEMHR_SRCS utils/makemhr/loaddef.cpp utils/makemhr/loaddef.h utils/makemhr/loadsofa.cpp utils/makemhr/loadsofa.h utils/makemhr/makemhr.cpp utils/makemhr/makemhr.h) add_executable(makemhr ${MAKEMHR_SRCS}) target_compile_definitions(makemhr PRIVATE ${CPP_DEFS}) target_include_directories(makemhr PRIVATE ${OpenAL_BINARY_DIR} ${OpenAL_SOURCE_DIR}/utils) target_compile_options(makemhr PRIVATE ${C_FLAGS}) target_link_libraries(makemhr PRIVATE ${LINKER_FLAGS} alsoft.sofa-support ${UNICODE_FLAG} alsoft::fmt) set_target_properties(makemhr PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/utils/makemhr/loaddef.cpp" "${CMAKE_SOURCE_DIR}/utils/makemhr/loaddef.h" "${CMAKE_SOURCE_DIR}/utils/makemhr/loadsofa.cpp" "${CMAKE_SOURCE_DIR}/utils/makemhr/loadsofa.h" "${CMAKE_SOURCE_DIR}/utils/makemhr/makemhr.cpp" "${CMAKE_SOURCE_DIR}/utils/makemhr/makemhr.h") if(ALSOFT_INSTALL_EXAMPLES) set(EXTRA_INSTALLS ${EXTRA_INSTALLS} makemhr) endif() set(SOFAINFO_SRCS utils/sofa-info.cpp) add_executable(sofa-info ${SOFAINFO_SRCS}) target_compile_definitions(sofa-info PRIVATE ${CPP_DEFS}) target_include_directories(sofa-info PRIVATE ${OpenAL_BINARY_DIR} ${OpenAL_SOURCE_DIR}/utils) target_compile_options(sofa-info PRIVATE ${C_FLAGS}) target_link_libraries(sofa-info PRIVATE alsoft.common ${LINKER_FLAGS} alsoft.sofa-support ${UNICODE_FLAG} alsoft::fmt) set_target_properties(sofa-info PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/utils/sofa-info.cpp") endif() message(STATUS "Building utility programs") if(NOT ALSOFT_NO_CONFIG_UTIL) add_subdirectory(utils/alsoft-config) endif() message(STATUS "") endif() # Add a static library with common functions used by multiple example targets add_library(alsoft.excommon STATIC EXCLUDE_FROM_ALL examples/common/alhelpers.c examples/common/alhelpers.h examples/common/alhelpers.hpp) target_compile_definitions(alsoft.excommon PUBLIC ${CPP_DEFS}) target_include_directories(alsoft.excommon PUBLIC ${OpenAL_BINARY_DIR} ${OpenAL_SOURCE_DIR}/common) target_compile_options(alsoft.excommon PUBLIC ${C_FLAGS}) target_link_libraries(alsoft.excommon PUBLIC OpenAL PRIVATE ${RT_LIB}) set_target_properties(alsoft.excommon PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) if(ALSOFT_EXAMPLES) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/examples/common/alhelpers.c" "${CMAKE_SOURCE_DIR}/examples/common/alhelpers.h") add_executable(altonegen examples/altonegen.c) target_link_libraries(altonegen PRIVATE ${LINKER_FLAGS} ${MATH_LIB} alsoft.excommon ${UNICODE_FLAG}) set_target_properties(altonegen PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/examples/altonegen.c") add_executable(alrecord examples/alrecord.c) target_link_libraries(alrecord PRIVATE ${LINKER_FLAGS} alsoft.excommon ${UNICODE_FLAG}) set_target_properties(alrecord PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/examples/alrecord.c") add_executable(aldebug examples/aldebug.cpp) target_link_libraries(aldebug PRIVATE ${LINKER_FLAGS} alsoft.common alsoft.excommon ${UNICODE_FLAG} alsoft::fmt ${MODULES_TARGET}) set_target_properties(aldebug PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/examples/aldebug.cpp") add_executable(allafplay examples/allafplay.cpp) target_link_libraries(allafplay PRIVATE ${LINKER_FLAGS} alsoft.common alsoft.excommon ${UNICODE_FLAG} alsoft::fmt ${MODULES_TARGET}) set_target_properties(allafplay PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/examples/allafplay.cpp") if(ALSOFT_INSTALL_EXAMPLES) set(EXTRA_INSTALLS ${EXTRA_INSTALLS} altonegen alrecord aldebug allafplay) endif() message(STATUS "Building example programs") if(SNDFILE_FOUND) add_executable(alplay examples/alplay.c) target_link_libraries(alplay PRIVATE ${LINKER_FLAGS} SndFile::SndFile alsoft.excommon ${UNICODE_FLAG}) set_target_properties(alplay PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/examples/alplay.c") add_executable(alstream examples/alstream.c) target_link_libraries(alstream PRIVATE ${LINKER_FLAGS} SndFile::SndFile alsoft.excommon ${UNICODE_FLAG}) set_target_properties(alstream PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/examples/alstream.c") add_executable(alreverb examples/alreverb.c) target_link_libraries(alreverb PRIVATE ${LINKER_FLAGS} SndFile::SndFile alsoft.excommon ${UNICODE_FLAG}) set_target_properties(alreverb PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/examples/alreverb.c") add_executable(almultireverb examples/almultireverb.c) target_link_libraries(almultireverb PRIVATE ${LINKER_FLAGS} SndFile::SndFile alsoft.excommon ${MATH_LIB} ${UNICODE_FLAG}) set_target_properties(almultireverb PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/examples/almultireverb.c") add_executable(allatency examples/allatency.c) target_link_libraries(allatency PRIVATE ${LINKER_FLAGS} SndFile::SndFile alsoft.excommon ${UNICODE_FLAG}) set_target_properties(allatency PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/examples/allatency.c") add_executable(alhrtf examples/alhrtf.c) target_link_libraries(alhrtf PRIVATE ${LINKER_FLAGS} SndFile::SndFile alsoft.excommon ${MATH_LIB} ${UNICODE_FLAG}) set_target_properties(alhrtf PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/examples/alhrtf.c") add_executable(alstreamcb examples/alstreamcb.cpp) target_link_libraries(alstreamcb PRIVATE ${LINKER_FLAGS} SndFile::SndFile alsoft.common alsoft.excommon ${UNICODE_FLAG} alsoft::fmt ${MODULES_TARGET}) set_target_properties(alstreamcb PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/examples/alstreamcb.cpp") add_executable(aldirect examples/aldirect.cpp) target_link_libraries(aldirect PRIVATE ${LINKER_FLAGS} SndFile::SndFile alsoft.common alsoft.excommon ${UNICODE_FLAG} alsoft::fmt ${MODULES_TARGET}) set_target_properties(aldirect PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/examples/aldirect.cpp") add_executable(alconvolve examples/alconvolve.c) target_link_libraries(alconvolve PRIVATE ${LINKER_FLAGS} alsoft.common SndFile::SndFile alsoft.excommon ${UNICODE_FLAG}) set_target_properties(alconvolve PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/examples/alconvolve.c") if(ALSOFT_INSTALL_EXAMPLES) set(EXTRA_INSTALLS ${EXTRA_INSTALLS} alplay alstream alreverb almultireverb allatency alhrtf aldirect) endif() message(STATUS "Building SndFile example programs") endif() # Can't safely use SDL3 and SDL2 together if(SDL3_FOUND AND NOT HAVE_SDL2) message(STATUS "Building SDL3 example programs") add_executable(alloopback examples/alloopback.c) target_link_libraries(alloopback PRIVATE ${LINKER_FLAGS} SDL3::SDL3 alsoft.excommon ${MATH_LIB}) set_target_properties(alloopback PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/examples/alloopback.c") if(ALSOFT_INSTALL_EXAMPLES) set(EXTRA_INSTALLS ${EXTRA_INSTALLS} alloopback) endif() set(FFVER_OK FALSE) if(FFMPEG_FOUND) set(FFVER_OK TRUE) if(AVFORMAT_VERSION VERSION_LESS "59.27.100") message(STATUS "libavformat is too old! (${AVFORMAT_VERSION}, wanted 59.27.100)") set(FFVER_OK FALSE) endif() if(AVCODEC_VERSION VERSION_LESS "59.37.100") message(STATUS "libavcodec is too old! (${AVCODEC_VERSION}, wanted 59.37.100)") set(FFVER_OK FALSE) endif() if(AVUTIL_VERSION VERSION_LESS "57.28.100") message(STATUS "libavutil is too old! (${AVUTIL_VERSION}, wanted 57.28.100)") set(FFVER_OK FALSE) endif() if(SWSCALE_VERSION VERSION_LESS "6.7.100") message(STATUS "libswscale is too old! (${SWSCALE_VERSION}, wanted 6.7.100)") set(FFVER_OK FALSE) endif() if(SWRESAMPLE_VERSION VERSION_LESS "4.7.100") message(STATUS "libswresample is too old! (${SWRESAMPLE_VERSION}, wanted 4.7.100)") set(FFVER_OK FALSE) endif() endif() if(FFVER_OK) add_executable(alffplay examples/alffplay.cpp) target_include_directories(alffplay PRIVATE ${FFMPEG_INCLUDE_DIRS}) target_link_libraries(alffplay PRIVATE ${LINKER_FLAGS} SDL3::SDL3 ${FFMPEG_LIBRARIES} alsoft.common alsoft.excommon alsoft::fmt ${MODULES_TARGET}) set_target_properties(alffplay PROPERTIES ${ALSOFT_STD_VERSION_PROPS}) list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_SOURCE_DIR}/examples/alffplay.cpp") if(ALSOFT_INSTALL_EXAMPLES) set(EXTRA_INSTALLS ${EXTRA_INSTALLS} alffplay) endif() message(STATUS "Building SDL3+FFmpeg example programs") endif() endif() message(STATUS "") endif() set(CLANG_TIDY_EXECUTABLE "clang-tidy") if(DEFINED ENV{CLANG_TIDY_EXECUTABLE}) set(CLANG_TIDY_EXECUTABLE $ENV{CLANG_TIDY_EXECUTABLE}) endif() add_custom_target(clang-tidy-check ${CLANG_TIDY_EXECUTABLE} -format-style=file -p ${CMAKE_BINARY_DIR}/compile_commands.json ${NEED_ANALYZE_SOURCE_FILES} DEPENDS ${NEED_ANALYZE_SOURCE_FILES}) if(ALSOFT_TESTS) add_subdirectory(tests) endif() if(EXTRA_INSTALLS) install(TARGETS ${EXTRA_INSTALLS} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif()