Use C++17 Bessel functions

Move Bessel functions availability checks from configuration time to
inclusion time to be more robust and allow the use of ABI compatible
compilers (e.g., Ceres is compiled using Clang but is used in a project
compiled using GCC.)

Since libc++ does not yet implement special math functions, we fallback
to their POSIX implementation if available. However, then only the
deprecated BesselJ{0,1,n} are provided.

Fixes #814

Change-Id: Ic3e62452b36e90cb22644cc8e553e3dd1881193f
diff --git a/include/ceres/internal/port.h b/include/ceres/internal/port.h
index b8cb0ff..d78ed51 100644
--- a/include/ceres/internal/port.h
+++ b/include/ceres/internal/port.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2023 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
 #ifndef CERES_PUBLIC_INTERNAL_PORT_H_
 #define CERES_PUBLIC_INTERNAL_PORT_H_
 
+#include <cmath>  // Necessary for __cpp_lib_math_special_functions feature test
+
 // A macro to mark a function/variable/class as deprecated.
 // We use compiler specific attributes rather than the c++
 // attribute because they do not mix well with each other.
@@ -88,4 +90,22 @@
 #define CERES_RESTORE_DEPRECATED_WARNING
 #endif  // defined(_MSC_VER)
 
+#if defined(__cpp_lib_math_special_functions) &&      \
+    ((__cpp_lib_math_special_functions >= 201603L) || \
+     defined(__STDCPP_MATH_SPEC_FUNCS__) &&           \
+         (__STDCPP_MATH_SPEC_FUNCS__ >= 201003L))
+// If defined, indicates whether C++17 Bessel functions (of the first kind) are
+// available. Some standard library implementations, such as libc++ (Android
+// NDK, Apple, Clang) do not yet provide these functions. Implementations that
+// do not support C++17, but support ISO 29124:2010, provide the functions if
+// __STDCPP_MATH_SPEC_FUNCS__ is defined by the implementation to a value at
+// least 201003L and if the user defines __STDCPP_WANT_MATH_SPEC_FUNCS__ before
+// including any standard library headers. Standard library Bessel functions are
+// preferred over any other implementation.
+#define CERES_HAS_CPP17_BESSEL_FUNCTIONS
+#elif defined(_SVID_SOURCE) || defined(_BSD_SOURCE) || defined(_XOPEN_SOURCE)
+// If defined, indicates that j0, j1, and jn from <math.h> are available.
+#define CERES_HAS_POSIX_BESSEL_FUNCTIONS
+#endif
+
 #endif  // CERES_PUBLIC_INTERNAL_PORT_H_