Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers __init__.py Source File

__init__.py

00001 """
00002 mbed SDK
00003 Copyright (c) 2011-2017 ARM Limited
00004 
00005 Licensed under the Apache License, Version 2.0 (the "License");
00006 you may not use this file except in compliance with the License.
00007 You may obtain a copy of the License at
00008 
00009     http://www.apache.org/licenses/LICENSE-2.0
00010 
00011 Unless required by applicable law or agreed to in writing, software
00012 distributed under the License is distributed on an "AS IS" BASIS,
00013 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014 See the License for the specific language governing permissions and
00015 limitations under the License.
00016 
00017 Title: GNU ARM Eclipse (http://gnuarmeclipse.github.io) exporter.
00018 
00019 Description: Creates a managed build project that can be imported by 
00020 the GNU ARM Eclipse plug-ins.
00021 
00022 Author: Liviu Ionescu <ilg@livius.net>
00023 """
00024 
00025 import os
00026 import copy
00027 import tempfile
00028 import shutil
00029 import copy
00030 
00031 from subprocess import call, Popen, PIPE
00032 from os.path import splitext, basename, relpath, dirname, exists, join, dirname
00033 from random import randint
00034 from json import load
00035 
00036 from tools.export.exporters import Exporter, apply_supported_whitelist
00037 from tools.options import list_profiles
00038 from tools.targets import TARGET_MAP
00039 from tools.utils import NotSupportedException
00040 from tools.build_api import prepare_toolchain
00041 
00042 # =============================================================================
00043 
00044 
00045 class UID :
00046     """
00047     Helper class, used to generate unique ids required by .cproject symbols.
00048     """
00049     @property
00050     def id(self):
00051         return "%0.9u" % randint(0, 999999999)
00052 
00053 # Global UID generator instance.
00054 # Passed to the template engine, and referred as {{u.id}}.
00055 # Each invocation generates a new number.
00056 u = UID()
00057 
00058 # =============================================================================
00059 
00060 
00061 POST_BINARY_WHITELIST = set([
00062     "TEENSY3_1Code.binary_hook",
00063     "MCU_NRF51Code.binary_hook",
00064     "LPCTargetCode.lpc_patch",
00065     "LPC4088Code.binary_hook"
00066 ])
00067 
00068 class GNUARMEclipse(Exporter ):
00069     NAME = 'GNU ARM Eclipse'
00070     TOOLCHAIN = 'GCC_ARM'
00071 
00072     @classmethod
00073     def is_target_supported(cls, target_name):
00074         target = TARGET_MAP[target_name]
00075         return apply_supported_whitelist(
00076             cls.TOOLCHAIN, POST_BINARY_WHITELIST, target)
00077 
00078     # override
00079     @property
00080     def flags(self):
00081         """Returns a dictionary of toolchain flags.
00082         Keys of the dictionary are:
00083         cxx_flags    - c++ flags
00084         c_flags      - c flags
00085         ld_flags     - linker flags
00086         asm_flags    - assembler flags
00087         common_flags - common options
00088 
00089         The difference from the parent function is that it does not
00090         add macro definitions, since they are passed separately.
00091         """
00092 
00093         config_header = self.toolchain.get_config_header()
00094         flags = {key + "_flags": copy.deepcopy(value) for key, value
00095                  in self.toolchain.flags.iteritems()}
00096         if config_header:
00097             config_header = relpath(config_header,
00098                                     self.resources.file_basepath[config_header])
00099             flags['c_flags'] += self.toolchain.get_config_option(config_header)
00100             flags['cxx_flags'] += self.toolchain.get_config_option(
00101                 config_header)
00102         return flags
00103 
00104     def toolchain_flags(self, toolchain):
00105         """Returns a dictionary of toolchain flags.
00106         Keys of the dictionary are:
00107         cxx_flags    - c++ flags
00108         c_flags      - c flags
00109         ld_flags     - linker flags
00110         asm_flags    - assembler flags
00111         common_flags - common options
00112 
00113         The difference from the above is that it takes a parameter.
00114         """
00115 
00116         # Note: use the config options from the currently selected toolchain.
00117         config_header = self.toolchain.get_config_header()
00118 
00119         flags = {key + "_flags": copy.deepcopy(value) for key, value
00120                  in toolchain.flags.iteritems()}
00121         if config_header:
00122             config_header = relpath(config_header,
00123                                     self.resources.file_basepath[config_header])
00124             header_options = self.toolchain.get_config_option(config_header)
00125             flags['c_flags'] += header_options
00126             flags['cxx_flags'] += header_options
00127         return flags
00128 
00129     def validate_resources(self):
00130         if not self.resources.linker_script:
00131             raise NotSupportedException("No linker script found.")
00132 
00133     def create_jinja_ctx(self):
00134 
00135         self.validate_resources()
00136 
00137         self.resources.win_to_unix()
00138 
00139         # TODO: use some logger to display additional info if verbose
00140 
00141         libraries = []
00142         # print 'libraries'
00143         # print self.resources.libraries
00144         for lib in self.resources.libraries:
00145             l, _ = splitext(basename(lib))
00146             libraries.append(l[3:])
00147 
00148         self.system_libraries = [
00149             'stdc++', 'supc++', 'm', 'c', 'gcc', 'nosys'
00150         ]
00151 
00152         # Read in all profiles, we'll extract compiler options.
00153         profiles = self.get_all_profiles()
00154 
00155         profile_ids = [s.lower() for s in profiles]
00156         profile_ids.sort()
00157 
00158         # TODO: get the list from existing .cproject
00159         build_folders = [s.capitalize() for s in profile_ids]
00160         build_folders.append('BUILD')
00161         # print build_folders
00162 
00163         objects = [self.filter_dot(s) for s in self.resources.objects]
00164         for bf in build_folders:
00165             objects = [o for o in objects if not o.startswith(bf + '/')]
00166         # print 'objects'
00167         # print objects
00168 
00169         self.compute_exclusions()
00170 
00171         self.include_path = [
00172             self.filter_dot(s) for s in self.resources.inc_dirs]
00173         print 'Include folders: {0}'.format(len(self.include_path))
00174 
00175         self.as_defines = self.toolchain.get_symbols(True)
00176         self.c_defines = self.toolchain.get_symbols()
00177         self.cpp_defines = self.c_defines
00178         print 'Symbols: {0}'.format(len(self.c_defines))
00179 
00180         self.ld_script = self.filter_dot(
00181             self.resources.linker_script)
00182         print 'Linker script: {0}'.format(self.ld_script)
00183 
00184         self.options = {}
00185         for id in profile_ids:
00186 
00187             # There are 4 categories of options, a category common too
00188             # all tools and a specific category for each of the tools.
00189             opts = {}
00190             opts['common'] = {}
00191             opts['as'] = {}
00192             opts['c'] = {}
00193             opts['cpp'] = {}
00194             opts['ld'] = {}
00195 
00196             opts['id'] = id
00197             opts['name'] = opts['id'].capitalize()
00198 
00199             print
00200             print 'Build configuration: {0}'.format(opts['name'])
00201 
00202             profile = profiles[id]
00203 
00204             # A small hack, do not bother with src_path again,
00205             # pass an empty string to avoid crashing.
00206             src_paths = ['']
00207             target_name = self.toolchain.target.name
00208             toolchain = prepare_toolchain(
00209                 src_paths, "", target_name, self.TOOLCHAIN, build_profile=[profile])
00210 
00211             # Hack to fill in build_dir
00212             toolchain.build_dir = self.toolchain.build_dir
00213 
00214             flags = self.toolchain_flags(toolchain)
00215 
00216             print 'Common flags:', ' '.join(flags['common_flags'])
00217             print 'C++ flags:', ' '.join(flags['cxx_flags'])
00218             print 'C flags:', ' '.join(flags['c_flags'])
00219             print 'ASM flags:', ' '.join(flags['asm_flags'])
00220             print 'Linker flags:', ' '.join(flags['ld_flags'])
00221 
00222             # Most GNU ARM Eclipse options have a parent,
00223             # either debug or release.
00224             if '-O0' in flags['common_flags'] or '-Og' in flags['common_flags']:
00225                 opts['parent_id'] = 'debug'
00226             else:
00227                 opts['parent_id'] = 'release'
00228 
00229             self.process_options(opts, flags)
00230 
00231             opts['as']['defines'] = self.as_defines
00232             opts['c']['defines'] = self.c_defines
00233             opts['cpp']['defines'] = self.cpp_defines
00234 
00235             opts['common']['include_paths'] = self.include_path
00236             opts['common']['excluded_folders'] = '|'.join(
00237                 self.excluded_folders)
00238 
00239             opts['ld']['library_paths'] = [
00240                 self.filter_dot(s) for s in self.resources.lib_dirs]
00241 
00242             opts['ld']['object_files'] = objects
00243             opts['ld']['user_libraries'] = libraries
00244             opts['ld']['system_libraries'] = self.system_libraries
00245             opts['ld']['script'] = join(id.capitalize(),
00246                                         "linker-script-%s.ld" % id)
00247             opts['cpp_cmd'] = '"{}"'.format(toolchain.preproc[0]) + " " + " ".join(toolchain.preproc[1:])
00248 
00249             # Unique IDs used in multiple places.
00250             # Those used only once are implemented with {{u.id}}.
00251             uid = {}
00252             uid['config'] = u.id
00253             uid['tool_c_compiler'] = u.id
00254             uid['tool_c_compiler_input'] = u.id
00255             uid['tool_cpp_compiler'] = u.id
00256             uid['tool_cpp_compiler_input'] = u.id
00257 
00258             opts['uid'] = uid
00259 
00260             self.options[id] = opts
00261 
00262         jinja_ctx = {
00263             'name': self.project_name,
00264             'ld_script': self.ld_script,
00265 
00266             # Compiler & linker command line options
00267             'options': self.options,
00268 
00269             # Must be an object with an `id` property, which
00270             # will be called repeatedly, to generate multiple UIDs.
00271             'u': u,
00272         }
00273         return jinja_ctx
00274 
00275     # override
00276     def generate(self):
00277         """
00278         Generate the .project and .cproject files.
00279         """
00280         jinja_ctx = self.create_jinja_ctx()
00281 
00282         print
00283         print 'Create a GNU ARM Eclipse C++ managed project'
00284         print 'Project name: {0}'.format(self.project_name)
00285         print 'Target: {0}'.format(self.toolchain.target.name)
00286         print 'Toolchain: {0}'.format(self.TOOLCHAIN)
00287 
00288         self.gen_file('gnuarmeclipse/.project.tmpl', jinja_ctx,
00289                       '.project', trim_blocks=True, lstrip_blocks=True)
00290         self.gen_file('gnuarmeclipse/.cproject.tmpl', jinja_ctx,
00291                       '.cproject', trim_blocks=True, lstrip_blocks=True)
00292         self.gen_file('gnuarmeclipse/makefile.targets.tmpl', jinja_ctx,
00293                       'makefile.targets', trim_blocks=True, lstrip_blocks=True)
00294         self.gen_file('gnuarmeclipse/mbedignore.tmpl', jinja_ctx, '.mbedignore')
00295 
00296         print
00297         print 'Done. Import the \'{0}\' project in Eclipse.'.format(self.project_name)
00298 
00299     # override
00300     @staticmethod
00301     def build(project_name, log_name="build_log.txt", cleanup=True):
00302         """
00303         Headless build an Eclipse project.
00304 
00305         The following steps are performed:
00306         - a temporary workspace is created, 
00307         - the project is imported,
00308         - a clean build of all configurations is performed and 
00309         - the temporary workspace is removed.
00310 
00311         The build results are in the Debug & Release folders.
00312 
00313         All executables (eclipse & toolchain) must be in the PATH.
00314 
00315         The general method to start a headless Eclipse build is:
00316 
00317         $ eclipse \
00318         --launcher.suppressErrors \
00319         -nosplash \
00320         -application org.eclipse.cdt.managedbuilder.core.headlessbuild \
00321         -data /path/to/workspace \
00322         -import /path/to/project \
00323         -cleanBuild "project[/configuration] | all"
00324         """
00325 
00326         # TODO: possibly use the log file.
00327 
00328         # Create a temporary folder for the workspace.
00329         tmp_folder = tempfile.mkdtemp()
00330 
00331         cmd = [
00332             'eclipse',
00333             '--launcher.suppressErrors',
00334             '-nosplash',
00335             '-application org.eclipse.cdt.managedbuilder.core.headlessbuild',
00336             '-data', tmp_folder,
00337             '-import', os.getcwd(),
00338             '-cleanBuild', project_name
00339         ]
00340 
00341         p = Popen(' '.join(cmd), shell=True, stdout=PIPE, stderr=PIPE)
00342         out, err = p.communicate()
00343         ret_code = p.returncode
00344         stdout_string = "=" * 10 + "STDOUT" + "=" * 10 + "\n"
00345         err_string = "=" * 10 + "STDERR" + "=" * 10 + "\n"
00346         err_string += err
00347 
00348         ret_string = "SUCCESS\n"
00349         if ret_code != 0:
00350             ret_string += "FAILURE\n"
00351 
00352         print "%s\n%s\n%s\n%s" % (stdout_string, out, err_string, ret_string)
00353 
00354         if log_name:
00355             # Write the output to the log file
00356             with open(log_name, 'w+') as f:
00357                 f.write(stdout_string)
00358                 f.write(out)
00359                 f.write(err_string)
00360                 f.write(ret_string)
00361 
00362         # Cleanup the exported and built files
00363         if cleanup:
00364             if exists(log_name):
00365                 os.remove(log_name)
00366             os.remove('.project')
00367             os.remove('.cproject')
00368             if exists('Debug'):
00369                 shutil.rmtree('Debug')
00370             if exists('Release'):
00371                 shutil.rmtree('Release')
00372             if exists('makefile.targets'):
00373                 os.remove('makefile.targets')
00374 
00375         # Always remove the temporary folder.
00376         if exists(tmp_folder):
00377             shutil.rmtree(tmp_folder)
00378 
00379         if ret_code == 0:
00380             # Return Success
00381             return 0
00382 
00383         # Seems like something went wrong.
00384         return -1
00385 
00386    # -------------------------------------------------------------------------
00387 
00388     @staticmethod
00389     def get_all_profiles():
00390         tools_path = dirname(dirname(dirname(__file__)))
00391         file_names = [join(tools_path, "profiles", fn) for fn in os.listdir(
00392             join(tools_path, "profiles")) if fn.endswith(".json")]
00393 
00394         # print file_names
00395 
00396         profile_names = [basename(fn).replace(".json", "")
00397                          for fn in file_names]
00398         # print profile_names
00399 
00400         profiles = {}
00401 
00402         for fn in file_names:
00403             content = load(open(fn))
00404             profile_name = basename(fn).replace(".json", "")
00405             profiles[profile_name] = content
00406 
00407         return profiles
00408 
00409     # -------------------------------------------------------------------------
00410     # Process source files/folders exclusions.
00411 
00412     def compute_exclusions(self):
00413         """
00414         With the project root as the only source folder known to CDT,
00415         based on the list of source files, compute the folders to not
00416         be included in the build.
00417 
00418         The steps are:
00419         - get the list of source folders, as dirname(source_file)
00420         - compute the top folders (subfolders of the project folder)
00421         - iterate all subfolders and add them to a tree, with all 
00422         nodes markes as 'not used'
00423         - iterate the source folders and mark them as 'used' in the
00424         tree, including all intermediate nodes
00425         - recurse the tree and collect all unused folders; descend
00426         the hierarchy only for used nodes
00427         """
00428         source_folders = [self.filter_dot(s) for s in set(dirname(
00429             src) for src in self.resources.c_sources + self.resources.cpp_sources + self.resources.s_sources)]
00430 
00431         self.excluded_folders = set(self.resources.ignored_dirs) - set(self.resources.inc_dirs)
00432         print 'Source folders: {0}, with {1} exclusions'.format(len(source_folders), len(self.excluded_folders))
00433 
00434 
00435     # -------------------------------------------------------------------------
00436 
00437     @staticmethod
00438     def filter_dot(str):
00439         """
00440         Remove the './' prefix, if present.
00441         This function assumes that resources.win_to_unix()
00442         replaced all windows backslashes with slashes.
00443         """
00444         if str == None:
00445             return None
00446         if str[:2] == './':
00447             return str[2:]
00448         return str
00449 
00450     # -------------------------------------------------------------------------
00451 
00452     def dump_tree(self, nodes, depth=0):
00453         for k in nodes.keys():
00454             node = nodes[k]
00455             parent_name = node['parent'][
00456                 'name'] if 'parent' in node.keys() else ''
00457             print '  ' * depth, node['name'], node['is_used'], parent_name
00458             if len(node['children'].keys()) != 0:
00459                 self.dump_tree(node['children'], depth + 1)
00460 
00461     def dump_paths(self, nodes, depth=0):
00462         for k in nodes.keys():
00463             node = nodes[k]
00464             parts = []
00465             while True:
00466                 parts.insert(0, node['name'])
00467                 if 'parent' not in node:
00468                     break
00469                 node = node['parent']
00470             path = '/'.join(parts)
00471             print path, nodes[k]['is_used']
00472             self.dump_paths(nodes[k]['children'], depth + 1)
00473 
00474     # -------------------------------------------------------------------------
00475 
00476     def process_options(self, opts, flags_in):
00477         """
00478         CDT managed projects store lots of build options in separate
00479         variables, with separate IDs in the .cproject file.
00480         When the CDT build is started, all these options are brought
00481         together to compose the compiler and linker command lines.
00482 
00483         Here the process is reversed, from the compiler and linker
00484         command lines, the options are identified and various flags are
00485         set to control the template generation process.
00486 
00487         Once identified, the options are removed from the command lines.
00488 
00489         The options that were not identified are options that do not 
00490         have CDT equivalents and will be passed in the 'Other options' 
00491         categories.
00492 
00493         Although this process does not have a very complicated logic,
00494         given the large number of explicit configuration options
00495         used by the GNU ARM Eclipse managed build plug-in, it is tedious...
00496         """
00497 
00498         # Make a copy of the flags, to be one by one removed after processing.
00499         flags = copy.deepcopy(flags_in)
00500 
00501         if False:
00502             print
00503             print 'common_flags', flags['common_flags']
00504             print 'asm_flags', flags['asm_flags']
00505             print 'c_flags', flags['c_flags']
00506             print 'cxx_flags', flags['cxx_flags']
00507             print 'ld_flags', flags['ld_flags']
00508 
00509         # Initialise the 'last resort' options where all unrecognised
00510         # options will be collected.
00511         opts['as']['other'] = ''
00512         opts['c']['other'] = ''
00513         opts['cpp']['other'] = ''
00514         opts['ld']['other'] = ''
00515 
00516         MCPUS = {
00517             'Cortex-M0': {'mcpu': 'cortex-m0', 'fpu_unit': None},
00518             'Cortex-M0+': {'mcpu': 'cortex-m0plus', 'fpu_unit': None},
00519             'Cortex-M1': {'mcpu': 'cortex-m1', 'fpu_unit': None},
00520             'Cortex-M3': {'mcpu': 'cortex-m3', 'fpu_unit': None},
00521             'Cortex-M4': {'mcpu': 'cortex-m4', 'fpu_unit': None},
00522             'Cortex-M4F': {'mcpu': 'cortex-m4', 'fpu_unit': 'fpv4spd16'},
00523             'Cortex-M7': {'mcpu': 'cortex-m7', 'fpu_unit': None},
00524             'Cortex-M7F': {'mcpu': 'cortex-m7', 'fpu_unit': 'fpv4spd16'},
00525             'Cortex-M7FD': {'mcpu': 'cortex-m7', 'fpu_unit': 'fpv5d16'},
00526             'Cortex-A9': {'mcpu': 'cortex-a9', 'fpu_unit': 'vfpv3'}
00527         }
00528 
00529         # Remove options that are supplied by CDT
00530         self.remove_option(flags['common_flags'], '-c')
00531         self.remove_option(flags['common_flags'], '-MMD')
00532 
00533         # As 'plan B', get the CPU from the target definition.
00534         core = self.toolchain.target.core
00535 
00536         opts['common']['arm.target.family'] = None
00537 
00538         # cortex-m0, cortex-m0-small-multiply, cortex-m0plus,
00539         # cortex-m0plus-small-multiply, cortex-m1, cortex-m1-small-multiply,
00540         # cortex-m3, cortex-m4, cortex-m7.
00541         str = self.find_options(flags['common_flags'], '-mcpu=')
00542         if str != None:
00543             opts['common']['arm.target.family'] = str[len('-mcpu='):]
00544             self.remove_option(flags['common_flags'], str)
00545             self.remove_option(flags['ld_flags'], str)
00546         else:
00547             if core not in MCPUS:
00548                 raise NotSupportedException(
00549                     'Target core {0} not supported.'.format(core))
00550             opts['common']['arm.target.family'] = MCPUS[core]['mcpu']
00551 
00552         opts['common']['arm.target.arch'] = 'none'
00553         str = self.find_options(flags['common_flags'], '-march=')
00554         arch = str[len('-march='):]
00555         archs = {'armv6-m': 'armv6-m', 'armv7-m': 'armv7-m', 'armv7-a': 'armv7-a'}
00556         if arch in archs:
00557             opts['common']['arm.target.arch'] = archs[arch]
00558             self.remove_option(flags['common_flags'], str)
00559 
00560         opts['common']['arm.target.instructionset'] = 'thumb'
00561         if '-mthumb' in flags['common_flags']:
00562             self.remove_option(flags['common_flags'], '-mthumb')
00563             self.remove_option(flags['ld_flags'], '-mthumb')
00564         elif '-marm' in flags['common_flags']:
00565             opts['common']['arm.target.instructionset'] = 'arm'
00566             self.remove_option(flags['common_flags'], '-marm')
00567             self.remove_option(flags['ld_flags'], '-marm')
00568 
00569         opts['common']['arm.target.thumbinterwork'] = False
00570         if '-mthumb-interwork' in flags['common_flags']:
00571             opts['common']['arm.target.thumbinterwork'] = True
00572             self.remove_option(flags['common_flags'], '-mthumb-interwork')
00573 
00574         opts['common']['arm.target.endianness'] = None
00575         if '-mlittle-endian' in flags['common_flags']:
00576             opts['common']['arm.target.endianness'] = 'little'
00577             self.remove_option(flags['common_flags'], '-mlittle-endian')
00578         elif '-mbig-endian' in flags['common_flags']:
00579             opts['common']['arm.target.endianness'] = 'big'
00580             self.remove_option(flags['common_flags'], '-mbig-endian')
00581 
00582         opts['common']['arm.target.fpu.unit'] = None
00583         # default, fpv4spd16, fpv5d16, fpv5spd16
00584         str = self.find_options(flags['common_flags'], '-mfpu=')
00585         if str != None:
00586             fpu = str[len('-mfpu='):]
00587             fpus = {
00588                 'fpv4-sp-d16': 'fpv4spd16',
00589                 'fpv5-d16': 'fpv5d16',
00590                 'fpv5-sp-d16': 'fpv5spd16'
00591             }
00592             if fpu in fpus:
00593                 opts['common']['arm.target.fpu.unit'] = fpus[fpu]
00594 
00595                 self.remove_option(flags['common_flags'], str)
00596                 self.remove_option(flags['ld_flags'], str)
00597         if opts['common']['arm.target.fpu.unit'] == None:
00598             if core not in MCPUS:
00599                 raise NotSupportedException(
00600                     'Target core {0} not supported.'.format(core))
00601             if MCPUS[core]['fpu_unit']:
00602                 opts['common'][
00603                     'arm.target.fpu.unit'] = MCPUS[core]['fpu_unit']
00604 
00605         # soft, softfp, hard.
00606         str = self.find_options(flags['common_flags'], '-mfloat-abi=')
00607         if str != None:
00608             opts['common']['arm.target.fpu.abi'] = str[
00609                 len('-mfloat-abi='):]
00610             self.remove_option(flags['common_flags'], str)
00611             self.remove_option(flags['ld_flags'], str)
00612 
00613         opts['common']['arm.target.unalignedaccess'] = None
00614         if '-munaligned-access' in flags['common_flags']:
00615             opts['common']['arm.target.unalignedaccess'] = 'enabled'
00616             self.remove_option(flags['common_flags'], '-munaligned-access')
00617         elif '-mno-unaligned-access' in flags['common_flags']:
00618             opts['common']['arm.target.unalignedaccess'] = 'disabled'
00619             self.remove_option(flags['common_flags'], '-mno-unaligned-access')
00620 
00621         # Default optimisation level for Release.
00622         opts['common']['optimization.level'] = '-Os'
00623 
00624         # If the project defines an optimisation level, it is used
00625         # only for the Release configuration, the Debug one used '-Og'.
00626         str = self.find_options(flags['common_flags'], '-O')
00627         if str != None:
00628             levels = {
00629                 '-O0': 'none', '-O1': 'optimize', '-O2': 'more',
00630                 '-O3': 'most', '-Os': 'size', '-Og': 'debug'
00631             }
00632             if str in levels:
00633                 opts['common']['optimization.level'] = levels[str]
00634                 self.remove_option(flags['common_flags'], str)
00635 
00636         include_files = []
00637         for all_flags in [flags['common_flags'], flags['c_flags'], flags['cxx_flags']]:
00638             while '-include' in all_flags:
00639                 ix = all_flags.index('-include')
00640                 str = all_flags[ix + 1]
00641                 if str not in include_files:
00642                     include_files.append(str)
00643                 self.remove_option(all_flags, '-include')
00644                 self.remove_option(all_flags, str)
00645 
00646         opts['common']['include_files'] = include_files
00647 
00648         if '-ansi' in flags['c_flags']:
00649             opts['c']['compiler.std'] = '-ansi'
00650             self.remove_option(flags['c_flags'], str)
00651         else:
00652             str = self.find_options(flags['c_flags'], '-std')
00653             std = str[len('-std='):]
00654             c_std = {
00655                 'c90': 'c90', 'c89': 'c90', 'gnu90': 'gnu90', 'gnu89': 'gnu90',
00656                 'c99': 'c99', 'c9x': 'c99', 'gnu99': 'gnu99', 'gnu9x': 'gnu98',
00657                 'c11': 'c11', 'c1x': 'c11', 'gnu11': 'gnu11', 'gnu1x': 'gnu11'
00658             }
00659             if std in c_std:
00660                 opts['c']['compiler.std'] = c_std[std]
00661                 self.remove_option(flags['c_flags'], str)
00662 
00663         if '-ansi' in flags['cxx_flags']:
00664             opts['cpp']['compiler.std'] = '-ansi'
00665             self.remove_option(flags['cxx_flags'], str)
00666         else:
00667             str = self.find_options(flags['cxx_flags'], '-std')
00668             std = str[len('-std='):]
00669             cpp_std = {
00670                 'c++98': 'cpp98', 'c++03': 'cpp98',
00671                 'gnu++98': 'gnucpp98', 'gnu++03': 'gnucpp98',
00672                 'c++0x': 'cpp0x', 'gnu++0x': 'gnucpp0x',
00673                 'c++11': 'cpp11', 'gnu++11': 'gnucpp11',
00674                 'c++1y': 'cpp1y', 'gnu++1y': 'gnucpp1y',
00675                 'c++14': 'cpp14', 'gnu++14': 'gnucpp14',
00676                 'c++1z': 'cpp1z', 'gnu++1z': 'gnucpp1z',
00677             }
00678             if std in cpp_std:
00679                 opts['cpp']['compiler.std'] = cpp_std[std]
00680                 self.remove_option(flags['cxx_flags'], str)
00681 
00682         # Common optimisation options.
00683         optimization_options = {
00684             '-fmessage-length=0': 'optimization.messagelength',
00685             '-fsigned-char': 'optimization.signedchar',
00686             '-ffunction-sections': 'optimization.functionsections',
00687             '-fdata-sections': 'optimization.datasections',
00688             '-fno-common': 'optimization.nocommon',
00689             '-fno-inline-functions': 'optimization.noinlinefunctions',
00690             '-ffreestanding': 'optimization.freestanding',
00691             '-fno-builtin': 'optimization.nobuiltin',
00692             '-fsingle-precision-constant': 'optimization.spconstant',
00693             '-fPIC': 'optimization.PIC',
00694             '-fno-move-loop-invariants': 'optimization.nomoveloopinvariants',
00695         }
00696 
00697         for option in optimization_options:
00698             opts['common'][optimization_options[option]] = False
00699             if option in flags['common_flags']:
00700                 opts['common'][optimization_options[option]] = True
00701                 self.remove_option(flags['common_flags'], option)
00702 
00703         # Common warning options.
00704         warning_options = {
00705             '-fsyntax-only': 'warnings.syntaxonly',
00706             '-pedantic': 'warnings.pedantic',
00707             '-pedantic-errors': 'warnings.pedanticerrors',
00708             '-w': 'warnings.nowarn',
00709             '-Wunused': 'warnings.unused',
00710             '-Wuninitialized': 'warnings.uninitialized',
00711             '-Wall': 'warnings.allwarn',
00712             '-Wextra': 'warnings.extrawarn',
00713             '-Wmissing-declarations': 'warnings.missingdeclaration',
00714             '-Wconversion': 'warnings.conversion',
00715             '-Wpointer-arith': 'warnings.pointerarith',
00716             '-Wpadded': 'warnings.padded',
00717             '-Wshadow': 'warnings.shadow',
00718             '-Wlogical-op': 'warnings.logicalop',
00719             '-Waggregate-return': 'warnings.agreggatereturn',
00720             '-Wfloat-equal': 'warnings.floatequal',
00721             '-Werror': 'warnings.toerrors',
00722         }
00723 
00724         for option in warning_options:
00725             opts['common'][warning_options[option]] = False
00726             if option in flags['common_flags']:
00727                 opts['common'][warning_options[option]] = True
00728                 self.remove_option(flags['common_flags'], option)
00729 
00730         # Common debug options.
00731         debug_levels = {
00732             '-g': 'default',
00733             '-g1': 'minimal',
00734             '-g3': 'max',
00735         }
00736         opts['common']['debugging.level'] = 'none'
00737         for option in debug_levels:
00738             if option in flags['common_flags']:
00739                 opts['common'][
00740                     'debugging.level'] = debug_levels[option]
00741                 self.remove_option(flags['common_flags'], option)
00742 
00743         debug_formats = {
00744             '-ggdb': 'gdb',
00745             '-gstabs': 'stabs',
00746             '-gstabs+': 'stabsplus',
00747             '-gdwarf-2': 'dwarf2',
00748             '-gdwarf-3': 'dwarf3',
00749             '-gdwarf-4': 'dwarf4',
00750             '-gdwarf-5': 'dwarf5',
00751         }
00752 
00753         opts['common']['debugging.format'] = ''
00754         for option in debug_levels:
00755             if option in flags['common_flags']:
00756                 opts['common'][
00757                     'debugging.format'] = debug_formats[option]
00758                 self.remove_option(flags['common_flags'], option)
00759 
00760         opts['common']['debugging.prof'] = False
00761         if '-p' in flags['common_flags']:
00762             opts['common']['debugging.prof'] = True
00763             self.remove_option(flags['common_flags'], '-p')
00764 
00765         opts['common']['debugging.gprof'] = False
00766         if '-pg' in flags['common_flags']:
00767             opts['common']['debugging.gprof'] = True
00768             self.remove_option(flags['common_flags'], '-gp')
00769 
00770         # Assembler options.
00771         opts['as']['usepreprocessor'] = False
00772         while '-x' in flags['asm_flags']:
00773             ix = flags['asm_flags'].index('-x')
00774             str = flags['asm_flags'][ix + 1]
00775 
00776             if str == 'assembler-with-cpp':
00777                 opts['as']['usepreprocessor'] = True
00778             else:
00779                 # Collect all other assembler options.
00780                 opts['as']['other'] += ' -x ' + str
00781 
00782             self.remove_option(flags['asm_flags'], '-x')
00783             self.remove_option(flags['asm_flags'], 'assembler-with-cpp')
00784 
00785         opts['as']['nostdinc'] = False
00786         if '-nostdinc' in flags['asm_flags']:
00787             opts['as']['nostdinc'] = True
00788             self.remove_option(flags['asm_flags'], '-nostdinc')
00789 
00790         opts['as']['verbose'] = False
00791         if '-v' in flags['asm_flags']:
00792             opts['as']['verbose'] = True
00793             self.remove_option(flags['asm_flags'], '-v')
00794 
00795         # C options.
00796         opts['c']['nostdinc'] = False
00797         if '-nostdinc' in flags['c_flags']:
00798             opts['c']['nostdinc'] = True
00799             self.remove_option(flags['c_flags'], '-nostdinc')
00800 
00801         opts['c']['verbose'] = False
00802         if '-v' in flags['c_flags']:
00803             opts['c']['verbose'] = True
00804             self.remove_option(flags['c_flags'], '-v')
00805 
00806         warning_options = {
00807             '-Wmissing-prototypes': 'warnings.missingprototypes',
00808             '-Wstrict-prototypes': 'warnings.strictprototypes',
00809             '-Wbad-function-cast': 'warnings.badfunctioncast',
00810         }
00811 
00812         for option in warning_options:
00813             opts['c'][warning_options[option]] = False
00814             if option in flags['common_flags']:
00815                 opts['c'][warning_options[option]] = True
00816                 self.remove_option(flags['common_flags'], option)
00817 
00818         # C++ options.
00819         opts['cpp']['nostdinc'] = False
00820         if '-nostdinc' in flags['cxx_flags']:
00821             opts['cpp']['nostdinc'] = True
00822             self.remove_option(flags['cxx_flags'], '-nostdinc')
00823 
00824         opts['cpp']['nostdincpp'] = False
00825         if '-nostdinc++' in flags['cxx_flags']:
00826             opts['cpp']['nostdincpp'] = True
00827             self.remove_option(flags['cxx_flags'], '-nostdinc++')
00828 
00829         optimization_options = {
00830             '-fno-exceptions': 'optimization.noexceptions',
00831             '-fno-rtti': 'optimization.nortti',
00832             '-fno-use-cxa-atexit': 'optimization.nousecxaatexit',
00833             '-fno-threadsafe-statics': 'optimization.nothreadsafestatics',
00834         }
00835 
00836         for option in optimization_options:
00837             opts['cpp'][optimization_options[option]] = False
00838             if option in flags['cxx_flags']:
00839                 opts['cpp'][optimization_options[option]] = True
00840                 self.remove_option(flags['cxx_flags'], option)
00841             if option in flags['common_flags']:
00842                 opts['cpp'][optimization_options[option]] = True
00843                 self.remove_option(flags['common_flags'], option)
00844 
00845         warning_options = {
00846             '-Wabi': 'warnabi',
00847             '-Wctor-dtor-privacy': 'warnings.ctordtorprivacy',
00848             '-Wnoexcept': 'warnings.noexcept',
00849             '-Wnon-virtual-dtor': 'warnings.nonvirtualdtor',
00850             '-Wstrict-null-sentinel': 'warnings.strictnullsentinel',
00851             '-Wsign-promo': 'warnings.signpromo',
00852             '-Weffc++': 'warneffc',
00853         }
00854 
00855         for option in warning_options:
00856             opts['cpp'][warning_options[option]] = False
00857             if option in flags['cxx_flags']:
00858                 opts['cpp'][warning_options[option]] = True
00859                 self.remove_option(flags['cxx_flags'], option)
00860             if option in flags['common_flags']:
00861                 opts['cpp'][warning_options[option]] = True
00862                 self.remove_option(flags['common_flags'], option)
00863 
00864         opts['cpp']['verbose'] = False
00865         if '-v' in flags['cxx_flags']:
00866             opts['cpp']['verbose'] = True
00867             self.remove_option(flags['cxx_flags'], '-v')
00868 
00869         # Linker options.
00870         linker_options = {
00871             '-nostartfiles': 'nostart',
00872             '-nodefaultlibs': 'nodeflibs',
00873             '-nostdlib': 'nostdlibs',
00874         }
00875 
00876         for option in linker_options:
00877             opts['ld'][linker_options[option]] = False
00878             if option in flags['ld_flags']:
00879                 opts['ld'][linker_options[option]] = True
00880                 self.remove_option(flags['ld_flags'], option)
00881 
00882         opts['ld']['gcsections'] = False
00883         if '-Wl,--gc-sections' in flags['ld_flags']:
00884             opts['ld']['gcsections'] = True
00885             self.remove_option(flags['ld_flags'], '-Wl,--gc-sections')
00886 
00887         opts['ld']['flags'] = []
00888         to_remove = []
00889         for opt in flags['ld_flags']:
00890             if opt.startswith('-Wl,--wrap,'):
00891                 opts['ld']['flags'].append(
00892                     '--wrap=' + opt[len('-Wl,--wrap,'):])
00893                 to_remove.append(opt)
00894         for opt in to_remove:
00895             self.remove_option(flags['ld_flags'], opt)
00896 
00897         # Other tool remaining options are separated by category.
00898         opts['as']['otherwarnings'] = self.find_options(
00899             flags['asm_flags'], '-W')
00900 
00901         opts['c']['otherwarnings'] = self.find_options(
00902             flags['c_flags'], '-W')
00903         opts['c']['otheroptimizations'] = self.find_options(flags[
00904             'c_flags'], '-f')
00905 
00906         opts['cpp']['otherwarnings'] = self.find_options(
00907             flags['cxx_flags'], '-W')
00908         opts['cpp']['otheroptimizations'] = self.find_options(
00909             flags['cxx_flags'], '-f')
00910 
00911         # Other common remaining options are separated by category.
00912         opts['common']['optimization.other'] = self.find_options(
00913             flags['common_flags'], '-f')
00914         opts['common']['warnings.other'] = self.find_options(
00915             flags['common_flags'], '-W')
00916 
00917         # Remaining common flags are added to each tool.
00918         opts['as']['other'] += ' ' + \
00919             ' '.join(flags['common_flags']) + ' ' + \
00920             ' '.join(flags['asm_flags'])
00921         opts['c']['other'] += ' ' + \
00922             ' '.join(flags['common_flags']) + ' ' + ' '.join(flags['c_flags'])
00923         opts['cpp']['other'] += ' ' + \
00924             ' '.join(flags['common_flags']) + ' ' + \
00925             ' '.join(flags['cxx_flags'])
00926         opts['ld']['other'] += ' ' + \
00927             ' '.join(flags['common_flags']) + ' ' + ' '.join(flags['ld_flags'])
00928 
00929         if len(self.system_libraries) > 0:
00930             opts['ld']['other'] += ' -Wl,--start-group '
00931             opts['ld'][
00932                 'other'] += ' '.join('-l' + s for s in self.system_libraries)
00933             opts['ld']['other'] += ' -Wl,--end-group '
00934 
00935         # Strip all 'other' flags, since they might have leading spaces.
00936         opts['as']['other'] = opts['as']['other'].strip()
00937         opts['c']['other'] = opts['c']['other'].strip()
00938         opts['cpp']['other'] = opts['cpp']['other'].strip()
00939         opts['ld']['other'] = opts['ld']['other'].strip()
00940 
00941         if False:
00942             print
00943             print opts
00944 
00945             print
00946             print 'common_flags', flags['common_flags']
00947             print 'asm_flags', flags['asm_flags']
00948             print 'c_flags', flags['c_flags']
00949             print 'cxx_flags', flags['cxx_flags']
00950             print 'ld_flags', flags['ld_flags']
00951 
00952     @staticmethod
00953     def find_options(lst, option):
00954         tmp = [str for str in lst if str.startswith(option)]
00955         if len(tmp) > 0:
00956             return tmp[0]
00957         else:
00958             return None
00959 
00960     @staticmethod
00961     def find_options(lst, prefix):
00962         other = ''
00963         opts = [str for str in lst if str.startswith(prefix)]
00964         if len(opts) > 0:
00965             for opt in opts:
00966                 other += ' ' + opt
00967                 GNUARMEclipse.remove_option(lst, opt)
00968         return other.strip()
00969 
00970     @staticmethod
00971     def remove_option(lst, option):
00972         if option in lst:
00973             lst.remove(option)
00974 
00975 # =============================================================================