From a4c24a33c1ed32d9d51c8df763ec6ad574587d02 Mon Sep 17 00:00:00 2001 From: Bruce Dawson Date: Thu, 16 Jun 2022 00:47:21 -0700 Subject: Build ninja with C++11 (#2089) * Build ninja with C++11 In order to allow future use of std::chrono to make the stats code portable it is desirable to compile with C++11. Doing so also allows use of std::unordered_map, and reduces the number of #ifdefs in the ninja source code. Switching to C++11 requires modifying both CMakeLists.txt and configure.py, for MSVC and for other build systems. For MSVC the required change is adding /Zc:__cplusplus to tell the compiler to give a more accurate value for the __cplusplus macro. For other platforms the change is to add -std=c++11 or the CMake equivalent. This change makes some progress towards resolving issue #2004. * Delete code and instructions C++11 guarantees that string::data() gives null-terminated pointers, so explicitly adding a null terminator is no longer needed. The Google C++ Style Guide already recommends avoiding unnecessary use of C++14 and C++17 so repeating this in CONTRIBUTING.md is not critical. These changes both came from PR-review suggestions. * Only set cxx_std_11 if standard is 98 * Return to unconditional target_compile_features use After much discussion it sounds like using target_compile_features unconditionally is best. --- CMakeLists.txt | 4 ++++ CONTRIBUTING.md | 3 --- configure.py | 4 ++++ src/graph.cc | 4 ---- src/hash_map.h | 44 -------------------------------------------- src/missing_deps.h | 7 ------- src/parser.cc | 7 ------- 7 files changed, 8 insertions(+), 65 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 22b8158..9c0f27a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,8 @@ endif() if(MSVC) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") string(REPLACE "/GR" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) + # Note that these settings are separately specified in configure.py, and + # these lists should be kept in sync. add_compile_options(/W4 /wd4100 /wd4267 /wd4706 /wd4702 /wd4244 /GR- /Zc:__cplusplus) add_compile_definitions(_CRT_SECURE_NO_WARNINGS) else() @@ -138,6 +140,8 @@ else() endif() endif() +target_compile_features(libninja PUBLIC cxx_std_11) + #Fixes GetActiveProcessorCount on MinGW if(MINGW) target_compile_definitions(libninja PRIVATE _WIN32_WINNT=0x0601 __USE_MINGW_ANSI_STDIO=1) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index be1fc02..c6c190c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,9 +14,6 @@ Generally it's the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) with a few additions: -* Any code merged into the Ninja codebase which will be part of the main - executable must compile as C++03. You may use C++11 features in a test or an - unimportant tool if you guard your code with `#if __cplusplus >= 201103L`. * We have used `using namespace std;` a lot in the past. For new contributions, please try to avoid relying on it and instead whenever possible use `std::`. However, please do not change existing code simply to add `std::` unless your diff --git a/configure.py b/configure.py index 4390434..99a2c86 100755 --- a/configure.py +++ b/configure.py @@ -305,6 +305,8 @@ if platform.is_msvc(): else: n.variable('ar', configure_env.get('AR', 'ar')) +# Note that build settings are separately specified in CMakeLists.txt and +# these lists should be kept in sync. if platform.is_msvc(): cflags = ['/showIncludes', '/nologo', # Don't print startup banner. @@ -320,6 +322,7 @@ if platform.is_msvc(): # Disable warnings about ignored typedef in DbgHelp.h '/wd4091', '/GR-', # Disable RTTI. + '/Zc:__cplusplus', # Disable size_t -> int truncation warning. # We never have strings or arrays larger than 2**31. '/wd4267', @@ -339,6 +342,7 @@ else: '-Wno-unused-parameter', '-fno-rtti', '-fno-exceptions', + '-std=c++11', '-fvisibility=hidden', '-pipe', '-DNINJA_PYTHON="%s"' % options.with_python] if options.debug: diff --git a/src/graph.cc b/src/graph.cc index 041199a..95fc1dc 100644 --- a/src/graph.cc +++ b/src/graph.cc @@ -402,11 +402,7 @@ string EdgeEnv::LookupVariable(const string& var) { if (var == "in" || var == "in_newline") { int explicit_deps_count = edge_->inputs_.size() - edge_->implicit_deps_ - edge_->order_only_deps_; -#if __cplusplus >= 201103L return MakePathList(edge_->inputs_.data(), explicit_deps_count, -#else - return MakePathList(&edge_->inputs_[0], explicit_deps_count, -#endif var == "in" ? ' ' : '\n'); } else if (var == "out") { int explicit_outs_count = edge_->outputs_.size() - edge_->implicit_outs_; diff --git a/src/hash_map.h b/src/hash_map.h index 55d2c9d..4353609 100644 --- a/src/hash_map.h +++ b/src/hash_map.h @@ -53,7 +53,6 @@ unsigned int MurmurHash2(const void* key, size_t len) { return h; } -#if (__cplusplus >= 201103L) || (_MSC_VER >= 1900) #include namespace std { @@ -68,56 +67,13 @@ struct hash { }; } -#elif defined(_MSC_VER) -#include - -using stdext::hash_map; -using stdext::hash_compare; - -struct StringPieceCmp : public hash_compare { - size_t operator()(const StringPiece& key) const { - return MurmurHash2(key.str_, key.len_); - } - bool operator()(const StringPiece& a, const StringPiece& b) const { - int cmp = memcmp(a.str_, b.str_, min(a.len_, b.len_)); - if (cmp < 0) { - return true; - } else if (cmp > 0) { - return false; - } else { - return a.len_ < b.len_; - } - } -}; - -#else -#include - -using __gnu_cxx::hash_map; - -namespace __gnu_cxx { -template<> -struct hash { - size_t operator()(StringPiece key) const { - return MurmurHash2(key.str_, key.len_); - } -}; -} -#endif - /// A template for hash_maps keyed by a StringPiece whose string is /// owned externally (typically by the values). Use like: /// ExternalStringHash::Type foos; to make foos into a hash /// mapping StringPiece => Foo*. template struct ExternalStringHashMap { -#if (__cplusplus >= 201103L) || (_MSC_VER >= 1900) typedef std::unordered_map Type; -#elif defined(_MSC_VER) - typedef hash_map Type; -#else - typedef hash_map Type; -#endif }; #endif // NINJA_MAP_H_ diff --git a/src/missing_deps.h b/src/missing_deps.h index ae57074..7a615da 100644 --- a/src/missing_deps.h +++ b/src/missing_deps.h @@ -19,9 +19,7 @@ #include #include -#if __cplusplus >= 201103L #include -#endif struct DepsLog; struct DiskInterface; @@ -68,13 +66,8 @@ struct MissingDependencyScanner { int missing_dep_path_count_; private: -#if __cplusplus >= 201103L using InnerAdjacencyMap = std::unordered_map; using AdjacencyMap = std::unordered_map; -#else - typedef std::map InnerAdjacencyMap; - typedef std::map AdjacencyMap; -#endif AdjacencyMap adjacency_map_; }; diff --git a/src/parser.cc b/src/parser.cc index 756922d..5f303c5 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -31,13 +31,6 @@ bool Parser::Load(const string& filename, string* err, Lexer* parent) { return false; } - // The lexer needs a nul byte at the end of its input, to know when it's done. - // It takes a StringPiece, and StringPiece's string constructor uses - // string::data(). data()'s return value isn't guaranteed to be - // null-terminated (although in practice - libc++, libstdc++, msvc's stl -- - // it is, and C++11 demands that too), so add an explicit nul byte. - contents.resize(contents.size() + 1); - return Parse(filename, contents, err); } -- cgit v0.12