Files
gem5/ext/systemc/SConscript
Gabe Black 960b9246c5 scons: Convert gem5_scons.Configure to a context manager.
This has two purposes. First, SCons assumes that once you call
Configure, you won't set up the environment the Configure is based on
until after you get the environment back from it again with
conf.Finish(). We get away with this when the cache mode for config
tests is not "force", since Configure just reuses the environment we
pass in, and any changes we make are immediately communicated between
the two.

If the cache mode *is* "force" though, SCons modifies the decider so
that everything the conf environment goes to build looks like it's out
of date. It does that by cloning the original environment, and then
using that clone to do its tests. That causes a problem because we have
a long lived "conf" object and make further changes to main, and since
the two environments are now separate the one in conf doesn't see those
updates.

Second, and more subtly, we export our "main" and "env" environments so
that other SConsopts and SConscript files can use them and define things
in them. The way Configure is designed, if the config caching mode is
"force", then it will create a new environment, and then that
environment will replace what the, for instance, "main" variable points
to when "main = conf.Finish()" is executed.

Unfortunately, if we've already Export()-ed main, we've exported what
the "main" variable pointed to at that time. Our view of "main" will
track with the value that conf.Finish() returned, but since that
construction environment is mearly derived from the main we Exported and
not actually the same thing, they have diverged at that point and will
behave independently.

To solve both of these problems, this change modifies the
gem5_scons.Configure() method so that it's a context manager instead of
a regular function. As before, it will call Configure for us and create
a configuration context, which it will yield as the "with" value. When
the context exits, all the variables in the context Finish() returns
will be shoved back into the original context with Replace(). This isn't
perfect since variables which were deleted in the environment (probably
very rare in practice) will not exist and so will not overwrite the
still existent variable in the original dict.

This has several advantages. The environment never splits into two
copies which continue on independently. It makes the lifetime of a
configuration context short, which is good because behavior during that
time is tricky and unintuitive. It also makes the scope of the context
very clear, so that you won't miss the fact that you're in a special
setting and need to pay attention to what environment you're modifying.

Also, this keeps the conceptual overhead of configuration localized to
where the configuration is happening. In parts of the SConscripts which
are not doing anything with conf, etc, they don't have to modify their
behavior since no configuration context is active.

This change is based on this change from Hanhwi Jang who identified this
problem and proposed an initial solution:

https://gem5-review.googlesource.com/c/public/gem5/+/44265

Change-Id: Iae0a292d6b375c5da98619f31392ca1de6216fcd
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/44389
Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br>
Reviewed-by: Hanhwi Jang <jang.hanhwi@gmail.com>
Maintainer: Bobby R. Bruce <bbruce@ucdavis.edu>
Tested-by: kokoro <noreply+kokoro@google.com>
2021-04-13 01:04:54 +00:00

85 lines
2.9 KiB
Python

# Copyright (c) 2017, TU Dresden
# Copyright (c) 2017, University of Kaiserslautern
# All rights reserved.
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Authors: Christian Menard
# Matthias Jung
import os
from m5.util.terminal import get_termcap
Import('main')
systemc = main.Clone()
build_root = Dir('.').abspath
src_root = Dir('.').srcdir.abspath
systemc.Prepend(CPPPATH=Dir('./src'))
systemc.Prepend(CPATH=Dir('./src'))
systemc.Prepend(CXXFLAGS=['-DSC_INCLUDE_FX'])
systemc.Prepend(CFLAGS=['-DSC_INCLUDE_FX'])
conf = Configure(systemc,
conf_dir = os.path.join(build_root, '.scons_config'),
log_file = os.path.join(build_root, 'scons_config.log'))
systemc = conf.env
if systemc['PLATFORM'] == 'darwin':
systemc.Append(LINKFLAGS=['-undefined', 'dynamic_lookup'])
arch = None
systemc['COROUTINE_LIB'] = ''
if conf.CheckDeclaration('__i386__'):
systemc['COROUTINE_LIB'] = 'qt'
systemc['QT_ARCH'] = 'i386'
arch = 'i386'
elif conf.CheckDeclaration('__x86_64__'):
systemc['COROUTINE_LIB'] = 'qt'
systemc['QT_ARCH'] = 'iX86_64'
arch = 'x86_64'
else:
termcap = get_termcap(GetOption('use_colors'))
print(termcap.Yellow + termcap.Bold +
"Warning: Unrecognized architecture for systemc." + termcap.Normal)
systemc = conf.Finish()
if systemc['COROUTINE_LIB'] == 'pthreads':
systemc.Prepend(CXXFLAGS=['-DSC_USE_PTHREADS'])
systemc_files = []
def SystemCSource(*args):
for arg in args:
systemc_files.append(systemc.File(arg))
if arch:
for root, dirs, files in os.walk(src_root):
if 'SConscript.sc' in files:
build_dir = os.path.relpath(root, src_root)
systemc.SConscript(os.path.join(root, 'SConscript.sc'),
exports=['systemc', 'SystemCSource'],
variant_dir=os.path.join(build_root, build_dir))
systemc.Library('libsystemc', systemc_files)
systemc.SharedLibrary('libsystemc', systemc_files)