Fallback to Boost.Regex if <regex> is broken

A large number of g++ versions ship a <regex> that declares all of the
required functions, but don't actually implement them, making using them
result in a linker error.

Fallback to Boost.Regex if the host C++11 <regex> implementation is
broken; the interface is the same anyway, only differing in the
containing namespace.

Unfortunately, Boost.Regex is not a header-only library, but this is not
a big deal because all major Linux distributions ship it, and Visual
Studio implements <regex> since 2010 (the oldest version we still
support).
stable-5.4
Nicolas Hake 2013-10-29 16:27:27 +01:00
parent 2686cfd6f0
commit 924e0538fc
3 changed files with 33 additions and 10 deletions

View File

@ -1,7 +1,7 @@
# OpenClonk, http://www.openclonk.org
#
# Copyright (c) 2009-2011 Günther Brammer
# Copyright (c) 2009-2012 Nicolas Hake
# Copyright (c) 2009-2013 Nicolas Hake
# Copyright (c) 2009 David Dormagen
# Copyright (c) 2009-2012 Armin Burgmeier
# Copyright (c) 2009-2010 Sven Eberhardt
@ -106,6 +106,14 @@ CHECK_CXX_SOURCE_COMPILES("int main() { void *d = nullptr; }" HAVE_NULLPTR)
CHECK_CXX_SOURCE_COMPILES("int main() { static_assert(true, \"\"); }" HAVE_STATIC_ASSERT)
set(CMAKE_REQUIRED_FLAGS "${SAFE_CMAKE_REQUIRED_FLAGS}")
# g++'s libstdc++ doesn't properly support <regex> until 4.8.1 (maybe later?).
# They ship a header that declares functions, but they don't ship an
# implementation for some things (like std::regex_iterator).
# This needs to test *linking*, not compilation; cmake does both at the same
# time, so the test below works.
CHECK_CXX_SOURCE_COMPILES("#include <regex>\nint main() { std::cregex_iterator ri; }" HAVE_WORKING_REGEX)
CMAKE_DEPENDENT_OPTION(USE_BOOST_REGEX "Use Boost.Regex even if the C++ runtime has a working implementation of <regex>" OFF "HAVE_WORKING_REGEX" ON)
if(MSVC_VERSION GREATER 1499)
list(APPEND OC_CXX_FLAGS /MP)
list(REMOVE_ITEM OC_CXX_FLAGS_DEBUG /Gm)
@ -842,12 +850,8 @@ include(FindPNG)
include(FindZLIB)
include_directories(${JPEG_INCLUDE_DIR} ${PNG_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})
find_package("Boost" 1.40.0)
if(NOT Boost_INCLUDE_DIR)
message(SEND_ERROR "Could not find the Boost C++ Libraries")
else()
include_directories(SYSTEM ${Boost_INCLUDE_DIR})
endif()
find_package("Boost" 1.40.0 REQUIRED)
include_directories(SYSTEM ${Boost_INCLUDE_DIR})
include(FindThreads)
if(NOT WIN32)
@ -1423,6 +1427,15 @@ if(HAVE_UPNP)
target_link_libraries(openclonk ${UPNP_LIBRARIES})
endif()
if(USE_BOOST_REGEX)
SET(Boost_USE_STATIC_LIBS ON)
find_package(Boost 1.40.0 REQUIRED COMPONENTS regex)
# Disable automatic linking, we'll do it ourselves
add_definitions(-DBOOST_REGEX_NO_LIB)
target_link_libraries(libc4script ${Boost_REGEX_LIBRARY})
target_link_libraries(c4group ${Boost_REGEX_LIBRARY})
endif()
add_subdirectory(tests EXCLUDE_FROM_ALL)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)

View File

@ -181,6 +181,9 @@
/* Developer mode */
#cmakedefine WITH_DEVELOPER_MODE 1
/* Define to 1 if you want to use Boost.Regex instead of <regex>. */
#cmakedefine USE_BOOST_REGEX 1
/* Glib */
#cmakedefine WITH_GLIB 1

View File

@ -38,7 +38,14 @@
#include <C4Config.h>
#include <C4Game.h>
#include <regex>
#ifdef USE_BOOST_REGEX
# undef new
# include <boost/regex.hpp>
namespace re = boost;
#else
# include <regex>
namespace re = std;
#endif
#ifdef HAVE_ICONV
#ifdef HAVE_LANGINFO_H
@ -390,7 +397,7 @@ namespace
{
std::string GetResStr(const char *id, const char *stringtbl)
{
static std::regex line_pattern("^([^=]+)=(.*)\\r?$", std::regex_constants::optimize);
static re::regex line_pattern("^([^=]+)=(.*)\\r?$", re::regex_constants::optimize);
assert(stringtbl);
if (!stringtbl)
{
@ -401,7 +408,7 @@ namespace
const char *begin = stringtbl;
const char *end = begin + std::char_traits<char>::length(begin);
for (auto it = std::cregex_iterator(begin, end, line_pattern); it != std::cregex_iterator(); ++it)
for (auto it = re::cregex_iterator(begin, end, line_pattern); it != re::cregex_iterator(); ++it)
{
assert(it->size() == 3);
if (it->size() != 3)