mbed-os

Fork of mbed-os by erkin yucel

Committer:
elessair
Date:
Sun Oct 23 15:10:02 2016 +0000
Revision:
0:f269e3021894
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
elessair 0:f269e3021894 1 """ The new way of doing exports """
elessair 0:f269e3021894 2 import sys
elessair 0:f269e3021894 3 from os.path import join, abspath, dirname, exists
elessair 0:f269e3021894 4 from os.path import basename, relpath, normpath, splitext
elessair 0:f269e3021894 5 from os import makedirs, walk
elessair 0:f269e3021894 6 ROOT = abspath(join(dirname(__file__), ".."))
elessair 0:f269e3021894 7 sys.path.insert(0, ROOT)
elessair 0:f269e3021894 8 import copy
elessair 0:f269e3021894 9 from shutil import rmtree
elessair 0:f269e3021894 10 import zipfile
elessair 0:f269e3021894 11
elessair 0:f269e3021894 12 from tools.build_api import prepare_toolchain
elessair 0:f269e3021894 13 from tools.build_api import scan_resources
elessair 0:f269e3021894 14 from tools.export import EXPORTERS
elessair 0:f269e3021894 15 from tools.toolchains import Resources
elessair 0:f269e3021894 16
elessair 0:f269e3021894 17
elessair 0:f269e3021894 18 def get_exporter_toolchain(ide):
elessair 0:f269e3021894 19 """ Return the exporter class and the toolchain string as a tuple
elessair 0:f269e3021894 20
elessair 0:f269e3021894 21 Positional arguments:
elessair 0:f269e3021894 22 ide - the ide name of an exporter
elessair 0:f269e3021894 23 """
elessair 0:f269e3021894 24 return EXPORTERS[ide], EXPORTERS[ide].TOOLCHAIN
elessair 0:f269e3021894 25
elessair 0:f269e3021894 26
elessair 0:f269e3021894 27 def rewrite_basepath(file_name, resources, export_path, loc):
elessair 0:f269e3021894 28 """ Replace the basepath of filename with export_path
elessair 0:f269e3021894 29
elessair 0:f269e3021894 30 Positional arguments:
elessair 0:f269e3021894 31 file_name - the absolute path to a file
elessair 0:f269e3021894 32 resources - the resources object that the file came from
elessair 0:f269e3021894 33 export_path - the final destination of the file after export
elessair 0:f269e3021894 34 """
elessair 0:f269e3021894 35 new_f = join(loc, relpath(file_name, resources.file_basepath[file_name]))
elessair 0:f269e3021894 36 resources.file_basepath[join(export_path, new_f)] = export_path
elessair 0:f269e3021894 37 return new_f
elessair 0:f269e3021894 38
elessair 0:f269e3021894 39
elessair 0:f269e3021894 40 def subtract_basepath(resources, export_path, loc=""):
elessair 0:f269e3021894 41 """ Rewrite all of the basepaths with the export_path
elessair 0:f269e3021894 42
elessair 0:f269e3021894 43 Positional arguments:
elessair 0:f269e3021894 44 resources - the resource object to rewrite the basepaths of
elessair 0:f269e3021894 45 export_path - the final destination of the resources with respect to the
elessair 0:f269e3021894 46 generated project files
elessair 0:f269e3021894 47 """
elessair 0:f269e3021894 48 keys = ['s_sources', 'c_sources', 'cpp_sources', 'hex_files',
elessair 0:f269e3021894 49 'objects', 'libraries', 'inc_dirs', 'headers', 'linker_script',
elessair 0:f269e3021894 50 'lib_dirs']
elessair 0:f269e3021894 51 for key in keys:
elessair 0:f269e3021894 52 vals = getattr(resources, key)
elessair 0:f269e3021894 53 if isinstance(vals, set):
elessair 0:f269e3021894 54 vals = list(vals)
elessair 0:f269e3021894 55 if isinstance(vals, list):
elessair 0:f269e3021894 56 new_vals = []
elessair 0:f269e3021894 57 for val in vals:
elessair 0:f269e3021894 58 new_vals.append(rewrite_basepath(val, resources, export_path,
elessair 0:f269e3021894 59 loc))
elessair 0:f269e3021894 60 if isinstance(getattr(resources, key), set):
elessair 0:f269e3021894 61 setattr(resources, key, set(new_vals))
elessair 0:f269e3021894 62 else:
elessair 0:f269e3021894 63 setattr(resources, key, new_vals)
elessair 0:f269e3021894 64 elif vals:
elessair 0:f269e3021894 65 setattr(resources, key, rewrite_basepath(vals, resources,
elessair 0:f269e3021894 66 export_path, loc))
elessair 0:f269e3021894 67
elessair 0:f269e3021894 68
elessair 0:f269e3021894 69 def generate_project_files(resources, export_path, target, name, toolchain, ide,
elessair 0:f269e3021894 70 macros=None):
elessair 0:f269e3021894 71 """Generate the project files for a project
elessair 0:f269e3021894 72
elessair 0:f269e3021894 73 Positional arguments:
elessair 0:f269e3021894 74 resources - a Resources object containing all of the files needed to build
elessair 0:f269e3021894 75 this project
elessair 0:f269e3021894 76 export_path - location to place project files
elessair 0:f269e3021894 77 name - name of the project
elessair 0:f269e3021894 78 toolchain - a toolchain class that corresponds to the toolchain used by the
elessair 0:f269e3021894 79 IDE or makefile
elessair 0:f269e3021894 80 ide - IDE name to export to
elessair 0:f269e3021894 81
elessair 0:f269e3021894 82 Optional arguments:
elessair 0:f269e3021894 83 macros - additional macros that should be defined within the exported
elessair 0:f269e3021894 84 project
elessair 0:f269e3021894 85 """
elessair 0:f269e3021894 86 exporter_cls, _ = get_exporter_toolchain(ide)
elessair 0:f269e3021894 87 exporter = exporter_cls(target, export_path, name, toolchain,
elessair 0:f269e3021894 88 extra_symbols=macros, resources=resources)
elessair 0:f269e3021894 89 exporter.check_supported()
elessair 0:f269e3021894 90 exporter.generate()
elessair 0:f269e3021894 91 files = exporter.generated_files
elessair 0:f269e3021894 92 return files, exporter
elessair 0:f269e3021894 93
elessair 0:f269e3021894 94
elessair 0:f269e3021894 95 def zip_export(file_name, prefix, resources, project_files, inc_repos):
elessair 0:f269e3021894 96 """Create a zip file from an exported project.
elessair 0:f269e3021894 97
elessair 0:f269e3021894 98 Positional Parameters:
elessair 0:f269e3021894 99 file_name - the file name of the resulting zip file
elessair 0:f269e3021894 100 prefix - a directory name that will prefix the entire zip file's contents
elessair 0:f269e3021894 101 resources - a resources object with files that must be included in the zip
elessair 0:f269e3021894 102 project_files - a list of extra files to be added to the root of the prefix
elessair 0:f269e3021894 103 directory
elessair 0:f269e3021894 104 """
elessair 0:f269e3021894 105 with zipfile.ZipFile(file_name, "w") as zip_file:
elessair 0:f269e3021894 106 for prj_file in project_files:
elessair 0:f269e3021894 107 zip_file.write(prj_file, join(prefix, basename(prj_file)))
elessair 0:f269e3021894 108 for loc, resource in resources.iteritems():
elessair 0:f269e3021894 109 for res in [resource] + resource.features.values():
elessair 0:f269e3021894 110 to_zip = (
elessair 0:f269e3021894 111 res.headers + res.s_sources + res.c_sources +\
elessair 0:f269e3021894 112 res.cpp_sources + res.libraries + res.hex_files + \
elessair 0:f269e3021894 113 [res.linker_script] + res.bin_files + res.objects + \
elessair 0:f269e3021894 114 res.json_files + res.lib_refs + res.lib_builds)
elessair 0:f269e3021894 115 if inc_repos:
elessair 0:f269e3021894 116 for directory in res.repo_dirs:
elessair 0:f269e3021894 117 for root, _, files in walk(directory):
elessair 0:f269e3021894 118 for repo_file in files:
elessair 0:f269e3021894 119 source = join(root, repo_file)
elessair 0:f269e3021894 120 to_zip.append(source)
elessair 0:f269e3021894 121 res.file_basepath[source] = res.base_path
elessair 0:f269e3021894 122 to_zip += res.repo_files
elessair 0:f269e3021894 123 for source in to_zip:
elessair 0:f269e3021894 124 if source:
elessair 0:f269e3021894 125 zip_file.write(
elessair 0:f269e3021894 126 source,
elessair 0:f269e3021894 127 join(prefix, loc,
elessair 0:f269e3021894 128 relpath(source, res.file_basepath[source])))
elessair 0:f269e3021894 129 for source in res.lib_builds:
elessair 0:f269e3021894 130 target_dir, _ = splitext(source)
elessair 0:f269e3021894 131 dest = join(prefix, loc,
elessair 0:f269e3021894 132 relpath(target_dir, res.file_basepath[source]),
elessair 0:f269e3021894 133 ".bld", "bldrc")
elessair 0:f269e3021894 134 zip_file.write(source, dest)
elessair 0:f269e3021894 135
elessair 0:f269e3021894 136
elessair 0:f269e3021894 137
elessair 0:f269e3021894 138 def export_project(src_paths, export_path, target, ide,
elessair 0:f269e3021894 139 libraries_paths=None, linker_script=None, clean=False,
elessair 0:f269e3021894 140 notify=None, verbose=False, name=None, inc_dirs=None,
elessair 0:f269e3021894 141 jobs=1, silent=False, extra_verbose=False, config=None,
elessair 0:f269e3021894 142 macros=None, zip_proj=None, inc_repos=False,
elessair 0:f269e3021894 143 build_profile=None):
elessair 0:f269e3021894 144 """Generates a project file and creates a zip archive if specified
elessair 0:f269e3021894 145
elessair 0:f269e3021894 146 Positional Arguments:
elessair 0:f269e3021894 147 src_paths - a list of paths from which to find source files
elessair 0:f269e3021894 148 export_path - a path specifying the location of generated project files
elessair 0:f269e3021894 149 target - the mbed board/mcu for which to generate the executable
elessair 0:f269e3021894 150 ide - the ide for which to generate the project fields
elessair 0:f269e3021894 151
elessair 0:f269e3021894 152 Keyword Arguments:
elessair 0:f269e3021894 153 libraries_paths - paths to additional libraries
elessair 0:f269e3021894 154 linker_script - path to the linker script for the specified target
elessair 0:f269e3021894 155 clean - removes the export_path if it exists
elessair 0:f269e3021894 156 notify - function is passed all events, and expected to handle notification
elessair 0:f269e3021894 157 of the user, emit the events to a log, etc.
elessair 0:f269e3021894 158 verbose - assigns the notify function to toolchains print_notify_verbose
elessair 0:f269e3021894 159 name - project name
elessair 0:f269e3021894 160 inc_dirs - additional include directories
elessair 0:f269e3021894 161 jobs - number of threads
elessair 0:f269e3021894 162 silent - silent build - no output
elessair 0:f269e3021894 163 extra_verbose - assigns the notify function to toolchains
elessair 0:f269e3021894 164 print_notify_verbose
elessair 0:f269e3021894 165 config - toolchain's config object
elessair 0:f269e3021894 166 macros - User-defined macros
elessair 0:f269e3021894 167 zip_proj - string name of the zip archive you wish to creat (exclude arg
elessair 0:f269e3021894 168 if you do not wish to create an archive
elessair 0:f269e3021894 169 """
elessair 0:f269e3021894 170
elessair 0:f269e3021894 171 # Convert src_path to a list if needed
elessair 0:f269e3021894 172 if isinstance(src_paths, dict):
elessair 0:f269e3021894 173 paths = sum(src_paths.values(), [])
elessair 0:f269e3021894 174 elif isinstance(src_paths, list):
elessair 0:f269e3021894 175 paths = src_paths[:]
elessair 0:f269e3021894 176 else:
elessair 0:f269e3021894 177 paths = [src_paths]
elessair 0:f269e3021894 178
elessair 0:f269e3021894 179 # Extend src_paths wit libraries_paths
elessair 0:f269e3021894 180 if libraries_paths is not None:
elessair 0:f269e3021894 181 paths.extend(libraries_paths)
elessair 0:f269e3021894 182
elessair 0:f269e3021894 183 if not isinstance(src_paths, dict):
elessair 0:f269e3021894 184 src_paths = {"": paths}
elessair 0:f269e3021894 185
elessair 0:f269e3021894 186 # Export Directory
elessair 0:f269e3021894 187 if exists(export_path) and clean:
elessair 0:f269e3021894 188 rmtree(export_path)
elessair 0:f269e3021894 189 if not exists(export_path):
elessair 0:f269e3021894 190 makedirs(export_path)
elessair 0:f269e3021894 191
elessair 0:f269e3021894 192 _, toolchain_name = get_exporter_toolchain(ide)
elessair 0:f269e3021894 193
elessair 0:f269e3021894 194 # Pass all params to the unified prepare_resources()
elessair 0:f269e3021894 195 toolchain = prepare_toolchain(paths, target, toolchain_name,
elessair 0:f269e3021894 196 macros=macros, clean=clean, jobs=jobs,
elessair 0:f269e3021894 197 notify=notify, silent=silent, verbose=verbose,
elessair 0:f269e3021894 198 extra_verbose=extra_verbose, config=config,
elessair 0:f269e3021894 199 build_profile=build_profile)
elessair 0:f269e3021894 200 # The first path will give the name to the library
elessair 0:f269e3021894 201 if name is None:
elessair 0:f269e3021894 202 name = basename(normpath(abspath(src_paths[0])))
elessair 0:f269e3021894 203
elessair 0:f269e3021894 204 # Call unified scan_resources
elessair 0:f269e3021894 205 resource_dict = {loc: scan_resources(path, toolchain, inc_dirs=inc_dirs)
elessair 0:f269e3021894 206 for loc, path in src_paths.iteritems()}
elessair 0:f269e3021894 207 resources = Resources()
elessair 0:f269e3021894 208 toolchain.build_dir = export_path
elessair 0:f269e3021894 209 config_header = toolchain.get_config_header()
elessair 0:f269e3021894 210 resources.headers.append(config_header)
elessair 0:f269e3021894 211 resources.file_basepath[config_header] = dirname(config_header)
elessair 0:f269e3021894 212
elessair 0:f269e3021894 213 if zip_proj:
elessair 0:f269e3021894 214 subtract_basepath(resources, export_path)
elessair 0:f269e3021894 215 for loc, res in resource_dict.iteritems():
elessair 0:f269e3021894 216 temp = copy.deepcopy(res)
elessair 0:f269e3021894 217 subtract_basepath(temp, export_path, loc)
elessair 0:f269e3021894 218 resources.add(temp)
elessair 0:f269e3021894 219 else:
elessair 0:f269e3021894 220 for _, res in resource_dict.iteritems():
elessair 0:f269e3021894 221 resources.add(res)
elessair 0:f269e3021894 222
elessair 0:f269e3021894 223 # Change linker script if specified
elessair 0:f269e3021894 224 if linker_script is not None:
elessair 0:f269e3021894 225 resources.linker_script = linker_script
elessair 0:f269e3021894 226
elessair 0:f269e3021894 227 files, exporter = generate_project_files(resources, export_path,
elessair 0:f269e3021894 228 target, name, toolchain, ide,
elessair 0:f269e3021894 229 macros=macros)
elessair 0:f269e3021894 230 files.append(config_header)
elessair 0:f269e3021894 231 if zip_proj:
elessair 0:f269e3021894 232 if isinstance(zip_proj, basestring):
elessair 0:f269e3021894 233 zip_export(join(export_path, zip_proj), name, resource_dict, files, inc_repos)
elessair 0:f269e3021894 234 else:
elessair 0:f269e3021894 235 zip_export(zip_proj, name, resource_dict, files, inc_repos)
elessair 0:f269e3021894 236
elessair 0:f269e3021894 237 return exporter
elessair 0:f269e3021894 238
elessair 0:f269e3021894 239
elessair 0:f269e3021894 240 def print_results(successes, failures, skips=None):
elessair 0:f269e3021894 241 """ Print out the results of an export process
elessair 0:f269e3021894 242
elessair 0:f269e3021894 243 Positional arguments:
elessair 0:f269e3021894 244 successes - The list of exports that succeeded
elessair 0:f269e3021894 245 failures - The list of exports that failed
elessair 0:f269e3021894 246
elessair 0:f269e3021894 247 Keyword arguments:
elessair 0:f269e3021894 248 skips - The list of exports that were skipped
elessair 0:f269e3021894 249 """
elessair 0:f269e3021894 250 print
elessair 0:f269e3021894 251 if successes:
elessair 0:f269e3021894 252 print "Successful: "
elessair 0:f269e3021894 253 for success in successes:
elessair 0:f269e3021894 254 print " * %s" % success
elessair 0:f269e3021894 255 if failures:
elessair 0:f269e3021894 256 print "Failed: "
elessair 0:f269e3021894 257 for failure in failures:
elessair 0:f269e3021894 258 print " * %s" % failure
elessair 0:f269e3021894 259 if skips:
elessair 0:f269e3021894 260 print "Skipped: "
elessair 0:f269e3021894 261 for skip in skips:
elessair 0:f269e3021894 262 print " * %s" % skip
elessair 0:f269e3021894 263