From: Markus Blatt <markus@dr-blatt.de>
Date: Wed, 8 Mar 2023 19:47:36 +0100
Subject: Split Builtin.hpp into multiple compile units for g++-12.

g++-12 needs quite some memory and time to compile it.
We now use several Builtin*.cpp for the imlementations for different
starting letters of eclipse keywords to use less resources for
compiling.
---
 CMakeLists.txt                                     |  1 +
 CopyHeaders.cmake                                  |  3 +
 GenerateKeywords.cmake                             |  2 +
 opm/input/eclipse/Generator/KeywordGenerator.hpp   |  3 +-
 .../input/eclipse/Generator/KeywordGenerator.cpp   | 88 ++++++++++++++--------
 .../eclipse/Parser/createDefaultKeywordList.cpp    |  3 +-
 6 files changed, 65 insertions(+), 35 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index e5ae79e..6a00d68 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -137,6 +137,7 @@ macro (sources_hook)
     foreach (name A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
         list(INSERT opm-common_SOURCES 0 ${PROJECT_BINARY_DIR}/ParserKeywords/${name}.cpp)
         list(INSERT opm-common_SOURCES 0 ${PROJECT_BINARY_DIR}/ParserKeywords/ParserInit${name}.cpp)
+        list(INSERT opm-common_SOURCES 0 ${PROJECT_BINARY_DIR}/ParserKeywords/Builtin${name}.cpp)
         list(INSERT opm-common_HEADERS 0 ${PROJECT_BINARY_DIR}/include/opm/input/eclipse/Parser/ParserKeywords/${name}.hpp)
     endforeach()
     if (OPM_ENABLE_EMBEDDED_PYTHON)
diff --git a/CopyHeaders.cmake b/CopyHeaders.cmake
index 4c243e3..faf9f4e 100644
--- a/CopyHeaders.cmake
+++ b/CopyHeaders.cmake
@@ -34,4 +34,7 @@ foreach (name A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
     execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
                             ${BASE_DIR}/tmp_gen/ParserKeywords/ParserInit${name}.cpp
                             ${BASE_DIR}/ParserKeywords/ParserInit${name}.cpp)
+    execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
+                            ${BASE_DIR}/tmp_gen/ParserKeywords/Builtin${name}.cpp
+                            ${BASE_DIR}/ParserKeywords/Builtin${name}.cpp)
 endforeach()
diff --git a/GenerateKeywords.cmake b/GenerateKeywords.cmake
index 9320f92..ac21320 100644
--- a/GenerateKeywords.cmake
+++ b/GenerateKeywords.cmake
@@ -56,10 +56,12 @@ foreach (name A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
   list(APPEND _tmp_output ${PROJECT_BINARY_DIR}/tmp_gen/ParserKeywords/${name}.cpp
                           ${PROJECT_BINARY_DIR}/tmp_gen/include/opm/input/eclipse/Parser/ParserKeywords/${name}.hpp
                           ${PROJECT_BINARY_DIR}/tmp_gen/ParserKeywords/ParserInit${name}.cpp
+                          ${PROJECT_BINARY_DIR}/tmp_gen/ParserKeywords/Builtin${name}.cpp
                           ${PROJECT_BINARY_DIR}/tmp_gen/include/opm/input/eclipse/Parser/ParserKeywords/ParserInit${name}.hpp)
   list(APPEND _target_output ${PROJECT_BINARY_DIR}/ParserKeywords/${name}.cpp
                              ${PROJECT_BINARY_DIR}/include/opm/input/eclipse/Parser/ParserKeywords/${name}.hpp
                              ${PROJECT_BINARY_DIR}/ParserKeywords/ParserInit${name}.cpp
+                             ${PROJECT_BINARY_DIR}/ParserKeywords/Builtin${name}.cpp
                              ${PROJECT_BINARY_DIR}/include/opm/input/eclipse/Parser/ParserKeywords/ParserInit${name}.hpp)
 endforeach()
 
diff --git a/opm/input/eclipse/Generator/KeywordGenerator.hpp b/opm/input/eclipse/Generator/KeywordGenerator.hpp
index 7c24f18..aa7af85 100644
--- a/opm/input/eclipse/Generator/KeywordGenerator.hpp
+++ b/opm/input/eclipse/Generator/KeywordGenerator.hpp
@@ -38,7 +38,8 @@ namespace Opm {
         static std::string headerHeader( const std::string& );
         static void updateFile(const std::stringstream& newContent, const std::string& filename);
 
-        void updateBuiltInHeader(const KeywordLoader& loader, const std::string& headerBuildPath, const std::string& headerPath) const;
+        void updateBuiltInHeader(const KeywordLoader& loader, const std::string& headerBuildPath,
+                                 const std::string& headerPath, const std::string& sourcePath) const;
         void updateInitSource(const KeywordLoader& loader, const std::string& sourceFile, const std::string& sourcePath) const;
         void updateKeywordSource(const KeywordLoader& loader, const std::string& sourceFile ) const;
         void updatePybindSource(const KeywordLoader& loader , const std::string& sourceFile ) const;
diff --git a/src/opm/input/eclipse/Generator/KeywordGenerator.cpp b/src/opm/input/eclipse/Generator/KeywordGenerator.cpp
index 418f311..b1a2dd7 100644
--- a/src/opm/input/eclipse/Generator/KeywordGenerator.cpp
+++ b/src/opm/input/eclipse/Generator/KeywordGenerator.cpp
@@ -93,60 +93,79 @@ namespace Opm {
         write_file(stream.str(), file, verbose, desc);
     }
 
-    void KeywordGenerator::updateBuiltInHeader(const KeywordLoader& loader, const std::string& headerBuildPath, const std::string& headerPath) const {
-        std::stringstream newSource;
-        newSource << R"(#ifndef PARSER_KEYWORDS_BUILTIN_HPP
+    void KeywordGenerator::updateBuiltInHeader(const KeywordLoader& loader, const std::string& headerBuildPath, const std::string& headerPath,
+                                               const std::string& sourcePath ) const {
+        std::stringstream newHeader;
+        std::map<char, std::stringstream> newSources;
+
+        newHeader << R"(#ifndef PARSER_KEYWORDS_BUILTIN_HPP
 #define PARSER_KEYWORDS_BUILTIN_HPP
 #include <unordered_map>
 #include <fmt/format.h>
+#include <opm/input/eclipse/Parser/ParserKeyword.hpp>
 )";
 
         for(const auto& kw_pair : loader) {
             const auto& first_char = kw_pair.first;
-            newSource << fmt::format("#include <opm/input/eclipse/Parser/ParserKeywords/{}.hpp>\n", first_char);
+            newSources[first_char]  << fmt::format("#include <opm/input/eclipse/Parser/ParserKeywords/{}.hpp>\n", first_char)
+                                    << fmt::format("#include <{}/Builtin.hpp>\n",  headerPath)
+                                    << "namespace Opm { namespace ParserKeywords {\n";
         }
 
-        newSource << R"(
+        newHeader << R"(
 namespace Opm {
 namespace ParserKeywords {
 struct Builtin {
 )";
         for(const auto& kw_pair : loader) {
             const auto& keywords = kw_pair.second;
+            auto& source = newSources[kw_pair.first];
             for (const auto& kw: keywords)
-                newSource << fmt::format("    const ::Opm::ParserKeywords::{0} {0};\n", kw.className());
-        }
-
-        for(const auto& kw_pair : loader) {
-            const auto& keywords = kw_pair.second;
-            for (const auto& kw: keywords)
-                newSource << fmt::format("    const ::Opm::ParserKeyword& get_{0}() {{ return this->{0}; }};\n",kw.className());
+            {
+                newHeader << fmt::format("    const ::Opm::ParserKeyword get_{0}();\n",kw.className());
+                source << fmt::format("const ::Opm::ParserKeyword Builtin::get_{0}() {{ return {0}(); }};\n",kw.className());
+            }
         }
 
-        newSource << R"(
-     const ::Opm::ParserKeyword& operator[](const std::string& keyword) const {
-     if (this->keywords.empty()) {
+        newHeader << R"(
+    const ::Opm::ParserKeyword& operator[](const std::string& keyword) const {
+        if (this->keywords.empty()) {
 )";
+        std::stringstream declareEmplace;
 
         for(const auto& kw_pair : loader) {
             const auto& keywords = kw_pair.second;
+            auto& source = newSources[kw_pair.first];
+            newHeader << fmt::format("            emplace{}(this->keywords);\n", kw_pair.first);
+            source << fmt::format(R"(
+void Builtin::emplace{}([[maybe_unused]] std::unordered_map<std::string, ::Opm::ParserKeyword>& keywords) const {{
+)",
+                                  kw_pair.first);
+            declareEmplace << fmt::format(R"(
+    void emplace{}(std::unordered_map<std::string, ::Opm::ParserKeyword>& keywords) const;
+)",
+                                          kw_pair.first);
+
             for (const auto& kw: keywords)
-                newSource << fmt::format("            this->keywords.emplace(\"{0}\", this->{0});\n", kw.className());
+                source << fmt::format("    keywords.emplace(\"{0}\", {0}());\n", kw.className());
+            source <<"}\n";
+            source <<"} }\n";
         }
 
-     newSource << R"(     }
-     const auto kw_iter = this->keywords.find(keyword);
-     if (kw_iter == this->keywords.end())
-         throw std::invalid_argument(fmt::format("No builtin keyword: {}", keyword));
-     return kw_iter->second;
-}
+        newHeader << R"(        }
+        const auto kw_iter = this->keywords.find(keyword);
+        if (kw_iter == this->keywords.end())
+            throw std::invalid_argument(fmt::format("No builtin keyword: {}", keyword));
+        return kw_iter->second;
+    }
 
-     const ::Opm::ParserKeyword& getKeyword(const std::string& keyword) const { return this->operator[](keyword); }
+    const ::Opm::ParserKeyword& getKeyword(const std::string& keyword) const { return this->operator[](keyword); }
 )";
 
-        newSource << R"(
-private:
-      mutable std::unordered_map<std::string, ::Opm::ParserKeyword> keywords;
+        newHeader << "private:\n";
+        newHeader << declareEmplace.str();
+        newHeader << R"(
+    mutable std::unordered_map<std::string, ::Opm::ParserKeyword> keywords;
 };
 }
 }
@@ -154,7 +173,13 @@ private:
 )";
 
         const auto final_path = headerBuildPath + headerPath+ "/Builtin.hpp";
-        write_file( newSource, final_path, m_verbose, "header" );
+        write_file( newHeader, final_path, m_verbose, "header" );
+        for(auto&& [first_char, source]: newSources)
+        {
+            auto sourceFile = std::filesystem::path(sourcePath) / fmt::format("Builtin{}.cpp",
+                                                                              first_char);
+            write_file(source, sourceFile, m_verbose, fmt::format("builtin source for {}", first_char));
+        }
     }
 
     void KeywordGenerator::updateInitSource(const KeywordLoader& loader , const std::string& sourceFile,
@@ -190,21 +215,18 @@ void addDefaultKeywords{0}(Parser& p);
             std::stringstream sourceStr;
             sourceStr << fmt::format(R"(
 #include <opm/input/eclipse/Parser/Parser.hpp>
-#include <opm/input/eclipse/Parser/ParserKeywords/Builtin.hpp>
 #include<opm/input/eclipse/Parser/ParserKeywords/ParserInit{0}.hpp>
 #include <opm/input/eclipse/Parser/ParserKeywords/{0}.hpp>
 
 namespace Opm {{
 namespace ParserKeywords {{
-void addDefaultKeywords{0}(Parser& p){{
-    Builtin keywords;
+void addDefaultKeywords{0}([[maybe_unused]] Parser& p){{
+    //Builtin keywords;
 )",
                                      first_char);
-            for (const auto& kw_pair : loader) {
                 const auto& keywords = kw_pair.second;
                 for (const auto& kw : keywords)
-                    sourceStr << fmt::format("    p.addParserKeyword( keywords.{} );", kw.className()) << std::endl;
-            }
+                    sourceStr << fmt::format("    p.addParserKeyword( {}() );", kw.className()) << std::endl;
             sourceStr << R"(
 
 }
diff --git a/src/opm/input/eclipse/Parser/createDefaultKeywordList.cpp b/src/opm/input/eclipse/Parser/createDefaultKeywordList.cpp
index 88c8cf1..ec8d73d 100644
--- a/src/opm/input/eclipse/Parser/createDefaultKeywordList.cpp
+++ b/src/opm/input/eclipse/Parser/createDefaultKeywordList.cpp
@@ -60,7 +60,8 @@ int main(int argc, char ** argv) {
     generator.updateKeywordSource(loader , source_file_path );
     generator.updateInitSource(loader , init_file_name , source_file_path );
     generator.updateHeader(loader, header_file_base_path, header_file_path );
-    generator.updateBuiltInHeader(loader, header_file_base_path, header_file_path );
+    generator.updateBuiltInHeader(loader, header_file_base_path, header_file_path,
+                                  source_file_path );
     generator.updateTest( loader , test_file_name );
     if (argc >= 8)
         generator.updatePybindSource(loader , argv[7]);
