Files
mlpack/fastlib/trunk/script/buildsys.py
T

654 lines
25 KiB
Python

"""The build system is in this file.
Skip to the end (class Loader, function load) for all available
build rule types.
See dep.py for information on the non-intuitive way these classes
as "metarules" link together and generate real code.
"""
import dep
import util
import glob
import os
import sys
def sq(str):
"""escape a string for use in a shell"""
if isinstance(str, list):
return [sq(s) for s in str]
else:
return util.shellquote(str)
def mq(str):
"""escape a string for use in makefiles"""
if isinstance(str, list):
return [mq(s) for s in str]
else:
return str.replace(" ", "\ ")
class Types:
HEADER="buildsys/.h"
GCC_SOURCE="buildsys/gcc" # .c, .cpp, etc
OBJECT="buildsys/.o"
LINKABLE="buildsys/.a"
BINFILE="buildsys/bin"
SCRIPT="buildsys/script"
DIR="buildsys/dir"
PLACEHOLDER="buildsys/placeholder"
MISC="buildsys/misc"
ANY="buildsys/*"
class CompilerInfo:
def __init__(self):
(self.kernel, nodename, release, version, self.arch) = os.uname()
self.lflags_fortran = "-lg2c"
def compiler_program(self, extension):
# for instance, turn "gcc %s -c %s -o ..." into just "gcc"
return self.command_from_ext[extension].split(" ")[0]
class GCCCompiler(CompilerInfo):
def __init__(self):
CompilerInfo.__init__(self)
use_gfortran = True
check_gfortran_existence = os.popen("which gfortran")
check_gfortran_existence_result = check_gfortran_existence.read()
check_gfortran_existence.close()
check_gfortran_existence_result = check_gfortran_existence_result[:len(check_gfortran_existence_result) - 1]
if len(check_gfortran_existence_result) == 0 or check_gfortran_existence_result[0] != '/': # '/' test for Macs
check_gfortran_existence = os.popen("which gfortran-4")
check_gfortran_existence_result = check_gfortran_existence.read()
check_gfortran_existence.close()
check_gfortran_existence_result = check_gfortran_existence_result[:len(check_gfortran_existence_result) - 1]
if len(check_gfortran_existence_result) == 0 or check_gfortran_existence_result[0] != '/': # '/' test for Macs
use_gfortran = False
print "!!! Using g77. GFortran will be preferred eventually."
self.name = "gcc"
self.mode_dictionary = {
"verbose": "-g -DDEBUG -DVERBOSE",
"debug": "-g3 -DDEBUG -O0",
"check": "-O2 -finline-functions -finline-limit=2000 -g -DDEBUG",
"fast": "-O2 -finline-functions -finline-limit=2000 -fomit-frame-pointer -g -DNDEBUG",
"unsafe": "-O3 -ffast-math -g -fomit-frame-pointer -DNDEBUG",
"profile" : "-O2 -pg -finline-limit=12 -DPROFILE -DNDEBUG",
"small": "-Os -DNDEBUG",
"trace": "-g -DNDEBUG"
}
self.command_from_ext = {
"c" : "gcc %s -c %s -o %s -Wall",
"cc" : "g++ -Wall -Woverloaded-virtual -fno-exceptions -Wparentheses -fno-exceptions %s -c %s -o %s",
"f" : "gfortran %s -c %s -o %s -Wall -Wno-uninitialized"
}
if use_gfortran:
self.lflags_fortran = "-lgfortran"
else:
self.lflags_fortran = "-lg2c"
self.command_from_ext["f"] = "g77 %s -c %s -o %s -Wall -Wno-uninitialized"
self.linker = "g++"
self.lflags_start = ""
self.lflags_end = "-lm -lpthread %s" % (self.lflags_fortran)
class GCC4Compiler(GCCCompiler):
def __init__(self):
GCCCompiler.__init__(self)
self.name = "gcc4"
self.command_from_ext["c"] = "gcc4 %s -c %s -o %s -Wall";
self.command_from_ext["cc"] = "g++4 -Wall -Woverloaded-virtual -fno-exceptions -Wparentheses -fno-exceptions %s -c %s -o %s";
self.linker = "g++4"
class GCCdash4Compiler(GCCCompiler):
def __init__(self):
GCCCompiler.__init__(self)
self.name = "gcc-4"
self.command_from_ext["c"] = "gcc-4 %s -c %s -o %s -Wall";
self.command_from_ext["cc"] = "g++-4 -Wall -Woverloaded-virtual -fno-exceptions -Wparentheses -fno-exceptions %s -c %s -o %s";
self.linker = "g++-4"
class ICCCompiler(CompilerInfo):
def __init__(self):
CompilerInfo.__init__(self)
self.name = "icc"
self.mode_dictionary = {
"verbose": "-g -DDEBUG -DVERBOSE",
"debug": "-g -DDEBUG",
"check": "-O2 -g -DDEBUG",
"fast": "-O3 -g -fomit-frame-pointer -DNDEBUG",
"unsafe": "-O3 -ffast-math -g -fomit-frame-pointer -DNDEBUG",
"profile" : "-O2 -pg -finline-limit=8 -DPROFILE -DNDEBUG",
"small": "-Os"
}
self.command_from_ext = {
"c" : "icc %s -c %s -o %s",
"cc" : "icc %s -c %s -o %s -fno-exceptions",
"f" : "ifort %s -c %s -o %s -Wall"
}
self.linker = "icc"
self.lflags_start = ""
self.lflags_end = "-lm -lpthread %s" % (self.lflags_fortran)
class MPICompiler(CompilerInfo):
def __init__(self):
CompilerInfo.__init__(self)
self.name = "mpi"
self.mode_dictionary = {
"verbose": "-g -DDEBUG -DVERBOSE",
"debug": "-g -DDEBUG",
"check": "-O2 -g -DDEBUG",
"fast": "-O3 -g -fomit-frame-pointer -DNDEBUG",
"unsafe": "-O3 -ffast-math -g -fomit-frame-pointer -DNDEBUG",
"profile" : "-O2 -pg -finline-limit=8 -DPROFILE -DNDEBUG",
"small": "-Os"
}
self.command_from_ext = {
"c" : "mpicc %s -c %s -o %s",
"cc" : "mpiCC -fno-exceptions %s -c %s -o %s",
"f" : "mpif77 %s -c %s -o %s -Wall"
}
self.linker = "mpiCC"
self.lflags_start = ""
self.lflags_end = "-lm -lpthread %s" % (self.lflags_fortran)
compiler_choices = [GCCCompiler(), GCC4Compiler(), GCCdash4Compiler(), MPICompiler(), ICCCompiler()]
compilers = dict([(c.name, c) for c in compiler_choices])
class MakeBuildSys(dep.DepSys):
"""Build system.
"""
def __init__(self, source_dir, bin_dir, keep_dir):
"""Initialize a 'Build System' or 'Makefile'.
source_dir - source code directory
bin_dir - binaries generated by build system go here
keep_dir - generated files that you want to keep a while go here
"""
dep.DepSys.__init__(self)
self.source_dir = source_dir
self.bin_dir = bin_dir
self.keep_dir = keep_dir
self.entries = []
def begin(self, state):
return MakeBuildSysEntry(self, state)
def add_realrule(self, realrule):
self.entries.append(realrule)
def to_makefile(self):
def shorten(fname):
if "/bin/" in fname:
return fname[fname.rindex("/bin/")+1:]
else:
return fname
lines = []
self.entries.reverse()
i = 0
for (outfiles_orig, infiles, commands) in self.entries:
i += 1
outfiles = []
for outfile in outfiles_orig:
if not (outfile in infiles):
outfiles.append(outfile)
if not outfiles:
outfiles = [("pseudo_%d" % i)]
if commands:
lines.append("%s: %s" % (" ".join(mq(outfiles)), " ".join(mq(infiles))))
outfiles_short = [shorten(outfile) for outfile in outfiles]
lines.extend(["\t@echo '... Making %s'" % (" ".join(outfiles_short))])
lines.extend(["\t@" + c for c in commands])
elif infiles:
lines.append("%s: %s" % (" ".join(mq(outfiles)), " ".join(mq(infiles))))
lines.extend(["\t@echo '*** Done with %s'" % (" ".join(infiles))])
self.entries.reverse()
lines.append("clean:")
lines.append("\t@echo 'Removing the bin/ directory.'");
lines.append("\trm -rf %s/*" % (sq(self.bin_dir)))
return lines
class MakeBuildSysEntry(dep.DepSysEntry):
def __init__(self, sys, state):
dep.DepSysEntry.__init__(self, sys, state)
self.commands = []
def _make_name(self, simplename, parameterization):
# NOTE: I'm completely ignoring the file list (self.state.files)
KEEP_DIR = "KEEP/"
if simplename.startswith(KEEP_DIR):
# "!" means that file should be placed in semi-permanent storage.
dirname = self.keep_dir(*parameterization)
simplename = simplename[len(KEEP_DIR):]
else:
dirname = self.bin_dir(*parameterization)
return os.path.join(dirname, simplename)
def __name_pmz(self, pmz):
"""names a parameterization"""
def name_part(param_name):
if param_name in pmz:
return self.state.params[param_name]
else:
return "COMMON"
allowed_sequence = ["arch", "kernel", "mode", "compiler", "cflags"]
(arch, kernel, mode, compiler, cflags) = [name_part(x) for x in allowed_sequence]
for param in pmz:
if not param in allowed_sequence:
raise Exception("I can't deal with extra parameterization yet: '%s' not in '%s'" % (param, allowed_sequence))
return "%s_%s_%s_%s_%s" % (arch, kernel, mode, compiler, util.sanitize_basename(cflags))
def bin_dir(self, *pmz):
return os.path.join(self.sys.bin_dir, self.__name_pmz(pmz))
def keep_dir(self, *pmz):
return os.path.join(self.sys.keep_dir, self.__name_pmz(pmz))
def source_file(self, real_path, fake_path):
return dep.DestFile(real_path, fake_path)
def makefile(self):
return self.source_file(os.path.abspath("./Makefile"), "Makefile")
def ensure_writable(self, name):
self.command("mkdir -p %s" % (sq(os.path.dirname(name))))
def command(self, str):
self.commands.append(str)
def end(self, files):
infiles = {}
for file in dep.filemap_to_files(self.state.files):
infiles[file.name] = None
outfiles = [file.name for (classname, file) in files]
self.sys.add_realrule((outfiles, list(infiles.keys()), self.commands))
class SourceRule(dep.Metarule):
def __init__(self, type, real_path, fake_path):
dep.Metarule.__init__(self)
self.real_path = real_path
self.fake_path = fake_path
self.type = type
def doit(self, realrule, files, params):
return [(self.type, realrule.source_file(self.real_path, self.fake_path))]
class CompileRule(dep.Metarule):
def __init__(self, source, headers, cflags):
dep.Metarule.__init__(self, source=[source], headers=headers)
self.cflags = cflags
def doit(self, realrule, files, params):
compiler = compilers[params["compiler"]]
source = files["source"].single(Types.GCC_SOURCE)
dot = source.simplename.rindex(".")
sourceextension = source.simplename[dot+1:]
simplename = source.simplename[:dot] + ".o"
object = realrule.file("obj/" + simplename.replace("/", "_"),
"arch", "kernel", "mode", "compiler", "cflags")
# TODO: -I flags
my_includes = "-I%s -I%s -I%s" % (
sq(realrule.bin_dir("arch", "kernel", "compiler")),
sq(realrule.bin_dir("arch", "kernel", "compiler", "cflags")),
sq(realrule.sys.source_dir))
mode = params["mode"]
my_flags = my_includes + " " + compiler.mode_dictionary[params["mode"]] \
+ " " + self.cflags + " " + params["cflags"]
if not sourceextension in compiler.command_from_ext:
raise Exception("Don't know how to compile files of type '*.%s'." % sourceextension)
command_template = compiler.command_from_ext[sourceextension]
(source_dirname, source_basename) = os.path.split(source.name)
compile_cmd = command_template % (my_flags, sq(source_basename), sq(object.name))
realrule.command("cd " + sq(source_dirname) + " && " + compile_cmd)
return [(Types.OBJECT, object)]
class ArchiveRule(dep.Metarule):
def __init__(self, name, objects):
dep.Metarule.__init__(self, objects=objects)
self.name = name
def doit(self, realrule, files, params):
objects = files["objects"].many(Types.OBJECT)
if len(objects) != 0:
libfile = realrule.file("lib" + self.name + ".a",
"arch", "kernel", "mode", "compiler")
archive_and_export_rule = "ar r %s %s" % \
(sq(libfile), \
" ".join([sq(x.name) for x in objects]))
if params["prefix"] != "":
destination_parent_dir = params["prefix"].rstrip("/").rstrip(os.sep) \
+ "/lib/"
archive_and_export_rule += \
" && mkdir -p " + \
destination_parent_dir + \
" && cp " + sq(libfile) + " " + \
destination_parent_dir
realrule.command(archive_and_export_rule)
return [(Types.LINKABLE, libfile)]
else:
# no compilable code was found -- just don't create an object
return []
#return [(Types.OBJECT, object) for object in objects]
class HeaderSummaryRule(dep.Metarule):
def __init__(self, name, objects):
dep.Metarule.__init__(self, objects=objects)
self.name = name
def doit(self, realrule, files, params):
libfile = realrule.file("lib" + self.name + ".h")
generate_header_rule = "touch %s" % (sq(libfile))
# If the user specified the --prefix option, then export the header files.
if params["prefix"] != "":
for each_header in files["objects"].to_names():
destination_subpath = each_header \
[len(os.path.realpath \
(os.path.dirname \
(os.path.realpath \
(os.path.dirname \
(sys.argv[0])))).rstrip(os.sep) \
+ os.sep):]
destination_subdir = os.path.dirname(destination_subpath)
destination_parent_dir = params["prefix"].rstrip("/").rstrip(os.sep) \
+ "/include/fastlib2/"
destination_newdir = destination_parent_dir + destination_subdir
# This seems like a hack, but I do not have a good clean
# solution.
if os.path.basename(each_header) == "basic_types.h":
destination_newdir = os.path.dirname \
(os.path.dirname \
(os.path.dirname(destination_newdir))) + \
"/fastlib/base/base"
generate_header_rule += " && mkdir -p " + destination_newdir + \
" && cp " + each_header + " " + \
destination_newdir
realrule.command(generate_header_rule)
return [(Types.PLACEHOLDER, libfile)]
class BinRule(dep.Metarule):
def __init__(self, name, deplibs, cflags):
self.name = name
self.cflags = cflags
dep.Metarule.__init__(self, deplibs=deplibs)
def doit(self, realrule, files, params):
compiler = compilers[params["compiler"]]
binfile = realrule.file(self.name,
"arch", "kernel", "mode", "compiler", "cflags")
# TO-DO: Link flags necessary?
lflags_start = compiler.lflags_start
lflags_end = compiler.lflags_end
cflags = compiler.mode_dictionary[params["mode"]]
reversed_libs = list(files["deplibs"].to_names())
reversed_libs.reverse()
realrule.command(compiler.linker + " -o %s %s %s %s %s %s %s" % (
sq(binfile.name), cflags,
lflags_start, " ".join(sq(reversed_libs)), lflags_end,
self.cflags, params["cflags"]))
return [(Types.BINFILE, binfile)]
class LibRule(dep.Metarule):
"""LibRule returns all relevant archive files for this library and libraries
it depends on.
In addition, a LibRule exposes header files.
"""
# TODO: "sources" will also natively support C++ files
def __init__(self, name, sources, headers, deplibs, cflags = ""):
source_rules = sources
self.header_rules = headers
# TODO: Be careful about depending on extra stuff?
for dep_lib in deplibs:
if isinstance(dep_lib, LibRule):
self.header_rules.append(dep_lib.header_summary_rule)
self.header_summary_rule = HeaderSummaryRule(name, self.header_rules)
self.compile_rules = [CompileRule(source_rule, self.header_rules, cflags)
for source_rule in source_rules]
self.archive_rule = ArchiveRule(name, self.compile_rules)
dep.Metarule.__init__(self, archive=[self.archive_rule], deplibs=deplibs)
def doit(self, realrule, files, params):
return files["deplibs"].to_pairs() + files["archive"].to_pairs()
class MakefileRule(dep.Metarule):
"""
Plug created so that symlinks are re-created whenever the Makefile changes.
"""
def __init__(self):
dep.Metarule.__init__(self)
def doit(self, realrule, files, params):
file = realrule.makefile()
return [(Types.MISC, file)]
class SymlinkRule(dep.Metarule):
def __init__(self, filerules, dest_dir):
dep.Metarule.__init__(self, filerules=filerules, makefile=[MakefileRule()])
self.dest_dir = dest_dir
def doit(self, realrule, files, params):
all = []
pairs = files["filerules"].to_pairs()
for (classname, file) in pairs:
sourcename = file.name
shortname = os.path.basename(file.name)
destname = os.path.join(self.dest_dir, shortname)
# the symlink's simplename will be the same as the original's
destfile = realrule.source_file(destname, shortname)
realrule.command("rm -f %s" % sq(destname))
realrule.command("ln -s -f %s %s" % (sq(sourcename), sq(destname)))
all.append((classname, destfile))
realrule.command("echo '*** Created %d symlinks in %s.'" % (len(pairs), self.dest_dir))
return all
class WgetRule(dep.Metarule):
def __init__(self, url, type, real_path, fake_path):
self.real_path = real_path
self.fake_path = fake_path
self.url = url
self.type = type
dep.Metarule.__init__(self)
def doit(self, realrule, files, params):
(real_dir, filename) = os.path.split(self.real_path)
echo_message = "Downloading the file using " + params["downloader"] + "..."
realrule.command("echo '" + echo_message + "'")
if os.path.basename(params["downloader"]) == "wget":
realrule.command("cd %s && %s %s" % (
sq(real_dir), params["downloader"], sq(filename)))
else:
realrule.command("cd %s && %s %s -o %s" % (
sq(real_dir), params["downloader"], sq(filename), sq(self.url)))
return [(self.type, realrule.source_file(self.real_path, self.fake_path))]
# Parameter loader
BUILD_FILE = "build.py"
class Loader:
"""Responsible for loading build files and helping them stitch together.
There are concepts of real and fake paths:
- Real path: Where the file is located exactly on the file system.
- Fake path: Where results generated by this file are relative to the
build system. If the real path is within the build directories, then
the fake path is just the relative path from the root of the build
system. However, we also support building small code trees that are
not in the build system. In this, the "fake" path starts with "outside"
to indicate it is outside the build system, and has the full path.
Example:
Say my build path is
~/fastlib/c (this is real_rootpath)
Someone wants to build ~/fastlib/c/foo/bar, the fake path is "foo/bar".
But if someone wants to build ~/foo/bar, the fake path is
"outside/home/yourname/foo/bar".
See also ../script/fl-build.
"""
def __init__(self, real_rootpath):
self.real_root = real_rootpath.rstrip(os.sep)
self.thebuildsys = MakeBuildSys(
self.real_root, os.path.join(self.real_root, "bin"),
os.path.join(self.real_root, "bin_keep"))
self.loader_map = {}
def pathjoin(self, left, right, defaultprefix, lsep = "/", rsep = "/"):
def helper(left, right):
if right and right[0] == ".":
right_index = (right + "/").index(rsep)
right_first = right[:right_index]
right_rest = right[right_index+1:]
if right_first == ".":
return helper(left, right_rest)
else:
try:
left_index = left.rindex(lsep)
except:
left_index = 0
return helper(left[:left_index], right_rest)
else:
return left + lsep + right.replace(rsep, lsep)
left = left.rstrip(lsep)
right = right.rstrip(rsep)
if not right:
return left
elif right[0] != ".":
if right[0] == rsep:
return right.replace(rsep, lsep)
else:
return defaultprefix + right.replace(rsep, lsep)
else:
return helper(left, right)
def pathjoin_real(self, left, right):
return self.pathjoin(left, right, self.real_root + "/", os.sep, "/")
def pathjoin_fake(self, left, right):
return self.pathjoin(left, right, "", "/", "/")
def find_rule(self, rule_path, cur_real_path, cur_fake_path, posttext = ""):
#print "trying: %s" % fullname
(path_rel, rule_name) = rule_path.split(":")
fake_path = self.pathjoin_fake(cur_fake_path, path_rel)
real_path = self.pathjoin_real(cur_real_path, path_rel)
if rule_name == "":
rule_name = fake_path.split("/")[-1]
if not fake_path in self.loader_map:
self.load(real_path, fake_path, posttext)
elif posttext:
print "XXX Ignored Post-text: ", posttext
if rule_name == "VERYSPECIALPYTHONSTRING":
dependencies = {}
for target_string in self.loader_map[fake_path]:
cur_rule_object = Loader.find_rule(self, ":" + target_string,
cur_real_path, cur_fake_path,
posttext)
if not target_string in dependencies:
dependencies[target_string] = [cur_rule_object]
else:
dependencies[target_string] += [cur_rule_object]
def convert_to_list(sysentry, files, params):
ret = []
for file_key in files:
ret += files[file_key].to_pairs()
return ret
new_custom_rule = dep.CustomRule(dependencies, convert_to_list)
self.loader_map[fake_path][rule_name] = new_custom_rule
return new_custom_rule
if not rule_name in self.loader_map[fake_path]:
raise Exception("Rule '%s' not found in '%s'." % (rule_name, real_path))
#print "Found [%s][%s] aka [%s]" % (fullname, defaultpath, path)
return self.loader_map[fake_path][rule_name]
def load(self, real_path, fake_path, posttext = ""):
"""Loads build rules, by exposing a 'register' function.
real_path - path on file system
fake_path - path according to build system
posttext - optionally inject text at the end of a build file
"""
# !!!!! LOOK AT ME! All the functions in build rules are defined here!
self.loader_map[fake_path] = {}
selfname = fake_path.split("/")[-1]
def register(name, rule):
if name in self.loader_map[fake_path]:
raise Exception("Duplicate rule %s:%s" % (fake_path, name))
self.loader_map[fake_path][name] = rule
return rule
def find(rule_name):
return self.find_rule(rule_name, real_path, fake_path)
def pathify_real(name):
return self.pathjoin_real(real_path, "./" + name)
def pathify_fake(name):
return self.pathjoin_fake(fake_path, "./" + name)
def sourcerule(type, name):
if isinstance(name, str):
# If there is a colon, it is a rule; otherwise, it is just a file.
if ":" in name:
return find(name)
else:
return SourceRule(type, pathify_real(name), pathify_fake(name))
else:
return name
def sourcerules(type, names):
return [sourcerule(type, name) for name in names]
def lglob(mask, *exclude):
(relpath, namemask) = os.path.split(mask)
full_path = os.path.join(real_path, mask)
basenames = [os.path.basename(f)
for f in glob.glob(os.path.join(real_path, mask))]
return [os.path.join(relpath, basename)
for basename in basenames if not basename in exclude]
def customrule(name, dependencies, doit_fn):
return register(name, dep.CustomRule(dependencies, doit_fn))
def librule(name = selfname,
sources = [], headers = [], deplibs = [], tests = [], cflags = ""):
long_name = pathify_fake(name).replace("/", "_")
lib = LibRule(long_name,
sourcerules(Types.GCC_SOURCE, sources),
sourcerules(Types.HEADER , headers),
sourcerules(Types.LINKABLE, deplibs),
cflags)
register(name, lib)
for test_source in tests:
# TO-DO: Recursively run tests
test_name = test_source[:test_source.rindex(".")]
test_lib = LibRule(long_name + "_" + test_name,
[sourcerule(Types.GCC_SOURCE, test_source)], [], [lib], cflags)
test_bin = BinRule(pathify_fake(test_name), [test_lib], cflags)
register(test_name, test_bin)
return lib
def wgetrule(name, url, type = Types.ANY, fname = None):
if fname == None:
fname = url[url.rindex('/')+1:]
register(name, WgetRule(url, type,
pathify_real(fname), pathify_fake(fname)))
def binrule(name, deplibs = [], sources = [], headers = [], cflags = "", linkables = None):
if linkables:
print "!!! Warning: 'linkables' is deprecated, it has been renamed 'deplibs'"
deplibs += linkables
# (source, headers, cflags)
longname = pathify_fake(name)
if sources:
lib = librule(name = name + "__auto",
sources = sources, headers = headers, deplibs = deplibs,
cflags = cflags)
deplibs = deplibs + [lib]
register(name, BinRule(longname, sourcerules(Types.LINKABLE, deplibs), cflags))
build_file_path = os.path.join(real_path, BUILD_FILE)
print "... Reading %s" % (build_file_path)
try:
text = util.readfile(build_file_path)
except IOError:
print "!!! Build file '%s' not found, assuming blank." % build_file_path
text = ""
# remove DOS line feeds and add posttext
text = text.replace("\r", "") + "\n" + posttext
exec text in {"register" : register, "Types" : Types,
"find" : find, "dep" : dep, "lglob" : lglob,
"sourcerule" : sourcerule, "sourcerules" : sourcerules,
"librule" : librule, "binrule" : binrule,
"customrule" : customrule, "wgetrule" : wgetrule,
"compilers" : compilers, "os" : os, "sq" : sq}