boost: Smarter logic for Boost detection & download
Auto-enable C++11 flag if detected Boost version is >= 1.65
But don't auto-disable if -DCXX11 was passed and detected Boost
version is too old for that. Instead, just download a newer
version of Boost that works with C++11 (1.75)
Replace throw with _GLIBC_THROW or _GLIBC_USE_NO_EXCEPT
gcc's implementation of C++11 requires this, even though clang's doesn't
Also, update setting of compiler flags in CMakeLists.txt
diff --git a/CMakeLists.txt b/CMakeLists.txt
index da573e8..a4231fb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -57,6 +57,32 @@
FORCE)
endif(NOT CMAKE_BUILD_TYPE)
+# The C++11 standard overlaps a lot with older versions of Boost.
+# So before deciding what standard to use for the whole project, we
+# first detect Boost to see what version is on the system.
+#
+# C++11 is required for recent versions of Boost but will cause problems
+# for older versions of Boost. Therefore, we detect it here intstead of
+# in src/CMakeLists.txt where the other 3rd party libraries are detected.
+#
+find_package(Boost)
+if(Boost_FOUND)
+ # We use BOOST_ASSERT_MSG, which only exists in Boost 1.47 and later.
+ if(Boost_VERSION_MACRO LESS 104700)
+ message(STATUS "Found Boost ${Boost_VERSION_STRING}, but too old for MADlib")
+ set(Boost_FOUND FALSE)
+ elseif(CXX11 AND (Boost_VERSION_MACRO LESS 106500))
+ message(STATUS "Found Boost ${Boost_VERSION_STRING}, but too old for C++11")
+ set(Boost_FOUND FALSE)
+ else()
+ message(STATUS "Found Boost ${Boost_VERSION_STRING}")
+ if(106500 LESS Boost_VERSION_MACRO)
+ message(STATUS "Auto-enabling -DCXX11, because Boost >= v1.65 requires C++11")
+ set(CXX11 TRUE)
+ endif(106500 LESS Boost_VERSION_MACRO)
+ endif()
+endif(Boost_FOUND)
+
if(CMAKE_COMPILER_IS_GNUCC)
# Let's store the gcc version in a variable
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
@@ -70,9 +96,7 @@
# http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_02_01_01
# We specify that we are POSIX.1-2001 compliant and XSI-conforming. We only
# need to specify _XOPEN_SOURCE as _POSIX_C_SOURCE will be set implicitly.
- set(CMAKE_C_FLAGS "-std=c99 -D_GLIBCXX_USE_CXX11_ABI=0 -pedantic -Wall -Wextra -Wno-clobbered -D_XOPEN_SOURCE=600"
- CACHE STRING
- "Flags used by the compiler during all build types." FORCE)
+ set(CMAKE_C_FLAGS "-pedantic -Wall -Wextra -Wno-clobbered -D_XOPEN_SOURCE=600")
if((CMAKE_C_COMPILER_VERSION VERSION_EQUAL 5.0) OR (CMAKE_C_COMPILER_VERSION VERSION_GREATER 5.0))
# Versions 5+ fail with the "Release" build type i.e. when optimization
# level is -O3 or greater.
@@ -86,7 +110,7 @@
elseif(CMAKE_C_COMPILER_ID STREQUAL "SunPro")
set(CMAKE_C_FLAGS "-xc99=%all")
endif()
-
+
if(CMAKE_COMPILER_IS_GNUCXX)
# Let's store the gcc version in a variable
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion
@@ -100,15 +124,29 @@
set(SSE_DISABLE_OPTIONS "-mno-sse2")
endif()
- # We need the 1998 standard plus amendments (ISO/IEC 14882:2003) plus TR1
- # Unfortunately, we only get this with gnu++98
- # Special notes:
- # - long long is not part of the C++ 1998/2003 standard, but it is such a
- # common (and useful) extension that we do not want to hear warnings about
- # it.
- set(CMAKE_CXX_FLAGS "-std=gnu++98 -D_GLIBCXX_USE_CXX11_ABI=0 -fdiagnostics-show-option -Wall -Wextra -pedantic -Wconversion -Wno-long-long -Wno-clobbered ${SSE_DISABLE_OPTIONS} -fstrict-aliasing"
- CACHE STRING
- "Flags used by the compiler during all build types." FORCE)
+ set(CMAKE_CXX_FLAGS "-fdiagnostics-show-option -Wall -Wextra -pedantic -Wconversion -Wno-long-long -Wno-clobbered ${SSE_DISABLE_OPTIONS} -fstrict-aliasing"
+ )
+ if (CXX11)
+ set(CMAKE_CXX_FLAGS "-std=gnu++11 ${CMAKE_CXX_FLAGS}"
+ CACHE STRING
+ "Flags used by the compiler during all build types." FORCE)
+ set(CMAKE_C_FLAGS "-std=gnu11 ${CMAKE_C_FLAGS}"
+ CACHE STRING
+ "Flags used by the compiler during all build types." FORCE)
+ else(CXX11)
+ # We need the 1998 standard plus amendments (ISO/IEC 14882:2003) plus TR1
+ # Unfortunately, we only get this with gnu++98
+ # Special notes:
+ # - long long is not part of the C++ 1998/2003 standard, but it is such a
+ # common (and useful) extension that we do not want to hear warnings about
+ # it.
+ set(CMAKE_CXX_FLAGS "-std=gnu++98 ${CMAKE_CXX_FLAGS}"
+ CACHE STRING
+ "Flags used by the compiler during all build types." FORCE)
+ set(CMAKE_C_FLAGS "-std=gnu99 ${CMAKE_C_FLAGS}"
+ CACHE STRING
+ "Flags used by the compiler during all build types." FORCE)
+ endif(CXX11)
if((CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 5.0) OR (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.0))
# Versions 5+ fail with the "Release" build type i.e. when optimization
@@ -122,13 +160,25 @@
set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-isystem ")
endif(APPLE)
elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
-if (CXX11)
- set(CMAKE_CXX_FLAGS "-stdlib=libc++ -std=c++11 -D_GLIBCXX_USE_CXX11_ABI=1")
-else (CXX11)
- set(CMAKE_CXX_FLAGS "-stdlib=libstdc++ -D_GLIBCXX_USE_CXX11_ABI=0")
-endif(CXX11)
+ if(CXX11)
+ set(CMAKE_CXX_FLAGS "-stdlib=libc++ -std=c++11"
+ CACHE STRING
+ "Flags used by the compiler during all build types." FORCE)
+ else(CXX11)
+ set(CMAKE_CXX_FLAGS "-stdlib=libstdc++"
+ CACHE STRING
+ "Flags used by the compiler during all build types." FORCE)
+ endif(CXX11)
endif(CMAKE_COMPILER_IS_GNUCXX)
+if(CXX11)
+ add_definitions("-D_GLIBCXX_USE_CXX11_ABI=1")
+ # TODO: for recent cmake, add_compile_definitions("_GLIBCXX_USE_CXX11_ABI=1")
+else(CXX11)
+ add_definitions("-D_GLIBCXX_USE_CXX11_ABI=0")
+ # TODO: for recent cmake, add_compile_definitions("_GLIBCXX_USE_CXX11_ABI=0")
+endif(CXX11)
+
# force a `m4_' prefix to all builtins
if(FREEBSD)
set(M4_ARGUMENTS "-P")
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 41b475d..7825028 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -34,21 +34,25 @@
# running cmake:
# "-DBOOST_TAR_SOURCE=/path/to/boost_x_x_x.tar.gz"
-set(BOOST_TAR_VERSION "1.61.0")
-set(BOOST_TAR_MD5 874805ba2e2ee415b1877ef3297bf8ad)
-
-string(REPLACE "." "_" _BOOST_TAR_VERSION_UNDERSCORES ${BOOST_TAR_VERSION})
-set(BOOST_TAR "boost_${_BOOST_TAR_VERSION_UNDERSCORES}.tar.gz")
-set(BOOST_URL "${SOURCEFORGE_BASE_URL}/boost/files/${BOOST_TAR}")
+if (CXX11)
+ set(BOOST_TAR_VERSION "1.75.0") # If CXX11 is enabled, we can use latest version of Boost
+ set(BOOST_TAR_MD5 38813f6feb40387dfe90160debd71251)
+else(CXX11)
+ set(BOOST_TAR_VERSION "1.61.0") # Most recent version that includes TR1 (necessary for old C++ compilers)
+ set(BOOST_TAR_MD5 874805ba2e2ee415b1877ef3297bf8ad)
+endif(CXX11)
+ string(REPLACE "." "_" _BOOST_TAR_VERSION_UNDERSCORES ${BOOST_TAR_VERSION})
+ set(BOOST_TAR "boost_${_BOOST_TAR_VERSION_UNDERSCORES}.tar.gz")
+ set(BOOST_URL "${SOURCEFORGE_BASE_URL}/boost/files/${BOOST_TAR}")
if(NOT BOOST_TAR_SOURCE)
- find_file(BOOST_TAR_SOURCE ${BOOST_TAR}
+ find_file(BOOST_TAR_SOURCE ${BOOST_TAR} # If not user-specified, try finding in downloads dir
PATHS ${MAD_THIRD_PARTY}/downloads)
-endif(NOT BOOST_TAR_SOURCE)
-if(NOT BOOST_TAR_SOURCE)
- set(BOOST_TAR_SOURCE ${BOOST_URL})
-endif (NOT BOOST_TAR_SOURCE)
+ if (NOT BOOST_TAR_SOURCE)
+ set(BOOST_TAR_SOURCE ${BOOST_URL}) # If not found locally, download
+ endif()
+endif(NOT BOOST_TAR_SOURCE)
# We always download Eigen (unless it is already present in
# ${CMAKE_CURRENT_BINARY_DIR}/third_party/downloads). It is also possible to
@@ -104,19 +108,7 @@
# try this at home.
# ==============================================================================
-# -- Third-party dependencies: Find or download Boost --------------------------
-
-# set(Boost_INCLUDE_DIRS "/usr/local/opt/boost/include")
-find_package(Boost 1.47)
-if(Boost_FOUND)
- # We use BOOST_ASSERT_MSG, which only exists in Boost 1.47 and later.
- if(Boost_MACRO_VERSION LESS 104700)
- set(Boost_FOUND FALSE)
- else(Boost_MACRO_VERSION LESS 104700)
- message(STATUS "Actual version of Boost found: ${Boost_VERSION_STRING}")
- endif(Boost_MACRO_VERSION LESS 104700)
-endif(Boost_FOUND)
-
+# -- Third-party dependencies: Download the Boost if not previously detected
if(Boost_FOUND)
message(STATUS "Boost include directory ${Boost_INCLUDE_DIRS}")
include_directories(${Boost_INCLUDE_DIRS})
@@ -135,7 +127,6 @@
include_directories(BEFORE SYSTEM ${MAD_THIRD_PARTY}/src/EP_boost)
endif(Boost_FOUND)
-
# -- Third-party dependencies: Download the C++ linear-algebra library Eigen ---
ExternalProject_Add(EP_eigen
PREFIX ${MAD_THIRD_PARTY}
diff --git a/src/dbal/BoostIntegration/MathToolkit_impl.hpp b/src/dbal/BoostIntegration/MathToolkit_impl.hpp
index 2b93c8c..402aeec 100644
--- a/src/dbal/BoostIntegration/MathToolkit_impl.hpp
+++ b/src/dbal/BoostIntegration/MathToolkit_impl.hpp
@@ -57,14 +57,12 @@
int prec = 2 + (std::numeric_limits<T>::digits * 30103UL) / 100000UL;
#endif // _GLIBCXX_USE_CXX11_ABI
- throw std::domain_error(inMessage);
-
std:: string *msg = new std::string(
(boost::format(inMessage)
% boost::io::group(std::setprecision(prec), inVal)
).str()
);
-
+
// Some Boost error messages contain a space before the punctuation mark,
// which we will remove.
std::string::iterator lastChar = msg->end() - 1;
diff --git a/src/ports/postgres/dbconnector/NewDelete.cpp b/src/ports/postgres/dbconnector/NewDelete.cpp
index a4de2df..8f909a8 100644
--- a/src/ports/postgres/dbconnector/NewDelete.cpp
+++ b/src/ports/postgres/dbconnector/NewDelete.cpp
@@ -26,6 +26,11 @@
// the search paths, which might point to a port-specific dbconnector.hpp
#include <dbconnector/dbconnector.hpp>
+#ifdef _LIBCPP_COMPILER_CLANG
+#define _GLIBCXX_THROW(a) throw(a)
+#define _GLIBCXX_USE_NOEXCEPT noexcept
+#endif
+
/**
* @brief operator new for PostgreSQL. Throw on fail.
*
@@ -34,7 +39,7 @@
* that size.
*/
void*
-operator new(std::size_t size) throw (std::bad_alloc) {
+operator new(std::size_t size) _GLIBCXX_THROW (std::bad_alloc) {
return madlib::defaultAllocator().allocate<
madlib::dbal::FunctionContext,
madlib::dbal::DoNotZero,
@@ -42,7 +47,7 @@
}
void*
-operator new[](std::size_t size) throw (std::bad_alloc) {
+operator new[](std::size_t size) _GLIBCXX_THROW (std::bad_alloc) {
return madlib::defaultAllocator().allocate<
madlib::dbal::FunctionContext,
madlib::dbal::DoNotZero,
@@ -58,12 +63,12 @@
* <tt>operator new(std::size_t)</tt>.
*/
void
-operator delete(void *ptr) throw() {
+operator delete(void *ptr) _GLIBCXX_USE_NOEXCEPT {
madlib::defaultAllocator().free<madlib::dbal::FunctionContext>(ptr);
}
void
-operator delete[](void *ptr) throw() {
+operator delete[](void *ptr) _GLIBCXX_USE_NOEXCEPT {
madlib::defaultAllocator().free<madlib::dbal::FunctionContext>(ptr);
}
@@ -75,7 +80,7 @@
* indication, instead of a bad_alloc exception.
*/
void*
-operator new(std::size_t size, const std::nothrow_t&) throw() {
+operator new(std::size_t size, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT {
return madlib::defaultAllocator().allocate<
madlib::dbal::FunctionContext,
madlib::dbal::DoNotZero,
@@ -83,7 +88,7 @@
}
void*
-operator new[](std::size_t size, const std::nothrow_t&) throw() {
+operator new[](std::size_t size, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT {
return madlib::defaultAllocator().allocate<
madlib::dbal::FunctionContext,
madlib::dbal::DoNotZero,
@@ -97,11 +102,11 @@
* <tt>operator new(std::size_t, const std::nothrow_t&)</tt>.
*/
void
-operator delete(void *ptr, const std::nothrow_t&) throw() {
+operator delete(void *ptr, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT {
madlib::defaultAllocator().free<madlib::dbal::FunctionContext>(ptr);
}
void
-operator delete[](void *ptr, const std::nothrow_t&) throw() {
+operator delete[](void *ptr, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT {
madlib::defaultAllocator().free<madlib::dbal::FunctionContext>(ptr);
}