Add support for MSVC 2013 Update 5 or newer

Use the CMake WriteCompilerDetectionHeader module to add generate a
header with compatibility macros.

    - For static constants, use `const` instead of `constexpr`

    - Drop `noexcept` if not supported by the compiler

    - Use ASCII string literals if unicode literals are not supported
      and replace unicode opening/closing single quotes with ASCII
      backticks.
This commit is contained in:
Taylor Braun-Jones 2016-05-23 15:40:10 -04:00
parent f55b63e258
commit dd069b6893
3 changed files with 60 additions and 21 deletions

View File

@ -26,7 +26,7 @@ RETURN()
ENDIF()
cmake_minimum_required(VERSION 2.6)
cmake_minimum_required(VERSION 3.1)
project(cxxopts)
set(VERSION "0.0.1")

View File

@ -18,9 +18,34 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
add_executable(example example.cpp)
add_executable(example example.cpp cxxopts.hpp)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
target_link_libraries(example ${CXXOPTS_LINKER_LIBRARIES})
# Visual Studio 12 2013 Update 5 or newer is required to fix in-class member
# initialization using std::make_shared<type>.
# https://connect.microsoft.com/VisualStudio/feedbackdetail/view/818825
if(MSVC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0.21005.1)
message(SEND_ERROR "Visual Studio 12 2013 Update 5 or newer is required.")
endif()
install(FILES cxxopts.hpp DESTINATION include)
target_link_libraries(example
${CXXOPTS_LINKER_LIBRARIES}
)
target_compile_features(example PUBLIC
cxx_auto_type
)
target_include_directories(example PUBLIC
${CMAKE_CURRENT_BINARY_DIR}
)
include(WriteCompilerDetectionHeader)
write_compiler_detection_header(
FILE cxxopts_compiler_detection.h
PREFIX cxxopts
COMPILERS GNU MSVC Clang
FEATURES
cxx_unicode_literals
cxx_constexpr
cxx_noexcept
)
install(FILES cxxopts.hpp ${CMAKE_CURRENT_BINARY_DIR}/cxxopts_compiler_detection.h DESTINATION include)

View File

@ -40,6 +40,20 @@ THE SOFTWARE.
#include <vector>
#include <string.h>
#include <cxxopts_compiler_detection.h>
#if cxxopts_COMPILER_CXX_CONSTEXPR
#define cxxopts_CONSTEXPR_OR_CONST constexpr
#else
#define cxxopts_CONSTEXPR_OR_CONST const
#endif
#if cxxopts_COMPILER_CXX_UNICODE_LITERALS
#define cxxopts_U8(x) u8 ## x
#else
#define cxxopts_U8(x) x
#endif
//when we ask cxxopts to use Unicode, help strings are processed using ICU,
//which results in the correct lengths being computed for strings when they
//are formatted for the help output
@ -272,7 +286,7 @@ namespace cxxopts
}
virtual const char*
what() const noexcept
what() const cxxopts_NOEXCEPT
{
return m_message.c_str();
}
@ -304,7 +318,7 @@ namespace cxxopts
{
public:
option_exists_error(const std::string& option)
: OptionSpecException(u8"Option " + option + u8" already exists")
: OptionSpecException(cxxopts_U8("Option `") + option + cxxopts_U8("` already exists"))
{
}
};
@ -313,7 +327,7 @@ namespace cxxopts
{
public:
invalid_option_format_error(const std::string& format)
: OptionSpecException(u8"Invalid option format " + format + u8"")
: OptionSpecException(cxxopts_U8("Invalid option format `") + format + cxxopts_U8("`"))
{
}
};
@ -322,7 +336,7 @@ namespace cxxopts
{
public:
option_not_exists_exception(const std::string& option)
: OptionParseException(u8"Option " + option + u8" does not exist")
: OptionParseException(cxxopts_U8("Option `") + option + cxxopts_U8("` does not exist"))
{
}
};
@ -331,7 +345,7 @@ namespace cxxopts
{
public:
missing_argument_exception(const std::string& option)
: OptionParseException(u8"Option " + option + u8" is missing an argument")
: OptionParseException(cxxopts_U8("Option `") + option + cxxopts_U8("` is missing an argument"))
{
}
};
@ -340,7 +354,7 @@ namespace cxxopts
{
public:
option_requires_argument_exception(const std::string& option)
: OptionParseException(u8"Option " + option + u8" requires an argument")
: OptionParseException(cxxopts_U8("Option `") + option + cxxopts_U8("` requires an argument"))
{
}
};
@ -354,8 +368,8 @@ namespace cxxopts
const std::string& arg
)
: OptionParseException(
u8"Option " + option + u8" does not take an argument, but argument"
+ arg + " given")
cxxopts_U8("Option `") + option + cxxopts_U8("` does not take an argument, but argument`")
+ arg + "` given")
{
}
};
@ -364,7 +378,7 @@ namespace cxxopts
{
public:
option_not_present_exception(const std::string& option)
: OptionParseException(u8"Option " + option + u8" not present")
: OptionParseException(cxxopts_U8("Option `") + option + cxxopts_U8("` not present"))
{
}
};
@ -377,7 +391,7 @@ namespace cxxopts
const std::string& arg
)
: OptionParseException(
u8"Argument " + arg + u8" failed to parse"
cxxopts_U8("Argument `") + arg + cxxopts_U8("` failed to parse")
)
{
}
@ -429,25 +443,25 @@ namespace cxxopts
template <typename T>
struct value_has_arg
{
static constexpr bool value = true;
static cxxopts_CONSTEXPR_OR_CONST bool value = true;
};
template <>
struct value_has_arg<bool>
{
static constexpr bool value = false;
static cxxopts_CONSTEXPR_OR_CONST bool value = false;
};
template <typename T>
struct type_is_container
{
static constexpr bool value = false;
static cxxopts_CONSTEXPR_OR_CONST bool value = false;
};
template <typename T>
struct type_is_container<std::vector<T>>
{
static constexpr bool value = true;
static cxxopts_CONSTEXPR_OR_CONST bool value = true;
};
template <typename T>
@ -822,8 +836,8 @@ namespace cxxopts
namespace
{
constexpr int OPTION_LONGEST = 30;
constexpr int OPTION_DESC_GAP = 2;
cxxopts_CONSTEXPR_OR_CONST int OPTION_LONGEST = 30;
cxxopts_CONSTEXPR_OR_CONST int OPTION_DESC_GAP = 2;
std::basic_regex<char> option_matcher
("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([a-zA-Z]+)");