scons,python: Always generate default create() methods.

We were originally generating default create() methods along side the
pybind definitions, but unfortunately those are only included when
python support is included. Since the SimObject Param structs are
unconditionally provided even if the thing calling their create()
methods is not, we need to also unconditionally provide the default
create() definitions. We do that by putting them in their own new .cc
files.

Change-Id: I29d1573d578794b3fe7ec2bc16ef5c8c58e56d0e
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/42589
Maintainer: Gabe Black <gabe.black@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Reviewed-by: Earl Ou <shunhsingou@google.com>
diff --git a/src/SConscript b/src/SConscript
index 5fe0ab2..31fce0c 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -917,7 +917,7 @@
 # Create all of the SimObject param headers and enum headers
 #
 
-def createSimObjectParamStruct(target, source, env):
+def createSimObjectParamDecl(target, source, env):
     assert len(target) == 1 and len(source) == 1
 
     name = source[0].get_text_contents()
@@ -927,6 +927,16 @@
     obj.cxx_param_decl(code)
     code.write(target[0].abspath)
 
+def createSimObjectParamDef(target, source, env):
+    assert len(target) == 1 and len(source) == 1
+
+    name = source[0].get_text_contents()
+    obj = sim_objects[name]
+
+    code = code_formatter()
+    obj.cxx_param_def(code)
+    code.write(target[0].abspath)
+
 def createSimObjectCxxConfig(is_header):
     def body(target, source, env):
         assert len(target) == 1 and len(source) == 1
@@ -987,9 +997,16 @@
     hh_file = File('params/%s.hh' % name)
     params_hh_files.append(hh_file)
     env.Command(hh_file, Value(name),
-                MakeAction(createSimObjectParamStruct, Transform("SO PARAM")))
+                MakeAction(createSimObjectParamDecl, Transform("SOPARMHH")))
     env.Depends(hh_file, depends + extra_deps)
 
+    if not getattr(simobj, 'abstract', False) and hasattr(simobj, 'type'):
+        cc_file = File('params/%s.cc' % name)
+        env.Command(cc_file, Value(name),
+                    MakeAction(createSimObjectParamDef, Transform("SOPARMCC")))
+        env.Depends(cc_file, depends + extra_deps)
+        Source(cc_file)
+
 # C++ parameter description files
 if GetOption('with_cxx_config'):
     for name,simobj in sorted(sim_objects.items()):
diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py
index e604a20..bdce718 100644
--- a/src/python/m5/SimObject.py
+++ b/src/python/m5/SimObject.py
@@ -368,7 +368,7 @@
 
     if not is_header:
         code('{')
-        if hasattr(simobj, 'abstract') and simobj.abstract:
+        if getattr(simobj, 'abstract', False):
             code('    return NULL;')
         else:
             code('    return this->create();')
@@ -700,6 +700,80 @@
     def pybind_predecls(cls, code):
         code('#include "${{cls.cxx_header}}"')
 
+    def cxx_param_def(cls, code):
+        code('''
+#include <type_traits>
+
+#include "base/compiler.hh"
+
+#include "${{cls.cxx_header}}"
+#include "params/${cls}.hh"
+
+''')
+        code()
+        code('namespace')
+        code('{')
+        code()
+        # If we can't define a default create() method for this params struct
+        # because the SimObject doesn't have the right constructor, use
+        # template magic to make it so we're actually defining a create method
+        # for this class instead.
+        code('class Dummy${cls}ParamsClass')
+        code('{')
+        code('  public:')
+        code('    ${{cls.cxx_class}} *create() const;')
+        code('};')
+        code()
+        code('template <class CxxClass, class Enable=void>')
+        code('class Dummy${cls}Shunt;')
+        code()
+        # This version directs to the real Params struct and the default
+        # behavior of create if there's an appropriate constructor.
+        code('template <class CxxClass>')
+        code('class Dummy${cls}Shunt<CxxClass, std::enable_if_t<')
+        code('    std::is_constructible<CxxClass,')
+        code('        const ${cls}Params &>::value>>')
+        code('{')
+        code('  public:')
+        code('    using Params = ${cls}Params;')
+        code('    static ${{cls.cxx_class}} *')
+        code('    create(const Params &p)')
+        code('    {')
+        code('        return new CxxClass(p);')
+        code('    }')
+        code('};')
+        code()
+        # This version diverts to the DummyParamsClass and a dummy
+        # implementation of create if the appropriate constructor does not
+        # exist.
+        code('template <class CxxClass>')
+        code('class Dummy${cls}Shunt<CxxClass, std::enable_if_t<')
+        code('    !std::is_constructible<CxxClass,')
+        code('        const ${cls}Params &>::value>>')
+        code('{')
+        code('  public:')
+        code('    using Params = Dummy${cls}ParamsClass;')
+        code('    static ${{cls.cxx_class}} *')
+        code('    create(const Params &p)')
+        code('    {')
+        code('        return nullptr;')
+        code('    }')
+        code('};')
+        code()
+        code('} // anonymous namespace')
+        code()
+        # An implementation of either the real Params struct's create
+        # method, or the Dummy one. Either an implementation is
+        # mandantory since this was shunted off to the dummy class, or
+        # one is optional which will override this weak version.
+        code('M5_VAR_USED ${{cls.cxx_class}} *')
+        code('Dummy${cls}Shunt<${{cls.cxx_class}}>::Params::create() const')
+        code('{')
+        code('    return Dummy${cls}Shunt<${{cls.cxx_class}}>::')
+        code('        create(*this);')
+        code('}')
+
+
     def pybind_decl(cls, code):
         py_class_name = cls.pybind_class
 
@@ -713,9 +787,6 @@
         code('''#include "pybind11/pybind11.h"
 #include "pybind11/stl.h"
 
-#include <type_traits>
-
-#include "base/compiler.hh"
 #include "params/$cls.hh"
 #include "python/pybind11/core.hh"
 #include "sim/init.hh"
@@ -797,76 +868,6 @@
         code()
         code('static EmbeddedPyBind embed_obj("${0}", module_init, "${1}");',
              cls, cls._base.type if cls._base else "")
-        if not hasattr(cls, 'abstract') or not cls.abstract:
-            if 'type' in cls.__dict__:
-                code()
-                # This namespace can't *actually* be anonymous, or the compiler
-                # gets upset about having a weak symbol init.
-                code('namespace anonymous_params')
-                code('{')
-                code()
-                # If we can't define a default create() method for this params
-                # struct because the SimObject doesn't have the right
-                # constructor, use template magic to make it so we're actually
-                # defining a create method for this class instead.
-                code('class Dummy${cls}ParamsClass')
-                code('{')
-                code('  public:')
-                code('    ${{cls.cxx_class}} *create() const;')
-                code('};')
-                code()
-                code('template <class CxxClass, class Enable=void>')
-                code('class DummyShunt;')
-                code()
-                # This version directs to the real Params struct and the
-                # default behavior of create if there's an appropriate
-                # constructor.
-                code('template <class CxxClass>')
-                code('class DummyShunt<CxxClass, std::enable_if_t<')
-                code('    std::is_constructible<CxxClass,')
-                code('        const ${cls}Params &>::value>>')
-                code('{')
-                code('  public:')
-                code('    using Params = ${cls}Params;')
-                code('    static ${{cls.cxx_class}} *')
-                code('    create(const Params &p)')
-                code('    {')
-                code('        return new CxxClass(p);')
-                code('    }')
-                code('};')
-                code()
-                # This version diverts to the DummyParamsClass and a dummy
-                # implementation of create if the appropriate constructor does
-                # not exist.
-                code('template <class CxxClass>')
-                code('class DummyShunt<CxxClass, std::enable_if_t<')
-                code('    !std::is_constructible<CxxClass,')
-                code('        const ${cls}Params &>::value>>')
-                code('{')
-                code('  public:')
-                code('    using Params = Dummy${cls}ParamsClass;')
-                code('    static ${{cls.cxx_class}} *')
-                code('    create(const Params &p)')
-                code('    {')
-                code('        return nullptr;')
-                code('    }')
-                code('};')
-                code()
-                code('} // namespace anonymous_params')
-                code()
-                code('using namespace anonymous_params;')
-                code()
-                # A weak implementation of either the real Params struct's
-                # create method, or the Dummy one if we don't want to have
-                # any default implementation. Either an implementation is
-                # mandantory since this was shunted off to the dummy class, or
-                # one is optional which will override this weak version.
-                code('M5_WEAK ${{cls.cxx_class}} *')
-                code('DummyShunt<${{cls.cxx_class}}>::Params::create() const')
-                code('{')
-                code('    return DummyShunt<${{cls.cxx_class}}>::')
-                code('        create(*this);')
-                code('}')
 
     _warned_about_nested_templates = False