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>
This commit is contained in:
Gabe Black
2021-03-08 22:16:41 -08:00
parent 6572078a99
commit 7bb690c1ee
2 changed files with 94 additions and 76 deletions

View File

@@ -917,7 +917,7 @@ PySource('m5', 'python/m5/info.py')
# 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 @@ def createSimObjectParamStruct(target, source, env):
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 @@ for name,simobj in sorted(sim_objects.items()):
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()):

View File

@@ -368,7 +368,7 @@ def createCxxConfigDirectoryEntryFile(code, name, simobj, is_header):
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 @@ class MetaSimObject(type):
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 @@ class MetaSimObject(type):
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 @@ module_init(py::module_ &m_internal)
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