source: rtems-source-builder/source-builder/sb/defaults.py @ c80560d

4.104.114.9
Last change on this file since c80560d was c80560d, checked in by Chris Johns <chrisj@…>, on Nov 5, 2012 at 11:09:40 PM

Move into the source-builder tree.

  • Property mode set to 100644
File size: 24.1 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2010-2012 Chris Johns (chrisj@rtems.org)
4# All rights reserved.
5#
6# This file is part of the RTEMS Tools package in 'rtems-tools'.
7#
8# Permission to use, copy, modify, and/or distribute this software for any
9# purpose with or without fee is hereby granted, provided that the above
10# copyright notice and this permission notice appear in all copies.
11#
12# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20#
21# Determine the defaults and load the specific file.
22#
23
24import glob
25import pprint
26import re
27import os
28
29import error
30import execute
31import path
32
33basepath = 'sb'
34
35#
36# All paths in defaults must be Unix format. Do not store any Windows format
37# paths in the defaults.
38#
39# Every entry must describe the type of checking a host must pass.
40#
41
42defaults = {
43# Nothing
44'nil':                 ('none', 'none', ''),
45
46# Set to invalid values.
47'_bset':               ('none',    'none', ''),
48'name':                ('none',    'none', ''),
49'version':             ('none',    'none', ''),
50'release':             ('none',    'none', ''),
51
52# GNU triples needed to build packages
53'_host':               ('triplet', 'required', ''),
54'_build':              ('triplet', 'required', '%{_host}'),
55'_target':             ('none',    'optional', ''),
56
57# Paths
58'_host_platform':      ('none',    'none',     '%{_host_cpu}-%{_host_vendor}-%{_host_os}%{?_gnu}'),
59'_build':              ('none',    'none',     '%{_host}'),
60'_arch':               ('none',    'none',     '%{_host_arch}'),
61'_sbdir':              ('none',    'none',     ''),
62'_topdir':             ('dir',     'required',  path.shell(os.getcwd())),
63'_configdir':          ('dir',     'optional', '%{_topdir}/config:%{_sbdir}/config'),
64'_tardir':             ('dir',     'optional', '%{_topdir}/tar'),
65'_sourcedir':          ('dir',     'optional', '%{_topdir}/sources'),
66'_patchdir':           ('dir',     'optional', '%{_topdir}/patches:%{_sbdir}/patches'),
67'_builddir':           ('dir',     'optional', '%{_topdir}/build/%{name}-%{version}-%{release}'),
68'_docdir':             ('dir',     'none',     '%{_defaultdocdir}'),
69'_tmppath':            ('dir',     'none',     '%{_topdir}/build/tmp'),
70'_tmproot':            ('dir',     'none',     '%{_tmppath}/source-build-%(%{__id_u} -n)/%{_bset}'),
71'buildroot:':          ('dir',     'none',     '%{_tmppath}/%{name}-root-%(%{__id_u} -n)'),
72'_datadir':            ('dir',     'none',     '%{_prefix}/share'),
73'_defaultdocdir':      ('dir',     'none',     '%{_prefix}/share/doc'),
74'_exeext':             ('none',    'none',     ''),
75'_exec_prefix':        ('dir',     'none',     '%{_prefix}'),
76'_bindir':             ('dir',     'none',     '%{_exec_prefix}/bin'),
77'_sbindir':            ('dir',     'none',     '%{_exec_prefix}/sbin'),
78'_libexecdir':         ('dir',     'none',     '%{_exec_prefix}/libexec'),
79'_datarootdir':        ('dir',     'none',     '%{_prefix}/share'),
80'_datadir':            ('dir',     'none',     '%{_datarootdir}'),
81'_sysconfdir':         ('dir',     'none',     '%{_prefix}/etc'),
82'_sharedstatedir':     ('dir',     'none',     '%{_prefix}/com'),
83'_localstatedir':      ('dir',     'none',     '%{prefix}/var'),
84'_includedir':         ('dir',     'none',     '%{_prefix}/include'),
85'_lib':                ('dir',     'none',     'lib'),
86'_libdir':             ('dir',     'none',     '%{_exec_prefix}/%{_lib}'),
87'_libexecdir':         ('dir',     'none',     '%{_exec_prefix}/libexec'),
88'_mandir':             ('dir',     'none',     '%{_datarootdir}/man'),
89'_infodir':            ('dir',     'none',     '%{_datarootdir}/info'),
90'_localedir':          ('dir',     'none',     '%{_datarootdir}/locale'),
91'_localedir':          ('dir',     'none',     '%{_datadir}/locale'),
92'_localstatedir':      ('dir',     'none',     '%{_prefix}/var'),
93'_prefix':             ('dir',     'none',     '%{_usr}'),
94'_usr':                ('dir',     'none',     '/usr/local'),
95'_usrsrc':             ('dir',     'none',     '%{_usr}/src'),
96'_var':                ('dir',     'none',     '/usr/local/var'),
97'_varrun':             ('dir',     'none',     '%{_var}/run'),
98
99# Defaults, override in platform specific modules.
100'___setup_shell':      ('exe',     'required', '/bin/sh'),
101'__aclocal':           ('exe',     'optional', 'aclocal'),
102'__ar':                ('exe',     'required', 'ar'),
103'__arch_install_post': ('exe',     'none',     '%{nil}'),
104'__as':                ('exe',     'required', 'as'),
105'__autoconf':          ('exe',     'required', 'autoconf'),
106'__autoheader':        ('exe',     'required', 'autoheader'),
107'__automake':          ('exe',     'required', 'automake'),
108'__awk':               ('exe',     'required', 'awk'),
109'__bash':              ('exe',     'optional', '/bin/bash'),
110'__bzip2':             ('exe',     'required', '/usr/bin/bzip2'),
111'__cat':               ('exe',     'required', '/bin/cat'),
112'__cc':                ('exe',     'required', '/usr/bin/gcc'),
113'__chgrp':             ('exe',     'required', '/usr/bin/chgrp'),
114'__chmod':             ('exe',     'required', '/bin/chmod'),
115'__chown':             ('exe',     'required', '/usr/sbin/chown'),
116'__cp':                ('exe',     'required', '/bin/cp'),
117'__cpp':               ('exe',     'none',     '%{__cc} -E'),
118'__cxx':               ('exe',     'required', '/usr/bin/g++'),
119'__grep':              ('exe',     'required', '/usr/bin/grep'),
120'__gzip':              ('exe',     'required', '/usr/bin/gzip'),
121'__id':                ('exe',     'required', '/usr/bin/id'),
122'__id_u':              ('exe',     'none',     '%{__id} -u'),
123'__install':           ('exe',     'required', '/usr/bin/install'),
124'__install_info':      ('exe',     'optional', '/usr/bin/install-info'),
125'__ld':                ('exe',     'required', '/usr/bin/ld'),
126'__ldconfig':          ('exe',     'required', '/sbin/ldconfig'),
127'__ln_s':              ('exe',     'none',     'ln -s'),
128'__make':              ('exe',     'required', 'make'),
129'__mkdir':             ('exe',     'required', '/bin/mkdir'),
130'__mkdir_p':           ('exe',     'none',     '/bin/mkdir -p'),
131'__mv':                ('exe',     'required', '/bin/mv'),
132'__nm':                ('exe',     'required', '/usr/bin/nm'),
133'__objcopy':           ('exe',     'optional', '/usr/bin//objcopy'),
134'__objdump':           ('exe',     'optional', '/usr/bin/objdump'),
135'__patch':             ('exe',     'required', '/usr/bin/patch'),
136'__perl':              ('exe',     'optional', 'perl'),
137'__ranlib':            ('exe',     'required', 'ranlib'),
138'__rm':                ('exe',     'required', '/bin/rm'),
139'__sed':               ('exe',     'required', '/usr/bin/sed'),
140'__setup_post':        ('exe',     'none',     '%{__chmod} -R a+rX,g-w,o-w .'),
141'__sh':                ('exe',     'required', '/bin/sh'),
142'__tar':               ('exe',     'required', '/usr/bin/tar'),
143'__tar_extract':       ('exe',     'none',     '%{__tar} -xvvf'),
144'__unzip':             ('exe',     'required', '/usr/bin/unzip'),
145'__xz':                ('exe',     'required', '/usr/bin/xz'),
146
147# Shell Build Settings.
148'___build_args': ('none', 'none', '-e'),
149'___build_cmd':  ('none', 'none', '%{?_sudo:%{_sudo} }%{?_remsh:%{_remsh} %{_remhost} }%{?_remsudo:%{_remsudo} }%{?_remchroot:%{_remchroot} %{_remroot} }%{___build_shell} %{___build_args}'),
150'___build_post': ('none', 'none', 'exit 0'),
151
152# Prebuild set up script.
153'___build_pre': ('none', 'none', '''# ___build_pre in as set up in defaults.py
154# Directories
155SB_SOURCE_DIR="%{_sourcedir}"
156SB_BUILD_DIR="%{_builddir}"
157SB_OPT_FLAGS="%{optflags}"
158SB_ARCH="%{_arch}"
159SB_OS="%{_os}"
160export SB_SOURCE_DIR SB_BUILD_DIR SB_OPT_FLAGS SB_ARCH SB_OS
161# Documentation
162SB_DOC_DIR="%{_docdir}"
163export SB_DOC_DIR
164# Packages
165SB_PACKAGE_NAME="%{name}"
166SB_PACKAGE_VERSION="%{version}"
167SB_PACKAGE_RELEASE="%{release}"
168export SBPACKAGE_NAME SB_PACKAGE_VERSION SB_PACKAGE_RELEASE
169# Build root directory
170%{?buildroot:SB_BUILD_ROOT="%{buildroot}"}
171export SB_BUILD_ROOT
172# The compiler flags
173%{?_targetcflags:CFLAGS_FOR_TARGET="%{_targetcflags}"}
174%{?_targetcxxflags:CXXFLAGS_FOR_TARGET="%{_targetcxxflags}"}
175export CFLAGS_FOR_TARGET
176# Default environment set up.
177LANG=C
178export LANG
179unset DISPLAY || :
180umask 022
181cd "%{_builddir}"'''),
182'___build_shell': ('none', 'none', '%{?_buildshell:%{_buildshell}}%{!?_buildshell:/bin/sh}'),
183'___build_template': ('none', 'none', '''#!%{___build_shell}
184%{___build_pre}
185%{nil}'''),
186
187# Configure command
188'configure': ('none', 'none', '''
189CFLAGS="${CFLAGS:-%optflags}" ; export CFLAGS ;
190CXXFLAGS="${CXXFLAGS:-%optflags}" ; export CXXFLAGS ;
191FFLAGS="${FFLAGS:-%optflags}" ; export FFLAGS ;
192./configure --build=%{_build} --host=%{_host} \
193      --target=%{_target_platform} \
194      --program-prefix=%{?_program_prefix} \
195      --prefix=%{_prefix} \
196      --exec-prefix=%{_exec_prefix} \
197      --bindir=%{_bindir} \
198      --sbindir=%{_sbindir} \
199      --sysconfdir=%{_sysconfdir} \
200      --datadir=%{_datadir} \
201      --includedir=%{_includedir} \
202      --libdir=%{_libdir} \
203      --libexecdir=%{_libexecdir} \
204      --localstatedir=%{_localstatedir} \
205      --sharedstatedir=%{_sharedstatedir} \
206      --mandir=%{_mandir} \
207      --infodir=%{_infodir}''')
208}
209
210class command_line:
211    """Process the command line in a common way for all Tool Builder commands."""
212
213    _defaults = { 'params'   : [],
214                  'warn-all' : '0',
215                  'quiet'    : '0',
216                  'force'    : '0',
217                  'trace'    : '0',
218                  'dry-run'  : '0',
219                  'no-clean' : '0',
220                  'no-smp'   : '0',
221                  'rebuild'  : '0' }
222
223    #
224    # The define and if it is a path and needs conversion.
225    #
226    _long_opts = { '--prefix'         : ('_prefix', True),
227                   '--prefixbase'     : ('_prefixbase', True),
228                   '--topdir'         : ('_topdir', True),
229                   '--configdir'      : ('_configdir', True),
230                   '--builddir'       : ('_builddir', True),
231                   '--sourcedir'      : ('_sourcedir', True),
232                   '--tmppath'        : ('_tmppath', True),
233                   '--log'            : ('_logfile', False),
234                   '--url'            : ('_url_base', False),
235                   '--targetcflags'   : ('_targetcflags', False),
236                   '--targetcxxflags' : ('_targetcxxflags', False),
237                   '--libstdcxxflags' : ('_libstdcxxflags', False) }
238
239    _long_true_opts = { '--force'    : '_force',
240                        '--trace'    : '_trace',
241                        '--dry-run'  : '_dry_run',
242                        '--warn-all' : '_warn_all',
243                        '--no-clean' : '_no_clean',
244                        '--no-smp'   : '_no_smp',
245                        '--rebuild'  : '_rebuild' }
246
247    _target_triplets = { '--host'   : '_host',
248                         '--build'  : '_build',
249                         '--target' : '_target' }
250
251    def _help(self):
252        print '%s: [options] [args]' % (self.command_name)
253        print 'Source Builder, an RTEMS Tools Project (c) 2012 Chris Johns'
254        print 'Options and arguments:'
255        print '--force                : Create directories that are not present'
256        print '--trace                : Trace the execution (not current used)'
257        print '--dry-run              : Do everything but actually run the build'
258        print '--warn-all             : Generate warnings'
259        print '--no-clean             : Do not clean up the build tree'
260        print '--no-smp               : Run with 1 job and not as many as CPUs'
261        print '--rebuild              : Rebuild (not used)'
262        print '--host                 : Set the host triplet'
263        print '--build                : Set the build triplet'
264        print '--target               : Set the target triplet'
265        print '--prefix path          : Tools build prefix, ie where they are installed'
266        print '--prefixbase path      : '
267        print '--topdir path          : Top of the build tree, default is $PWD'
268        print '--configdir path       : Path to the configuration directory, default: ./config'
269        print '--builddir path        : Path to the build directory, default: ./build'
270        print '--sourcedir path       : Path to the source directory, default: ./source'
271        print '--tmppath path         : Path to the temp directory, default: ./tmp'
272        print '--log file             : Log file where all build out is written too'
273        print '--url url              : URL to look for source'
274        print '--targetcflags flags   : List of C flags for the target code'
275        print '--targetcxxflags flags : List of C++ flags for the target code'
276        print '--libstdcxxflags flags : List of C++ flags to build the target libstdc++ code'
277        print '--with-<label>         : Add the --with-<label> to the build'
278        print '--without-<label>      : Add the --without-<label> to the build'
279        if self.optargs:
280            for a in self.optargs:
281                print '%-22s : %s' % (a, self.optargs[a])
282        raise error.exit()
283
284    def __init__(self, argv, optargs):
285        self.command_path = path.dirname(argv[0])
286        if len(self.command_path) == 0:
287            self.command_path = '.'
288        self.command_name = path.basename(argv[0])
289        self.args = argv[1:]
290        self.optargs = optargs
291        self.defaults = {}
292        for to in command_line._long_true_opts:
293            self.defaults[command_line._long_true_opts[to]] = ('none', 'none', '0')
294        self.defaults['_sbdir'] = ('dir', 'required', path.shell(self.command_path))
295        self._process()
296
297    def __str__(self):
298        def _dict(dd):
299            s = ''
300            ddl = dd.keys()
301            ddl.sort()
302            for d in ddl:
303                s += '  ' + d + ': ' + str(dd[d]) + '\n'
304            return s
305
306        s = 'command: ' + self.command() + \
307            '\nargs: ' + str(self.args) + \
308            '\nopts:\n' + _dict(self.opts)
309
310        return s
311
312    def _process(self):
313
314        def _process_lopt(opt, arg, long_opts, args, values = False):
315            for lo in long_opts:
316                if values and opt.startswith(lo):
317                    equals = opt.find('=')
318                    if equals < 0:
319                        if arg == len(args) - 1:
320                            raise error.general('missing option value: ' + lo)
321                        arg += 1
322                        value = args[arg]
323                    else:
324                        value = opt[equals + 1:]
325                    if type(long_opts[lo]) is tuple:
326                        if long_opts[lo][1]:
327                            value = path.shell(value)
328                        macro = long_opts[lo][0]
329                    else:
330                        macro = long_opts[lo]
331                    return lo, macro, value, arg
332                elif opt == lo:
333                    return lo, long_opts[lo], True, arg
334            return None, None, None, arg
335
336        self.opts = command_line._defaults
337        i = 0
338        while i < len(self.args):
339            a = self.args[i]
340            if a.startswith('-'):
341                if a.startswith('--'):
342                    if a.startswith('--warn-all'):
343                        self.opts['warn-all'] = True
344                    elif a == '--help':
345                        self._help()
346                    else:
347                        lo, macro, value, i = _process_lopt(a, i,
348                                                            command_line._long_true_opts,
349                                                            self.args)
350                        if lo:
351                            self.defaults[macro] = ('none', 'none', '1')
352                            self.opts[lo[2:]] = '1'
353                        else:
354                            lo, macro, value, i = _process_lopt(a, i,
355                                                                command_line._long_opts,
356                                                                self.args, True)
357                            if lo:
358                                self.defaults[macro] = ('none', 'none', value)
359                                self.opts[lo[2:]] = value
360                            else:
361                                #
362                                # The target triplet is 'cpu-vendor-os'.
363                                #
364                                lo, macro, value, i = _process_lopt(a, i,
365                                                                    command_line._target_triplets,
366                                                                    self.args, True)
367                                if lo:
368                                    #
369                                    # This is a target triplet. Run it past config.sub to make
370                                    # make sure it is ok.
371                                    #
372                                    e = execute.capture_execution()
373                                    config_sub = path.join(self.command_path,
374                                                           basepath, 'config.sub')
375                                    exit_code, proc, output = e.shell(config_sub + ' ' + value)
376                                    if exit_code == 0:
377                                        value = output
378                                    self.defaults[macro] = ('triplet', 'none', value)
379                                    self.opts[lo[2:]] = value
380                                    _arch = macro + '_cpu'
381                                    _vendor = macro + '_vendor'
382                                    _os = macro + '_os'
383                                    _arch_value = ''
384                                    _vendor_value = ''
385                                    _os_value = ''
386                                    dash = value.find('-')
387                                    if dash >= 0:
388                                        _arch_value = value[:dash]
389                                        value = value[dash + 1:]
390                                    dash = value.find('-')
391                                    if dash >= 0:
392                                        _vendor_value = value[:dash]
393                                        value = value[dash + 1:]
394                                    if len(value):
395                                        _os_value = value
396                                    self.defaults[_arch] = ('none', 'none', _arch_value)
397                                    self.defaults[_vendor] = ('none', 'none', _vendor_value)
398                                    self.defaults[_os] = ('none', 'none', _os_value)
399                                if not lo and a not in self.optargs:
400                                    raise error.general('invalid argument (try --help): %s' % (a))
401                else:
402                    if a == '-f':
403                        self.opts['force'] = '1'
404                    elif a == '-n':
405                        self.opts['dry-run'] = '1'
406                    elif a == '-q':
407                        self.opts['quiet'] = '1'
408                    elif a == '-?':
409                        self._help()
410                    else:
411                        raise error.general('invalid argument (try --help): %s' % (a))
412            else:
413                self.opts['params'].append(a)
414            i += 1
415
416    def _post_process(self, _defaults):
417        if self.no_smp():
418            _defaults['_smp_mflags'] = ('none', 'none', _defaults['nil'][2])
419        if _defaults['_host'][2] == _defaults['nil'][2]:
420            raise error.general('host not set')
421        return _defaults
422
423    def expand(self, s, _defaults):
424        """Simple basic expander of config file macros."""
425        mf = re.compile(r'%{[^}]+}')
426        expanded = True
427        while expanded:
428            expanded = False
429            for m in mf.findall(s):
430                name = m[2:-1]
431                if name in _defaults:
432                    s = s.replace(m, _defaults[name][2])
433                    expanded = True
434                else:
435                    raise error.general('cannot process default macro: ' + m)
436        return s
437
438    def command(self):
439        return path.join(self.command_path, self.command_name)
440
441    def force(self):
442        return self.opts['force'] != '0'
443
444    def dry_run(self):
445        return self.opts['dry-run'] != '0'
446
447    def set_dry_run(self):
448        self.opts['dry-run'] = '1'
449
450    def quiet(self):
451        return self.opts['quiet'] != '0'
452
453    def trace(self):
454        return self.opts['trace'] != '0'
455
456    def warn_all(self):
457        return self.opts['warn-all'] != '0'
458
459    def no_clean(self):
460        return self.opts['no-clean'] != '0'
461
462    def no_smp(self):
463        return self.opts['no-smp'] != '0'
464
465    def rebuild(self):
466        return self.opts['rebuild'] != '0'
467
468    def params(self):
469        return self.opts['params']
470
471    def get_arg(self, arg):
472        if not arg in self.optargs:
473            raise error.internal('bad arg: %s' % (arg))
474        for a in self.args:
475            if a.startswith(arg):
476                return a
477        return None
478
479    def get_config_files(self, config):
480        #
481        # Convert to shell paths and return shell paths.
482        #
483        # @fixme should this use a passed in set of defaults and not
484        #        not the initial set of values ?
485        #
486        config = path.shell(config)
487        if '*' in config or '?' in config:
488            print config
489            configdir = path.dirname(config)
490            configbase = path.basename(config)
491            if len(configbase) == 0:
492                configbase = '*'
493            if not configbase.endswith('.cfg'):
494                configbase = configbase + '.cfg'
495            if len(configdir) == 0:
496                configdir = self.expand(defaults['_configdir'][2], defaults)
497            configs = []
498            for cp in configdir.split(':'):
499                hostconfigdir = path.host(cp)
500                for f in glob.glob(os.path.join(hostconfigdir, configbase)):
501                    configs += path.shell(f)
502        else:
503            configs = [config]
504        return configs
505
506    def config_files(self):
507        configs = []
508        for config in self.opts['params']:
509            configs.extend(self.get_config_files(config))
510        return configs
511
512    def logfiles(self):
513        if 'log' in self.opts:
514            return self.opts['log'].split(',')
515        return ['stdout']
516
517    def urls(self):
518        if 'url' in self.opts:
519            return self.opts['url'].split(',')
520        return None
521
522    def prefixbase(self):
523        if 'prefixbase' in self.opts:
524            return self.opts['prefixbase']
525        return None
526
527def load(args, optargs = None):
528    """
529    Copy the defaults, get the host specific values and merge them overriding
530    any matching defaults, then create an options object to handle the command
531    line merging in any command line overrides. Finally post process the
532    command line.
533    """
534    d = defaults
535    overrides = None
536    if os.name == 'nt':
537        import windows
538        overrides = windows.load()
539    else:
540        uname = os.uname()
541        try:
542            if uname[0] == 'Darwin':
543                import darwin
544                overrides = darwin.load()
545            elif uname[0] == 'FreeBSD':
546                import freebsd
547                overrides = freebsd.load()
548            elif uname[0] == 'Linux':
549                import linux
550                overrides = linux.load()
551        except:
552            pass
553    if overrides is None:
554        raise error.general('no hosts defaults found; please add')
555    for k in overrides:
556        d[k] = overrides[k]
557    o = command_line(args, optargs)
558    for k in o.defaults:
559        d[k] = o.defaults[k]
560    d = o._post_process(d)
561    return o, d
562
563if __name__ == '__main__':
564    import sys
565    try:
566        _opts, _defaults = load(args = sys.argv)
567        print _opts
568        pprint.pprint(_defaults)
569    except error.general, gerr:
570        print gerr
571        sys.exit(1)
572    except error.internal, ierr:
573        print ierr
574        sys.exit(1)
575    sys.exit(0)
Note: See TracBrowser for help on using the repository browser.