Remove all the SCons files pending starting a new build system.

This commit is contained in:
Russel Winder
2009-07-28 14:47:00 +01:00
parent ba1cc0c6bc
commit d40c76de84
25 changed files with 0 additions and 1435 deletions

View File

@@ -1,459 +0,0 @@
#
# Almost enough mechanism to build a toy OS
#
# Copyright (C) 2007 Bahadir Balban
#
import os
import sys
import shutil
from string import split
from os.path import join
from os import sys
import glob
# The root directory of the repository where this file resides:
project_root = os.getcwd()
source_root = os.path.join(project_root, 'src')
headers_root = os.path.join(project_root, 'include')
project_tools_root = os.path.join(project_root, 'tools')
cml2_tools_root = os.path.join(project_tools_root, 'cml2-tools')
config_h = os.path.join(headers_root, "l4/config.h")
# Make sure python modules can be imported from tools and cml-tools
sys.path.append(project_tools_root)
sys.path.append(cml2_tools_root)
import cml2header
import cmlconfigure
# The linker script to link the final executable
linker_script = join(headers_root, 'l4/arch/arm/mylink.lds')
# Environment to build sources
#env = None
###########################################
# #
# ARM kernel build environment #
# #
###########################################
kernel_env = Environment(CC = 'arm-none-eabi-gcc',
# We don't use -nostdinc because sometimes we need standard headers,
# such as stdarg.h e.g. for variable args, as in printk().
CCFLAGS = ['-g', '-mcpu=arm926ej-s', '-nostdlib', '-ffreestanding', \
'-std=gnu99', '-Wall', '-Werror'],
LINKFLAGS = ['-nostdlib', '-T' + linker_script],
ASFLAGS = ['-D__ASSEMBLY__'],
PROGSUFFIX = '.axf', # The suffix to use for final executable
ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path
LIBS = 'gcc', # libgcc.a - This is required for division routines.
CPPPATH = headers_root,
CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h -D__KERNEL__')
#########################################
# #
# TEST BUILDING ENVIRONMENT #
# #
#########################################
# The purpose of test build is somewhat similar to regression/unit
# testing. There are individual tests for each interesting
# function/module (e.g. memory allocator layers). For each individual
# test only the relevant sources' SConscript files are picked up.
# So we don't build a whole kernel, but many little individual tests.
tests_env = Environment(CC = 'gcc -m32',
CCFLAGS = ['-g', '-std=gnu99', '-Wall', '-Werror'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = 'gcc',
CPPPATH = '#include',
CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h -D__KERNEL__')
# Dictionary mappings for configuration symbols to directories of
# sources that relate to those symbols.
arch_to_dir = { 'ARCH_ARM' : 'arm', \
'ARCH_TEST' : 'tests' }
plat_to_dir = { 'ARM_PLATFORM_PB926' : 'pb926', \
'TEST_PLATFORM' : 'tests' }
subarch_to_dir = { 'ARM_SUBARCH_V5' : 'v5', \
'TEST_SUBARCH' : 'tests' }
driver_to_dir = { 'DRIVER_UART_PL011' : 'uart/pl011', \
'DRIVER_TIMER_SP804' : 'timer/sp804', \
'DRIVER_IRQCTRL_PL190' : 'irq/pl190' }
arch_to_env = { 'arm' : kernel_env, \
'tests' : tests_env }
def kprocess_config_symbols(config_symbols):
'''
Checks configuration symbols and discovers the directories with
SConscripts that needs to be compiled for those symbols.
Also derives symbols and adds them to CPPFLAGS.
'''
archdir = None
subarchdir = None
platdir = None
driversdirs = []
for sym in config_symbols:
for arch in arch_to_dir:
if sym == arch:
archdir = arch_to_dir[arch]
env = arch_to_env[arch]
Export('env')
if arch == 'ARCH_TEST':
env.Append(CPPFLAGS = '-DSUBARCH_TEST ')
env.Append(CPPFLAGS = '-DPLATFORM_TEST ')
subarchdir = "tests"
platdir = "tests"
for subarch in subarch_to_dir:
if sym == subarch:
subarchdir = subarch_to_dir[subarch]
for plat in plat_to_dir:
if sym == plat:
platdir = plat_to_dir[plat]
for driver in driver_to_dir:
if sym == driver:
# There can me multiple drivers, so making a list.
driversdirs.append(driver_to_dir[driver])
if archdir == None:
print "Error: No config symbol found for architecture"
sys.exit()
if subarchdir == None:
print "Error: No config symbol found for subarchitecture"
sys.exit()
if platdir == None:
print "Error: No config symbol found for platform"
sys.exit()
# Update config.h with derived values. Unfortunately CML2 does not handle
# derived symbols well yet. This can be fixed in the future.
f = open(config_h, "a")
f.seek(0, 2)
f.write("/* Symbols derived from this file by SConstruct\process_config_symbols() */")
f.write("\n#define __ARCH__\t\t%s\n" % archdir)
f.write("#define __PLATFORM__\t\t%s\n" % platdir)
f.write("#define __SUBARCH__\t\t%s\n\n" % subarchdir)
f.close()
return archdir, subarchdir, platdir, driversdirs
def process_config_symbols(config_symbols):
'''
Checks configuration symbols and discovers the directories with
SConscripts that needs to be compiled for those symbols.
'''
archdir = None
subarchdir = None
platdir = None
driversdirs = []
for sym,val in config_symbols:
if sym == "__ARCH__":
archdir = val
env = arch_to_env[val]
Export('env')
if sym == "__PLATFORM__":
platdir = val
if sym == "__SUBARCH__":
subarchdir = val
for driver in driver_to_dir:
if sym == driver:
# There can me multiple drivers, so making a list.
driversdirs.append(driver_to_dir[driver])
if archdir == None:
print "Error: No config symbol found for architecture"
sys.exit()
if subarchdir == None:
print "Error: No config symbol found for subarchitecture"
sys.exit()
if platdir == None:
print "Error: No config symbol found for platform"
sys.exit()
return archdir, subarchdir, platdir, driversdirs
def gather_config_symbols(header_file):
'''
Gathers configuration symbols from config.h to be used in the build. This
is particularly used for determining what sources to build. Each Sconscript
has the option to select sources to build based on the symbols imported to it.
'''
if not os.path.exists(header_file):
print "\n\%s does not exist. "\
"Please run: `scons configure' first\n\n" % header_file
sys.exit()
f = open(header_file)
config_symbols = []
while True:
line = f.readline()
if line == "":
break
str_parts = split(line)
if len(str_parts) > 0:
if str_parts[0] == "#define":
config_symbols.append((str_parts[1], str_parts[2]))
f.close()
Export('config_symbols')
return config_symbols
def gather_sconscripts(config_symbols):
"Gather all SConscripts to be compiled depending on configuration symbols"
arch, subarch, plat, drivers = process_config_symbols(config_symbols)
dirpath = []
allpaths = []
# Paths for the SConscripts: sc_<path> etc. glob.glob is useful in that
# it returns `None' for non-existing paths.
sc_generic = glob.glob("src/generic/SConscript")
sc_api = glob.glob("src/api/SConscript")
sc_lib = glob.glob("src/lib/SConscript")
sc_platform = glob.glob("src/platform/" + plat + "/SConscript")
sc_arch = glob.glob("src/arch/" + arch + "/SConscript")
sc_glue = glob.glob("src/glue/" + arch + "/SConscript")
sc_subarch = glob.glob("src/arch/" + arch + "/" + subarch + "/SConscript")
sc_drivers = []
for driver in drivers:
sc_drivers.append("src/drivers/" + driver + "/SConscript")
#print "\nSConscripts collected for this build:"
for dirpath in [sc_generic, sc_api, sc_lib, sc_platform, sc_arch, sc_subarch, sc_glue]:
for path in dirpath:
# print path
allpaths.append(join(os.getcwd(), path[:-11]))
for drvpath in sc_drivers:
allpaths.append(join(os.getcwd(), drvpath[:-11]))
return allpaths
def gather_kernel_build_paths(scons_script_path_list):
'''
Takes the list of all SConscript files, and returns the list of
corresponding build directories for each SConscript file.
'''
build_path_list = []
for path in scons_script_path_list:
build_path_list.append('build' + path)
return build_path_list
def declare_kernel_build_paths(script_paths):
'''
Gathers all SConscript files and their corresponding
distinct build directories. Declares the association
to the scons build system.
'''
# Get all the script and corresponding build paths
build_paths = gather_kernel_build_paths(script_paths)
script_paths.sort()
build_paths.sort()
# Declare build paths
for script_path, build_path in zip(script_paths, build_paths):
# print "Sources in " + script_path + " will be built in: " + build_path
BuildDir(build_path, script_path)
return build_paths
def build_and_gather(bpath_list):
'''
Given a SConscript build path list, declares all
SConscript files and builds them, gathers and
returns the resulting object files.
'''
obj_list = []
for path in bpath_list:
# print "Building files in: " + path
o = SConscript(path + '/' + 'SConscript')
obj_list.append(o)
return obj_list
def determine_target(config_symbols):
if "ARCH_TEST" in config_symbols:
target = "tests"
else:
target = "kernel"
return target
def build_kernel_objs(config_symbols):
"Builds the final kernel executable."
# Declare builddir <--> SConscript association
script_paths = gather_sconscripts(config_symbols)
build_paths = declare_kernel_build_paths(script_paths)
# Declare Sconscript files, build and gather objects.
objs = build_and_gather(build_paths)
return objs
#################################################################
# Kernel and Test Targets #
# Executes python functions and compiles the kernel. #
#################################################################
# Unfortunately the build system is imperative rather than declarative,
# and this is the entry point. This inconvenience is due to the fact that
# it is not easily possible in SCons to produce a target list dynamically,
# which, is generated by the `configure' target.
if "build" in COMMAND_LINE_TARGETS:
config_symbols = gather_config_symbols(config_h)
target = determine_target(config_symbols)
if target == "kernel":
built_objs = build_kernel_objs(config_symbols)
kernel_target = kernel_env.Program('build/start', built_objs)
kernel_env.Alias('build', kernel_target)
elif target == "tests":
built_objs = build_kernel_objs(config_symbols)
tests_target = tests_env.Program('build/tests', built_objs)
tests_env.Alias('build', tests_target)
else:
print "Invalid or unknown target.\n"
#################################################################
# The Configuration Targets: #
# Executes python functions/commands to configure the kernel. #
#################################################################
# Configuration Build Details: #
# ---------------------------- #
# 1) Compiles the ruleset for given architecture/platform. #
# 2) Invokes the CML2 kernel configurator using the given #
# ruleset. #
# 3) Configurator output is translated into a header file. #
# #
# For more information on this see the cml2 manual. Recap: #
# The cml file defines the rules (i.e. option a and b #
# implies c etc.) The compiler converts it to a pickled #
# form. The configurator reads it and brings up a UI menu. #
# Saving the selections results in a configuration file, #
# which in turn is converted to a header file includable #
# by the C sources. #
#################################################################
def cml_configure(target, source, env):
default_target = 'config.out'
default_source = 'rules.out'
target = str(target[0])
source = str(source[0])
# Strangely, cmlconfigure.py's command line option parsing is fairly broken
# if you specify an input or output file a combination of things can happen,
# so we supply no options, and move the defaults ifile= ./rules.out
# ofile=./config.out around to match with supplied target/source arguments.
# Move source to where cmlconfigure.py expects to find it.
print "Moving", source, "to", default_source
shutil.move(source, default_source)
cml2_configure_cmd = cml2_tools_root + '/cmlconfigure.py -c'
os.system(cml2_configure_cmd)
# Move target file to where the build system expects to find it.
print "Moving", default_target, "to", target
shutil.move(default_target, target)
print "Moving", default_source, "back to", source
shutil.move(default_source, source)
return None
def cml_compile(target, source, env):
# Same here, this always produces a default file.
default_target = "rules.out"
target = str(target[0])
source = str(source[0])
cml2_compile_cmd = cml2_tools_root + '/cmlcompile.py < ' + source + ' > ' + target
os.system(cml2_compile_cmd)
print "Moving " + default_target + " to " + target
shutil.move(default_target, target)
return None
def derive_symbols(config_header):
'''
Reads target header (config.h), derives symbols, and appends them to the same file.
Normally CML2 should do this on-the-fly but, doesn't so this function explicitly
does it here.
'''
archdir = None
subarchdir = None
platdir = None
driversdirs = []
config_symbols = gather_config_symbols(config_header)
for sym,val in config_symbols:
for arch in arch_to_dir:
if sym == arch:
archdir = arch_to_dir[arch]
if arch == "ARCH_TEST":
# These are derived from ARCH_TEST, but don't need to be written,
# because they are unused. Instead, __ARCH__ test etc. are derived
# from these and written to config.h because those are used by the
# build system. IOW these are transitional symbols.
config_symbols.append(("TEST_SUBARCH","1"))
config_symbols.append(("TEST_PLATFORM","1"))
for subarch in subarch_to_dir:
if sym == subarch:
subarchdir = subarch_to_dir[subarch]
for plat in plat_to_dir:
if sym == plat:
platdir = plat_to_dir[plat]
for driver in driver_to_dir:
if sym == driver:
# There can me multiple drivers, so making a list.
driversdirs.append(driver_to_dir[driver])
if archdir == None:
print "Error: No config symbol found for architecture"
sys.exit()
if subarchdir == None:
print "Error: No config symbol found for subarchitecture"
sys.exit()
if platdir == None:
print "Error: No config symbol found for platform"
sys.exit()
# Update config.h with derived values. Unfortunately CML2 does not handle
# derived symbols well yet. This can be fixed in the future.
f = open(config_h, "a")
f.seek(0, 2)
f.write("/* Symbols derived from this file by SConstruct\derive_symbols() */")
f.write("\n#define __ARCH__\t\t%s\n" % archdir)
f.write("#define __PLATFORM__\t\t%s\n" % platdir)
f.write("#define __SUBARCH__\t\t%s\n\n" % subarchdir)
f.close()
def cml_config2header(target, source, env):
'''
Translate the output of cml2 configurator to a C header file,
to be included by the kernel.
'''
target = str(target[0])
source = str(source[0])
config_translator = cml2header.cml2header_translator()
if config_translator.translate(source, target) < 0:
print 'Configuration translation failed.'
##
## CML2 is incapable of deriving symbols. Hence, derived
## symbols are handled here.
derive_symbols(target)
# `hash' ('#') is a shorthand meaning `relative to
# the root directory'. But this only works for
# well-defined variables, not all paths, and only
# if we use a relative build directory for sources.
# Individual Build commands for configuration targets
cml_compiled_target = kernel_env.Command('#build/rules.out', '#configs/arm.cml', cml_compile)
cml_configured_target = kernel_env.Command('#build/config.out', '#build/rules.out', cml_configure)
cml_translated_target = kernel_env.Command(config_h, '#build/config.out', cml_config2header)
if "configure" in COMMAND_LINE_TARGETS:
# This ensures each time `scons configure' is typed, a configuration occurs.
# Otherwise the build system would think target is up-to-date and do nothing.
kernel_env.AlwaysBuild(cml_compiled_target)
kernel_env.AlwaysBuild(cml_configured_target)
kernel_env.AlwaysBuild(cml_translated_target)
# Commandline aliases for each individual configuration targets
kernel_env.Alias('cmlcompile', cml_compiled_target)
kernel_env.Alias('cmlconfigure', cml_configured_target)
kernel_env.Alias('cmltranslate', cml_translated_target)
# Below alias is enough to trigger all config dependency tree.
kernel_env.Alias('configure', cml_translated_target)

View File

@@ -1,76 +0,0 @@
Import("*")
import os
import glob
from os.path import join
arch = "arm"
platform = "pb926"
variant1 = "userspace"
variant2 = "baremetal"
builddir_var1 = join("build", variant1)
builddir_var2 = join("build", variant2)
crt0bdir_var1 = join("build", "crt")
crt0bdir_var2 = join("build", "crt")
BuildDir(builddir_var1, "src")
BuildDir(builddir_var2, "src")
BuildDir(crt0bdir_var1, "crt")
BuildDir(crt0bdir_var2, "crt")
headers_var1 = ["#include", "#include/sys-%s/arch-%s" % (variant1, arch)]
headers_var2 = ["#include", "#include/sys-%s/arch-%s" % (variant2, arch)]
env_var1 = Environment(CC = 'arm-none-linux-gnueabi-gcc',
CCFLAGS = ['-g', '-nostdinc', '-nostdlib', '-ffreestanding'],
LINKFLAGS = ['-nostdlib'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = 'gcc',
CPPPATH = headers_var1)
env_var2 = Environment(CC = 'arm-none-linux-gnueabi-gcc',
CCFLAGS = ['-g', '-nostdinc', '-nostdlib', '-ffreestanding'],
LINKFLAGS = ['-nostdlib'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = 'gcc',
CPPPATH = headers_var2)
def src_glob(src_base, src_paths, builddir):
"""Src glob is used to find source files easily e.g: src_glob("src/*.c"),
the reason we can't just use glob is due to the way SCons handles out
of directory builds."""
search = os.path.join(src_base, src_paths)
dir = os.path.dirname(search)
if dir != "":
dir = dir + os.sep
src_path = Dir('.').srcnode().abspath
files = glob.glob(src_path + os.sep + search)
files = map(os.path.basename, files)
ret_files = []
for file in files:
ret_files.append(builddir + dir[len(src_base):] + file)
return ret_files
src_var1 = src_glob("src", "*.c", builddir_var1) + \
src_glob("src", "sys-%s/*.c" % variant1, builddir_var1) + \
src_glob("src", "sys-%s/arch-%s/*.c" % (variant1, arch), builddir_var1) + \
src_glob("src", "sys-%s/arch-%s/plat-%s/*.c" % (variant1, arch, platform), builddir_var1) + \
src_glob("src", "arch-%s/*.S" % arch, builddir_var1) + \
src_glob("src", "arch-%s/*.c" % arch, builddir_var1)
src_var2 = src_glob("src", "*.c", builddir_var2) + \
src_glob("src", "sys-%s/*.c" % variant2, builddir_var2) + \
src_glob("src", "sys-%s/arch-%s/*.c" % (variant2, arch), builddir_var2) + \
src_glob("src", "sys-%s/arch-%s/plat-%s/*.c" % (variant2, arch, platform), builddir_var2) + \
src_glob("src", "arch-%s/*.S" % arch, builddir_var2) + \
src_glob("src", "arch-%s/*.c" % arch, builddir_var2)
crt_var1 = env_var1.StaticObject(src_glob("crt", \
"sys-%s/arch-%s/crt0.S" % (variant1, arch), crt0bdir_var1), ASFLAGS=env_var1["CCFLAGS"])
crt_var2 = env_var2.StaticObject(src_glob("crt", \
"sys-%s/arch-%s/crt0.S" % (variant2, arch), crt0bdir_var2), ASFLAGS=env_var2["CCFLAGS"])
libc_var1 = env_var1.StaticLibrary(join("build",variant1) + "/c-" + variant1, src_var1)
libc_var2 = env_var2.StaticLibrary(join("build",variant2) + "/c-" + variant2, src_var2)

View File

@@ -1,42 +0,0 @@
Import("*")
import os
import glob
libs = ["gcc"]
arch = 'arm'
# C library information
clibvariant = "baremetal"
clibroot = os.getcwd() + '/../c'
clibpath = os.getcwd() + clibroot + '/build/' + clibvariant
cincpath = [clibroot + '/include', clibroot + '/include/arch/%s' % arch]
env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
CCFLAGS = ['-g', '-nostdinc', '-nostdlib', '-ffreestanding'],
LINKFLAGS = ['-nostdlib'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = ['gcc','c-' + clibvariant],
LIBPATH = clibpath,
CPPPATH = ['#include'] + cincpath)
def src_glob(search):
"""Src glob is used to find source files easily e.g: src_glob("src/*.c"),
the reason we can't just use glob is due to the way SCons handles out
of directory builds."""
dir = os.path.dirname(search)
if dir != "":
dir = dir + os.sep
src_path = Dir('.').srcnode().abspath
files = glob.glob(src_path + os.sep + search)
files = map(os.path.basename, files)
ret_files = []
for file in files:
ret_files.append(dir + file)
return ret_files
src = src_glob("src/*.c")
libelf = env.StaticLibrary('elf', src)

View File

@@ -1,51 +0,0 @@
Import("*")
import os
import glob
from os.path import join
arch = 'arm'
clibvariant = 'baremetal'
# C library information
clibroot = join(os.getcwd(), '../libs/c')
clibpath = join(join(clibroot, 'build'), clibvariant)
cincpath = [join(clibroot, 'include'), join(clibroot,'include/arch/%s' % arch)]
crt0objpath = join(clibroot, 'build/crt/sys-%s/arch-%s/crt0.o' % (clibvariant, arch))
clibname = "c-" + clibvariant
# Elf library information
elflibpath = os.getcwd() + '/../libs/elf'
elfincpath = [elflibpath + '/include']
env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding'],
LINKFLAGS = ['-nostdlib', '-Tmylink.lds'],
ENV = {'PATH' : os.environ['PATH']},
PROGSUFFIX = '.axf',
LIBS = ['elf', clibname, 'gcc', clibname], # Note there's a dependency order here.
# Left libs depend on libs on their right.
CPPPATH = ['#'] + cincpath + elfincpath)
env.Append(LIBPATH = [clibpath, elflibpath])
def src_glob(search):
"""Src glob is used to find source files easily e.g: src_glob("src/*.c"),
the reason we can't just use glob is due to the way SCons handles out
of directory builds."""
dir = os.path.dirname(search)
if dir != "":
dir = dir + os.sep
src_path = Dir('.').srcnode().abspath
files = glob.glob(src_path + os.sep + search)
files = map(os.path.basename, files)
ret_files = []
for file in files:
ret_files.append(dir + file)
return ret_files
src = src_glob("*.c")
src += src_glob("*.S")
obj_list = env.Object(src)
loader = env.Program("final", obj_list + [crt0objpath])

View File

@@ -1,10 +0,0 @@
# Inherit global environment
Import('env')
Import('config_symbols')
# The set of source files associated with this SConscript file.
src_local = ['kip.c', 'syscall.c', 'thread.c', 'ipc.c', 'space.c', 'mutex.c']
obj = env.Object(src_local)
Return('obj')

View File

@@ -1,10 +0,0 @@
# Inherit global environment
Import('env')
# The set of source files associated with this SConscript file.
src_local = ['head.S', 'vectors.S', 'syscall.S', 'exception.c', 'bootdesc.c']
obj = env.Object(src_local)
Return('obj')

View File

@@ -1,10 +0,0 @@
# Inherit global environment
Import('env')
# The set of source files associated with this SConscript file.
src_local = ['mm.c', 'mmu_ops.S', 'mutex.S']
obj = env.Object(src_local)
Return('obj')

View File

@@ -1,9 +0,0 @@
# Inherit global environment
Import('env')
# The set of source files associated with this SConscript file.
src_local = ['linker.c']
obj = env.Object(src_local)
Return('obj')

View File

@@ -1,10 +0,0 @@
# Inherit global environment
Import('env')
# The set of source files associated with this SConscript file.
src_local = ['pl190_vic.c']
obj = env.Object(src_local)
Return('obj')

View File

@@ -1,10 +0,0 @@
# Inherit global environment
Import('env')
# The set of source files associated with this SConscript file.
src_local = ['sp804_timer.c']
obj = env.Object(src_local)
Return('obj')

View File

@@ -1,10 +0,0 @@
# Inherit global environment
Import('env')
# The set of source files associated with this SConscript file.
src_local = ['pl011_uart.c']
obj = env.Object(src_local)
Return('obj')

View File

@@ -1,10 +0,0 @@
# Inherit global environment
Import('env')
# The set of source files associated with this SConscript file.
src_local = ['physmem.c', 'irq.c', 'scheduler.c', 'time.c', 'tcb.c', 'pgalloc.c', 'kmalloc.c', 'space.c']
obj = env.Object(src_local)
Return('obj')

View File

@@ -1,10 +0,0 @@
# Inherit global environment
Import('env')
# The set of source files associated with this SConscript file.
src_local = ['init.c', 'memory.c', 'systable.c']
obj = env.Object(src_local)
Return('obj')

View File

@@ -1,9 +0,0 @@
# Inherit global environment
Import('env')
# The set of source files associated with this SConscript file.
src_local = ['main.c', 'test_kmalloc.c', 'test_memcache.c', 'test_allocpage.c', 'test_alloc_generic.c', 'debug.c', 'memory.c', 'clz.c']
obj = env.Object(src_local)
Return('obj')

View File

@@ -1,12 +0,0 @@
# Inherit global environment
Import('env')
Import('config_symbols')
# The set of source files associated with this SConscript file.
src_local = ['printk.c', 'putc.c', 'string.c', 'bit.c', 'wait.c', 'mutex.c', 'idpool.c', 'memcache.c']
if "ARCH_TEST" not in config_symbols:
obj = env.Object(src_local)
else:
obj = []
Return('obj')

View File

@@ -1,10 +0,0 @@
# Inherit global environment
Import('env')
# The set of source files associated with this SConscript file.
src_local = ['printascii.S','platform.c', 'uart.c', 'timer.c', 'irq.c']
obj = env.Object(src_local)
Return('obj')

View File

@@ -1,10 +0,0 @@
# Inherit global environment
Import('env')
# The set of source files associated with this SConscript file.
src_local = ['offsets.c']
obj = env.Object(src_local)
Return('obj')

View File

@@ -1,123 +0,0 @@
#
# Build script to autogenerate a bootdesc image
#
# Copyright (C) 2007 Bahadir Balban
#
import os
import sys
import shutil
from os.path import join
# The root directory of the repository where this file resides:
project_root = "../.."
tools_root = "../../tools"
kernel = join(project_root, "build/start.axf")
mm0 = join(project_root, "tasks/mm0/mm0.axf")
fs0 = join(project_root, "tasks/fs0/fs0.axf")
test0 = join(project_root, "tasks/test0/test0.axf")
#test1 = join(project_root, "tasks/test1/test1.axf")
#blkdev0 = join(project_root, "tasks/fsbin/blkdev0.axf")
images = [kernel, mm0, fs0, test0]
autogen_templ = "bootdesc.c.append"
def get_image_name_start_end(image, target):
'''
Using readelf.py utility, extracts name, start, end triplet from an arm-elf image.
'''
rest, name = os.path.split(image)
if name[-4] == ".":
name = name[:-4]
os.system(join(tools_root, "pyelf/readelf.py --lma-start-end " + \
image + " > " + target))
bootdesc_template = \
'''
struct bootdesc bootdesc = {
.desc_size = sizeof(struct bootdesc) + sizeof(struct svc_image) * %s,
.total_images = %s,
.images = {
%s
},
};
'''
images_template = \
''' [%s] = {
.name = "%s",
.phys_start = %s,
.phys_end = %s,
},
'''
images_template_end = \
'''
},
'''
def generate_bootdesc(source, target, env):
'''
Extracts name, start, end information from the kernel and each svc task.
Uses this information to produce bootdesc.c
'''
source.sort()
images = []
images_string = ""
for node in source:
if str(node)[-4:] == ".axf":
rest, imgname = os.path.split(str(node))
images.append((str(node), imgname[:-4]))
elif str(node) [-6:] == ".templ":
# Static template that has type definitions.
#rest, original_template = os.path.split(str(node))
original_template = str(node)
index = 0
for imgpath, imgname in images:
get_image_name_start_end(imgpath, imgname + ".txt")
if imgname != "start":
f = open(imgname + ".txt", "r")
svc_name = f.readline()[:-1]
[start, startval] = str.split(f.readline()[:-1])
[end, endval] = str.split(f.readline()[:-1])
f.close()
images_string += images_template % (str(index), svc_name, \
hex(int(startval, 16)), hex(int(endval, 16)))
index += 1
# Autogenerated template with actual data.
autogen_template = open(autogen_templ, "w+")
autogen_template.write(bootdesc_template % (str(index), str(index), images_string))
autogen_template.close()
os.system("cat " + original_template + " > " + str(target[0]))
os.system("cat " + autogen_templ + " >> " + str(target[0]))
def relocate_bootdesc(source, target, env):
f = open("start.txt", "r")
kernel_name = f.readline()[:-1]
[start, startval] = str.split(f.readline()[:-1])
[end, endval] = str.split(f.readline()[:-1])
os.system("arm-none-linux-gnueabi-objcopy --adjust-section-vma .data=" + \
hex(int(endval,16)) + " " + str(source[0]))
os.system("mv " + str(source[0]) + " " + str(target[0]))
# The kernel build environment:
env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
# We don't use -nostdinc because sometimes we need standard headers,
# such as stdarg.h e.g. for variable args, as in printk().
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', '-Werror'],
LINKFLAGS = ['-nostdlib','-Tlinker.lds'],
ASFLAGS = ['-D__ASSEMBLY__'],
PROGSUFFIX = '.axf', # The suffix to use for final executable
ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path
LIBS = 'gcc', # libgcc.a - This is required for division routines.
CPPPATH = '#include') # `hash' ('#') is a shorthand meaning `relative to
# the root directory'. But this only works for
# well-defined variables, not all paths, and only
# if we use a relative build directory for sources.
bootdesc_src = env.Command("bootdesc.c", ["bootdesc.c.templ"] + images, generate_bootdesc)
objs = env.Object('bootdesc.c')
bootdesc = env.Program('bootdesc_data', objs)
bootdesc_relocated = env.Command("bootdesc.axf", "bootdesc_data.axf", relocate_bootdesc)
env.Depends(bootdesc_relocated, bootdesc)

View File

@@ -1,75 +0,0 @@
#
# User space application build script
#
# Copyright (C) 2007 Bahadir Balban
#
import os
import sys
import shutil
from os.path import join
from glob import glob
task_name = "fs0"
# The root directory of the repository where this file resides:
project_root = "../.."
tools_root = join(project_root, "tools")
prev_image = join(project_root, "tasks/mm0/mm0.axf")
libs_path = join(project_root, "libs")
ld_script = "include/linker.lds"
physical_base_ld_script = "include/physical_base.lds"
# libc paths:
libc_variant = "userspace"
libc_libpath = join(libs_path, "c/build/%s" % libc_variant)
libc_incpath = join(libc_libpath, "include")
libc_crt0 = join(libs_path, "c/build/crt/sys-userspace/arch-arm/crt0.o")
libc_name = "c-%s" % libc_variant
#libmem paths:
libmem_path = "../libmem"
libmem_incpath = "../libmem"
# libl4 paths:
libl4_path = "../libl4"
libl4_incpath1 = join(libl4_path, "include")
# libposix paths:
libposix_path = "../libposix"
libposix_incpath = join(libposix_path, "include")
# kernel paths:
kernel_incpath = join(project_root, "include")
# If crt0 is in its library path, it becomes hard to link with it.
# For instance the linker script must use an absolute path for it.
def copy_crt0(source, target, env):
os.system("cp " + str(source[0]) + " " + str(target[0]))
def get_physical_base(source, target, env):
os.system(join(tools_root, "pyelf/readelf.py --first-free-page " + \
prev_image + " >> " + physical_base_ld_script))
# The kernel build environment:
env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
# We don't use -nostdinc because sometimes we need standard headers,
# such as stdarg.h e.g. for variable args, as in printk().
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', '-Werror'],
LINKFLAGS = ['-nostdlib', '-T' + ld_script, "-L" + libc_libpath, "-L" + libl4_path,\
"-L" + libmem_path, "-L" + libposix_path],
ASFLAGS = ['-D__ASSEMBLY__'],
PROGSUFFIX = '.axf', # The suffix to use for final executable
ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path
LIBS = [libc_name, 'gcc', 'libmc', 'libl4', 'gcc', libc_name, "posix"],
CPPFLAGS = "-D__USERSPACE__",
CPPPATH = ['#include', libl4_incpath1, kernel_incpath, libc_incpath, \
libposix_incpath, libmem_incpath])
src = [glob("src/*.c"), glob("*.c"), glob("src/arch/arm/*.c"), glob("src/memfs/*.c"), glob("src/lib/*.c")]
objs = env.Object(src)
physical_base = env.Command(physical_base_ld_script, prev_image, get_physical_base)
crt0_copied = env.Command("crt0.o", libc_crt0, copy_crt0)
task = env.Program(task_name, objs + [crt0_copied])
env.Alias(task_name, task)
env.Depends(task, physical_base)

View File

@@ -1,84 +0,0 @@
#
# Copyright (C) 2007 Bahadir Balban
#
import os
import glob
import sys
from os.path import join
from string import split
# libposix paths:
libposix_libpath = "../libposix"
libposix_incpath = "../libposix/include/posix"
project_root = "../.."
kernel_headers = join(project_root, "include")
config_h = join(project_root, "include/l4/config.h")
env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding'],
LINKFLAGS = ['-nostdlib'],
ASFLAGS = ['-D__ASSEMBLY__'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = 'gcc',
CPPPATH = ['#include', libposix_incpath])
def extract_arch_subarch_plat(config_header):
'''
From the autogenerated kernel config.h, extracts platform, archictecture,
subarchitecture information. This is used to include the relevant headers
from the kernel directories.
'''
arch = None
subarch = None
plat = None
if not os.path.exists(config_header):
print "\n\nconfig.h does not exist. "\
"Please run: `scons configure' first\n\n"
sys.exit()
f = open(config_h, "r")
while True:
line = f.readline()
if line == "":
break
parts = split(line)
if len(parts) > 0:
if parts[0] == "#define":
if parts[1] == "__ARCH__":
arch = parts[2]
elif parts[1] == "__PLATFORM__":
plat = parts[2]
elif parts[1] == "__SUBARCH__":
subarch = parts[2]
f.close()
if arch == None:
print "Error: No config symbol found for architecture"
sys.exit()
if subarch == None:
print "Error: No config symbol found for subarchitecture"
sys.exit()
if plat == None:
print "Error: No config symbol found for platform"
sys.exit()
return arch, subarch, plat
def create_symlinks(arch):
if not os.path.exists("include/l4lib/arch"):
os.system("ln -s %s %s" % ("arch-" + arch, "include/l4lib/arch"))
arch, subarch, plat = extract_arch_subarch_plat(config_h)
create_symlinks(arch) # Creates symlinks to architecture specific directories.
headers = ["#include", "#include/libl4/arch", kernel_headers]
env.Append(CPPPATH = headers)
src = glob.glob("src/*.c") + glob.glob("src/%s/*.[cS]" % arch)
libl4 = env.StaticLibrary('l4', src)

View File

@@ -1,67 +0,0 @@
#
# Copyright (C) 2007 Bahadir Balban
#
import os
import glob
import sys
from os.path import join
from string import split
project_root = "../.."
headers_root = join(project_root, "include/l4")
config_h = join(headers_root, "config.h")
#libl4 paths
libl4_headers = join(project_root, "tasks/libl4/include")
libl4_libpath = join(project_root, "tasks/libl4")
mm = "mm"
kmalloc = "kmalloc"
memcache = "memcache"
tests = "tests"
mm_dir = mm
kmalloc_dir = kmalloc
memcache_dir = memcache
tests_dir = tests
test_env = Environment(CC = 'gcc -m32',
CCFLAGS = ['-g', '-std=gnu99', '-Wall', '-Werror'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = ['gcc', 'mm', 'km', 'mc'],
LIBPATH = ['#'],
CPPPATH = ['#include', join(project_root, "include"), "#", libl4_headers])
env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
CCFLAGS = ['-g', '-nostdlib', '-Wall', '-Werror', '-ffreestanding', '-std=gnu99'],
LINKFLAGS = ['-nostdlib'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = 'gcc',
CPPPATH = [join(project_root, "include"), "#", libl4_headers])
if os.path.exists(config_h) is False:
print "\nThis build requires a valid kernel configuration header."
print "Please run `scons configure' in the kernel root directory."
print "Choose the `tests' target to build memory allocator tests,"
print "or any other target for real use.\n"
sys.exit()
mm_src = glob.glob("%s/*.c" % mm_dir)
kmalloc_src = glob.glob("%s/*.c" % kmalloc_dir)
memcache_src = glob.glob("%s/*.c" % memcache_dir)
tests_src = glob.glob ("%s/*.c" % tests_dir)
if "tests" in COMMAND_LINE_TARGETS:
print "WARNING!!! Did you configure the kernel with test target first???"
libmm = test_env.StaticLibrary(mm, mm_src)
libkmalloc = test_env.StaticLibrary("km", kmalloc_src)
libmemcache = test_env.StaticLibrary("mc", memcache_src)
test_prog = test_env.Program("test", tests_src)
env.Alias("tests", test_prog)
else:
libmm = env.StaticLibrary(mm, mm_src)
libkmalloc = env.StaticLibrary("km", kmalloc_src)
libmemcache = env.StaticLibrary("mc", memcache_src)

View File

@@ -1,9 +0,0 @@
# Inherit global environment
Import('env')
# The set of source files associated with this SConscript file.
src_local = ['main.c', 'test_kmalloc.c', 'test_memcache.c', 'test_allocpage.c', 'test_alloc_generic.c', 'debug.c', 'memory.c', 'clz.c']
obj = env.Object(src_local)
Return('obj')

View File

@@ -1,74 +0,0 @@
#
# Copyright (C) 2007 Bahadir Balban
#
import os
import glob
import sys
from os.path import join
from string import split
project_root = "../.."
kernel_headers = join(project_root, "include")
l4lib_headers = join(project_root, "tasks/libl4/include")
config_h = join(project_root, "include/l4/config.h")
env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
CCFLAGS = ['-g', '-std=gnu99', '-nostdlib', '-ffreestanding'],
LINKFLAGS = ['-nostdlib'],
CPPPATH = ['#include'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = 'gcc')
def extract_arch_subarch_plat(config_header):
'''
From the autogenerated kernel config.h, extracts platform, archictecture,
subarchitecture information. This is used to include the relevant headers
from the kernel directories.
'''
arch = None
subarch = None
plat = None
if not os.path.exists(config_header):
print "\n\nconfig.h does not exist. "\
"Please run: `scons configure' first\n\n"
sys.exit()
f = open(config_h, "r")
while True:
line = f.readline()
if line == "":
break
parts = split(line)
if len(parts) > 0:
if parts[0] == "#define":
if parts[1] == "__ARCH__":
arch = parts[2]
elif parts[1] == "__PLATFORM__":
plat = parts[2]
elif parts[1] == "__SUBARCH__":
subarch = parts[2]
f.close()
if arch == None:
print "Error: No config symbol found for architecture"
sys.exit()
if subarch == None:
print "Error: No config symbol found for subarchitecture"
sys.exit()
if plat == None:
print "Error: No config symbol found for platform"
sys.exit()
return arch, subarch, plat
arch, subarch, plat = extract_arch_subarch_plat(config_h)
headers = ["#include/posix", l4lib_headers, kernel_headers]
env.Append(CPPPATH = headers)
src = glob.glob("src/*.c") + glob.glob("*.c")
libposix = env.StaticLibrary('posix', src)

View File

@@ -1,136 +0,0 @@
#
# User space application build script
#
# Copyright (C) 2007 Bahadir Balban
#
import os
import sys
import shutil
from string import split
from os.path import join
from glob import glob
task_name = "mm0"
# The root directory of the repository where this file resides:
project_root = "../.."
tools_root = join(project_root, "tools")
prev_image = join(project_root, "build/start.axf")
libs_path = join(project_root, "libs")
ld_script = "include/linker.lds"
physical_base_ld_script = "include/physical_base.lds"
# libc paths:
libc_variant = "userspace"
libc_libpath = join(libs_path, "c/build/%s" % libc_variant)
libc_incpath = join(libc_libpath, "include")
libc_crt0 = join(libs_path, "c/build/crt/sys-userspace/arch-arm/crt0.o")
libc_name = "c-%s" % libc_variant
# libl4 paths:
libl4_path = "../libl4"
libl4_incpath = join(libl4_path, "include")
# libposix paths:
libposix_path = "../libposix"
libposix_incpath = join(libposix_path, "include")
#libmem paths:
libmem_path = "../libmem"
libmem_incpath = "../libmem"
# kernel paths:
kernel_incpath = join(project_root, "include")
# Kernel config header.
config_h = join(project_root, "include/l4/config.h")
# If crt0 is in its library path, it becomes hard to link with it.
# For instance the linker script must use an absolute path for it.
def copy_crt0(source, target, env):
os.system("cp " + str(source[0]) + " " + str(target[0]))
def get_physical_base(source, target, env):
os.system(join(tools_root, "pyelf/readelf.py --first-free-page " + \
prev_image +" >> " + physical_base_ld_script))
# The kernel build environment:
env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
# We don't use -nostdinc because sometimes we need standard headers,
# such as stdarg.h e.g. for variable args, as in printk().
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', '-Werror' ],
LINKFLAGS = ['-nostdlib', '-T' + ld_script, "-L" + libc_libpath, "-L" + libl4_path, \
"-L" + libposix_path, "-L" + libmem_path],
ASFLAGS = ['-D__ASSEMBLY__'],
PROGSUFFIX = '.axf', # The suffix to use for final executable
ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path
LIBS = [libc_name, 'libl4', 'libmm', 'libmc', 'libkm', 'libposix', \
'gcc', libc_name], # libgcc.a - This is required for division routines.
CPPFLAGS = "-D__USERSPACE__",
CPPPATH = ['#include', libl4_incpath, libc_incpath, kernel_incpath, \
libmem_incpath, libposix_incpath])
def extract_arch_subarch_plat(config_header):
'''
From the autogenerated kernel config.h, extracts platform, archictecture,
subarchitecture information. This is used to include the relevant headers
from the kernel directories.
'''
arch = None
subarch = None
plat = None
if not os.path.exists(config_header):
print "\n\nconfig.h does not exist. "\
"Please run: `scons configure' first\n\n"
sys.exit()
f = open(config_h, "r")
while True:
line = f.readline()
if line == "":
break
parts = split(line)
if len(parts) > 0:
if parts[0] == "#define":
if parts[1] == "__ARCH__":
arch = parts[2]
elif parts[1] == "__PLATFORM__":
plat = parts[2]
elif parts[1] == "__SUBARCH__":
subarch = parts[2]
f.close()
if arch == None:
print "Error: No config symbol found for architecture"
sys.exit()
if subarch == None:
print "Error: No config symbol found for subarchitecture"
sys.exit()
if plat == None:
print "Error: No config symbol found for platform"
sys.exit()
return arch, subarch, plat
def create_symlinks(arch):
arch_path = "include/arch"
arch_path2 ="src/arch"
if os.path.exists(arch_path):
os.system("rm %s" % (arch_path))
os.system("ln -s %s %s" % ("arch-" + arch, arch_path))
if os.path.exists(arch_path2):
os.system("rm %s" % (arch_path2))
os.system("ln -s %s %s" % ("arch-" + arch, arch_path2))
arch, subarch, plat = extract_arch_subarch_plat(config_h)
create_symlinks(arch) # Creates symlinks to architecture specific directories.
src = [glob("src/*.c"), glob("src/lib/*.c"), glob("src/lib/elf/*.c"), glob("*.c"), glob("src/arch/*.c")]
objs = env.Object(src)
physical_base = env.Command(physical_base_ld_script, prev_image, get_physical_base)
crt0_copied = env.Command("crt0.o", libc_crt0, copy_crt0)
task = env.Program(task_name, objs + [crt0_copied])
env.Alias(task_name, task)
env.Depends(task, physical_base)

View File

@@ -1,109 +0,0 @@
#
# User space application build script
#
# Copyright (C) 2007 Bahadir Balban
#
import os
import sys
import shutil
from os.path import join
from glob import glob
task_name = "test0"
# The root directory of the repository where this file resides:
project_root = "../.."
tools_root = join(project_root, "tools")
prev_image = join(project_root, "tasks/fs0/fs0.axf")
libs_path = join(project_root, "libs")
ld_script = "include/linker.lds"
physical_base_ld_script = "include/physical_base.lds"
# Libc situation:
# Libposix has uClibc (and therefore posix) headers.
# NICTA libc implements printf for us for now.
# Libposix implements posix calls for us, e.g. mmap.
# In conclusion nicta libc and libposix complement each other
# they should not clash. In future libposix will be part of uclibc
# and uclibc will be used.
# libc paths:
libc_variant = "userspace"
libc_libpath = join(libs_path, "c/build/%s" % libc_variant)
libc_incpath = join(libc_libpath, "include")
libc_crt0 = join(libs_path, "c/build/crt/sys-userspace/arch-arm/crt0.o")
libc_name = "c-%s" % libc_variant
# libposix paths:
libposix_libpath = "../libposix"
libposix_incpath = "../libposix/include/posix"
# libl4 paths:
libl4_path = "../libl4"
libl4_incpath = join(libl4_path, "include")
# kernel paths:
kernel_incpath = join(project_root, "include")
# If crt0 is in its library path, it becomes hard to link with it.
# For instance the linker script must use an absolute path for it.
def copy_crt0(source, target, env):
os.system("cp " + str(source[0]) + " " + str(target[0]))
def get_physical_base(source, target, env):
os.system(join(tools_root, "pyelf/readelf.py --first-free-page " + \
prev_image + " >> " + physical_base_ld_script))
# The kernel build environment:
env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
# We don't use -nostdinc because sometimes we need standard headers,
# such as stdarg.h e.g. for variable args, as in printk().
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', '-Werror'],
LINKFLAGS = ['-nostdlib', '-T' + ld_script, "-L" + libc_libpath, "-L" + libl4_path, \
'-L' + libposix_libpath],
ASFLAGS = ['-D__ASSEMBLY__'],
PROGSUFFIX = '.axf', # The suffix to use for final executable
ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path
LIBS = [libc_name, 'gcc', libc_name, 'libl4', 'libposix', libc_name],
CPPFLAGS = "-D__USERSPACE__",
CPPPATH = ['#include', libl4_incpath, libposix_incpath, kernel_incpath])
test_exec_ld_script = "include/test_exec_linker.lds"
# The kernel build environment:
test_exec_env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
# We don't use -nostdinc because sometimes we need standard headers,
# such as stdarg.h e.g. for variable args, as in printk().
CCFLAGS = ['-O3', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', '-Werror'],
LINKFLAGS = ['-nostdlib', '-T' + test_exec_ld_script, "-L" + libc_libpath, "-L" + libl4_path, \
'-L' + libposix_libpath],
ASFLAGS = ['-D__ASSEMBLY__'],
PROGSUFFIX = '.axf', # The suffix to use for final executable
ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path
LIBS = [libc_name, 'gcc', libc_name, 'libl4', 'libposix', libc_name],
CPPFLAGS = "-D__USERSPACE__",
CPPPATH = ['#include', libl4_incpath, libposix_incpath, kernel_incpath])
src = [glob("src/*.c"), glob("*.c"), glob("*.S"), glob("src/arch/arm/*.c"), glob("../libcont/*.c")]
objs = env.Object(src)
physical_base = env.Command(physical_base_ld_script, prev_image, get_physical_base)
crt0_copied = env.Command("crt0.o", libc_crt0, copy_crt0)
test_exec_src = [glob("src/test_exec/*.c")]
test_exec_objs = test_exec_env.Object(test_exec_src)
test_exec_name = "test_exec"
test_exec = test_exec_env.Program(test_exec_name, test_exec_objs + [crt0_copied])
test_exec_env.Alias(test_exec_name, test_exec)
env.Depends(objs, test_exec)
task = env.Program(task_name, objs + [crt0_copied])
env.Alias(task_name, task)
# I find this to be a BUG related to SCons. SCons is still good compared to
# notoriously horrible makefiles, but it could have been better.
# if test_exec doesn't depend on physical_base, test_exec is compiled but
# task complains that physical_base is not there. However we already declared
# its dependency below.
env.Depends(test_exec, physical_base)
env.Depends(task, physical_base)