aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas "Cakeisalie5" Touhey <thomas@touhey.fr>2017-07-28 15:47:13 +0200
committerThomas "Cakeisalie5" Touhey <thomas@touhey.fr>2017-07-28 15:47:13 +0200
commit1404783751b0fb1fa4e3651504c3bbbf7b698d95 (patch)
tree8feb069d7d83fc214c41f54224c4c896413d93b7
parent8ccd8524760e5ccd0403fee769c51cb0b9cd1a16 (diff)
Saving, unfinished yet.
-rw-r--r--.gitignore2
-rw-r--r--LICENSE.md3
-rw-r--r--arch/all/core/include/alloca.h1
-rwxr-xr-xtools/Internals/__init__.py2
-rwxr-xr-xtools/Internals/args.py29
-rw-r--r--tools/Internals/cache.py50
-rwxr-xr-xtools/Internals/copyright.py44
-rwxr-xr-xtools/Internals/exceptions.py17
-rwxr-xr-xtools/Internals/headers.py345
-rw-r--r--tools/Internals/headers/__init__.py4
-rw-r--r--tools/Internals/headers/eval.py7
-rw-r--r--tools/Internals/headers/manager.py408
-rw-r--r--tools/Internals/headers/output.py70
-rw-r--r--tools/Internals/headers/parse.py298
-rw-r--r--tools/Internals/headers/profile.py74
-rw-r--r--tools/Internals/locales/en_US.yml7
-rw-r--r--tools/Internals/locales/fr_FR.yml12
-rwxr-xr-xtools/Internals/module.py33
-rwxr-xr-xtools/Internals/tools/gnu_ar.py8
-rwxr-xr-xtools/Internals/tools/gnu_as.py8
-rwxr-xr-xtools/Internals/tools/gnu_gcc.py8
-rwxr-xr-xtools/Internals/tools/renesas_asmsh.py6
-rwxr-xr-xtools/Internals/tools/renesas_optlnk.py6
-rwxr-xr-xtools/Internals/tools/renesas_shc.py8
-rw-r--r--tools/Internals/topc.py2
-rwxr-xr-xtools/configure.py132
-rwxr-xr-xtools/make.py66
-rwxr-xr-xtools/updatesource.py12
28 files changed, 1157 insertions, 505 deletions
diff --git a/.gitignore b/.gitignore
index 628422c..429ba16 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,7 +10,7 @@
# cache
/build.yml
/.config.yml
-/.makeinc-cache
+/.*cache*
.*.chg
# that was for modules
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..081cece
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,3 @@
+# libcarrot license
+libcarrot is made of symbols with different licenses.
+This will be clarified in a short amount of time.
diff --git a/arch/all/core/include/alloca.h b/arch/all/core/include/alloca.h
index 1699b26..99dd14e 100644
--- a/arch/all/core/include/alloca.h
+++ b/arch/all/core/include/alloca.h
@@ -26,6 +26,7 @@ __BEGIN_DECLS
/* there isn't a function in the library.
* you should *really* use the macros. */
+
extern void *alloca _OF((size_t __size)) __THROW;
#include_bits <alloca.h>
diff --git a/tools/Internals/__init__.py b/tools/Internals/__init__.py
index 18d4571..2b7d9a1 100755
--- a/tools/Internals/__init__.py
+++ b/tools/Internals/__init__.py
@@ -8,5 +8,7 @@ from .copyright import *
from .tools import *
from .module import *
from .topc import *
+from .cache import *
+from .headers import *
# End of file.
diff --git a/tools/Internals/args.py b/tools/Internals/args.py
index 4a62e7d..45e51eb 100755
--- a/tools/Internals/args.py
+++ b/tools/Internals/args.py
@@ -1,17 +1,24 @@
#!/usr/bin/env python3
""" argparse extensions for the libcarrot utilities. """
-import os, sys, argparse, platform, re
+import os as _os
+import sys as _sys
+import argparse as _argparse
+import platform as _platform
+import re as _re
+
from .locale import *
-class CarrotHelpFormatter(argparse.HelpFormatter):
+__all__ = ['CarrotArgumentParser']
+
+class _CarrotHelpFormatter(_argparse.HelpFormatter):
""" Custom argument parser help message formatter to eliminate some of
the problems I had with the default one (linked to metavars). """
def __init__(self, *args, **kwargs):
kwargs['max_help_position'] = 78
kwargs['width'] = 79
- super(CarrotHelpFormatter, self).__init__(*args, **kwargs)
+ super(_CarrotHelpFormatter, self).__init__(*args, **kwargs)
def _format_usage(self, usage, actions, groups, prefix):
if prefix is None:
@@ -51,8 +58,8 @@ class CarrotHelpFormatter(argparse.HelpFormatter):
part_regexp = r'\(.*?\)+|\[.*?\]+|\S+'
opt_usage = format(optionals, groups)
pos_usage = format(positionals, groups)
- opt_parts = re.findall(part_regexp, opt_usage)
- pos_parts = re.findall(part_regexp, pos_usage)
+ opt_parts = _re.findall(part_regexp, opt_usage)
+ pos_parts = _re.findall(part_regexp, pos_usage)
assert ' '.join(opt_parts) == opt_usage
assert ' '.join(pos_parts) == pos_usage
@@ -133,7 +140,7 @@ class CarrotHelpFormatter(argparse.HelpFormatter):
return ', '.join(parts)
-class CarrotArgumentParser(argparse.ArgumentParser):
+class CarrotArgumentParser(_argparse.ArgumentParser):
""" Custom class for libcarrot argument parsing. """
def __init__(self, description=None):
@@ -141,19 +148,19 @@ class CarrotArgumentParser(argparse.ArgumentParser):
# Get the prefix chars.
prefix_chars = '-'
- if platform.system == "Windows":
+ if _platform.system == "Windows":
prefix_chars += '/'
# Get the program name.
- env = os.environ
+ env = _os.environ
if 'PROGNAME' in env:
prog = env['PROGNAME']
else:
- prog = os.path.basename(sys.argv[0])
+ prog = _os.path.basename(_sys.argv[0])
super(CarrotArgumentParser, self).__init__(prog=prog,
description=description, prefix_chars=prefix_chars,
- formatter_class=CarrotHelpFormatter, add_help=False)
+ formatter_class=_CarrotHelpFormatter, add_help=False)
self._action_groups = []
self._positionals = \
@@ -178,7 +185,7 @@ class CarrotArgumentParser(argparse.ArgumentParser):
super(CarrotArgumentParser, self).add_argument(*public_names,
**kwargs)
if hidden_names:
- kwargs['help'] = argparse.SUPPRESS
+ kwargs['help'] = _argparse.SUPPRESS
super(CarrotArgumentParser, self).add_argument(*hidden_names,
**kwargs)
diff --git a/tools/Internals/cache.py b/tools/Internals/cache.py
new file mode 100644
index 0000000..54df890
--- /dev/null
+++ b/tools/Internals/cache.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+""" Simple cache management for the library.
+"""
+
+import os as _os
+import copy as _copy
+import yaml as _yaml
+
+class CacheManager:
+ """ The cache manager. """
+
+ __default_cache_path = _os.path.join(_os.path.dirname(__file__),
+ '..', '..', '.cache.yml')
+
+ def __init__(self, path=__default_cache_path):
+ """ Load the cache. """
+
+ try: data = _yaml.load(open(path).read())
+ except FileNotFoundError: data = {}
+ if data == None: data = {}
+
+ self.__path = path
+ self.__categories = {}
+ for key in data:
+ if type(data[key]) != dict:
+ continue
+ self.__categories[key] = data[key]
+
+ def get(self, name, default={}):
+ """ Get a specific cache out of the overall cache folder. """
+
+ if not name in self.__categories:
+ return default
+ return _copy.deepcopy(self.__categories[key])
+
+ def set(self, name, cache):
+ """ Set the cache. """
+
+ if type(cache) != dict:
+ raise Exception("[INT] Cache setting argument should be a dict")
+ self.__categories[name] = _copy.deepcopy(cache)
+
+ def __del__(self):
+ """ Don't forget to save it. """
+
+ with open(self.__path, 'w') as out:
+ print(_yaml.dump(self.__categories,
+ version=(1, 2), width=60), file=out, end='')
+
+# End of file.
diff --git a/tools/Internals/copyright.py b/tools/Internals/copyright.py
index 3bdef79..232f865 100755
--- a/tools/Internals/copyright.py
+++ b/tools/Internals/copyright.py
@@ -3,15 +3,17 @@
Based on the `copyright.yml` files -- see `FORMAT.md` for its description.
"""
-import os, re, fnmatch
-from datetime import date
+import os as _os
+import re as _re
+import fnmatch as _fnmatch
+import datetime as _datetime
+import yaml as _yaml
-import yaml
from .exceptions import *
-__all__ = ["get_copyright_rules", "get_copyright"]
+__all__ = ["get_copyright_rules", "get_copyright", "merge_copyrights"]
-__default_maintainer = ((2016, date.today().year),
+__default_maintainer = ((2016, _datetime.date.today().year),
'Thomas "Cakeisalie5" Touhey', 'thomas@touhey.fr')
# ---
@@ -21,19 +23,19 @@ __default_maintainer = ((2016, date.today().year),
def get_copyright_rules(root):
""" Get the copyright rules from a root. """
- root = os.path.join(root, '')
+ root = _os.path.join(root, '')
rules = {}
# Copyright file thing.
- for rt, _, _ in os.walk(root):
+ for rt, _, _ in _os.walk(root):
# Ignore file.
try:
- with open(os.path.join(rt, '.gitignore')) as f:
+ with open(_os.path.join(rt, '.gitignore')) as f:
rulz = []
for line in f.readlines():
# Get what's before the comment.
- line = re.sub('([^\\\\](\\\\\\\\)*)#.*$', '\\1', line)
- line = re.sub('\\\\(.*)', '\\1', line)
+ line = _re.sub('([^\\\\](\\\\\\\\)*)#.*$', '\\1', line)
+ line = _re.sub('\\\\(.*)', '\\1', line)
line = line.strip()
if line: rulz.append(line)
@@ -41,11 +43,11 @@ def get_copyright_rules(root):
for l in rulz:
if l[0] == '/':
nm = l[1:].split('/')
- bases = [os.path.join(rt, *nm)]
+ bases = [_os.path.join(rt, *nm)]
else:
nm = l.split('/')
- bases = [os.path.join(rt, *nm),
- os.path.join(rt, '**', *nm)]
+ bases = [_os.path.join(rt, *nm),
+ _os.path.join(rt, '**', *nm)]
for base in bases:
rules[base] = '===IGNORED==='
@@ -54,8 +56,8 @@ def get_copyright_rules(root):
# Copyright file.
try:
- with open(os.path.join(rt, 'copyright.yml')) as f:
- d_rules = yaml.load_all(f.read())
+ with open(_os.path.join(rt, 'copyright.yml')) as f:
+ d_rules = _yaml.load_all(f.read())
# Read each rule.
for rule in d_rules:
@@ -78,7 +80,7 @@ def get_copyright_rules(root):
for m in ml:
spl = m.split('/')
- m = os.path.join(rt, *spl)
+ m = _os.path.join(rt, *spl)
rules[m] = {'authors': authors, 'license': l}
except FileNotFoundError:
pass
@@ -93,14 +95,14 @@ def __match(rule, path):
""" Check if a path matches a rule. """
# Check if the full path is matched.
- if fnmatch.fnmatch(path, rule):
+ if _fnmatch.fnmatch(path, rule):
return True
# Check if one of the parent directories is matched.
while True:
- dirname, filename = os.path.split(path)
+ dirname, filename = _os.path.split(path)
if not dirname: break
- if fnmatch.fnmatch(dirname, rule):
+ if _fnmatch.fnmatch(dirname, rule):
return True
path = dirname
@@ -110,9 +112,9 @@ def __match(rule, path):
def get_copyright(rules, path):
""" Get a path's copyright using a set of rules. """
- if not os.path.isfile(path):
+ if not _os.path.isfile(path):
raise NotAFileException
- if os.path.basename(path) == 'copyright.yml':
+ if _os.path.basename(path) == 'copyright.yml':
raise IgnoredFileException
match = None
diff --git a/tools/Internals/exceptions.py b/tools/Internals/exceptions.py
index 65d4490..4154d5b 100755
--- a/tools/Internals/exceptions.py
+++ b/tools/Internals/exceptions.py
@@ -3,7 +3,7 @@
To manage them correctly, you should use the `do_main()` function.
"""
-import sys
+import sys as _sys
from .locale import *
#*****************************************************************************#
@@ -48,7 +48,7 @@ def Raise(exc):
try:
raise exc
except PotatoWarning as e:
- print(loc['prefix']['warning'], str(e), file=sys.stderr)
+ print(loc['prefix']['warning'], str(e), file=_sys.stderr)
# Main function wrapper.
@@ -60,7 +60,7 @@ def do_main(main_func):
except SilentException:
exit(1)
except PotatoException as e:
- print(loc['prefix']['error'], str(e), file=sys.stderr)
+ print(loc['prefix']['error'], str(e), file=_sys.stderr)
exit(e.ret)
#*****************************************************************************#
# Internal exceptions #
@@ -272,4 +272,15 @@ class IncompatibleLicensesException(PotatoException):
ags = ('first_license', 'second_license')
msg = loc['exceptions']['IncompatibleLicenses']
+# ---
+# Super-preprocessor exceptions.
+# ---
+
+class DuplicateHeaderException(PotatoException):
+ """ Duplicate header! """
+
+ ret = 2
+ ags = ('name', 'first_module', 'second_module')
+ msg = loc['exceptions']['DuplicateHeader']
+
# End of file.
diff --git a/tools/Internals/headers.py b/tools/Internals/headers.py
deleted file mode 100755
index 8db4799..0000000
--- a/tools/Internals/headers.py
+++ /dev/null
@@ -1,345 +0,0 @@
-#!/usr/bin/env python3
-""" This file mainly deals with the libcarrot super-preprocessor.
- It was previously called 'makeinc' or 'makeinc.py', but has been merged
- into the internals for more efficient calls.
-
- What it basically does is:
- - add full (comment) headers out of metas, with licence content & stuff;
- - add include guards;
- - reindent preprocessor directives;
- - add the `#include_bits` preprocessor directive, which embeds zero or
- more "header bits" using the bits PATH (list of directories where to
- find bits).
-
- Features to come are:
- - macro profiling, in order to skip some conditions and optimize the
- headers for the end user;
- - better header metadata (different licences from LGPLv3, ...).
-"""
-
-import os, textwrap
-from sys import stderr
-
-import yaml
-
-# ---
-# List files.
-# ---
-
-def __split_path(path):
- """ Split a path. """
-
- tree, leaf = os.path.split(path)
- if not tree: return (leaf,)
- return __split_path(tree) + (leaf,)
-
-def __list_includes_and_bits(modules):
- """ List the includes and bits as a tuple of two lists. """
-
- incs, bits = [], []
- for module_name, module in modules:
- for bit in modules.getfiles('bits'):
- nm = __split_path(os.path.join(
-
-
-
-
-
-
-
-
-def look_for_bits(name):
- bits = []
-
- for path in map(lambda x: os.path.join(x, name), args.bits):
- path = os.path.normpath(path)
- if os.path.exists(path):
- bits += [path]
- return bits
-
-def process(path_in, f_out, indent=0, isbit=False):
- global bts
- bdeps = []
-
- f_in = open(path_in)
- buf = ''; nl = 0
- original_indent = indent
- while True:
- # Increment the line number.
- nl += 1
-
- # Get the line.
- local = f_in.readline()
-
- # Check if is a header leader.
- if nl == 1 and local[:79] == "/* " + "*" * 76:
- while True:
- nl += 1
- line = f_in.readline()
- if line[:79] == " * " + "*" * 73 + " */":
- break
- continue
-
- # Puke it if not a preprocessor directive.
- line = local.lstrip()
- if not local and not buf:
- break
- if not buf and (not line or line[0] != '#'):
- print(local.rstrip(), file=f_out)
- continue
-
- # Check if it's a break.
- if local.rstrip()[-1] == '\\':
- buf += local.rstrip() + '\n'
- continue
- line = buf + local; buf = ''
-
- # Check the operation.
- comp = ' '.join(map(lambda x:x[:-1] if x[-1] == '\\' else x,
- line[1:].splitlines())).split()
- op = comp[0]
- if op == 'include_bits':
- if len(comp) != 2:
- print("ERROR in \"%s\" line %d:\n"%(path_in, nl) + \
- "should have 2 arguments to `include_bits`!",
- file=stderr)
- exit(1)
- name = comp[1]
- if len(name) < 3 or name[0] != '<' or name[-1] != '>':
- print("ERROR line %d: should be used like this:"%nl,
- file=stderr)
- print("#include_bits <name.ext>", file=stderr)
- exit(1)
- name = name[1:-1]
- fst = False
-
- bdeps.append(name)
- if not name in bts:
- if name in newbts: bts[name] = newbts[name]
- else: bts[name] = look_for_bits(name)
-
- fst = False
- for path in bts[name]:
- if not fst: fst = True
- else: print("", file=f_out)
- process(path, f_out, indent, True)
- else:
- if op in ['else', 'elif', 'endif'] \
- and indent > original_indent:
- indent -= 1
- print('#' + ' '*indent + line[1:].lstrip(), end='', file=f_out)
- if op in ['if', 'else', 'elif', 'ifdef', 'ifndef']:
- indent += 1
-
- return bdeps
-
-def make_header(base, name, out_path):
- global ics
-
- try: os.makedirs(os.path.dirname(localpath))
- except FileExistsError: pass
-
- if not should_remake(base, name, out_path):
- ics[name] = cache['inc'][name]
- return
-
- out = open(out_path, 'w')
- head = getheader(os.path.join(base, name))
- # Header.
- print("""\
-/* ****************************************************************************
- * %s -- %s *
- * This file is part of libcarrot.
- * libcarrot is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 3.0 of the License,
- * or (at your option) any later version.
- *
- * libcarrot is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with the libcarrot; if not, see <http://www.gnu.org/licenses/>.
- * ************************************************************************* */
-"""[:-1]%(name, head), file=out)
-
- # Include guard.
- if name[-2:].lower() == '.h':
- inc = name[:-2].upper().replace('/', '_')
- gds = ['_%s_H', '_%s_H_', '__%s_H', '__%s_H__', '_%s', '__%s',
- '__%s_H_INCLUDED__']
- elif name[-4:].lower() == '.hpp':
- inc = name[:-4].upper().replace('/', '_')
- gds = ['_%s_HPP']
- else:
- inc = name.upper().replace('/', '_')
- gds = ['__%s_NOEXT']
-
- max_before = max(map(lambda x:x.find("%s"), gds))
- max_after = max(map(lambda x:len(x) - x.find("%s") + len(inc), gds))
-
- for i in gds:
- before = " "*(max_before - i.find("%s"))
-
- print("#ifndef %s%s"%(before, i%inc), file=out)
- for i in gds:
- before = " "*(max_before - i.find("%s"))
- after = " "*(max_after - (len(i) - i.find("%s") + len(inc)))
-
- print("# define %s%s%s 1"%(before, i%inc, after), file=out)
- print("", file=out)
-
- # Make the main content.
- bdeps = process(os.path.join(base, name), out, 1)
-
- # Make the end.
- print("", file=out)
- for i in gds[::-1]:
- before = " "*(max_before - i.find("%s"))
- print("#endif /* %s%s */"%(before, i%inc), file=out)
- for i in gds:
- before = " "*(max_before - i.find("%s"))
- after = " "*(max_after - (len(i) - i.find("%s") + len(inc)))
-
- print("#ifndef %s%s"%(before, i%inc), file=out)
- print("# define %s%s%s 1"%(before, i%inc, after), file=out)
- print("#endif", file=out)
- out.close()
-
- ics[name] = {'base': base, 'bits': bdeps,
- 'mtim': os.path.getmtime(out_path)}
-#*****************************************************************************#
-# Check if should remake. #
-#*****************************************************************************#
-def __listinc(base):
- ''' List headers (files to process) in a directory. '''
-
- lst = []
- base = os.path.join(base, '')
- for root, _, nms in os.walk(base):
- lst += [os.path.join(root, name)[len(base):] for name in nms \
- if name[0] != '.' and (name[-2:].lower() == '.h' \
- or name[-4:].lower() != '.hpp' or name.find('.') < 0)]
- return lst
-
-def __should_remake(base, name, out_path, c_inc, c_oldbits, c_newbits):
- # Check if is in the cache.
- if not name in c_inc:
- return True
-
-def should_remake(base, name, out_path):
- global newbts, bts
-
- # Check if is in the cache.
- if not name in cache['inc']:
- return True
-
- # Check if the source path is different.
- try: mtim = os.path.getmtime(out_path)
- except: return True
-
- if base != cache['inc'][name]['base']:
- return True
-
- if mtim <= os.path.getmtime(os.path.join(base, name)):
- return True
-
- # Check for all of the bits
- # (only make fs interactions if you're obliged to).
- for nm in cache['inc'][name]['bits']:
- if newbts[nm] != cache['bits'][nm]:
- return True
- for nm in cache['inc'][name]['bits']:
- for bpath in newbts[nm]:
- if mtim <= os.path.getmtime(bpath):
- return True
-
- # Don't forget then to reproduce bits in cache!
- for nm in cache['inc'][name]['bits']:
- if not nm in bts:
- bts[nm] = newbts[nm]
-
- # Check if has been edited since last generation.
- if mtim > cache['inc'][name]['mtim']:
- print("""\
-ERROR: the output file \"%s\" has been edited since last gen.
-Please update the source file in \"%s\", or one of the bits,
-or delete it, and regenerate."""%(name, cache['inc'][name]['base']),
- file=stderr)
- exit(1)
-
- return False
-
-def suph(incdir, incdirs, bitdirs):
- """ Main function for the C super-preprocessor.
- Manages the cache, finds the headers, runs the function for
- each one of them. """
-
- # Open the cache.
- try:
- with open(args.cache) as f:
- cache = yaml.load(f.read())
- if not 'ver' in cache or cache['ver'] != 'bits-krieg':
- raise Exception
- except:
- cache = {}
-
- # Set the basic things in the cache.
- if not 'ver' in cache:
- cache = {'ver': 'bits-krieg'}
- if not 'bits' in cache:
- cache['bits'] = {}
- if not 'inc' in cache:
- cache['inc'] = {}
-
- # Update the new bits.
- newbts = {}
- for name in cache['bits']:
- newbts[name] = look_for_bits(name)
-
- # List includes.
- dirs = []
- names = []
- for base in args.path:
- lst = []
- base = os.path.join(base, '')
- for root, _, nms in os.walk(base):
- lst += [os.path.join(root, name)[len(base):] for name in nms \
- if name[0] != '.' and (name[-2:].lower() == '.h' \
- or name[-4:].lower() != '.hpp' or name.find('.') < 0)]
- for nm in lst:
- if not nm in names:
- dirs.append(base)
- names.append(nm)
- continue
- print('ERROR: "%s" is in "%s" and "%s", exiting"' \
- %(nm, dirs[names.index(nm)], base))
- exit(1)
-
- # Make the output include directory.
- try: os.makedirs(args.out)
- except FileExistsError: pass
-
- # Check for the intruders.
- lst = []
- for root, _, nms in os.walk(args.out):
- lst += [os.path.join(root, name)[len(os.path.join(args.out, '')):] \
- for name in nms]
- for nm in lst:
- if not nm in names:
- os.remove(os.path.join(args.out, nm))
-
- # Make the includes.
- for path in zip(dirs, names):
- localpath = os.path.join(args.out, path[1])
-
- make_header(path[0], path[1], localpath)
-
- # Save the cache.
- with open(args.cache, 'w') as cout:
- print(yaml.dump({'ver': 'bits-krieg', 'bits': bts, 'inc': ics},
- version=(1, 2), width=60), file=cout, end='')
-
-# End of file.
diff --git a/tools/Internals/headers/__init__.py b/tools/Internals/headers/__init__.py
new file mode 100644
index 0000000..7c47580
--- /dev/null
+++ b/tools/Internals/headers/__init__.py
@@ -0,0 +1,4 @@
+#!/usr/bin/env python3
+from .manager import process_headers
+
+# End of file.
diff --git a/tools/Internals/headers/eval.py b/tools/Internals/headers/eval.py
new file mode 100644
index 0000000..eb0eeef
--- /dev/null
+++ b/tools/Internals/headers/eval.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python3
+""" Placeholder. Lephe's working on this. """
+
+def evaluate(expr, known = {}):
+ return None
+
+# End of file.
diff --git a/tools/Internals/headers/manager.py b/tools/Internals/headers/manager.py
new file mode 100644
index 0000000..43def8f
--- /dev/null
+++ b/tools/Internals/headers/manager.py
@@ -0,0 +1,408 @@
+#!/usr/bin/env python3
+""" The include file manager, used for all internal operations.
+ Lists headers, opens them (and bits), updates the cache, and stuff.
+
+ The includes is a dictionary of {name: details}, where details is a
+ dictionary containing the following keys:
+
+ - 'bits': the bits name list.
+ - 'path': the source file's path.
+ - 'mtime': the source file's mtime.
+ - 'mname': the module name.
+ - 'role': the file's role.
+ - 'authors': the copyright list.
+ - 'license': the source file's license.
+ - 'content': the parsed content of the header.
+
+ The bits is a dictionary of {name: [details, ...]}, where each details
+ is a dictionary containing the following keys:
+
+ - 'path': the bit's path.
+ - 'mtime': the bit's mtime.
+ - 'authors': the bit's authors.
+ - 'license': the bit's license.
+ - 'content': the parsed content of the bit.
+"""
+
+import os as _os
+import itertools as _itertools
+
+from .parse import *
+from .output import *
+from .eval import *
+
+from ..topc import *
+from ..copyright import *
+
+class HeaderManager:
+ __VER = 'blitz'
+
+ def __split_path(self, path):
+ """ Split a path. """
+
+ tree, leaf = _os.path.split(path)
+ if not tree: return (leaf,)
+ return self.__split_path(tree) + (leaf,)
+
+ def __init__(self, outdir, modules, cachemgr):
+ """ Initialize the object.
+ Loads all of the includes and bits, checks which ones are to
+ make again, and other cool stuff. """
+
+ # Keep those, they could be useful.
+ self.__outdir = outdir
+ self.__modules = modules
+ self.__cachemgr = cachemgr
+
+ # Get the old includes and bits data from the cache.
+ self.__cache = self.__cachemgr.get('headers', {})
+ if 'magic' not in self.__cache or self.__cache['magic'] != self.__VER:
+ self.__cache.clear()
+ self.__cache['magic'] = self.__VER
+ if not 'bits' in self.__cache:
+ self.__cache['bits'] = {}
+ if not 'inc' in self.__cache:
+ self.__cache['inc'] = {}
+ if not 'out' in self.__cache:
+ self.__cache['out'] = ""
+
+ # Prepare for the includes and the bits.
+ self.__inc = {}
+ self.__bits = {}
+
+ # Optimized/converted includes.
+ self.__made_inc = {}
+
+ # Prepare the updated include and bit information.
+ self.__updated_inc = []
+ self.__updated_bits = []
+
+ # Look for all of the includes.
+ for module_name, module in modules.items():
+ for nm in module.getfiles('include', ext=['h', 'hpp', None]):
+ name = '/'.join(self.__split_path(nm))
+ if name in self.__inc:
+ raise DuplicateHeaderException(name, incs[name][1],
+ module_name)
+
+ path = module.getpath('include', nm)
+ role = module.getrole('include', nm)
+ authors, license = module.getcopyright('include', nm)
+
+ # Check if should remake.
+ updated = False
+ if not name in self.__cache['inc'] \
+ or inc['mtime'] > self.__cache['inc'][name]['mtime']:
+ content = self.__loadinc(path, name)
+ bits = self.__listbits(content)
+ updated = True # XXX: user's will?
+ else:
+ content = cache['inc'][name]['content']
+ bits = cache['inc'][name]['bits']
+
+ for bitname in bits:
+ self.__getbits(bitname)
+ if bitname in self.__updated_bits:
+ updated = True
+ for bit in self.__bits[bitname]:
+ raw = merge_copyrights(\
+ {'authors': authors, 'license': license},
+ {'authors': bit['authors'],
+ 'license': bit['license']})
+ authors = raw['authors']
+ license = raw['license']
+
+ inc = {
+ 'bits': bits,
+ 'path': path,
+ 'mtime': _os.path.getmtime(path),
+ 'mname': module_name,
+ 'role': role,
+ 'authors': authors,
+ 'license': license,
+ 'content': content
+ }
+
+ if name in self.__cache['inc'] \
+ and inc != cache['inc'][name]:
+ updated = True
+
+ if updated:
+ self.__updated_inc.append(name)
+ self.__inc[name] = inc
+
+ def __getbits(self, name):
+ """ Gather the bits corresponding to a name. """
+
+ if name in self.__bits:
+ return self.__bits[name]
+
+ bits = []
+ name_path = name.split('/')
+ name_path = _os.path.join('bits', *name_path)
+
+ gbitcache = self.__cache['bits'][name] \
+ if name in self.__cache['bits'] else []
+
+ for module_name, module in self.__modules.items():
+ # Get the bit.
+ path = module.getpath(name_path)
+ isfl = _os.path.isfile(path)
+ if not isfl: continue
+
+ # Get the bit cache.
+ try:
+ bcache = next(i for i in gbitcache if i['path'] == path)
+ except StopIteration:
+ bcache = {}
+
+ authors, license = module.getcopyright(name_path)
+ mtime = _os.path.getmtime(path)
+
+ if bcache and mtime <= bcache['mtime']:
+ content = bcache['content']
+ else:
+ content = parse_header(path)
+
+ bit = {
+ 'path': path,
+ 'mtime': mtime,
+ 'authors': authors,
+ 'license': license,
+ 'content': content
+ }
+
+ bits.append(bit)
+
+ self.__bits[name] = bits
+ if not name in self.__cache['bits'] \
+ or self.__bits[name] != self.__cache['bits'][name]:
+ self.__updated_bits.append(name)
+
+ return bits
+
+ def save(self):
+ """ Save the data into the cache. """
+
+ self.__cachemgr.set('headers', { \
+ 'bits': self.__bits, 'inc': self.__inc})
+
+ def __loadinc(self, path, name):
+ """ Parse a header file, add the include guards. """
+
+ # Parse the file.
+ content = parse_header(path)
+
+ # Return the content.
+ return content
+
+ def __listbits(self, content):
+ """ List all of the `include_bits` parameters in a parsed file.
+
+ This is very naïve: even behind impossible conditions, it
+ will load the bits, because when this is called, the file
+ content isn't optimized yet (as dependency headers might
+ not be loaded yet). """
+
+ bits = set()
+ for line in content:
+ if type(line) == CppIncludeBits:
+ bits.add(line.name)
+ elif type(line) == CppIf:
+ for expr, ins in line.conds:
+ bits.union(self.__listbits(ins))
+ bits.union(self.__listbits(line.eins))
+ return bits
+
+ def __fusion(self, known, *evolved):
+ """ Fusions reference and all evolutions.
+ Caution: modifies the first entry! """
+
+ # Collect the keys to check.
+ keys = set(known)
+ for e in evolved:
+ keys.union(e)
+
+ for key in keys:
+ # If key is the same in reference and conditions, do not
+ # touch it.
+ if all(key in e and e[key] == known[key] for e in evolved):
+ continue
+
+ # If key has disappeared in at least one of the conditions.
+ if key in known and any(not key in e for e in evolved):
+ del known[key]
+ continue
+
+ # If key is the same in all conditions.
+ if key in evolved[0] and all(key in e \
+ and e[key] == evolved[0][key] for e in evolved[1:]):
+ known[key] = evolved[0][key]
+ elif all(key in e and e[key] != False for e in evolved):
+ known[key] = True
+ elif key in known:
+ del known[key]
+
+ return known
+
+ def __loadbits(self, name):
+ """ Get the content corresponding to a set of bits. """
+
+ ins = []
+ first = True
+ for bit in self.__bits[name]:
+ if not bit['content']: continue
+
+ if first: first = False
+ else: ins += [CppRaw([""])]
+ ins.extend(bit['content'])
+
+ return ins
+
+ def __process_rec(self, content, known={}):
+ """ Process recursively a content, optimize it. """
+
+ made = []
+ for ins in content:
+ if type(ins) == CppDefine:
+ if ins.name in known and known[ins.name] != False:
+ # FIXME: already defined!
+ pass
+ known[ins.name] = ins.expr
+ made.append(ins)
+ elif type(ins) == CppUndef:
+ # XXX: not defined?
+ known[ins.name] = False
+ made.append(ins)
+ elif type(ins) == CppInclude:
+ # FIXME: profile.
+ pass
+ elif type(ins) == CppIncludeBits:
+ sub = self.__loadbits(ins.name)
+ made += self.__process_rec(sub, known)
+ elif type(ins) == CppIf:
+ conds = ins.conds.copy()
+ keep_if = False
+ while True:
+ if not conds:
+ sub = self.__process_rec(ins.eins, known)
+ made += sub
+ break
+
+ cond, sub = conds.pop(0)
+ ev = evaluate(cond, known.copy())
+
+ if ev == False:
+ # always false, just skip.
+ continue
+ elif ev == True:
+ # has been evaluated at always true!
+ sub = self.__process_rec(sub, known)
+ made += sub
+ break
+ else:
+ # result is unknown.
+ # evaluate the rest.
+ keep_if = True
+ conds.insert(0, (cond, sub))
+ break
+
+ # Keep the if.
+ if keep_if:
+ knowns = []
+ for i in range(len(conds)):
+ knowns.append(known.copy())
+ conds[i] = (conds[i][0],
+ self.__process_rec(conds[i][1]), knowns[-1])
+ knowns.append(known.copy())
+ eins = self.__process_rec(ins.eins, knowns[-1])
+
+ # Make it evolve.
+ known = self.__fusion(known, *knowns)
+
+ # Make the 'new' if.
+ newif = CppIf(conds[0][0], conds[0][1])
+ for cond in conds[1:]:
+ newif.addcond(cond[0], cond[1])
+ newif.setelse(eins)
+ made.append(newif)
+ else:
+ made.append(ins)
+
+ return made
+
+ def __makeguards(self, name):
+ # Get the include guard.
+ if name[-2:].lower() == '.h':
+ inc = name[:-2].upper().replace('/', '_')
+ #gds = ['_{}_H']
+ gds = ['_{}_H', '_{}_H', '__{}_H', '__{}_H__', '_{}', '__{}',
+ '__{}_H_INCLUDED__']
+ elif name[-4:].lower() == '.hpp':
+ inc = name[:-4].upper().replace('/', '_')
+ gds = ['_{}_HPP']
+ else:
+ inc = name.upper().replace('/', '_')
+ gds = ['__{}_NOEXT']
+
+ return list(map(lambda gd: gd.format(inc), gds))
+
+ def __processinc(self, name):
+ if name in self.__made_inc:
+ return self.__made_inc[name]
+
+ # Get the content.
+ content = self.__inc[name]['content']
+ gds = self.__makeguards(name)
+
+ # Define the include guards.
+ for gd in gds:
+ content[0:0] = [CppDefine(gd, '1')]
+
+ # Put the if. (one for all defines)
+ conds = ['!defined({})'.format(gds[0])]
+ for gd in gds[1:]:
+ add = '&& !defined({})'.format(gd)
+ if len(conds[-1]) + 1 + len(add) >= 72:
+ conds += ['\t' + add]
+ else:
+ conds[-1] += ' ' + add
+ content = [CppIf(conds, content)]
+
+ # Then check that all of the include guards are defined.
+ if len(gds) >= 2:
+ content.append(CppRaw(['',
+ '/* Make sure the include guards are defined. */', '']))
+ for gd in gds:
+ content.append(CppIf(['!defined({})'.format(gd)],
+ [CppDefine(gd, '1')]))
+
+ # Process through the recursive function.
+ self.__made_inc[name] = self.__process_rec(content)
+ return self.__made_inc[name]
+
+ def makeheader(self, name):
+ """ Make a header. """
+
+ info = self.__inc[name]
+ content = self.__processinc(name)
+ topc = make_top_comment(info['mname'], name, info['role'],
+ info['authors'], info['license'])
+ output_header(topc, content)
+
+ def process(self):
+ self.makeheader('alloca.h')
+ #print(self.__updated_inc)
+ pass
+
+# ---
+# Main function.
+# ---
+
+def process_headers(outdir, modules, cachemgr):
+ """ Process the headers (public function). """
+
+ mgr = HeaderManager(outdir, modules, cachemgr)
+ mgr.process()
+
+# End of file.
diff --git a/tools/Internals/headers/output.py b/tools/Internals/headers/output.py
new file mode 100644
index 0000000..e75833a
--- /dev/null
+++ b/tools/Internals/headers/output.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+""" Output a header. """
+
+import sys as _sys
+import string as _string
+
+from .parse import *
+
+__all__ = ["output_header"]
+
+def __validmacroname(name):
+ return all(c in _string.ascii_letters + '_' for c in name)
+
+def __output_recursive(content, out=_sys.stdout, sep='\n'):
+ """ Output the content in a recursive manner. """
+
+ for ins in content:
+ if type(ins) == CppRaw:
+ nxt = sep.join(ins.content)
+ elif type(ins) == CppDefine:
+ nxt = "#define {}".format(ins.name)
+ if ins.args != None:
+ nxt += "({})".format(', '.join(ins.args))
+ nxt += " {}".format((' \\' + sep).join(ins.expr))
+ elif type(ins) == CppUndef:
+ nxt = "#undef {}".format(ins.name)
+ elif type(ins) == CppInclude:
+ nxt = ins.name
+ if ins.typ == "local":
+ nxt = '"{}"'.format(nxt)
+ elif ins.typ == "path":
+ nxt = '<{}>'.format(nxt)
+ nxt = "#include {}".format(nxt)
+ elif type(ins) == CppError:
+ nxt = '#error "{}"'.format(nxt)
+ elif type(ins) == CppIf:
+ expr = (' \\' + sep).join(ins.conds[0][0])
+ if expr[0:8] == 'defined(' and expr[-1] == ')' \
+ and __validmacroname(expr[8:-1].strip()):
+ print("#ifdef {}".format(expr[8:-1].strip()),
+ end=sep, file=out)
+ elif expr[0:9] == '!defined(' and expr[-1] == ')' \
+ and __validmacroname(expr[9:-1].strip()):
+ print("#ifndef {}".format(expr[9:-1].strip()),
+ end=sep, file=out)
+ else:
+ print("#if {}".format(expr), end=sep, file=out)
+
+ __output_recursive(ins.conds[0][1], out=out, sep=sep)
+
+ for cond, sub in ins.conds[1:]:
+ print('#elif {}'.format(cond[0][0]), *cond[0][1:],
+ sep=sep, end=sep, file=out)
+ __output_recursive(cond[1], out=out, sep=sep)
+
+ nxt = '#endif'
+ else:
+ # We really shouldn't be here.
+ # But in case, here is a way to identify the problem.
+ nxt = '#<{}>'.format(type(ins).__name__)
+
+ print(nxt, end=sep, file=out)
+
+def output_header(topc, content, out=_sys.stdout, sep='\n'):
+ """ Output a header from its parsed form. """
+
+ print(sep.join(topc.split('\n')), end='', file=out)
+ __output_recursive(content, out=out, sep=sep)
+
+# End of file.
diff --git a/tools/Internals/headers/parse.py b/tools/Internals/headers/parse.py
new file mode 100644
index 0000000..227ce99
--- /dev/null
+++ b/tools/Internals/headers/parse.py
@@ -0,0 +1,298 @@
+#!/usr/bin/env python3
+""" Parse a file on the C preprocessor view, with libcarrot extensions.
+
+ The goal of this file is also to 'simplify' the preprocessor tree so
+ that it is valid with K&R C: no '&&' or '||' in #if directives, and
+ no `!=` too, only `==`.
+
+ Returns a directive list. Each directive is a tuple where the first
+ argument is the directive type, among:
+
+ - None: raw text, not a preprocessor instruction.
+ The tuple looks like (None, ["first line", "second line", "wow yeah"]).
+
+ - "include": include a file (in path, local, or using a variable).
+ The tuple looks like ("include", "local", "the/file.h"), where
+ "local" can be replaced by "path" or "expr".
+
+ - "include_bits": include all bits file corresponding to a name.
+ The tuple looks like ("include_bits", dir/bitname.h").
+
+ - "define": define a preprocessor constant or macro.
+ The tuple looks like ("define", "name", ("arg1", "arg2"), "value") with
+ arguments, or ("define", "name", None, "value") otherwise.
+
+ - "undef": if exists, un-define a macro (with or without arguments).
+ The tuple looks like ("undef", "name").
+
+ - "if": the condition. The first element is "if", the second element is
+ the condition tuple, the others except the last one are the elif
+ condition tuples, and the last element is the instructions list.
+ Each condition tuple is made of the expression to evaluate (non zero
+ means the condition is true) and the instructions.
+
+ Check out "The C Programming Language" section 4.11 for more information.
+"""
+
+# ---
+# Objects
+# ---
+
+class CppRaw:
+ def __init__(self, content):
+ self.content = content
+
+ def addcontent(self, content):
+ self.content.extend(content)
+
+class CppDefine:
+ def __init__(self, name, expr, args=None):
+ self.name = name
+ self.args = args
+ self.expr = expr
+
+class CppUndef:
+ def __init__(self, name):
+ self.name = name
+
+class CppInclude:
+ def __init__(self, name, typ):
+ self.name = name
+ self.typ = typ
+
+class CppIncludeBits:
+ def __init__(self, typ, name):
+ self.name = name
+ self.typ = typ
+
+class CppIf:
+ def __init__(self, cond, ins):
+ self.conds = [(cond, ins)]
+ self.eins = []
+
+ def addcond(self, cond, ins):
+ self.conds.append((cond, ins))
+
+ def setelse(self, ins):
+ self.eins = []
+
+class CppError:
+ def __init__(self, message):
+ self.message = message
+
+# ---
+# Parse content.
+# ---
+
+def __readline(src):
+ """ Read one line. """
+
+ lines = []
+ while True:
+ tmp = src.readline()
+ if tmp == '':
+ break
+
+ tmp = tmp.splitlines()[0]
+ hasnext = tmp and tmp[-1] == '\\'
+ lines += [tmp[:-1].rstrip() if hasnext else tmp.rstrip()]
+ if not hasnext:
+ break
+
+ return lines
+
+def __get_source_content(path, syntax='c'):
+ """ Get a source file content after the top comment. """
+
+ if syntax == 'c':
+ is_str = lambda x: x[:3] == '/* ' and \
+ all(c == '*' for c in x[3:])
+ is_end = lambda x: x[:3] == ' * ' and \
+ all(c == '*' for c in x[3:-3]) and x[-3:] == ' */'
+ else:
+ is_str = lambda x: x[0] == '#' and \
+ all(c == '*' for c in x[1:])
+ is_end = isstr
+
+ with open(path) as src:
+ line = __readline(src)
+
+ while True:
+ if not line or (len(line) == 1 and not is_str(line[0])):
+ break
+
+ while True:
+ line = __readline(src)
+ if not line or (len(line) == 1 and is_end(line[0])):
+ break
+
+ line = __readline(src)
+
+ lines = [line]
+ while True:
+ line = __readline(src)
+ if not line: break
+ lines.append(line)
+
+ return lines
+
+# ---
+# Sub-parsing functions.
+# ---
+
+def __parse_define(raw):
+ """ Get the define details out of the string, e.g. "CONSTANT some constant"
+ or "MY_MACRO(and_some, fancy_parameters) and_some - fancy_parameters".
+ Returns either (macro, None, value) or (macro, args, value). """
+
+ raw = '\n'.join(raw)
+
+ first = raw.split()[0]
+ if first.find('(') >= 0:
+ # Is a macro with arguments!
+ name = first.split('(')[0]
+ rest = raw[len(name) + 1:]
+ rpar = rest.find(')')
+ if rpar < 0:
+ raise Exception("Missing ')' in macro parameter list.")
+
+ # Get the argument list.
+ alst = rest[:rpar]
+ if alst.find('(') >= 0:
+ raise Exception("'(' cannot appear in macro list.")
+ args = ()
+ for arg in map(str.strip, alst.split(',')):
+ for c in (c for c in arg if c.isspace()):
+ raise Exception("Macro params. should be spl. using commas.")
+ args = args + (arg,)
+
+ # Get the expression to evaluate, return.
+ rest = rest[rpar + 1:].lstrip()
+ return (name, rest.split('\n'), args)
+
+ rest = raw[len(first) + 1:].lstrip()
+ return (first, rest.split('\n'))
+
+def __parse_name(raw):
+ """ Get a macro name out of a raw string. """
+
+ ret = '\n'.join(raw).strip()
+ # TODO: check that the name is good (ANSI, stuff).
+ return ret
+
+def __parse_header_ref(raw):
+ """ Get the header reference, such as "header.h" (for local references),
+ <header.h> (for path references) or VARIABLE_NAME (for variables). """
+
+ raw = '\n'.join(raw).strip()
+ if raw[0] == '<' and raw[-1] == '>':
+ return ('path', raw[1:-1].strip())
+ if raw[0] == '"' and raw[-1] == '"':
+ return ('local', raw[1:-1].strip())
+ return ('var', __parse_name(raw))
+
+def __get_inst(raw):
+ """ Get the instruction name and its parameters from a line group. """
+
+ full = '\n'.join(raw).lstrip()
+
+ # Check if is a preprocessor directive.
+ if not full or full[0] != '#':
+ return False
+
+ # Get the preprocessor directive.
+ tmp = full[1:].split()
+ if not tmp: return '===SKIP==='
+ inst = tmp[0]
+
+ # Get the rest.
+ rest = full[1:].lstrip()[len(inst):].lstrip()
+ return (inst, rest.split('\n'))
+
+# ---
+# Main parsing function.
+# ---
+
+def __parse_header_rec(lines):
+ """ The recursive function. """
+
+ ins = []
+ while lines:
+ # Get the instruction and arguments.
+ line = lines.pop()
+ result = __get_inst(line)
+ if not result:
+ if not ins or type(ins[-1]) != CppRaw:
+ ins.append(CppRaw(line))
+ else:
+ ins[-1].addcontent(line)
+ continue
+ if result == '===SKIP===':
+ continue
+ inst, rest = result
+
+ # Check using it:
+ # include, define, undef, if, elif, else, ifdef, ifndef
+ #
+ # Extensions: elifdef, elifndef, error
+ if inst == 'include':
+ ins.append(CppInclude(*__parse_header_ref(rest)))
+ elif inst == 'error':
+ ins.append(CppError(rest)) # FIXME: string?
+ elif inst == 'include_bits':
+ ins.append(CppIncludeBits(*__parse_header_ref(rest)))
+ elif inst == 'define':
+ ins.append(CppDefine(*__parse_define(rest)))
+ elif inst == 'undef':
+ ins.append(CppUndef(__parse_name(rest)))
+ elif inst == 'if' or inst == 'ifdef' or inst == 'ifndef':
+ if inst == 'if':
+ ini_check = rest
+ elif inst == 'ifdef':
+ ini_check = 'defined(%s)' % __parse_name(rest)
+ elif inst == 'ifndef':
+ ini_check = '!defined(%s)' % __parse_name(rest)
+ obj = CppIf(ini_check, __parse_header_rec(lines))
+
+ while True:
+ if not lines:
+ raise Exception("#endif expected!")
+ inst, rest = __get_inst(lines.pop())
+ if inst == 'else' or inst == 'endif':
+ break
+
+ sub = __parse_header_rec(lines)
+ if inst == 'elif':
+ check = rest
+ elif inst == 'elifdef':
+ check = 'defined(%s)' % __parse_name(rest)
+ elif inst == 'elifndef':
+ check = '!defined(%s)' % __parse_name(rest)
+ obj.addcond(check, __parse_header_rec(lines))
+
+ if inst == 'else':
+ obj.setelse(__parse_header_rec(lines))
+ if not lines:
+ raise Exception("#endif expected!")
+ inst, rest = __get_inst(lines.pop())
+ if inst != 'endif':
+ raise Exception("#endif expected!")
+ ins.append(obj)
+ elif inst == 'elif' or inst == 'elifdef' or inst == 'elifndef' \
+ or inst == 'else' or inst == 'endif':
+ lines.append(line) # reinsert the line so that it is re-read.
+ break
+ else:
+ # Invalid instruction!
+ raise Exception("Unknown preprocessor directive #%s"%inst)
+
+ return ins
+
+def parse_header(path):
+ """ Parse the header. """
+
+ lines = __get_source_content(path)
+ lines.reverse()
+ return __parse_header_rec(lines)
+
+# End of file.
diff --git a/tools/Internals/headers/profile.py b/tools/Internals/headers/profile.py
new file mode 100644
index 0000000..c93b30c
--- /dev/null
+++ b/tools/Internals/headers/profile.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+""" This file profiles.
+
+"""
+
+def profile(instructions, known = {}):
+ """ Update the known variables. """
+
+ for ins in instructions:
+ typ = ins[0]
+
+ if typ == "include":
+ # TODO: Profile the included file.
+ pass
+ elif typ == "include_bits":
+ # TODO: Profile the included bits.
+ pass
+ elif typ == "define":
+ name, args, value = ins[1:]
+ if name in known:
+ # TODO: hey, already defined!
+ pass
+ else:
+ known[name] = (args, value)
+ elif typ == "undef":
+ name = ins[1]
+ if name in known:
+ known[name] = None
+ elif typ == "if":
+ # Check each conditions.
+ go_with = None
+ conds = ins[1:-1]
+ while conds:
+ check, then_ins = conds[0]
+ typ = checks[0]
+ if typ == "defined" or typ == "!defined":
+ name = check[1]
+ if not name in known:
+ # FIXME: Hey, it is unknown!
+ pass
+ if (typ == "defined" and known[name] != None) \
+ or (typ == "!defined" and known[name] == None):
+ go_with = then_ins
+ break
+ # This check is false.
+ elif typ == "equal":
+ first, second = check[1:]
+ first = __eval(first)
+ second = __eval(second)
+ if False: # TODO: one of them is unknown
+ break
+ if first == second:
+ go_with = then_ins
+
+ # This condition has been evaluated as False,
+ # so just take it off.
+ conds = conds[1:]
+
+ # Look what was going on.
+ if conds:
+ # TODO: A condition has been evaluated as unknown.
+ # Go through all of the instructions in the left conditions,
+ # keeping in mind that we don't know if the final preprocessor
+ # is going to get through here.
+ pass
+ elif go_with:
+ # TODO: A condition has been evaluated as true.
+ # Evaluate these.
+ pass
+ else:
+ # TODO: All conditions have been evaluated as false.
+ # Evaluate the else instructions.
+ go_with = conds[-1]
+ pass
diff --git a/tools/Internals/locales/en_US.yml b/tools/Internals/locales/en_US.yml
index 6edfedc..ebe90e4 100644
--- a/tools/Internals/locales/en_US.yml
+++ b/tools/Internals/locales/en_US.yml
@@ -16,13 +16,12 @@ desc:
configure: >-
Configures libcarrot to adapt it to many kinds of systems.
getcopyright: >-
- Get the copyright of one or more files using the machine-readable
+ Gets the copyright of one or more files using the machine-readable
copyright information files.
make: >-
- Build libcarrot, clean (remove the generated files), install the built
- files, and more operations requiring the library to be configured.
+ Makes various operations requiring the library to be configured.
updatesource: >-
- Update the top comments of the module source, include files and
+ Updates the top comments of the module source, include files and
header bits using the machine-readable copyright and roles files.
prefix:
syntax: "Syntax"
diff --git a/tools/Internals/locales/fr_FR.yml b/tools/Internals/locales/fr_FR.yml
index 9f3c010..5f65826 100644
--- a/tools/Internals/locales/fr_FR.yml
+++ b/tools/Internals/locales/fr_FR.yml
@@ -12,6 +12,11 @@ args:
files: les fichiers à analyser
hide_pub: cacher les fichiers sans copyright
recursive: parcourir les dossiers récursivement
+ config: le chemin vers la configuration de l'utilisateur
+ cache: le chemin vers le fichier de cache
+ include: le dossier de sortie des entêtes C/C++
+ obj: le dossier de sortie des objets
+ command: la commande à exécuter
desc:
configure: >-
Configure la libcarrot pour l'adapter à divers systèmes.
@@ -19,9 +24,7 @@ desc:
Donne les auteurs d'un ou plusieurs fichiers à l'aide des fichiers de
copyright interprétable.
make: >-
- Construit la libcarrot, nettoie (supprime les fichiers générés),
- installe les fichiers construits, et plus d'opérations requérant la
- configuration du projet.
+ Réalise diverses opérations requérant la configuration du projet.
updatesource: >-
Met à jour le commentaire initial des fichiers source, inclus et de
bouts de fichiers inclus en utilisant les fichiers de copyright et de
@@ -87,3 +90,6 @@ exceptions:
"{path}" : le fichier n'existe pas !
IncompatibleLicenses:
Les licences "{first_license}" et "{second_license}" sont incompatibles !
+ DuplicateHeader:
+ Le header '{name}' est à la fois dans les modules '{first_module}' et
+ '{second_module}'.
diff --git a/tools/Internals/module.py b/tools/Internals/module.py
index e44185f..5a76aa3 100755
--- a/tools/Internals/module.py
+++ b/tools/Internals/module.py
@@ -12,6 +12,7 @@ import yaml
from time import time
from .exceptions import *
+from .copyright import *
class SourceModule:
""" The source module class.
@@ -19,7 +20,7 @@ class SourceModule:
with its elements easily.
"""
- def __init__(self, root, name, platform = None, mtim = None):
+ def __init__(self, root, name, platform = None, mtim = None, rules = []):
""" Initialize the class, gather the information from the platform
then the module configuration, and deduce module properties
out of it.
@@ -50,6 +51,7 @@ class SourceModule:
self.root = root
self.name = name
self.__root = root
+ self.__rules = rules
self.mtim = os.path.getmtime(mconfigpath)
# Get the usual things.
@@ -80,7 +82,7 @@ class SourceModule:
pass
def __go_through_dirs(self, roles, prefix=()):
- """ Read a roles file. """
+ """ (internal) Read a roles file. """
elements = {}
for key, element in roles.items():
@@ -88,7 +90,7 @@ class SourceModule:
if type(element) == dict:
elements.update(self.__go_through_dirs(element, key))
else:
- elements[key] = element
+ elements[os.path.join(*key)] = element
return elements
def getpath(self, *elements):
@@ -103,6 +105,21 @@ class SourceModule:
# Join it all and send it back!
return os.path.join(rt, *elements)
+ def getcopyright(self, *elements):
+ """ Get the copyright (using rules). """
+
+ return get_copyright(self.__rules,
+ os.path.join(self.__root, *elements))
+
+ def getrole(self, *elements):
+ """ Get the role of a file. """
+
+ # Split the path.
+ path = os.path.join(*elements)
+ if path in self.roles:
+ return self.roles[path]
+ return "(unknown role)"
+
def getfiles(self, *path, ext=[], full=False):
""" Get the list of files in a directory. """
@@ -131,7 +148,7 @@ class SourcePlatform:
with its element easily.
"""
- def __init__(self, root, name, glob = None, mtim = None):
+ def __init__(self, root, name, glob = None, mtim = None, rules=[]):
""" Initialize the class, gather the information from the platform
configuration, and deduce properties out of it.
@@ -160,6 +177,7 @@ class SourcePlatform:
self.__root = root
self.__name = name
self.__mtim = mtim
+ self.__rules = rules
# Get the properties.
self.description = pconfig['description']
@@ -179,7 +197,7 @@ class SourcePlatform:
if name in self.__loaded:
return self.__loaded[name]
module = SourceModule(os.path.join(self.__root, name),
- '%s/%s'%(self.__name, name), self, self.__mtim)
+ '%s/%s'%(self.__name, name), self, self.__mtim, self.__rules)
self.__loaded[name] = module
return module
@@ -197,7 +215,7 @@ class SourceGlobal:
""" The global source class.
Extracts data from the filesystem. """
- def __init__(self, root, mtim = None):
+ def __init__(self, root, mtim = None, rules = []):
""" Initialize the class, gather the information about the source,
and deduce properties out of it.
@@ -224,6 +242,7 @@ class SourceGlobal:
# Keep the arguments.
self.__root = root
self.__mtim = mtim
+ self.__rules = rules
# Get the properties.
self.version = gconfig['version']
@@ -240,7 +259,7 @@ class SourceGlobal:
return self.__loaded[name]
platform = SourcePlatform(os.path.join(self.__root, name),
- name, self, self.__mtim)
+ name, self, self.__mtim, self.__rules)
self.__loaded[name] = platform
return platform
diff --git a/tools/Internals/tools/gnu_ar.py b/tools/Internals/tools/gnu_ar.py
index 89b4ee0..0510109 100755
--- a/tools/Internals/tools/gnu_ar.py
+++ b/tools/Internals/tools/gnu_ar.py
@@ -18,6 +18,8 @@ import tempfile
from subprocess import call, check_output
from .utils import *
+__all__ = ["GNU_AR"]
+
#*****************************************************************************#
# Discovery, configuration #
#*****************************************************************************#
@@ -82,6 +84,8 @@ def __getparams(typ, arch, lib_format, obj_format):
# Usage #
#*****************************************************************************#
def __pack(params, lib, objs):
+ """ Pack using the GNU archiver. """
+
# Set up the MRI script.
tmp_fd, tmp_path = tempfile.mkstemp(suffix='.mri')
tmp = os.fdopen(tmp_fd, mode='w')
@@ -99,7 +103,9 @@ def __pack(params, lib, objs):
os.remove(tmp_path)
return ret
-__all__ = ["GNU_AR"]
+#*****************************************************************************#
+# Main utility descriptor #
+#*****************************************************************************#
GNU_AR = {
'getparams': __getparams,
'pack': __pack
diff --git a/tools/Internals/tools/gnu_as.py b/tools/Internals/tools/gnu_as.py
index d72d70e..96f2824 100755
--- a/tools/Internals/tools/gnu_as.py
+++ b/tools/Internals/tools/gnu_as.py
@@ -17,6 +17,8 @@ import os
from subprocess import call, check_output
from .utils import *
+__all__ = ["GNU_AS"]
+
#*****************************************************************************#
# Discovery, configuration #
#*****************************************************************************#
@@ -86,6 +88,8 @@ def __getparams(typ, arch, objfmt, syntax):
# Usage #
#*****************************************************************************#
def __asm(params, obj, src):
+ """ Assemble using the GNU assembler. """
+
# Set up the command line.
commandline = [params['path']]
commandline += ['-c', '-o', obj, src]
@@ -94,7 +98,9 @@ def __asm(params, obj, src):
# Make the call.
return call(commandline)
-__all__ = ["GNU_AS"]
+#*****************************************************************************#
+# Main utility descriptor #
+#*****************************************************************************#
GNU_AS = {
'getparams': __getparams,
'asm': __asm
diff --git a/tools/Internals/tools/gnu_gcc.py b/tools/Internals/tools/gnu_gcc.py
index 6e793c1..eddf1fb 100755
--- a/tools/Internals/tools/gnu_gcc.py
+++ b/tools/Internals/tools/gnu_gcc.py
@@ -18,6 +18,8 @@ from subprocess import call, check_output, DEVNULL
from tempfile import mkstemp
from .utils import *
+__all__ = ["GNU_GCC"]
+
#*****************************************************************************#
# Discovery, configuration #
#*****************************************************************************#
@@ -156,9 +158,9 @@ def __asmc(params, obj, src, incdirs):
# Make the call.
return call(commandline, env=__makeenv(incdirs))
-# Main entry.
-
-__all__ = ["GNU_GCC"]
+#*****************************************************************************#
+# Main utility descriptor #
+#*****************************************************************************#
GNU_GCC = {
'getparams': __getparams,
'cc': __cc,
diff --git a/tools/Internals/tools/renesas_asmsh.py b/tools/Internals/tools/renesas_asmsh.py
index ae39561..bbe59a5 100755
--- a/tools/Internals/tools/renesas_asmsh.py
+++ b/tools/Internals/tools/renesas_asmsh.py
@@ -10,6 +10,8 @@ import os, tempfile
from subprocess import call
from .utils import *
+__all__ = ["Renesas_Asmsh"]
+
#*****************************************************************************#
# Discovery, configuration #
#*****************************************************************************#
@@ -72,7 +74,9 @@ def __asm(self, obj, src, incdirs):
os.rename(tmpobj, obj)
return ret
-__all__ = ["Renesas_Asmsh"]
+#*****************************************************************************#
+# Main utility descriptor #
+#*****************************************************************************#
Renesas_Asmsh = {
'getparams': __getparams,
'asm': __asm
diff --git a/tools/Internals/tools/renesas_optlnk.py b/tools/Internals/tools/renesas_optlnk.py
index 29438d8..7d16fa8 100755
--- a/tools/Internals/tools/renesas_optlnk.py
+++ b/tools/Internals/tools/renesas_optlnk.py
@@ -19,6 +19,8 @@ import os, tempfile
from subprocess import call
from .utils import *
+__all__ = ["Renesas_OptLnk"]
+
#*****************************************************************************#
# Discovery, configuration #
#*****************************************************************************#
@@ -60,7 +62,9 @@ def __pack(params, lib, objs):
os.remove(tmpinfo[1])
return ret
-__all__ = ["Renesas_OptLnk"]
+#*****************************************************************************#
+# Main utility descriptor #
+#*****************************************************************************#
Renesas_OptLnk = {
'getparams': __getparams,
'pack': __pack
diff --git a/tools/Internals/tools/renesas_shc.py b/tools/Internals/tools/renesas_shc.py
index 53953f1..29d4b4b 100755
--- a/tools/Internals/tools/renesas_shc.py
+++ b/tools/Internals/tools/renesas_shc.py
@@ -10,6 +10,8 @@ import os
from subprocess import call
from .utils import *
+__all__ = ["Renesas_SHC"]
+
#*****************************************************************************#
# Discovery, configuration #
#*****************************************************************************#
@@ -63,7 +65,7 @@ def __cc(params, obj, src, incdirs, std):
if ret: return ret
def __cxx(self, obj, src, incdirs=[]):
- ''' Compile a C++ file. '''
+ """ Compile a C++ file. """
# Make the temporary thing with all of the subcommands.
tmpinfo = tempfile.mkstemp()
@@ -88,7 +90,9 @@ def __cxx(self, obj, src, incdirs=[]):
os.remove(tmpinfo[1])
return ret
-__all__ = ["Renesas_SHC"]
+#*****************************************************************************#
+# Main utility descriptor #
+#*****************************************************************************#
Renesas_SHC = {
'getparams': __getparams,
'cc': __cc,
diff --git a/tools/Internals/topc.py b/tools/Internals/topc.py
index 8966e94..22885f6 100644
--- a/tools/Internals/topc.py
+++ b/tools/Internals/topc.py
@@ -19,7 +19,7 @@ the Free Software Foundation, either version 3 of the License, or \
This file is distributed in the hope that it will be useful, \
but WITHOUT ANY WARRANTY; without even the implied warranty of \
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \
GNU Lesser General Lesser Public License for more details.
You should have received a copy of the GNU Lesser General Public License \
diff --git a/tools/configure.py b/tools/configure.py
index b12ccba..0632205 100755
--- a/tools/configure.py
+++ b/tools/configure.py
@@ -34,14 +34,25 @@ def __getendian():
#*****************************************************************************#
argparser = CarrotArgumentParser(loc['desc']['configure'])
+def __from_root(*x):
+ return os.path.normpath(os.path.join(os.path.dirname(__file__), '..', *x))
+
# Main arguments.
argparser.add_argument('-v', '/V', '--version', dest='version',
action='store_true', help=loc["args"]["version"])
argparser.add_argument('-q', '--quiet', '/-silent', dest='silent',
action='store_true', help=loc["args"]["quiet"])
-argparser.add_argument('-o', '--output', '/C', '/-config-cache', dest='out',
- default=os.path.join(os.getcwd(), '.config.yml'),
- help=loc["args"]["out"])
+
+# Paths.
+argparser.add_argument('-o', '--output', '--config-cache', dest='out',
+ default=__from_root('.config.yml'), help=loc["args"]["out"])
+argparser.add_argument('-C', '--cache', dest='cache',
+ default=__from_root('.cache.yml'), help=loc["args"]["cache"])
+argparser.add_argument('-i', '/I', '--include',
+ dest='incdir', default=__from_root('include'),
+ help=loc['args']['include'])
+argparser.add_argument('-O', '--obj', dest='objdir',
+ default=__from_root('obj'), help=loc['args']['obj'])
# Build-related configuration elements.
argparser.add_argument('-t', '--target', dest='target', default=None,
@@ -56,62 +67,50 @@ argparser.add_argument('-T', '--tooldir', dest='tooldir', default=None,
# Installation-related elements (TODO).
-argparser.add_argument('--root', help=argparse.SUPPRESS)
-argparser.add_argument('--prefix', help=argparse.SUPPRESS)
-argparser.add_argument('--libdir', help=argparse.SUPPRESS)
-argparser.add_argument('--includedir', help=argparse.SUPPRESS)
+argparser.add_argument('/-root')
+argparser.add_argument('/-prefix')
+argparser.add_argument('/-libdir')
+argparser.add_argument('/-includedir')
# Deprecated and hidden arguments.
-argparser.add_argument('--arch', dest='arch',
- default=__getarch(), help=argparse.SUPPRESS)
-argparser.add_argument('--endian', dest='endian',
- default=__getendian(), help=argparse.SUPPRESS)
-argparser.add_argument('--platform', dest='platform',
- default=__getplatform(), help=argparse.SUPPRESS)
+argparser.add_argument('/-arch', dest='arch', default=__getarch())
+argparser.add_argument('/-endian', dest='endian', default=__getendian())
+argparser.add_argument('/-platform', dest='platform', default=__getplatform())
# Reserved arguments (from the glibc configure script).
-argparser.add_argument('--maintainer', action='store_true',
- help=argparse.SUPPRESS)
-argparser.add_argument('--cache-file', help=argparse.SUPPRESS)
-
-argparser.add_argument('--exec-prefix', help=argparse.SUPPRESS)
-argparser.add_argument('--bindir', help=argparse.SUPPRESS)
-argparser.add_argument('--sbindir', help=argparse.SUPPRESS)
-argparser.add_argument('--libexecdir', help=argparse.SUPPRESS)
-argparser.add_argument('--sysconfdir', help=argparse.SUPPRESS)
-argparser.add_argument('--sharedstatedir', help=argparse.SUPPRESS)
-argparser.add_argument('--localstatedir', help=argparse.SUPPRESS)
-argparser.add_argument('--oldincludedir', help=argparse.SUPPRESS)
-argparser.add_argument('--datarootdir', help=argparse.SUPPRESS)
-argparser.add_argument('--datadir', help=argparse.SUPPRESS)
-argparser.add_argument('--infodir', help=argparse.SUPPRESS)
-argparser.add_argument('--localedir', help=argparse.SUPPRESS)
-argparser.add_argument('--mandir', help=argparse.SUPPRESS)
-argparser.add_argument('--docdir', help=argparse.SUPPRESS)
-argparser.add_argument('--htmldir', help=argparse.SUPPRESS)
-argparser.add_argument('--dvidir', help=argparse.SUPPRESS)
-argparser.add_argument('--pdfdir', help=argparse.SUPPRESS)
-argparser.add_argument('--psdir', help=argparse.SUPPRESS)
-
-argparser.add_argument('--disable-option-checking', action='store_true',
- help=argparse.SUPPRESS)
-argparser.add_argument('--disable-sanity-checks', action='store_true',
- help=argparse.SUPPRESS)
-argparser.add_argument('--enable-shared', action='store_true',
- help=argparse.SUPPRESS)
-argparser.add_argument('--enable-profile', action='store_true',
- help=argparse.SUPPRESS)
-argparser.add_argument('--disable-timezone-tools', action='store_true',
- help=argparse.SUPPRESS)
-argparser.add_argument('--enable-hardcoded-path-in-tests', action='store_true',
- help=argparse.SUPPRESS)
-argparser.add_argument('--enable-stackguard-randomization',
- action='store_true', help=argparse.SUPPRESS)
-argparser.add_argument('--enable-lock-elision', choices=('yes', 'no'),
- default='no', help=argparse.SUPPRESS)
-argparser.add_argument('--disable-hidden-plt', action='store_true',
- help=argparse.SUPPRESS)
+argparser.add_argument('/-maintainer', action='store_true')
+
+argparser.add_argument('/-exec-prefix')
+argparser.add_argument('/-bindir')
+argparser.add_argument('/-sbindir')
+argparser.add_argument('/-libexecdir')
+argparser.add_argument('/-sysconfdir')
+argparser.add_argument('/-sharedstatedir')
+argparser.add_argument('/-localstatedir')
+argparser.add_argument('/-oldincludedir')
+argparser.add_argument('/-datarootdir')
+argparser.add_argument('/-datadir')
+argparser.add_argument('/-infodir')
+argparser.add_argument('/-localedir')
+argparser.add_argument('/-mandir')
+argparser.add_argument('/-docdir')
+argparser.add_argument('/-htmldir')
+argparser.add_argument('/-dvidir')
+argparser.add_argument('/-pdfdir')
+argparser.add_argument('/-psdir')
+
+argparser.add_argument('/-disable-option-checking', action='store_true')
+argparser.add_argument('/-disable-sanity-checks', action='store_true')
+argparser.add_argument('/-enable-shared', action='store_true')
+argparser.add_argument('/-enable-profile', action='store_true')
+argparser.add_argument('/-disable-timezone-tools', action='store_true')
+argparser.add_argument('/-enable-hardcoded-path-in-tests', action='store_true')
+argparser.add_argument('/-enable-stackguard-randomization',
+ action='store_true')
+argparser.add_argument('/-enable-lock-elision', choices=('yes', 'no'),
+ default='no')
+argparser.add_argument('/-disable-hidden-plt', action='store_true')
#*****************************************************************************#
# Write the configuration #
#*****************************************************************************#
@@ -137,7 +136,7 @@ def main():
args.modules = addm
# Get the global source.
- g = SourceGlobal('arch')
+ g = SourceGlobal(__from_root('arch'))
# Check the main configuration.
if args.version:
@@ -167,9 +166,26 @@ def main():
# Write the configuration.
with open(args.out, "w") as out:
- print(yaml.dump({"magic": "potatosdk-1.0", "tools": found_tools,
- "modules": modules, "orig": ' '.join(map(shlex.quote, sys.argv))},
- version=(1, 2), width=60), file=out, end='')
+ # Make the paths configuration.
+ root = os.path.dirname(args.out)
+ paths = {
+ 'source': os.path.relpath('arch', root),
+ 'cache': os.path.relpath(args.cache, root),
+ 'incdir': os.path.relpath(args.incdir, root),
+ 'objdir': os.path.relpath(args.objdir, root)
+ }
+
+ # Make the configuration.
+ config = {
+ 'magic': 'potatosdk-1.0',
+ 'paths': paths,
+ 'tools': found_tools,
+ 'modules': modules,
+ 'orig': ' '.join(map(shlex.quote, sys.argv))
+ }
+
+ # Dump the configuration.
+ print(yaml.dump(config, version=(1, 2), width=60), file=out, end='')
# Tell the user we're done.
if not args.silent:
diff --git a/tools/make.py b/tools/make.py
index a7ea6e8..e928cd7 100755
--- a/tools/make.py
+++ b/tools/make.py
@@ -21,26 +21,21 @@ argparser = CarrotArgumentParser(loc['desc']['make'])
# Set up the arguments.
argparser.add_argument('-c', '--config', dest='config',
- default='.config.yml', help='the build configuration path')
-argparser.add_argument('-C', '--cache', dest='cache',
- default='.cache.yml', help='the make cache')
-
-argparser.add_argument('-i', '/I', '--include',
- dest='incdir', default='include',
- help='the generated include directory')
-argparser.add_argument('-O', '--obj', dest='objdir', default='obj',
- help='the generated objects directory')
-
-argparser.add_argument('command', help='the command to execute')
+ default=os.path.join(os.path.dirname(__file__), '..', '.config.yml'),
+ help=loc['args']['config'])
+argparser.add_argument('command', help=loc['args']['command'])
#*****************************************************************************#
# Commands #
#*****************************************************************************#
def clean(args):
""" Clean the project (remove generated files in order to
force rebuild). """
+
# Remove the caches.
try: os.remove('.makeinc-cache')
except FileNotFoundError: pass
+ try: os.remove('.cache.yml')
+ except FileNotFoundError: pass
# Remove the include folder.
try: rmtree('include')
@@ -60,37 +55,42 @@ def mrproper(args):
# Remove the configuration.
try: os.remove('.config.yml')
except FileNotFoundError: pass
- try: os.remove('build.yml')
- except FileNotFoundError: pass
def build(args):
""" Build the project with the current configuration. """
+
+ # Load the root.
+ # The `os.path.join()` usage here is for directories such as `.`,
+ # to replace `.config.yml` by `./.config.yml` for example.
+ root = os.path.dirname(args.config)
+ configpath = os.path.join(root, os.path.basename(args.config))
+
+ # Load the user configuration.
args.config = yaml.load(open(args.config).read())
+ source_root = os.path.join(root, args.config['paths']['source'])
+ cache_path = os.path.join(root, args.config['paths']['cache'])
+ incdir = os.path.join(root, args.config['paths']['incdir'])
+ objdir = os.path.join(root, args.config['paths']['objdir'])
- # Open the main configuration
- root = os.path.join(os.path.dirname(__file__), '..')
- globalconfig = yaml.load(open(os.path.join(root, "config.yml")).read())
- if 'arch' in globalconfig and not args.arch in globalconfig['arch']:
- print("Unsupported arch for libcarrot")
- exit(0)
- mroot = os.path.normpath(os.path.join(root, globalconfig['modules']))
+ # Load the cache.
+ args.cache = CacheManager(cache_path)
- # Setup the tools.
- tools.setup(args.config['tools'])
+ # Get the copyright rules.
+ rules = get_copyright_rules(root)
+
+ # Get the global source.
+ g = SourceGlobal(source_root, os.path.getmtime(configpath),
+ rules=rules)
# Gather the modules.
- ret, modules = gather_modules(mroot, args.config['modules'],
- os.path.getmtime(os.path.join(root, "build.yml")))
- if ret: return ret
+ modules = g.getmodules(args.config['modules'])
- # Make the include folder.
- incdirs = []; bitdirs = []
- for name, module in map(lambda x:(x, modules[x]), sorted(modules)):
- i, b = module.getpath('include'), module.getpath('bits')
- if os.path.isdir(i): incdirs.append(i)
- if os.path.isdir(b): bitdirs.append(b)
- ret = tools.suph(args.incdir, incdirs, bitdirs)
- if ret: exit(ret)
+ # Make the includes folder.
+ process_headers(incdir, modules, args.cache)
+ return # XXX: temp debug
+
+ # Setup the tools.
+ tools.setup(args.config['tools'])
# Get the maximum header modification time.
# TODO: only check the things for what is actually included in the
diff --git a/tools/updatesource.py b/tools/updatesource.py
index 3e8ac9f..c04910c 100755
--- a/tools/updatesource.py
+++ b/tools/updatesource.py
@@ -28,14 +28,6 @@ def __split_path(path):
if not tree: return (leaf,)
return __split_path(tree) + (leaf,)
-def __get_role(*path, module=None):
- """ Get a path role from a module. """
-
- path = __split_path(os.path.join(*path))
- if not path in module.roles:
- return "(unknown role)"
- return module.roles[path]
-
def __repeat(element):
""" Simple generator that repeateadly repeats a given element. """
@@ -51,7 +43,7 @@ def __get_files(name, module):
fp = map(lambda x: module.getpath(directory, x), lst)
names = map(lambda x: '/'.join(__split_path(x)), lst)
- roles = map(lambda x: __get_role(directory, x, module=module), lst)
+ roles = map(lambda x: module.getrole(directory, x), lst)
files.extend(zip(names, fp, roles, __repeat(name)))
return files
@@ -90,6 +82,8 @@ def main():
swp.write(topc)
swp.write(content)
+ # Comment the next line if you're doing experiments, so that the
+ # source file isn't affected.
os.rename(swap_path, path)
if __name__ == "__main__":