scons: Enforce gcc >= 4.4 or clang >= 2.9 and c++0x support
This patch checks that the compiler in use is either gcc >= 4.4 or clang >= 2.9. and enables building with --std=c++0x in all cases. As a consequence, we can tidy up the hashmap and always have static_assert available. If anyone wants to use alternative compilers, icc for example supports c++0x to a similar level and could be added if needed. This patch opens up for a more elaborate use of c++0x features that are present in gcc 4.4 and clang 2.9, e.g. auto typed variables, variadic templates, rvalues and move semantics, and strongly typed enums. There will be no going back on this one...
This commit is contained in:
parent
221302335b
commit
406891c62a
5 changed files with 38 additions and 175 deletions
63
SConstruct
63
SConstruct
|
@ -516,22 +516,25 @@ if main['GCC'] + main['CLANG'] > 1:
|
|||
|
||||
# Set up default C++ compiler flags
|
||||
if main['GCC']:
|
||||
# Check for a supported version of gcc, >= 4.4 is needed for c++0x
|
||||
# support. See http://gcc.gnu.org/projects/cxx0x.html for details
|
||||
gcc_version = readCommand([main['CXX'], '-dumpversion'], exception=False)
|
||||
if compareVersions(gcc_version, "4.4") < 0:
|
||||
print 'Error: gcc version 4.4 or newer required.'
|
||||
print ' Installed version:', gcc_version
|
||||
Exit(1)
|
||||
|
||||
main['GCC_VERSION'] = gcc_version
|
||||
main.Append(CCFLAGS=['-pipe'])
|
||||
main.Append(CCFLAGS=['-fno-strict-aliasing'])
|
||||
main.Append(CCFLAGS=['-Wall', '-Wno-sign-compare', '-Wundef'])
|
||||
# Read the GCC version to check for versions with bugs
|
||||
# Note CCVERSION doesn't work here because it is run with the CC
|
||||
# before we override it from the command line
|
||||
gcc_version = readCommand([main['CXX'], '-dumpversion'], exception=False)
|
||||
main['GCC_VERSION'] = gcc_version
|
||||
main.Append(CXXFLAGS=['-std=c++0x'])
|
||||
|
||||
# Check for versions with bugs
|
||||
if not compareVersions(gcc_version, '4.4.1') or \
|
||||
not compareVersions(gcc_version, '4.4.2'):
|
||||
print 'Info: Tree vectorizer in GCC 4.4.1 & 4.4.2 is buggy, disabling.'
|
||||
main.Append(CCFLAGS=['-fno-tree-vectorize'])
|
||||
# c++0x support in gcc is useful already from 4.4, see
|
||||
# http://gcc.gnu.org/projects/cxx0x.html for details
|
||||
if compareVersions(gcc_version, '4.4') >= 0:
|
||||
main.Append(CXXFLAGS=['-std=c++0x'])
|
||||
|
||||
# LTO support is only really working properly from 4.6 and beyond
|
||||
if compareVersions(gcc_version, '4.6') >= 0:
|
||||
|
@ -551,6 +554,9 @@ if main['GCC']:
|
|||
'-fuse-linker-plugin']
|
||||
|
||||
elif main['CLANG']:
|
||||
# Check for a supported version of clang, >= 2.9 is needed to
|
||||
# support similar features as gcc 4.4. See
|
||||
# http://clang.llvm.org/cxx_status.html for details
|
||||
clang_version_re = re.compile(".* version (\d+\.\d+)")
|
||||
clang_version_match = clang_version_re.match(CXX_version)
|
||||
if (clang_version_match):
|
||||
|
@ -571,11 +577,18 @@ elif main['CLANG']:
|
|||
# Ruby makes frequent use of extraneous parantheses in the printing
|
||||
# of if-statements
|
||||
main.Append(CCFLAGS=['-Wno-parentheses'])
|
||||
|
||||
# clang 2.9 does not play well with c++0x as it ships with C++
|
||||
# headers that produce errors, this was fixed in 3.0
|
||||
if compareVersions(clang_version, "3") >= 0:
|
||||
main.Append(CXXFLAGS=['-std=c++0x'])
|
||||
# On Mac OS X/Darwin we need to also use libc++ (part of XCode) as
|
||||
# opposed to libstdc++ to make the transition from TR1 to
|
||||
# C++11. See http://libcxx.llvm.org. However, clang has chosen a
|
||||
# strict implementation of the C++11 standard, and does not allow
|
||||
# incomplete types in template arguments (besides unique_ptr and
|
||||
# shared_ptr), and the libc++ STL containers create problems in
|
||||
# combination with the current gem5 code. For now, we stick with
|
||||
# libstdc++ and use the TR1 namespace.
|
||||
# if sys.platform == "darwin":
|
||||
# main.Append(CXXFLAGS=['-stdlib=libc++'])
|
||||
|
||||
else:
|
||||
print termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal,
|
||||
print "Don't know what compiler options to use for your compiler."
|
||||
|
@ -711,34 +724,17 @@ def CheckLeading(context):
|
|||
context.Result(ret)
|
||||
return ret
|
||||
|
||||
# Test for the presence of C++11 static asserts. If the compiler lacks
|
||||
# support for static asserts, base/compiler.hh enables a macro that
|
||||
# removes any static asserts in the code.
|
||||
def CheckStaticAssert(context):
|
||||
context.Message("Checking for C++11 static_assert support...")
|
||||
ret = context.TryCompile('''
|
||||
static_assert(1, "This assert is always true");
|
||||
''', extension=".cc")
|
||||
context.env.Append(HAVE_STATIC_ASSERT=ret)
|
||||
context.Result(ret)
|
||||
return ret
|
||||
|
||||
# Platform-specific configuration. Note again that we assume that all
|
||||
# builds under a given build root run on the same host platform.
|
||||
conf = Configure(main,
|
||||
conf_dir = joinpath(build_root, '.scons_config'),
|
||||
log_file = joinpath(build_root, 'scons_config.log'),
|
||||
custom_tests = { 'CheckLeading' : CheckLeading,
|
||||
'CheckStaticAssert' : CheckStaticAssert,
|
||||
})
|
||||
custom_tests = { 'CheckLeading' : CheckLeading })
|
||||
|
||||
# Check for leading underscores. Don't really need to worry either
|
||||
# way so don't need to check the return code.
|
||||
conf.CheckLeading()
|
||||
|
||||
# Check for C++11 features we want to use if they exist
|
||||
conf.CheckStaticAssert()
|
||||
|
||||
# Check if we should compile a 64 bit binary on Mac OS X/Darwin
|
||||
try:
|
||||
import platform
|
||||
|
@ -980,9 +976,8 @@ sticky_vars.AddVariables(
|
|||
)
|
||||
|
||||
# These variables get exported to #defines in config/*.hh (see src/SConscript).
|
||||
export_vars += ['USE_FENV', 'SS_COMPATIBLE_FP',
|
||||
'TARGET_ISA', 'CP_ANNOTATE', 'USE_POSIX_CLOCK', 'PROTOCOL',
|
||||
'HAVE_STATIC_ASSERT', 'HAVE_PROTOBUF']
|
||||
export_vars += ['USE_FENV', 'SS_COMPATIBLE_FP', 'TARGET_ISA', 'CP_ANNOTATE',
|
||||
'USE_POSIX_CLOCK', 'PROTOCOL', 'HAVE_PROTOBUF']
|
||||
|
||||
###################################################
|
||||
#
|
||||
|
|
|
@ -93,7 +93,6 @@ ElfFile('libelf_msize.c')
|
|||
|
||||
m4env = main.Clone()
|
||||
if m4env['GCC']:
|
||||
if compareVersions(m4env['GCC_VERSION'], '4') >= 0:
|
||||
m4env.Append(CCFLAGS=['-Wno-pointer-sign'])
|
||||
if compareVersions(m4env['GCC_VERSION'], '4.6') >= 0:
|
||||
m4env.Append(CCFLAGS=['-Wno-unused-but-set-variable',
|
||||
|
|
|
@ -43,8 +43,6 @@
|
|||
#ifndef __BASE_COMPILER_HH__
|
||||
#define __BASE_COMPILER_HH__
|
||||
|
||||
#include "config/have_static_assert.hh"
|
||||
|
||||
// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
|
||||
|
||||
#if defined(__GNUC__)
|
||||
|
@ -58,32 +56,4 @@
|
|||
#error "Need to define compiler options in base/compiler.hh"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define a compatibility macro that emulates the behavior of
|
||||
* static_assert using template magic if the compiler doesn't have
|
||||
* native support.
|
||||
*/
|
||||
#if !HAVE_STATIC_ASSERT
|
||||
|
||||
template<bool>
|
||||
struct static_assert_failure;
|
||||
|
||||
template<>
|
||||
struct static_assert_failure<false> {};
|
||||
|
||||
/* The following macro causes the compiler to evaluate the size of the
|
||||
* static_assert_failure struct. The templates are designed so that
|
||||
* only static_assert_failure<false> evaluates to a proper size, while
|
||||
* static_assert_failure<true> generates a compile time error.
|
||||
*/
|
||||
#define static_assert(expr, msg) \
|
||||
namespace ns_static_assert { \
|
||||
enum { \
|
||||
static_assert_ ## __LINE__ = \
|
||||
sizeof(static_assert_failure<!(expr)>) \
|
||||
}; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // __BASE_COMPILER_HH__
|
||||
|
|
|
@ -44,100 +44,42 @@
|
|||
#ifndef __HASHMAP_HH__
|
||||
#define __HASHMAP_HH__
|
||||
|
||||
#if defined(__GNUC__)
|
||||
|
||||
// for compilers that deprecate ext/hash_map, i.e. gcc >= 4.3 and
|
||||
// clang, use unordered_map
|
||||
|
||||
// we need to determine what is available, as in the non-c++0x case,
|
||||
// i.e. gcc == 4.3, the containers are in the std::tr1 namespace, and
|
||||
// only gcc >= 4.4 (with -std=c++0x) adds the final container
|
||||
// implementation in the std namespace
|
||||
|
||||
#if defined(__clang__)
|
||||
// align with -std=c++0x only for clang >= 3.0 in CCFLAGS and also
|
||||
// check if the header is present as this depends on what clang was
|
||||
// built against, using XCode clang 3.1, for example, the header is
|
||||
// not present without adding -stdlib=libc++
|
||||
#if (__clang_major__ >= 3 && __has_include(<unordered_map>))
|
||||
// check if the header is present, which requires -stdlib=libc++, and
|
||||
// that in turn causes problems with incomplete template parameters
|
||||
#if (__has_include(<unordered_map>))
|
||||
#define HAVE_STD_UNORDERED_MAP 1
|
||||
#else
|
||||
// we only support clang versions above 2.9 and these all have the tr1
|
||||
// unordered_map
|
||||
#define HAVE_STD_TR1_UNORDERED_MAP 1
|
||||
#endif
|
||||
#else
|
||||
// align with -std=c++0x only for gcc >= 4.4 in CCFLAGS, contrary to
|
||||
// clang we can rely entirely on the compiler version
|
||||
#if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4)
|
||||
// we only support gcc >= 4.4 as the other option
|
||||
#define HAVE_STD_UNORDERED_MAP 1
|
||||
#else
|
||||
#define HAVE_STD_TR1_UNORDERED_MAP 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// set a default value of 0
|
||||
// set a default value of 0 clang with the header in the tr1 namespace
|
||||
#ifndef HAVE_STD_UNORDERED_MAP
|
||||
#define HAVE_STD_UNORDERED_MAP 0
|
||||
#endif
|
||||
|
||||
// set a default value of 0
|
||||
#ifndef HAVE_STD_TR1_UNORDERED_MAP
|
||||
#define HAVE_STD_TR1_UNORDERED_MAP 0
|
||||
#endif
|
||||
|
||||
// now we are ready to deal with the actual includes based on what is
|
||||
// available
|
||||
#if (HAVE_STD_UNORDERED_MAP || HAVE_STD_TR1_UNORDERED_MAP)
|
||||
|
||||
#define hash_map unordered_map
|
||||
#define hash_multimap unordered_multimap
|
||||
#define hash_set unordered_set
|
||||
#define hash_multiset unordered_multiset
|
||||
|
||||
// these versions also have an existing hash function for strings and
|
||||
// 64-bit integer types
|
||||
#define HAVE_HASH_FUNCTIONS 1
|
||||
|
||||
#if HAVE_STD_UNORDERED_MAP
|
||||
|
||||
// clang or gcc >= 4.4
|
||||
// gcc or clang with libc++
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
// note that this assumes that -std=c++0x is added to the command line
|
||||
// which is done in the SConstruct CXXFLAGS for gcc >= 4.4 and clang
|
||||
// >= 3.0
|
||||
#define __hash_namespace std
|
||||
#define __hash_namespace_begin namespace std {
|
||||
#define __hash_namespace_end }
|
||||
#else
|
||||
// clang <= 3.0, gcc == 4.3
|
||||
// clang with libstdc++
|
||||
#include <tr1/unordered_map>
|
||||
#include <tr1/unordered_set>
|
||||
#define __hash_namespace std::tr1
|
||||
#define __hash_namespace_begin namespace std { namespace tr1 {
|
||||
#define __hash_namespace_end } }
|
||||
#endif
|
||||
#else
|
||||
// gcc < 4.3
|
||||
#include <ext/hash_map>
|
||||
#include <ext/hash_set>
|
||||
#define __hash_namespace __gnu_cxx
|
||||
#define __hash_namespace_begin namespace __gnu_cxx {
|
||||
#define __hash_namespace_end }
|
||||
#endif
|
||||
#else
|
||||
// non GNU compiler
|
||||
#include <hash_map>
|
||||
#include <hash_set>
|
||||
#define __hash_namsepace std
|
||||
#define __hash_namespace_begin namespace std {
|
||||
#define __hash_namespace_end }
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/types.hh"
|
||||
|
||||
namespace m5 {
|
||||
using ::__hash_namespace::hash_multimap;
|
||||
|
@ -147,47 +89,4 @@ namespace m5 {
|
|||
using ::__hash_namespace::hash;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////
|
||||
// Some default Hashing Functions
|
||||
//
|
||||
|
||||
__hash_namespace_begin
|
||||
|
||||
// if the hash functions for 64-bit integer types and strings are not
|
||||
// already available, then declare them here
|
||||
#if !defined(HAVE_HASH_FUNCTIONS)
|
||||
|
||||
#if !defined(__LP64__) && !defined(__alpha__) && !defined(__SUNPRO_CC)
|
||||
template<>
|
||||
struct hash<uint64_t> {
|
||||
size_t operator()(uint64_t r) const {
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct hash<int64_t> {
|
||||
size_t operator()(int64_t r) const {
|
||||
return r;
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct hash<std::string> {
|
||||
size_t operator()(const std::string &s) const {
|
||||
return(__stl_hash_string(s.c_str()));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<std::pair<std::string, uint64_t> > {
|
||||
size_t operator() (std::pair<std::string, uint64_t> r) const {
|
||||
return (__stl_hash_string(r.first.c_str())) ^ r.second;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
__hash_namespace_end
|
||||
|
||||
#endif // __HASHMAP_HH__
|
||||
|
|
|
@ -223,7 +223,7 @@ ScalarPrint::operator()(ostream &stream) const
|
|||
ccprintf(cdfstr, "%.2f%%", cdf * 100.0);
|
||||
|
||||
ccprintf(stream, "%-40s %12s %10s %10s", name,
|
||||
ValueToString(value, precision), pdfstr, cdfstr);
|
||||
ValueToString(value, precision), pdfstr.str(), cdfstr.str());
|
||||
|
||||
if (descriptions) {
|
||||
if (!desc.empty())
|
||||
|
|
Loading…
Reference in a new issue