mirror of
https://git.rtems.org/rtems-libbsd/
synced 2025-05-13 05:05:04 +08:00

- Provide support for separate user and kernel include paths in libbsd.py. - Update all added files with a suitable context to build them with. Supported contexts are `kernel` and `user`. - Kernel source use the kernel, CPU, and build header paths in this order. - User source use the user, kernel, CPU and build header paths in this order. The FreeBSD /usr/include tree has some kernel header files installed as well as user land header files. This complicates the separation as some kernel header files are not visible to user land code while other are. This is handled by appending the kernel header paths to the user header paths so user land code will include a user header with the same name as a kernel header over the kernel header but will find a kernel header if there is no matching user header file. Closes #4067
1101 lines
38 KiB
Python
Executable File
1101 lines
38 KiB
Python
Executable File
# SPDX-License-Identifier: BSD-2-Clause
|
|
"""Manage the libbsd build configuration data.
|
|
"""
|
|
|
|
# Copyright (c) 2015, 2020 Chris Johns <chrisj@rtems.org>. All rights reserved.
|
|
#
|
|
# Copyright (c) 2009, 2017 embedded brains GmbH. All rights reserved.
|
|
#
|
|
# embedded brains GmbH
|
|
# Dornierstr. 4
|
|
# 82178 Puchheim
|
|
# Germany
|
|
# <info@embedded-brains.de>
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
from __future__ import print_function
|
|
|
|
import codecs
|
|
import copy
|
|
import difflib
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
#
|
|
# Global controls.
|
|
#
|
|
LIBBSD_DIR = "."
|
|
FreeBSD_DIR = "freebsd-org"
|
|
verboseLevel = 0
|
|
isDryRun = False
|
|
isDiffMode = False
|
|
filesProcessedCount = 0
|
|
filesProcessed = []
|
|
filesTotal = 0
|
|
filesTotalLines = 0
|
|
filesTotalInserts = 0
|
|
filesTotalDeletes = 0
|
|
diffDetails = {}
|
|
|
|
verboseInfo = 1
|
|
verboseDetail = 2
|
|
verboseMoreDetail = 3
|
|
verboseDebug = 4
|
|
|
|
|
|
def verbose(level=verboseInfo):
|
|
return verboseLevel >= level
|
|
|
|
|
|
def changedFileSummary(statsReport=False):
|
|
|
|
global filesTotal, filesTotalLines, filesTotalInserts, filesTotalDeletes
|
|
|
|
if isDiffMode == False:
|
|
if verbose():
|
|
print('%d file(s) were changed:' % (filesProcessedCount))
|
|
for f in sorted(filesProcessed):
|
|
print(' %s' % (f))
|
|
else:
|
|
print('%d file(s) were changed.' % (filesProcessedCount))
|
|
if statsReport:
|
|
print('Stats Report:')
|
|
transparent = filesTotal - len(diffDetails)
|
|
changes = filesTotalInserts + filesTotalDeletes
|
|
opacity = (float(changes) / (filesTotalLines + changes)) * 100.0
|
|
print(' Total File(s):%d Unchanged:%d (%.1f%%) Changed:%d' \
|
|
' Opacity:%5.1f%% Lines:%d Edits:%d (+):%d (-):%d' % \
|
|
(filesTotal, transparent, (float(transparent) / filesTotal) * 100.0, len(diffDetails), \
|
|
opacity, filesTotalLines, changes, filesTotalInserts, filesTotalDeletes))
|
|
#
|
|
# Sort by opacity.
|
|
#
|
|
ordered_diffs = sorted(diffDetails.items(),
|
|
key=lambda diff: diff[1].opacity,
|
|
reverse=True)
|
|
for f in ordered_diffs:
|
|
print(' %s' % (diffDetails[f[0]].status()))
|
|
|
|
|
|
def readFile(name):
|
|
try:
|
|
contents = codecs.open(name,
|
|
mode='r',
|
|
encoding='utf-8',
|
|
errors='ignore').read()
|
|
except UnicodeDecodeError as ude:
|
|
print('error: reading: %s: %s' % (name, ude))
|
|
sys.exit(1)
|
|
return contents
|
|
|
|
|
|
def writeFile(name, contents):
|
|
path = os.path.dirname(name)
|
|
if not os.path.exists(path):
|
|
try:
|
|
os.makedirs(path)
|
|
except OSError as oe:
|
|
print('error: cannot create directory: %s: %s' % (path, oe))
|
|
sys.exit(1)
|
|
try:
|
|
codecs.open(name, mode='w', encoding='utf-8',
|
|
errors='ignore').write(contents)
|
|
except UnicodeDecodeError as ude:
|
|
print('error: write: %s: %s' % (name, ude))
|
|
sys.exit(1)
|
|
|
|
|
|
#
|
|
# A builder error.
|
|
#
|
|
class error(Exception):
|
|
"""Base class for exceptions."""
|
|
def __init__(self, msg):
|
|
self.msg = 'error: %s' % (msg)
|
|
|
|
def set_output(self, msg):
|
|
self.msg = msg
|
|
|
|
def __str__(self):
|
|
return self.msg
|
|
|
|
|
|
#
|
|
# Diff Record
|
|
#
|
|
class diffRecord:
|
|
def __init__(self, src, dst, orig, diff, inserts, deletes):
|
|
self.src = src
|
|
self.dst = dst
|
|
self.orig = orig
|
|
self.diff = diff
|
|
self.lines = len(orig)
|
|
self.inserts = inserts
|
|
self.deletes = deletes
|
|
self.changes = inserts + deletes
|
|
self.opacity = (float(self.changes) /
|
|
(self.lines + self.changes)) * 100.0
|
|
|
|
def __repr__(self):
|
|
return self.src
|
|
|
|
def status(self):
|
|
return 'opacity:%5.1f%% edits:%4d (+):%-4d (-):%-4d %s' % \
|
|
(self.opacity, self.changes, self.inserts, self.deletes, self.src)
|
|
|
|
|
|
#
|
|
# This stuff needs to move to libbsd.py.
|
|
#
|
|
|
|
|
|
# Move target dependent files under a machine directory
|
|
def mapCPUDependentPath(path):
|
|
return path.replace("include/", "include/machine/")
|
|
|
|
|
|
def fixIncludes(data):
|
|
data = re.sub('#include <sys/resource.h>',
|
|
'#include <rtems/bsd/sys/resource.h>', data)
|
|
data = re.sub('#include <sys/unistd.h>',
|
|
'#include <rtems/bsd/sys/unistd.h>', data)
|
|
return data
|
|
|
|
|
|
# revert fixing the include paths inside a C or .h file
|
|
def revertFixIncludes(data):
|
|
data = re.sub('#include <rtems/bsd/', '#include <', data)
|
|
data = re.sub('#include <util.h>', '#include <rtems/bsd/util.h>', data)
|
|
data = re.sub('#include <bsd.h>', '#include <rtems/bsd/bsd.h>', data)
|
|
data = re.sub('#include <zerocopy.h>', '#include <rtems/bsd/zerocopy.h>',
|
|
data)
|
|
data = re.sub('#include <modules.h>', '#include <rtems/bsd/modules.h>',
|
|
data)
|
|
return data
|
|
|
|
|
|
# fix include paths inside a C or .h file
|
|
def fixLocalIncludes(data):
|
|
data = re.sub('#include "opt_([^"]*)"',
|
|
'#include <rtems/bsd/local/opt_\\1>', data)
|
|
data = re.sub('#include "([^"]*)_if.h"',
|
|
'#include <rtems/bsd/local/\\1_if.h>', data)
|
|
data = re.sub('#include "miidevs([^"]*)"',
|
|
'#include <rtems/bsd/local/miidevs\\1>', data)
|
|
data = re.sub('#include "usbdevs([^"]*)"',
|
|
'#include <rtems/bsd/local/usbdevs\\1>', data)
|
|
return data
|
|
|
|
|
|
# revert fixing the include paths inside a C or .h file
|
|
def revertFixLocalIncludes(data):
|
|
data = re.sub('#include <rtems/bsd/local/([^>]*)>', '#include "\\1"', data)
|
|
return data
|
|
|
|
def assertNothing(path):
|
|
pass
|
|
|
|
def assertHeaderFile(path):
|
|
if path[-2] != '.' or path[-1] != 'h':
|
|
print("*** " + path + " does not end in .h")
|
|
print("*** Move it to a C source file list")
|
|
sys.exit(2)
|
|
|
|
|
|
def assertSourceFile(path):
|
|
if path[-2:] != '.c' and path[-2:] != '.S' and path[-3:] != '.cc':
|
|
print("*** " + path + " does not end in .c, .cc or .S")
|
|
print("*** Move it to a header file list")
|
|
sys.exit(2)
|
|
|
|
|
|
def assertHeaderOrSourceFile(path):
|
|
if path[-2] != '.' or (path[-1] != 'h' and path[-1] != 'c'):
|
|
print("*** " + path + " does not end in .h or .c")
|
|
print("*** Move it to another list")
|
|
sys.exit(2)
|
|
|
|
|
|
def diffSource(dstLines, srcLines, src, dst):
|
|
global filesTotal, filesTotalLines, filesTotalInserts, filesTotalDeletes
|
|
#
|
|
# Diff, note there is no line termination on each string. Expand the
|
|
# generator to list because the generator is not reusable.
|
|
#
|
|
diff = list(
|
|
difflib.unified_diff(dstLines,
|
|
srcLines,
|
|
fromfile=src,
|
|
tofile=dst,
|
|
n=5,
|
|
lineterm=''))
|
|
inserts = 0
|
|
deletes = 0
|
|
if len(diff) > 0:
|
|
if src in diffDetails and \
|
|
diffDetails[src].dst != dst and diffDetails[src].diff != diff:
|
|
raise error('repeated diff of file different: src:%s dst:%s' %
|
|
(src, dst))
|
|
for l in diff:
|
|
if l[0] == '-':
|
|
deletes += 1
|
|
elif l[0] == '+':
|
|
inserts += 1
|
|
diffDetails[src] = diffRecord(src, dst, srcLines, diff, inserts,
|
|
deletes)
|
|
|
|
#
|
|
# Count the total files, lines and the level of changes.
|
|
#
|
|
filesTotal += 1
|
|
filesTotalLines += len(srcLines)
|
|
filesTotalInserts += inserts
|
|
filesTotalDeletes += deletes
|
|
|
|
return diff
|
|
|
|
|
|
#
|
|
# Converters provide a way to alter the various types of code. The conversion
|
|
# process filters a file as it is copies from the source path to the
|
|
# destination path. Specialised versions are provided for different types of
|
|
# source.
|
|
#
|
|
class Converter(object):
|
|
def convert(self,
|
|
src,
|
|
dst,
|
|
hasSource=True,
|
|
sourceFilter=None,
|
|
srcContents=None):
|
|
|
|
global filesProcessed, filesProcessedCount
|
|
|
|
if verbose(verboseDebug):
|
|
print("convert: filter:%s: %s -> %s" % \
|
|
(['yes', 'no'][sourceFilter is None], src, dst))
|
|
|
|
#
|
|
# If there is no source raise an error if we expect source else print a
|
|
# warning and do not try and convert.
|
|
#
|
|
if srcContents is None:
|
|
if not os.path.exists(src):
|
|
if hasSource:
|
|
raise error('source not found: %s' % (src))
|
|
else:
|
|
print('warning: no source: %s' % (src))
|
|
return
|
|
|
|
#
|
|
# Files read as a single string if not passed in.
|
|
#
|
|
srcContents = readFile(src)
|
|
|
|
if os.path.exists(dst):
|
|
dstContents = readFile(dst)
|
|
else:
|
|
print('warning: no destination: %s' % (dst))
|
|
dstContents = ''
|
|
|
|
#
|
|
# Filter the source.
|
|
#
|
|
if sourceFilter is not None:
|
|
srcContents = sourceFilter(srcContents)
|
|
|
|
#
|
|
# Split into a list of lines.
|
|
#
|
|
srcLines = srcContents.split(os.linesep)
|
|
dstLines = dstContents.split(os.linesep)
|
|
|
|
if verbose(verboseDebug):
|
|
print('Unified diff: %s (lines:%d)' % (src, len(srcLines)))
|
|
|
|
#
|
|
# Diff, note there is no line termination on each string.
|
|
#
|
|
diff = diffSource(dstLines, srcLines, src, dst)
|
|
|
|
#
|
|
# The diff list is empty if the files are the same.
|
|
#
|
|
if len(diff) > 0:
|
|
|
|
if verbose(verboseDebug):
|
|
print('Unified diff length: %d' % len(diff))
|
|
|
|
filesProcessed += [dst]
|
|
filesProcessedCount += 1
|
|
if isDiffMode == False:
|
|
if verbose(verboseDetail):
|
|
print("UPDATE: %s -> %s" % (src, dst))
|
|
if isDryRun == False:
|
|
writeFile(dst, srcContents)
|
|
else:
|
|
print("diff -u %s %s" % (src, dst))
|
|
for l in diff:
|
|
print(l)
|
|
|
|
|
|
class NoConverter(Converter):
|
|
def convert(self, src, dst, hasSource=True, sourceFilter=None):
|
|
return '/* EMPTY */\n'
|
|
|
|
|
|
class FromFreeBSDToRTEMSHeaderConverter(Converter):
|
|
def sourceFilter(self, data):
|
|
data = fixLocalIncludes(data)
|
|
data = fixIncludes(data)
|
|
return data
|
|
|
|
def convert(self, src, dst):
|
|
sconverter = super(FromFreeBSDToRTEMSHeaderConverter, self)
|
|
sconverter.convert(src, dst, sourceFilter=self.sourceFilter)
|
|
|
|
|
|
class FromFreeBSDToRTEMSUserSpaceHeaderConverter(Converter):
|
|
def sourceFilter(self, data):
|
|
data = fixIncludes(data)
|
|
return data
|
|
|
|
def convert(self, src, dst):
|
|
sconverter = super(FromFreeBSDToRTEMSUserSpaceHeaderConverter, self)
|
|
sconverter.convert(src, dst, sourceFilter=self.sourceFilter)
|
|
|
|
|
|
class FromFreeBSDToRTEMSSourceConverter(Converter):
|
|
def sourceFilter(self, data):
|
|
data = fixLocalIncludes(data)
|
|
data = fixIncludes(data)
|
|
data = '#include <machine/rtems-bsd-kernel-space.h>\n\n' + data
|
|
return data
|
|
|
|
def convert(self, src, dst):
|
|
sconverter = super(FromFreeBSDToRTEMSSourceConverter, self)
|
|
sconverter.convert(src, dst, sourceFilter=self.sourceFilter)
|
|
|
|
|
|
class FromFreeBSDToRTEMSUserSpaceSourceConverter(Converter):
|
|
def sourceFilter(self, data):
|
|
data = fixIncludes(data)
|
|
data = '#include <machine/rtems-bsd-user-space.h>\n\n' + data
|
|
return data
|
|
|
|
def convert(self, src, dst):
|
|
sconverter = super(FromFreeBSDToRTEMSUserSpaceSourceConverter, self)
|
|
sconverter.convert(src, dst, sourceFilter=self.sourceFilter)
|
|
|
|
|
|
class FromRTEMSToFreeBSDHeaderConverter(Converter):
|
|
def sourceFilter(self, data):
|
|
data = revertFixLocalIncludes(data)
|
|
data = revertFixIncludes(data)
|
|
return data
|
|
|
|
def convert(self, src, dst):
|
|
sconverter = super(FromRTEMSToFreeBSDHeaderConverter, self)
|
|
sconverter.convert(src,
|
|
dst,
|
|
hasSource=False,
|
|
sourceFilter=self.sourceFilter)
|
|
|
|
|
|
class FromRTEMSToFreeBSDSourceConverter(Converter):
|
|
def sourceFilter(self, data):
|
|
data = re.sub('#include <machine/rtems-bsd-kernel-space.h>\n\n', '',
|
|
data)
|
|
data = re.sub('#include <machine/rtems-bsd-user-space.h>\n\n', '',
|
|
data)
|
|
data = revertFixLocalIncludes(data)
|
|
data = revertFixIncludes(data)
|
|
return data
|
|
|
|
def convert(self, src, dst):
|
|
sconverter = super(FromRTEMSToFreeBSDSourceConverter, self)
|
|
sconverter.convert(src,
|
|
dst,
|
|
hasSource=False,
|
|
sourceFilter=self.sourceFilter)
|
|
|
|
|
|
#
|
|
# Compose a path based for the various parts of the source tree.
|
|
#
|
|
class PathComposer(object):
|
|
def composeOriginPath(self, path):
|
|
return path
|
|
|
|
def composeLibBSDPath(self, path, prefix):
|
|
return os.path.join(prefix, path)
|
|
|
|
|
|
class FreeBSDPathComposer(PathComposer):
|
|
def composeOriginPath(self, path):
|
|
return os.path.join(FreeBSD_DIR, path)
|
|
|
|
def composeLibBSDPath(self, path, prefix):
|
|
return os.path.join(prefix, 'freebsd', path)
|
|
|
|
|
|
class RTEMSPathComposer(PathComposer):
|
|
def composeOriginPath(self, path):
|
|
return path
|
|
|
|
def composeLibBSDPath(self, path, prefix):
|
|
return os.path.join(prefix, 'rtemsbsd', path)
|
|
|
|
|
|
class LinuxPathComposer(PathComposer):
|
|
def composeOriginPath(self, path):
|
|
return path
|
|
|
|
def composeLibBSDPath(self, path, prefix):
|
|
return os.path.join(prefix, 'linux', path)
|
|
|
|
|
|
class CPUDependentFreeBSDPathComposer(FreeBSDPathComposer):
|
|
def composeLibBSDPath(self, path, prefix):
|
|
path = super(CPUDependentFreeBSDPathComposer,
|
|
self).composeLibBSDPath(path, prefix)
|
|
path = mapCPUDependentPath(path)
|
|
return path
|
|
|
|
|
|
class CPUDependentRTEMSPathComposer(RTEMSPathComposer):
|
|
def composeLibBSDPath(self, path, prefix):
|
|
path = super(CPUDependentRTEMSPathComposer,
|
|
self).composeLibBSDPath(path, prefix)
|
|
path = mapCPUDependentPath(path)
|
|
return path
|
|
|
|
|
|
class CPUDependentLinuxPathComposer(LinuxPathComposer):
|
|
def composeLibBSDPath(self, path, prefix):
|
|
path = super(CPUDependentLinuxPathComposer,
|
|
self).composeLibBSDPath(path, prefix)
|
|
path = mapCPUDependentPath(path)
|
|
return path
|
|
|
|
|
|
class TargetSourceCPUDependentPathComposer(CPUDependentFreeBSDPathComposer):
|
|
def __init__(self, targetCPU, sourceCPU):
|
|
self.targetCPU = targetCPU
|
|
self.sourceCPU = sourceCPU
|
|
|
|
def composeLibBSDPath(self, path, prefix):
|
|
path = super(TargetSourceCPUDependentPathComposer,
|
|
self).composeLibBSDPath(path, prefix)
|
|
path = path.replace(self.sourceCPU, self.targetCPU)
|
|
return path
|
|
|
|
|
|
class BuildSystemComposer(object):
|
|
def __init__(self, includes=None):
|
|
if type(includes) is not list:
|
|
self.includes = [includes]
|
|
else:
|
|
self.includes = includes
|
|
|
|
def __str__(self):
|
|
return ''
|
|
|
|
def getIncludes(self):
|
|
if None in self.includes:
|
|
incs = []
|
|
else:
|
|
incs = self.includes
|
|
return incs
|
|
|
|
def compose(self, path):
|
|
"""A None result means there is nothing to build."""
|
|
return None
|
|
|
|
@staticmethod
|
|
def filesAsDefines(files):
|
|
define_keys = ''
|
|
for f in files:
|
|
f = f.upper()
|
|
for c in '\/-.':
|
|
f = f.replace(c, '_')
|
|
define_keys += ' ' + f
|
|
return define_keys.strip()
|
|
|
|
@staticmethod
|
|
def cflagsIncludes(cflags, includes):
|
|
if type(cflags) is not list:
|
|
if cflags is not None:
|
|
_cflags = cflags.split(' ')
|
|
else:
|
|
_cflags = [None]
|
|
else:
|
|
_cflags = cflags
|
|
if type(includes) is not list:
|
|
_includes = [includes]
|
|
else:
|
|
_includes = includes
|
|
return _cflags, _includes
|
|
|
|
|
|
class SourceFileBuildComposer(BuildSystemComposer):
|
|
def __init__(self, cflags="default", includes=None):
|
|
self.cflags, self.includes = self.cflagsIncludes(cflags, includes)
|
|
|
|
def __str__(self):
|
|
return 'SF: ' + ' '.join(self.getFlags())
|
|
|
|
def compose(self, path):
|
|
flags = self.getFlags()
|
|
return ['sources', flags, ('default', None)], \
|
|
[path], self.cflags, self.includes
|
|
|
|
def getFlags(self):
|
|
return self.cflags + self.getIncludes()
|
|
|
|
|
|
class SourceFileIfHeaderComposer(SourceFileBuildComposer):
|
|
def __init__(self, headers, cflags="default", includes=None):
|
|
if headers is not list:
|
|
headers = [headers]
|
|
self.headers = headers
|
|
super(SourceFileIfHeaderComposer, self).__init__(cflags=cflags,
|
|
includes=includes)
|
|
|
|
def __str__(self):
|
|
return 'SFIH:' + ' '.join(self.getFlags()) + \
|
|
' ' + self.filesAsDefines(self.headers)
|
|
|
|
def compose(self, path):
|
|
r = SourceFileBuildComposer.compose(self, path)
|
|
r[0][2] = (self.filesAsDefines(self.headers), self.headers)
|
|
return r
|
|
|
|
|
|
class TestFragementComposer(BuildSystemComposer):
|
|
def __init__(self,
|
|
testName,
|
|
fileFragments,
|
|
configTest=None,
|
|
runTest=True,
|
|
netTest=False,
|
|
extraLibs=[]):
|
|
self.testName = testName
|
|
self.fileFragments = fileFragments
|
|
self.configTest = configTest
|
|
self.runTest = runTest
|
|
self.netTest = netTest
|
|
self.extraLibs = extraLibs
|
|
|
|
def __str__(self):
|
|
return 'TEST: ' + self.testName
|
|
|
|
def compose(self, path):
|
|
return ['tests', self.testName, ('default', None)], {
|
|
'configTest': self.configTest,
|
|
'files': self.fileFragments,
|
|
'run': self.runTest,
|
|
'net': self.netTest,
|
|
'libs': self.extraLibs
|
|
}
|
|
|
|
|
|
class TestIfHeaderComposer(TestFragementComposer):
|
|
def __init__(self,
|
|
testName,
|
|
headers,
|
|
fileFragments,
|
|
runTest=True,
|
|
netTest=False,
|
|
extraLibs=[]):
|
|
if headers is not list:
|
|
headers = [headers]
|
|
self.headers = headers
|
|
super(TestIfHeaderComposer, self).__init__(testName,
|
|
fileFragments,
|
|
'header',
|
|
runTest=runTest,
|
|
netTest=netTest,
|
|
extraLibs=extraLibs)
|
|
|
|
def compose(self, path):
|
|
r = TestFragementComposer.compose(self, path)
|
|
r[0][2] = (self.filesAsDefines(self.headers), self.headers)
|
|
return r
|
|
|
|
|
|
class TestIfLibraryComposer(TestFragementComposer):
|
|
def __init__(self,
|
|
testName,
|
|
libraries,
|
|
fileFragments,
|
|
runTest=True,
|
|
netTest=False,
|
|
extraLibs=[]):
|
|
if libraries is not list:
|
|
libraries = [libraries]
|
|
self.libraries = libraries
|
|
super(TestIfLibraryComposer, self).__init__(testName,
|
|
fileFragments,
|
|
'library',
|
|
runTest=runTest,
|
|
netTest=netTest,
|
|
extraLibs=extraLibs)
|
|
|
|
def compose(self, path):
|
|
r = TestFragementComposer.compose(self, path)
|
|
r[0][2] = (self.filesAsDefines(self.libraries), self.libraries)
|
|
return r
|
|
|
|
|
|
class KVMSymbolsBuildComposer(BuildSystemComposer):
|
|
def compose(self, path):
|
|
return ['KVMSymbols', 'files', ('default', None)], \
|
|
[path], self.includes
|
|
|
|
|
|
class RPCGENBuildComposer(BuildSystemComposer):
|
|
def compose(self, path):
|
|
return ['RPCGen', 'files', ('default', None)], \
|
|
[path]
|
|
|
|
|
|
class RouteKeywordsBuildComposer(BuildSystemComposer):
|
|
def compose(self, path):
|
|
return ['RouteKeywords', 'files', ('default', None)], \
|
|
[path]
|
|
|
|
|
|
class LexBuildComposer(BuildSystemComposer):
|
|
def __init__(self, sym, dep, cflags=None, includes=None, build=True):
|
|
self.sym = sym
|
|
self.dep = dep
|
|
self.cflags, self.includes = self.cflagsIncludes(cflags, includes)
|
|
self.build = build
|
|
|
|
def compose(self, path):
|
|
d = {
|
|
'file': path,
|
|
'sym': self.sym,
|
|
'dep': self.dep,
|
|
'build': self.build
|
|
}
|
|
if None not in self.cflags:
|
|
d['cflags'] = self.cflags
|
|
if None not in self.includes:
|
|
d['includes'] = self.includes
|
|
return ['lex', path, ('default', None)], d
|
|
|
|
|
|
class YaccBuildComposer(BuildSystemComposer):
|
|
def __init__(self, sym, header, cflags=None, includes=None, build=True):
|
|
self.sym = sym
|
|
self.header = header
|
|
self.cflags, self.includes = self.cflagsIncludes(cflags, includes)
|
|
self.build = build
|
|
|
|
def compose(self, path):
|
|
d = {
|
|
'file': path,
|
|
'sym': self.sym,
|
|
'header': self.header,
|
|
'build': self.build
|
|
}
|
|
if None not in self.cflags:
|
|
d['cflags'] = self.cflags
|
|
if None not in self.includes:
|
|
d['includes'] = self.includes
|
|
return ['yacc', path, ('default', None)], d
|
|
|
|
|
|
class File(object):
|
|
'''A file of source we move backwards and forwards and build.'''
|
|
def __init__(self, space, path, pathComposer, forwardConverter,
|
|
reverseConverter, buildSystemComposer):
|
|
if verbose(verboseMoreDetail):
|
|
print("FILE: %-6s %-50s F:%-45s R:%-45s" % \
|
|
(space, path,
|
|
forwardConverter.__class__.__name__,
|
|
reverseConverter.__class__.__name__))
|
|
self.space = space
|
|
self.path = path
|
|
self.pathComposer = pathComposer
|
|
self.originPath = self.pathComposer.composeOriginPath(self.path)
|
|
self.libbsdPath = self.pathComposer.composeLibBSDPath(
|
|
self.path, LIBBSD_DIR)
|
|
self.forwardConverter = forwardConverter
|
|
self.reverseConverter = reverseConverter
|
|
self.buildSystemComposer = buildSystemComposer
|
|
|
|
def __str__(self):
|
|
out = self.space[0].upper() + ' ' + self.path
|
|
bsc = str(self.buildSystemComposer)
|
|
if len(bsc) > 0:
|
|
out += ' (' + bsc + ')'
|
|
return out
|
|
|
|
def __eq__(self, other):
|
|
state = self.space == other.space
|
|
state = state and (self.path == self.path)
|
|
state = state and (self.pathComposer == self.pathComposer)
|
|
state = state and (self.originPath == self.originPath)
|
|
state = state and (self.forwardConverter == self.forwardConverter)
|
|
state = state and (self.self.reverseConverter == self.self.reverseConverter)
|
|
state = state and (self.buildSystemComposer == self.buildSystemComposer)
|
|
return state
|
|
|
|
def processSource(self, forward):
|
|
if forward:
|
|
if verbose(verboseDetail):
|
|
print("process source: %s => %s" %
|
|
(self.originPath, self.libbsdPath))
|
|
self.forwardConverter.convert(self.originPath, self.libbsdPath)
|
|
else:
|
|
if verbose(verboseDetail):
|
|
print("process source: %s => %s converter:%s" % \
|
|
(self.libbsdPath, self.originPath,
|
|
self.reverseConverter.__class__.__name__))
|
|
self.reverseConverter.convert(self.libbsdPath, self.originPath)
|
|
|
|
def getFragment(self):
|
|
return self.buildSystemComposer.compose(
|
|
self.pathComposer.composeLibBSDPath(self.path, ''))
|
|
|
|
def getPath(self):
|
|
return self.path
|
|
|
|
def getSpace(self):
|
|
return self.space
|
|
|
|
|
|
class Module(object):
|
|
'''Logical group of related files we can perform actions on'''
|
|
def __init__(self, manager, name, enabled=True):
|
|
self.manager = manager
|
|
self.name = name
|
|
self.conditionalOn = "none"
|
|
self.files = []
|
|
self.cpuDependentSourceFiles = {}
|
|
self.dependencies = []
|
|
|
|
def __str__(self):
|
|
out = [self.name + ': conditional-on=' + self.conditionalOn]
|
|
if len(self.dependencies) > 0:
|
|
out += [' Deps: ' + str(len(self.dependencies))]
|
|
out += [' ' + type(d).__name__ for d in self.dependencies]
|
|
if len(self.files) > 0:
|
|
counts = {}
|
|
for f in self.files:
|
|
space = f.getSpace()
|
|
if space not in counts:
|
|
counts[space] = 0
|
|
counts[space] += 1
|
|
count_str = ''
|
|
for space in sorted(counts.keys()):
|
|
count_str += '%s:%d ' % (space[0].upper(), counts[space])
|
|
count_str = count_str[:-1]
|
|
out += [' Files: %d (%s)' % (len(self.files), count_str)]
|
|
out += [' ' + str(f) for f in self.files]
|
|
if len(self.cpuDependentSourceFiles) > 0:
|
|
out += [' CPU Dep: ' + str(len(self.cpuDependentSourceFiles))]
|
|
for cpu in self.cpuDependentSourceFiles:
|
|
out += [' ' + cpu + ':']
|
|
out += [
|
|
' ' + str(f) for f in self.cpuDependentSourceFiles[cpu]
|
|
]
|
|
return os.linesep.join(out)
|
|
|
|
def initCPUDependencies(self, cpu):
|
|
if cpu not in self.cpuDependentSourceFiles:
|
|
self.cpuDependentSourceFiles[cpu] = []
|
|
|
|
def getName(self):
|
|
return self.name
|
|
|
|
def getFiles(self):
|
|
return (f for f in self.files)
|
|
|
|
def processSource(self, direction):
|
|
if verbose(verboseDetail):
|
|
print("process module: %s" % (self.name))
|
|
for f in self.files:
|
|
f.processSource(direction)
|
|
for cpu, files in self.cpuDependentSourceFiles.items():
|
|
for f in files:
|
|
f.processSource(direction)
|
|
|
|
def addFile(self, f):
|
|
if not isinstance(f, File):
|
|
raise TypeError('invalid type for addFiles: %s' % (type(f)))
|
|
self.files += [f]
|
|
|
|
def addFiles(self,
|
|
space,
|
|
newFiles,
|
|
pathComposer,
|
|
forwardConverter,
|
|
reverseConverter,
|
|
assertFile,
|
|
buildSystemComposer=BuildSystemComposer()):
|
|
files = []
|
|
for newFile in newFiles:
|
|
assertFile(newFile)
|
|
files += [
|
|
File(space, newFile, pathComposer, forwardConverter,
|
|
reverseConverter, buildSystemComposer)
|
|
]
|
|
return files
|
|
|
|
def addPlainTextFile(self, files):
|
|
self.files += self.addFiles('user', files,
|
|
FreeBSDPathComposer(), Converter(),
|
|
Converter(), assertNothing)
|
|
|
|
def addKernelSpaceHeaderFiles(self, files):
|
|
self.files += self.addFiles('kernel', files, FreeBSDPathComposer(),
|
|
FromFreeBSDToRTEMSHeaderConverter(),
|
|
FromRTEMSToFreeBSDHeaderConverter(),
|
|
assertHeaderOrSourceFile)
|
|
|
|
def addUserSpaceHeaderFiles(self, files):
|
|
self.files += self.addFiles(
|
|
'user', files, FreeBSDPathComposer(),
|
|
FromFreeBSDToRTEMSUserSpaceHeaderConverter(),
|
|
FromRTEMSToFreeBSDHeaderConverter(), assertHeaderFile)
|
|
|
|
def addRTEMSHeaderFiles(self, files):
|
|
self.files += self.addFiles('user', files, RTEMSPathComposer(),
|
|
NoConverter(), NoConverter(),
|
|
assertHeaderFile)
|
|
|
|
def addLinuxHeaderFiles(self, files):
|
|
self.files += self.addFiles('kernel', files, PathComposer(),
|
|
NoConverter(), NoConverter(),
|
|
assertHeaderFile)
|
|
|
|
def addCPUDependentFreeBSDHeaderFiles(self, files):
|
|
self.files += self.addFiles('kernel', files,
|
|
CPUDependentFreeBSDPathComposer(),
|
|
FromFreeBSDToRTEMSHeaderConverter(),
|
|
FromRTEMSToFreeBSDHeaderConverter(),
|
|
assertHeaderFile)
|
|
|
|
def addCPUDependentLinuxHeaderFiles(self, files):
|
|
self.files += self.addFiles('kernel', files,
|
|
CPUDependentLinuxPathComposer(),
|
|
NoConverter(), NoConverter(),
|
|
assertHeaderFile)
|
|
|
|
def addTargetSourceCPUDependentHeaderFiles(self, targetCPUs, sourceCPU,
|
|
files):
|
|
for cpu in targetCPUs:
|
|
self.files += self.addFiles(
|
|
'kernel', files,
|
|
TargetSourceCPUDependentPathComposer(cpu, sourceCPU),
|
|
FromFreeBSDToRTEMSHeaderConverter(), NoConverter(),
|
|
assertHeaderFile)
|
|
|
|
def addSourceFiles(self, files, sourceFileBuildComposer):
|
|
self.files += self.addFiles('user',
|
|
files, PathComposer(), NoConverter(),
|
|
NoConverter(), assertSourceFile,
|
|
sourceFileBuildComposer)
|
|
|
|
def addKernelSpaceSourceFiles(self, files, sourceFileBuildComposer):
|
|
self.files += self.addFiles('kernel', files, FreeBSDPathComposer(),
|
|
FromFreeBSDToRTEMSSourceConverter(),
|
|
FromRTEMSToFreeBSDSourceConverter(),
|
|
assertSourceFile, sourceFileBuildComposer)
|
|
|
|
def addUserSpaceSourceFiles(self, files, sourceFileBuildComposer):
|
|
self.files += self.addFiles(
|
|
'user', files, FreeBSDPathComposer(),
|
|
FromFreeBSDToRTEMSUserSpaceSourceConverter(),
|
|
FromRTEMSToFreeBSDSourceConverter(), assertSourceFile,
|
|
sourceFileBuildComposer)
|
|
|
|
def addRTEMSKernelSourceFiles(self, files, sourceFileBuildComposer):
|
|
self.files += self.addFiles('kernel', files, RTEMSPathComposer(),
|
|
NoConverter(), NoConverter(),
|
|
assertSourceFile, sourceFileBuildComposer)
|
|
|
|
def addRTEMSUserSourceFiles(self, files, sourceFileBuildComposer):
|
|
self.files += self.addFiles('user', files, RTEMSPathComposer(),
|
|
NoConverter(), NoConverter(),
|
|
assertSourceFile, sourceFileBuildComposer)
|
|
|
|
def addLinuxSourceFiles(self, files, sourceFileBuildComposer):
|
|
self.files += self.addFiles('kernel', files, PathComposer(),
|
|
NoConverter(), NoConverter(),
|
|
assertSourceFile, sourceFileBuildComposer)
|
|
|
|
def addCPUDependentFreeBSDSourceFiles(self, cpus, files,
|
|
sourceFileBuildComposer):
|
|
for cpu in cpus:
|
|
self.initCPUDependencies(cpu)
|
|
self.cpuDependentSourceFiles[cpu] += \
|
|
self.addFiles(
|
|
'kernel', files,
|
|
CPUDependentFreeBSDPathComposer(), FromFreeBSDToRTEMSSourceConverter(),
|
|
FromRTEMSToFreeBSDSourceConverter(), assertSourceFile,
|
|
sourceFileBuildComposer)
|
|
|
|
def addCPUDependentRTEMSSourceFiles(self, cpus, files,
|
|
sourceFileBuildComposer):
|
|
for cpu in cpus:
|
|
self.initCPUDependencies(cpu)
|
|
self.cpuDependentSourceFiles[cpu] += \
|
|
self.addFiles('kernel', files,
|
|
CPUDependentRTEMSPathComposer(), NoConverter(),
|
|
NoConverter(), assertSourceFile,
|
|
sourceFileBuildComposer)
|
|
|
|
def addCPUDependentLinuxSourceFiles(self, cpus, files,
|
|
sourceFileBuildComposer):
|
|
for cpu in cpus:
|
|
self.initCPUDependencies(cpu)
|
|
self.cpuDependentSourceFiles[cpu] += \
|
|
self.addFiles('kernel', files,
|
|
CPUDependentLinuxPathComposer(), NoConverter(),
|
|
NoConverter(), assertSourceFile,
|
|
sourceFileBuildComposer)
|
|
|
|
def addTest(self, testFragementComposer):
|
|
self.files += [
|
|
File('user', testFragementComposer.testName, PathComposer(),
|
|
NoConverter(), NoConverter(), testFragementComposer)
|
|
]
|
|
|
|
def addDependency(self, dep):
|
|
self.dependencies += [dep]
|
|
|
|
|
|
class ModuleManager(object):
|
|
'''A manager for a collection of modules.'''
|
|
def __init__(self):
|
|
self.modules = {}
|
|
self.generator = {}
|
|
self.configuration = {}
|
|
self.setGenerators()
|
|
|
|
def __getitem__(self, key):
|
|
if key not in self.modules:
|
|
raise KeyError('module %s not found' % (key))
|
|
return self.modules[key]
|
|
|
|
def __str__(self):
|
|
out = ['Modules: ' + str(len(self.modules)), '']
|
|
for m in sorted(self.modules):
|
|
out += [str(self.modules[m]), '']
|
|
return os.linesep.join(out)
|
|
|
|
def getAllModules(self):
|
|
if 'modules' in self.configuration:
|
|
return self.configuration['modules']
|
|
return []
|
|
|
|
def getEnabledModules(self):
|
|
if 'modules-enabled' in self.configuration:
|
|
return self.configuration['modules-enabled']
|
|
return []
|
|
|
|
def addModule(self, module):
|
|
self.modules[module.name] = module
|
|
|
|
def processSource(self, direction):
|
|
if verbose(verboseDetail):
|
|
print("process modules:")
|
|
for m in sorted(self.modules):
|
|
self.modules[m].processSource(direction)
|
|
|
|
def setConfiguration(self, config):
|
|
self.configuration = copy.deepcopy(config)
|
|
|
|
def getConfiguration(self):
|
|
return copy.deepcopy(self.configuration)
|
|
|
|
def updateConfiguration(self, config):
|
|
self.configuration.update(config)
|
|
|
|
def setModuleConfigiuration(self):
|
|
mods = sorted(self.modules.keys())
|
|
self.configuration['modules'] = mods
|
|
# Enabled modules are overwritten by config file. Default to all.
|
|
self.configuration['modules-enabled'] = mods
|
|
|
|
def generateBuild(self, only_enabled=True):
|
|
modules_to_process = self.getEnabledModules()
|
|
# Used for copy between FreeBSD and RTEMS
|
|
if only_enabled == False:
|
|
modules_to_process = self.getAllModules()
|
|
for m in modules_to_process:
|
|
if m not in self.modules:
|
|
raise KeyError('enabled module not registered: %s' % (m))
|
|
self.modules[m].generate()
|
|
|
|
def duplicateCheck(self):
|
|
dups = []
|
|
modules_to_check = sorted(self.getAllModules(), reverse=True)
|
|
while len(modules_to_check) > 1:
|
|
mod = modules_to_check.pop()
|
|
for m in modules_to_check:
|
|
if m not in self.modules:
|
|
raise KeyError('enabled module not registered: %s' % (m))
|
|
for fmod in self.modules[mod].getFiles():
|
|
for fm in self.modules[m].getFiles():
|
|
if fmod.getPath() == fm.getPath():
|
|
dups += [(m, mod, fm.getPath(), fm.getSpace())]
|
|
return dups
|
|
|
|
def setGenerators(self):
|
|
self.generator['convert'] = Converter
|
|
self.generator['no-convert'] = NoConverter
|
|
self.generator[
|
|
'from-FreeBSD-to-RTEMS-UserSpaceSourceConverter'] = \
|
|
FromFreeBSDToRTEMSUserSpaceSourceConverter
|
|
self.generator[
|
|
'from-RTEMS-To-FreeBSD-SourceConverter'] = FromRTEMSToFreeBSDSourceConverter
|
|
self.generator['buildSystemComposer'] = BuildSystemComposer
|
|
|
|
self.generator['file'] = File
|
|
|
|
self.generator['path'] = PathComposer
|
|
self.generator['freebsd-path'] = FreeBSDPathComposer
|
|
self.generator['rtems-path'] = RTEMSPathComposer
|
|
self.generator['cpu-path'] = CPUDependentFreeBSDPathComposer
|
|
self.generator[
|
|
'target-src-cpu--path'] = TargetSourceCPUDependentPathComposer
|
|
|
|
self.generator['source'] = SourceFileBuildComposer
|
|
self.generator['test'] = TestFragementComposer
|
|
self.generator['kvm-symbols'] = KVMSymbolsBuildComposer
|
|
self.generator['rpc-gen'] = RPCGENBuildComposer
|
|
self.generator['route-keywords'] = RouteKeywordsBuildComposer
|
|
self.generator['lex'] = LexBuildComposer
|
|
self.generator['yacc'] = YaccBuildComposer
|
|
|
|
self.generator['source-if-header'] = SourceFileIfHeaderComposer
|
|
self.generator['test-if-header'] = TestIfHeaderComposer
|
|
self.generator['test-if-library'] = TestIfLibraryComposer
|