mbed-os/tools/export/gnuarmeclipse/__init__.py

978 lines
37 KiB
Python
Raw Normal View History

2017-01-10 19:36:20 +00:00
"""
mbed SDK
Copyright (c) 2011-2017 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
2017-01-12 16:10:56 +00:00
Title: GNU ARM Eclipse (http://gnuarmeclipse.github.io) exporter.
Description: Creates a managed build project that can be imported by
the GNU ARM Eclipse plug-ins.
Author: Liviu Ionescu <ilg@livius.net>
2017-01-10 19:36:20 +00:00
"""
2017-01-12 16:10:56 +00:00
import os
import copy
2017-01-18 12:39:50 +00:00
import tempfile
import shutil
import copy
2017-01-18 12:39:50 +00:00
from subprocess import call, Popen, PIPE
from os.path import splitext, basename, relpath, dirname, exists, join, dirname
from random import randint
from json import load
2017-01-10 19:36:20 +00:00
from tools.export.exporters import Exporter, apply_supported_whitelist
from tools.options import list_profiles
2017-01-10 19:36:20 +00:00
from tools.targets import TARGET_MAP
2017-01-10 20:40:03 +00:00
from tools.utils import NotSupportedException
from tools.build_api import prepare_toolchain
2017-01-10 19:36:20 +00:00
2017-01-17 23:54:04 +00:00
# =============================================================================
2017-01-12 16:10:56 +00:00
class UID:
2017-01-12 16:10:56 +00:00
"""
Helper class, used to generate unique ids required by .cproject symbols.
"""
@property
def id(self):
return "%0.9u" % randint(0, 999999999)
2017-01-12 16:10:56 +00:00
# Global UID generator instance.
# Passed to the template engine, and referred as {{u.id}}.
# Each invocation generates a new number.
u = UID()
2017-01-10 19:36:20 +00:00
2017-01-17 23:54:04 +00:00
# =============================================================================
2017-01-12 16:10:56 +00:00
POST_BINARY_WHITELIST = set([
"TEENSY3_1Code.binary_hook",
"MCU_NRF51Code.binary_hook",
"LPCTargetCode.lpc_patch",
"LPC4088Code.binary_hook"
])
2017-01-10 19:36:20 +00:00
class GNUARMEclipse(Exporter):
NAME = 'GNU ARM Eclipse'
TOOLCHAIN = 'GCC_ARM'
@classmethod
def is_target_supported(cls, target_name):
target = TARGET_MAP[target_name]
return apply_supported_whitelist(
cls.TOOLCHAIN, POST_BINARY_WHITELIST, target)
2017-01-10 19:36:20 +00:00
2017-01-17 23:54:04 +00:00
# override
@property
def flags(self):
"""Returns a dictionary of toolchain flags.
Keys of the dictionary are:
cxx_flags - c++ flags
c_flags - c flags
ld_flags - linker flags
asm_flags - assembler flags
common_flags - common options
2017-01-12 16:10:56 +00:00
The difference from the parent function is that it does not
add macro definitions, since they are passed separately.
"""
config_header = self.toolchain.get_config_header()
flags = {key + "_flags": copy.deepcopy(value) for key, value
in self.toolchain.flags.iteritems()}
if config_header:
config_header = relpath(config_header,
self.resources.file_basepath[config_header])
flags['c_flags'] += self.toolchain.get_config_option(config_header)
flags['cxx_flags'] += self.toolchain.get_config_option(
config_header)
return flags
2017-01-10 19:36:20 +00:00
def toolchain_flags(self, toolchain):
"""Returns a dictionary of toolchain flags.
Keys of the dictionary are:
cxx_flags - c++ flags
c_flags - c flags
ld_flags - linker flags
asm_flags - assembler flags
common_flags - common options
The difference from the above is that it takes a parameter.
"""
# Note: use the config options from the currently selected toolchain.
config_header = self.toolchain.get_config_header()
flags = {key + "_flags": copy.deepcopy(value) for key, value
in toolchain.flags.iteritems()}
if config_header:
config_header = relpath(config_header,
self.resources.file_basepath[config_header])
header_options = self.toolchain.get_config_option(config_header)
flags['c_flags'] += header_options
flags['cxx_flags'] += header_options
return flags
2017-08-22 15:13:13 +00:00
def validate_resources(self):
2017-01-17 23:54:04 +00:00
if not self.resources.linker_script:
raise NotSupportedException("No linker script found.")
2017-01-12 16:10:56 +00:00
2017-08-22 15:13:13 +00:00
def create_jinja_ctx(self):
self.validate_resources()
2017-01-17 23:54:04 +00:00
self.resources.win_to_unix()
# TODO: use some logger to display additional info if verbose
libraries = []
# print 'libraries'
# print self.resources.libraries
for lib in self.resources.libraries:
l, _ = splitext(basename(lib))
libraries.append(l[3:])
self.system_libraries = [
'stdc++', 'supc++', 'm', 'c', 'gcc', 'nosys'
]
# Read in all profiles, we'll extract compiler options.
profiles = self.get_all_profiles()
profile_ids = [s.lower() for s in profiles]
profile_ids.sort()
2017-01-17 23:54:04 +00:00
# TODO: get the list from existing .cproject
build_folders = [s.capitalize() for s in profile_ids]
build_folders.append('BUILD')
# print build_folders
2017-01-17 23:54:04 +00:00
objects = [self.filter_dot(s) for s in self.resources.objects]
for bf in build_folders:
objects = [o for o in objects if not o.startswith(bf + '/')]
# print 'objects'
# print objects
self.compute_exclusions()
self.include_path = [
self.filter_dot(s) for s in self.resources.inc_dirs]
print 'Include folders: {0}'.format(len(self.include_path))
2017-01-17 23:54:04 +00:00
self.as_defines = self.toolchain.get_symbols(True)
self.c_defines = self.toolchain.get_symbols()
self.cpp_defines = self.c_defines
print 'Symbols: {0}'.format(len(self.c_defines))
2017-01-17 23:54:04 +00:00
self.ld_script = self.filter_dot(
self.resources.linker_script)
print 'Linker script: {0}'.format(self.ld_script)
2017-01-17 23:54:04 +00:00
self.options = {}
for id in profile_ids:
2017-01-17 23:54:04 +00:00
# There are 4 categories of options, a category common too
# all tools and a specific category for each of the tools.
opts = {}
opts['common'] = {}
opts['as'] = {}
opts['c'] = {}
opts['cpp'] = {}
opts['ld'] = {}
2017-01-17 23:54:04 +00:00
opts['id'] = id
opts['name'] = opts['id'].capitalize()
2017-01-17 23:54:04 +00:00
print
print 'Build configuration: {0}'.format(opts['name'])
2017-01-17 23:54:04 +00:00
profile = profiles[id]
2017-01-17 23:54:04 +00:00
# A small hack, do not bother with src_path again,
# pass an empty string to avoid crashing.
src_paths = ['']
target_name = self.toolchain.target.name
toolchain = prepare_toolchain(
src_paths, "", target_name, self.TOOLCHAIN, build_profile=[profile])
2017-01-17 23:54:04 +00:00
# Hack to fill in build_dir
toolchain.build_dir = self.toolchain.build_dir
toolchain.config = self.toolchain.config
toolchain.set_config_data(self.toolchain.config.get_config_data())
flags = self.toolchain_flags(toolchain)
print 'Common flags:', ' '.join(flags['common_flags'])
print 'C++ flags:', ' '.join(flags['cxx_flags'])
print 'C flags:', ' '.join(flags['c_flags'])
print 'ASM flags:', ' '.join(flags['asm_flags'])
print 'Linker flags:', ' '.join(flags['ld_flags'])
# Most GNU ARM Eclipse options have a parent,
# either debug or release.
if '-O0' in flags['common_flags'] or '-Og' in flags['common_flags']:
opts['parent_id'] = 'debug'
else:
opts['parent_id'] = 'release'
self.process_options(opts, flags)
opts['as']['defines'] = self.as_defines
opts['c']['defines'] = self.c_defines
opts['cpp']['defines'] = self.cpp_defines
opts['common']['include_paths'] = self.include_path
opts['common']['excluded_folders'] = '|'.join(
self.excluded_folders)
opts['ld']['library_paths'] = [
self.filter_dot(s) for s in self.resources.lib_dirs]
opts['ld']['object_files'] = objects
opts['ld']['user_libraries'] = libraries
opts['ld']['system_libraries'] = self.system_libraries
opts['ld']['script'] = join(id.capitalize(),
"linker-script-%s.ld" % id)
2017-09-27 10:31:45 +00:00
opts['cpp_cmd'] = '"{}"'.format(toolchain.preproc[0]) + " " + " ".join(toolchain.preproc[1:])
2017-01-17 23:54:04 +00:00
# Unique IDs used in multiple places.
# Those used only once are implemented with {{u.id}}.
uid = {}
uid['config'] = u.id
uid['tool_c_compiler'] = u.id
uid['tool_c_compiler_input'] = u.id
uid['tool_cpp_compiler'] = u.id
uid['tool_cpp_compiler_input'] = u.id
opts['uid'] = uid
self.options[id] = opts
jinja_ctx = {
'name': self.project_name,
'ld_script': self.ld_script,
# Compiler & linker command line options
'options': self.options,
2017-01-17 23:54:04 +00:00
# Must be an object with an `id` property, which
# will be called repeatedly, to generate multiple UIDs.
'u': u,
}
2017-08-22 15:13:13 +00:00
return jinja_ctx
# override
def generate(self):
"""
Generate the .project and .cproject files.
"""
jinja_ctx = self.create_jinja_ctx()
print
print 'Create a GNU ARM Eclipse C++ managed project'
print 'Project name: {0}'.format(self.project_name)
print 'Target: {0}'.format(self.toolchain.target.name)
print 'Toolchain: {0}'.format(self.TOOLCHAIN)
2017-01-17 23:54:04 +00:00
self.gen_file('gnuarmeclipse/.project.tmpl', jinja_ctx,
'.project', trim_blocks=True, lstrip_blocks=True)
self.gen_file('gnuarmeclipse/.cproject.tmpl', jinja_ctx,
'.cproject', trim_blocks=True, lstrip_blocks=True)
self.gen_file('gnuarmeclipse/makefile.targets.tmpl', jinja_ctx,
'makefile.targets', trim_blocks=True, lstrip_blocks=True)
self.gen_file('gnuarmeclipse/mbedignore.tmpl', jinja_ctx, '.mbedignore')
2017-01-17 23:54:04 +00:00
print
print 'Done. Import the \'{0}\' project in Eclipse.'.format(self.project_name)
2017-01-17 23:54:04 +00:00
# override
@staticmethod
2017-01-20 20:32:15 +00:00
def build(project_name, log_name="build_log.txt", cleanup=True):
2017-01-12 16:10:56 +00:00
"""
2017-01-18 12:39:50 +00:00
Headless build an Eclipse project.
The following steps are performed:
- a temporary workspace is created,
- the project is imported,
- a clean build of all configurations is performed and
- the temporary workspace is removed.
The build results are in the Debug & Release folders.
All executables (eclipse & toolchain) must be in the PATH.
The general method to start a headless Eclipse build is:
$ eclipse \
--launcher.suppressErrors \
-nosplash \
-application org.eclipse.cdt.managedbuilder.core.headlessbuild \
-data /path/to/workspace \
-import /path/to/project \
-cleanBuild "project[/configuration] | all"
2017-01-12 16:10:56 +00:00
"""
2017-01-17 23:54:04 +00:00
2017-01-18 12:39:50 +00:00
# TODO: possibly use the log file.
2017-01-17 23:54:04 +00:00
2017-01-18 12:39:50 +00:00
# Create a temporary folder for the workspace.
tmp_folder = tempfile.mkdtemp()
cmd = [
'eclipse',
'--launcher.suppressErrors',
2017-01-18 12:39:50 +00:00
'-nosplash',
'-application org.eclipse.cdt.managedbuilder.core.headlessbuild',
'-data', tmp_folder,
'-import', os.getcwd(),
'-cleanBuild', project_name
2017-01-18 12:39:50 +00:00
]
p = Popen(' '.join(cmd), shell=True, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
ret_code = p.returncode
2017-01-20 20:32:15 +00:00
stdout_string = "=" * 10 + "STDOUT" + "=" * 10 + "\n"
err_string = "=" * 10 + "STDERR" + "=" * 10 + "\n"
err_string += err
2017-01-20 20:32:15 +00:00
ret_string = "SUCCESS\n"
if ret_code != 0:
ret_string += "FAILURE\n"
print "%s\n%s\n%s\n%s" % (stdout_string, out, err_string, ret_string)
if log_name:
# Write the output to the log file
with open(log_name, 'w+') as f:
2017-01-20 20:32:15 +00:00
f.write(stdout_string)
f.write(out)
f.write(err_string)
f.write(ret_string)
2017-01-17 23:54:04 +00:00
# Cleanup the exported and built files
if cleanup:
if exists(log_name):
os.remove(log_name)
2017-01-17 23:54:04 +00:00
os.remove('.project')
os.remove('.cproject')
2017-01-18 12:39:50 +00:00
if exists('Debug'):
shutil.rmtree('Debug')
if exists('Release'):
shutil.rmtree('Release')
if exists('makefile.targets'):
os.remove('makefile.targets')
2017-01-17 23:54:04 +00:00
2017-01-18 12:39:50 +00:00
# Always remove the temporary folder.
if exists(tmp_folder):
shutil.rmtree(tmp_folder)
if ret_code == 0:
# Return Success
2017-01-17 23:54:04 +00:00
return 0
2017-01-18 12:39:50 +00:00
# Seems like something went wrong.
return -1
# -------------------------------------------------------------------------
@staticmethod
def get_all_profiles():
tools_path = dirname(dirname(dirname(__file__)))
file_names = [join(tools_path, "profiles", fn) for fn in os.listdir(
join(tools_path, "profiles")) if fn.endswith(".json")]
# print file_names
profile_names = [basename(fn).replace(".json", "")
for fn in file_names]
# print profile_names
profiles = {}
for fn in file_names:
content = load(open(fn))
profile_name = basename(fn).replace(".json", "")
profiles[profile_name] = content
return profiles
2017-01-17 23:54:04 +00:00
# -------------------------------------------------------------------------
# Process source files/folders exclusions.
2017-01-12 16:10:56 +00:00
def compute_exclusions(self):
"""
With the project root as the only source folder known to CDT,
based on the list of source files, compute the folders to not
be included in the build.
The steps are:
- get the list of source folders, as dirname(source_file)
2017-01-13 09:09:28 +00:00
- compute the top folders (subfolders of the project folder)
2017-01-12 16:10:56 +00:00
- iterate all subfolders and add them to a tree, with all
nodes markes as 'not used'
- iterate the source folders and mark them as 'used' in the
tree, including all intermediate nodes
- recurse the tree and collect all unused folders; descend
the hierarchy only for used nodes
"""
source_folders = [self.filter_dot(s) for s in set(dirname(
src) for src in self.resources.c_sources + self.resources.cpp_sources + self.resources.s_sources)]
2017-01-10 19:36:20 +00:00
self.excluded_folders = set(self.resources.ignored_dirs) - set(self.resources.inc_dirs)
2017-01-17 23:54:04 +00:00
print 'Source folders: {0}, with {1} exclusions'.format(len(source_folders), len(self.excluded_folders))
2017-01-13 09:09:28 +00:00
2017-01-17 23:54:04 +00:00
# -------------------------------------------------------------------------
2017-01-12 16:10:56 +00:00
2017-01-17 23:54:04 +00:00
@staticmethod
2017-01-18 17:09:16 +00:00
def filter_dot(str):
2017-01-17 23:54:04 +00:00
"""
Remove the './' prefix, if present.
This function assumes that resources.win_to_unix()
replaced all windows backslashes with slashes.
"""
2017-01-18 17:09:16 +00:00
if str == None:
2017-01-17 23:54:04 +00:00
return None
2017-01-18 17:09:16 +00:00
if str[:2] == './':
return str[2:]
return str
2017-01-17 23:54:04 +00:00
# -------------------------------------------------------------------------
2017-01-18 17:09:16 +00:00
def dump_tree(self, nodes, depth=0):
for k in nodes.keys():
node = nodes[k]
parent_name = node['parent'][
'name'] if 'parent' in node.keys() else ''
2017-01-18 17:09:16 +00:00
print ' ' * depth, node['name'], node['is_used'], parent_name
if len(node['children'].keys()) != 0:
self.dump_tree(node['children'], depth + 1)
def dump_paths(self, nodes, depth=0):
for k in nodes.keys():
node = nodes[k]
parts = []
2017-01-17 23:54:04 +00:00
while True:
2017-01-18 17:09:16 +00:00
parts.insert(0, node['name'])
if 'parent' not in node:
2017-01-17 23:54:04 +00:00
break
2017-01-18 17:09:16 +00:00
node = node['parent']
path = '/'.join(parts)
print path, nodes[k]['is_used']
2017-01-19 22:46:00 +00:00
self.dump_paths(nodes[k]['children'], depth + 1)
2017-01-17 23:54:04 +00:00
# -------------------------------------------------------------------------
def process_options(self, opts, flags_in):
2017-01-17 23:54:04 +00:00
"""
CDT managed projects store lots of build options in separate
variables, with separate IDs in the .cproject file.
When the CDT build is started, all these options are brought
together to compose the compiler and linker command lines.
Here the process is reversed, from the compiler and linker
command lines, the options are identified and various flags are
set to control the template generation process.
Once identified, the options are removed from the command lines.
The options that were not identified are options that do not
have CDT equivalents and will be passed in the 'Other options'
categories.
2017-01-18 17:09:16 +00:00
Although this process does not have a very complicated logic,
2017-01-17 23:54:04 +00:00
given the large number of explicit configuration options
2017-01-18 17:09:16 +00:00
used by the GNU ARM Eclipse managed build plug-in, it is tedious...
2017-01-17 23:54:04 +00:00
"""
# Make a copy of the flags, to be one by one removed after processing.
flags = copy.deepcopy(flags_in)
2017-01-17 23:54:04 +00:00
if False:
print
print 'common_flags', flags['common_flags']
print 'asm_flags', flags['asm_flags']
print 'c_flags', flags['c_flags']
print 'cxx_flags', flags['cxx_flags']
print 'ld_flags', flags['ld_flags']
# Initialise the 'last resort' options where all unrecognised
# options will be collected.
opts['as']['other'] = ''
opts['c']['other'] = ''
opts['cpp']['other'] = ''
opts['ld']['other'] = ''
2017-01-10 19:36:20 +00:00
MCPUS = {
'Cortex-M0': {'mcpu': 'cortex-m0', 'fpu_unit': None},
'Cortex-M0+': {'mcpu': 'cortex-m0plus', 'fpu_unit': None},
'Cortex-M1': {'mcpu': 'cortex-m1', 'fpu_unit': None},
'Cortex-M3': {'mcpu': 'cortex-m3', 'fpu_unit': None},
'Cortex-M4': {'mcpu': 'cortex-m4', 'fpu_unit': None},
'Cortex-M4F': {'mcpu': 'cortex-m4', 'fpu_unit': 'fpv4spd16'},
'Cortex-M7': {'mcpu': 'cortex-m7', 'fpu_unit': None},
'Cortex-M7F': {'mcpu': 'cortex-m7', 'fpu_unit': 'fpv4spd16'},
'Cortex-M7FD': {'mcpu': 'cortex-m7', 'fpu_unit': 'fpv5d16'},
'Cortex-A9': {'mcpu': 'cortex-a9', 'fpu_unit': 'vfpv3'}
2017-01-10 19:36:20 +00:00
}
2017-01-17 23:54:04 +00:00
# Remove options that are supplied by CDT
self.remove_option(flags['common_flags'], '-c')
self.remove_option(flags['common_flags'], '-MMD')
2017-01-12 16:10:56 +00:00
2017-01-17 23:54:04 +00:00
# As 'plan B', get the CPU from the target definition.
core = self.toolchain.target.core
opts['common']['arm.target.family'] = None
2017-01-12 16:10:56 +00:00
2017-01-17 23:54:04 +00:00
# cortex-m0, cortex-m0-small-multiply, cortex-m0plus,
# cortex-m0plus-small-multiply, cortex-m1, cortex-m1-small-multiply,
# cortex-m3, cortex-m4, cortex-m7.
str = self.find_options(flags['common_flags'], '-mcpu=')
if str != None:
opts['common']['arm.target.family'] = str[len('-mcpu='):]
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], str)
self.remove_option(flags['ld_flags'], str)
else:
if core not in MCPUS:
raise NotSupportedException(
'Target core {0} not supported.'.format(core))
opts['common']['arm.target.family'] = MCPUS[core]['mcpu']
2017-01-17 23:54:04 +00:00
opts['common']['arm.target.arch'] = 'none'
2017-01-17 23:54:04 +00:00
str = self.find_options(flags['common_flags'], '-march=')
arch = str[len('-march='):]
archs = {'armv6-m': 'armv6-m', 'armv7-m': 'armv7-m', 'armv7-a': 'armv7-a'}
2017-01-17 23:54:04 +00:00
if arch in archs:
opts['common']['arm.target.arch'] = archs[arch]
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], str)
opts['common']['arm.target.instructionset'] = 'thumb'
2017-01-17 23:54:04 +00:00
if '-mthumb' in flags['common_flags']:
self.remove_option(flags['common_flags'], '-mthumb')
self.remove_option(flags['ld_flags'], '-mthumb')
elif '-marm' in flags['common_flags']:
opts['common']['arm.target.instructionset'] = 'arm'
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], '-marm')
self.remove_option(flags['ld_flags'], '-marm')
opts['common']['arm.target.thumbinterwork'] = False
2017-01-17 23:54:04 +00:00
if '-mthumb-interwork' in flags['common_flags']:
opts['common']['arm.target.thumbinterwork'] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], '-mthumb-interwork')
opts['common']['arm.target.endianness'] = None
2017-01-17 23:54:04 +00:00
if '-mlittle-endian' in flags['common_flags']:
opts['common']['arm.target.endianness'] = 'little'
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], '-mlittle-endian')
elif '-mbig-endian' in flags['common_flags']:
opts['common']['arm.target.endianness'] = 'big'
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], '-mbig-endian')
opts['common']['arm.target.fpu.unit'] = None
2017-01-17 23:54:04 +00:00
# default, fpv4spd16, fpv5d16, fpv5spd16
str = self.find_options(flags['common_flags'], '-mfpu=')
if str != None:
fpu = str[len('-mfpu='):]
fpus = {
'fpv4-sp-d16': 'fpv4spd16',
'fpv5-d16': 'fpv5d16',
'fpv5-sp-d16': 'fpv5spd16'
}
if fpu in fpus:
opts['common']['arm.target.fpu.unit'] = fpus[fpu]
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], str)
self.remove_option(flags['ld_flags'], str)
if opts['common']['arm.target.fpu.unit'] == None:
2017-01-17 23:54:04 +00:00
if core not in MCPUS:
raise NotSupportedException(
'Target core {0} not supported.'.format(core))
if MCPUS[core]['fpu_unit']:
opts['common'][
2017-01-17 23:54:04 +00:00
'arm.target.fpu.unit'] = MCPUS[core]['fpu_unit']
# soft, softfp, hard.
str = self.find_options(flags['common_flags'], '-mfloat-abi=')
if str != None:
opts['common']['arm.target.fpu.abi'] = str[
2017-01-17 23:54:04 +00:00
len('-mfloat-abi='):]
self.remove_option(flags['common_flags'], str)
self.remove_option(flags['ld_flags'], str)
opts['common']['arm.target.unalignedaccess'] = None
2017-01-17 23:54:04 +00:00
if '-munaligned-access' in flags['common_flags']:
opts['common']['arm.target.unalignedaccess'] = 'enabled'
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], '-munaligned-access')
elif '-mno-unaligned-access' in flags['common_flags']:
opts['common']['arm.target.unalignedaccess'] = 'disabled'
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], '-mno-unaligned-access')
# Default optimisation level for Release.
opts['common']['optimization.level'] = '-Os'
2017-01-17 23:54:04 +00:00
# If the project defines an optimisation level, it is used
# only for the Release configuration, the Debug one used '-Og'.
str = self.find_options(flags['common_flags'], '-O')
if str != None:
levels = {
'-O0': 'none', '-O1': 'optimize', '-O2': 'more',
'-O3': 'most', '-Os': 'size', '-Og': 'debug'
}
if str in levels:
opts['common']['optimization.level'] = levels[str]
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], str)
include_files = []
for all_flags in [flags['common_flags'], flags['c_flags'], flags['cxx_flags']]:
while '-include' in all_flags:
ix = all_flags.index('-include')
str = all_flags[ix + 1]
if str not in include_files:
include_files.append(str)
self.remove_option(all_flags, '-include')
self.remove_option(all_flags, str)
opts['common']['include_files'] = include_files
2017-01-17 23:54:04 +00:00
if '-ansi' in flags['c_flags']:
opts['c']['compiler.std'] = '-ansi'
2017-01-17 23:54:04 +00:00
self.remove_option(flags['c_flags'], str)
else:
str = self.find_options(flags['c_flags'], '-std')
std = str[len('-std='):]
c_std = {
'c90': 'c90', 'c89': 'c90', 'gnu90': 'gnu90', 'gnu89': 'gnu90',
'c99': 'c99', 'c9x': 'c99', 'gnu99': 'gnu99', 'gnu9x': 'gnu98',
'c11': 'c11', 'c1x': 'c11', 'gnu11': 'gnu11', 'gnu1x': 'gnu11'
}
if std in c_std:
opts['c']['compiler.std'] = c_std[std]
2017-01-17 23:54:04 +00:00
self.remove_option(flags['c_flags'], str)
if '-ansi' in flags['cxx_flags']:
opts['cpp']['compiler.std'] = '-ansi'
2017-01-17 23:54:04 +00:00
self.remove_option(flags['cxx_flags'], str)
else:
str = self.find_options(flags['cxx_flags'], '-std')
std = str[len('-std='):]
cpp_std = {
'c++98': 'cpp98', 'c++03': 'cpp98',
'gnu++98': 'gnucpp98', 'gnu++03': 'gnucpp98',
'c++0x': 'cpp0x', 'gnu++0x': 'gnucpp0x',
'c++11': 'cpp11', 'gnu++11': 'gnucpp11',
'c++1y': 'cpp1y', 'gnu++1y': 'gnucpp1y',
'c++14': 'cpp14', 'gnu++14': 'gnucpp14',
'c++1z': 'cpp1z', 'gnu++1z': 'gnucpp1z',
}
if std in cpp_std:
opts['cpp']['compiler.std'] = cpp_std[std]
2017-01-17 23:54:04 +00:00
self.remove_option(flags['cxx_flags'], str)
# Common optimisation options.
optimization_options = {
'-fmessage-length=0': 'optimization.messagelength',
'-fsigned-char': 'optimization.signedchar',
'-ffunction-sections': 'optimization.functionsections',
'-fdata-sections': 'optimization.datasections',
'-fno-common': 'optimization.nocommon',
'-fno-inline-functions': 'optimization.noinlinefunctions',
'-ffreestanding': 'optimization.freestanding',
'-fno-builtin': 'optimization.nobuiltin',
'-fsingle-precision-constant': 'optimization.spconstant',
'-fPIC': 'optimization.PIC',
'-fno-move-loop-invariants': 'optimization.nomoveloopinvariants',
}
2017-01-12 16:10:56 +00:00
2017-01-17 23:54:04 +00:00
for option in optimization_options:
opts['common'][optimization_options[option]] = False
2017-01-17 23:54:04 +00:00
if option in flags['common_flags']:
opts['common'][optimization_options[option]] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], option)
# Common warning options.
warning_options = {
'-fsyntax-only': 'warnings.syntaxonly',
'-pedantic': 'warnings.pedantic',
'-pedantic-errors': 'warnings.pedanticerrors',
'-w': 'warnings.nowarn',
'-Wunused': 'warnings.unused',
'-Wuninitialized': 'warnings.uninitialized',
'-Wall': 'warnings.allwarn',
'-Wextra': 'warnings.extrawarn',
'-Wmissing-declarations': 'warnings.missingdeclaration',
'-Wconversion': 'warnings.conversion',
'-Wpointer-arith': 'warnings.pointerarith',
'-Wpadded': 'warnings.padded',
'-Wshadow': 'warnings.shadow',
'-Wlogical-op': 'warnings.logicalop',
'-Waggregate-return': 'warnings.agreggatereturn',
'-Wfloat-equal': 'warnings.floatequal',
'-Werror': 'warnings.toerrors',
}
2017-01-12 16:10:56 +00:00
2017-01-17 23:54:04 +00:00
for option in warning_options:
opts['common'][warning_options[option]] = False
2017-01-17 23:54:04 +00:00
if option in flags['common_flags']:
opts['common'][warning_options[option]] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], option)
# Common debug options.
debug_levels = {
'-g': 'default',
'-g1': 'minimal',
'-g3': 'max',
}
opts['common']['debugging.level'] = 'none'
2017-01-17 23:54:04 +00:00
for option in debug_levels:
if option in flags['common_flags']:
opts['common'][
2017-01-17 23:54:04 +00:00
'debugging.level'] = debug_levels[option]
self.remove_option(flags['common_flags'], option)
debug_formats = {
'-ggdb': 'gdb',
'-gstabs': 'stabs',
'-gstabs+': 'stabsplus',
'-gdwarf-2': 'dwarf2',
'-gdwarf-3': 'dwarf3',
'-gdwarf-4': 'dwarf4',
'-gdwarf-5': 'dwarf5',
}
opts['common']['debugging.format'] = ''
2017-01-17 23:54:04 +00:00
for option in debug_levels:
if option in flags['common_flags']:
opts['common'][
2017-01-17 23:54:04 +00:00
'debugging.format'] = debug_formats[option]
self.remove_option(flags['common_flags'], option)
opts['common']['debugging.prof'] = False
2017-01-17 23:54:04 +00:00
if '-p' in flags['common_flags']:
opts['common']['debugging.prof'] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], '-p')
opts['common']['debugging.gprof'] = False
2017-01-17 23:54:04 +00:00
if '-pg' in flags['common_flags']:
opts['common']['debugging.gprof'] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], '-gp')
# Assembler options.
opts['as']['usepreprocessor'] = False
2017-01-17 23:54:04 +00:00
while '-x' in flags['asm_flags']:
ix = flags['asm_flags'].index('-x')
str = flags['asm_flags'][ix + 1]
if str == 'assembler-with-cpp':
opts['as']['usepreprocessor'] = True
2017-01-17 23:54:04 +00:00
else:
# Collect all other assembler options.
opts['as']['other'] += ' -x ' + str
2017-01-17 23:54:04 +00:00
self.remove_option(flags['asm_flags'], '-x')
self.remove_option(flags['asm_flags'], 'assembler-with-cpp')
opts['as']['nostdinc'] = False
2017-01-17 23:54:04 +00:00
if '-nostdinc' in flags['asm_flags']:
opts['as']['nostdinc'] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['asm_flags'], '-nostdinc')
opts['as']['verbose'] = False
2017-01-17 23:54:04 +00:00
if '-v' in flags['asm_flags']:
opts['as']['verbose'] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['asm_flags'], '-v')
# C options.
opts['c']['nostdinc'] = False
2017-01-17 23:54:04 +00:00
if '-nostdinc' in flags['c_flags']:
opts['c']['nostdinc'] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['c_flags'], '-nostdinc')
opts['c']['verbose'] = False
2017-01-17 23:54:04 +00:00
if '-v' in flags['c_flags']:
opts['c']['verbose'] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['c_flags'], '-v')
warning_options = {
'-Wmissing-prototypes': 'warnings.missingprototypes',
'-Wstrict-prototypes': 'warnings.strictprototypes',
'-Wbad-function-cast': 'warnings.badfunctioncast',
}
2017-01-17 23:54:04 +00:00
for option in warning_options:
opts['c'][warning_options[option]] = False
2017-01-17 23:54:04 +00:00
if option in flags['common_flags']:
opts['c'][warning_options[option]] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], option)
# C++ options.
opts['cpp']['nostdinc'] = False
2017-01-17 23:54:04 +00:00
if '-nostdinc' in flags['cxx_flags']:
opts['cpp']['nostdinc'] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['cxx_flags'], '-nostdinc')
opts['cpp']['nostdincpp'] = False
2017-01-17 23:54:04 +00:00
if '-nostdinc++' in flags['cxx_flags']:
opts['cpp']['nostdincpp'] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['cxx_flags'], '-nostdinc++')
optimization_options = {
'-fno-exceptions': 'optimization.noexceptions',
'-fno-rtti': 'optimization.nortti',
'-fno-use-cxa-atexit': 'optimization.nousecxaatexit',
'-fno-threadsafe-statics': 'optimization.nothreadsafestatics',
}
2017-01-10 19:36:20 +00:00
2017-01-17 23:54:04 +00:00
for option in optimization_options:
opts['cpp'][optimization_options[option]] = False
2017-01-17 23:54:04 +00:00
if option in flags['cxx_flags']:
opts['cpp'][optimization_options[option]] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['cxx_flags'], option)
if option in flags['common_flags']:
opts['cpp'][optimization_options[option]] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], option)
warning_options = {
'-Wabi': 'warnabi',
'-Wctor-dtor-privacy': 'warnings.ctordtorprivacy',
'-Wnoexcept': 'warnings.noexcept',
'-Wnon-virtual-dtor': 'warnings.nonvirtualdtor',
'-Wstrict-null-sentinel': 'warnings.strictnullsentinel',
'-Wsign-promo': 'warnings.signpromo',
'-Weffc++': 'warneffc',
}
2017-01-17 23:54:04 +00:00
for option in warning_options:
opts['cpp'][warning_options[option]] = False
2017-01-17 23:54:04 +00:00
if option in flags['cxx_flags']:
opts['cpp'][warning_options[option]] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['cxx_flags'], option)
if option in flags['common_flags']:
opts['cpp'][warning_options[option]] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['common_flags'], option)
opts['cpp']['verbose'] = False
2017-01-17 23:54:04 +00:00
if '-v' in flags['cxx_flags']:
opts['cpp']['verbose'] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['cxx_flags'], '-v')
# Linker options.
linker_options = {
'-nostartfiles': 'nostart',
'-nodefaultlibs': 'nodeflibs',
'-nostdlib': 'nostdlibs',
2017-01-10 19:36:20 +00:00
}
2017-01-17 23:54:04 +00:00
for option in linker_options:
opts['ld'][linker_options[option]] = False
2017-01-17 23:54:04 +00:00
if option in flags['ld_flags']:
opts['ld'][linker_options[option]] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['ld_flags'], option)
opts['ld']['gcsections'] = False
2017-01-17 23:54:04 +00:00
if '-Wl,--gc-sections' in flags['ld_flags']:
opts['ld']['gcsections'] = True
2017-01-17 23:54:04 +00:00
self.remove_option(flags['ld_flags'], '-Wl,--gc-sections')
opts['ld']['flags'] = []
2017-01-17 23:54:04 +00:00
to_remove = []
for opt in flags['ld_flags']:
if opt.startswith('-Wl,--wrap,'):
opts['ld']['flags'].append(
'--wrap=' + opt[len('-Wl,--wrap,'):])
2017-01-17 23:54:04 +00:00
to_remove.append(opt)
for opt in to_remove:
self.remove_option(flags['ld_flags'], opt)
2017-01-17 23:54:04 +00:00
# Other tool remaining options are separated by category.
opts['as']['otherwarnings'] = self.find_options(
2017-01-17 23:54:04 +00:00
flags['asm_flags'], '-W')
opts['c']['otherwarnings'] = self.find_options(
2017-01-17 23:54:04 +00:00
flags['c_flags'], '-W')
opts['c']['otheroptimizations'] = self.find_options(flags[
'c_flags'], '-f')
2017-01-17 23:54:04 +00:00
opts['cpp']['otherwarnings'] = self.find_options(
2017-01-17 23:54:04 +00:00
flags['cxx_flags'], '-W')
opts['cpp']['otheroptimizations'] = self.find_options(
2017-01-17 23:54:04 +00:00
flags['cxx_flags'], '-f')
# Other common remaining options are separated by category.
opts['common']['optimization.other'] = self.find_options(
2017-01-17 23:54:04 +00:00
flags['common_flags'], '-f')
opts['common']['warnings.other'] = self.find_options(
2017-01-17 23:54:04 +00:00
flags['common_flags'], '-W')
# Remaining common flags are added to each tool.
opts['as']['other'] += ' ' + \
2017-01-17 23:54:04 +00:00
' '.join(flags['common_flags']) + ' ' + \
' '.join(flags['asm_flags'])
opts['c']['other'] += ' ' + \
2017-01-17 23:54:04 +00:00
' '.join(flags['common_flags']) + ' ' + ' '.join(flags['c_flags'])
opts['cpp']['other'] += ' ' + \
2017-01-17 23:54:04 +00:00
' '.join(flags['common_flags']) + ' ' + \
' '.join(flags['cxx_flags'])
opts['ld']['other'] += ' ' + \
2017-01-17 23:54:04 +00:00
' '.join(flags['common_flags']) + ' ' + ' '.join(flags['ld_flags'])
if len(self.system_libraries) > 0:
opts['ld']['other'] += ' -Wl,--start-group '
opts['ld'][
2017-01-17 23:54:04 +00:00
'other'] += ' '.join('-l' + s for s in self.system_libraries)
opts['ld']['other'] += ' -Wl,--end-group '
2017-01-17 23:54:04 +00:00
# Strip all 'other' flags, since they might have leading spaces.
opts['as']['other'] = opts['as']['other'].strip()
opts['c']['other'] = opts['c']['other'].strip()
opts['cpp']['other'] = opts['cpp']['other'].strip()
opts['ld']['other'] = opts['ld']['other'].strip()
2017-01-17 23:54:04 +00:00
if False:
print
print opts
2017-01-17 23:54:04 +00:00
print
print 'common_flags', flags['common_flags']
print 'asm_flags', flags['asm_flags']
print 'c_flags', flags['c_flags']
print 'cxx_flags', flags['cxx_flags']
print 'ld_flags', flags['ld_flags']
2017-01-12 16:10:56 +00:00
@staticmethod
2017-01-17 23:54:04 +00:00
def find_options(lst, option):
tmp = [str for str in lst if str.startswith(option)]
if len(tmp) > 0:
return tmp[0]
else:
return None
2017-01-12 16:10:56 +00:00
2017-01-17 23:54:04 +00:00
@staticmethod
def find_options(lst, prefix):
other = ''
opts = [str for str in lst if str.startswith(prefix)]
if len(opts) > 0:
for opt in opts:
other += ' ' + opt
GNUARMEclipse.remove_option(lst, opt)
return other.strip()
2017-01-12 16:10:56 +00:00
2017-01-17 23:54:04 +00:00
@staticmethod
def remove_option(lst, option):
if option in lst:
lst.remove(option)
2017-01-12 16:10:56 +00:00
2017-01-17 23:54:04 +00:00
# =============================================================================