Daiki Kato / mbed-os-lychee

Dependents:   mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers project_api.py Source File

project_api.py

00001 """ The new way of doing exports """
00002 import sys
00003 from os.path import join, abspath, dirname, exists
00004 from os.path import basename, relpath, normpath, splitext
00005 from os import makedirs, walk
00006 ROOT = abspath(join(dirname(__file__), ".."))
00007 sys.path.insert(0, ROOT)
00008 import copy
00009 from shutil import rmtree
00010 import zipfile
00011 
00012 from tools.build_api import prepare_toolchain
00013 from tools.build_api import scan_resources
00014 from tools.export import EXPORTERS
00015 from tools.toolchains import Resources
00016 
00017 
00018 def get_exporter_toolchain (ide):
00019     """ Return the exporter class and the toolchain string as a tuple
00020 
00021     Positional arguments:
00022     ide - the ide name of an exporter
00023     """
00024     return EXPORTERS[ide], EXPORTERS[ide].TOOLCHAIN
00025 
00026 
00027 def rewrite_basepath (file_name, resources, export_path, loc):
00028     """ Replace the basepath of filename with export_path
00029 
00030     Positional arguments:
00031     file_name - the absolute path to a file
00032     resources - the resources object that the file came from
00033     export_path - the final destination of the file after export
00034     """
00035     new_f = join(loc, relpath(file_name, resources.file_basepath[file_name]))
00036     resources.file_basepath[join(export_path, new_f)] = export_path
00037     return new_f
00038 
00039 
00040 def subtract_basepath (resources, export_path, loc=""):
00041     """ Rewrite all of the basepaths with the export_path
00042 
00043     Positional arguments:
00044     resources - the resource object to rewrite the basepaths of
00045     export_path - the final destination of the resources with respect to the
00046       generated project files
00047     """
00048     keys = ['s_sources', 'c_sources', 'cpp_sources', 'hex_files',
00049             'objects', 'libraries', 'inc_dirs', 'headers', 'linker_script',
00050             'lib_dirs']
00051     for key in keys:
00052         vals = getattr(resources, key)
00053         if isinstance(vals, set):
00054             vals = list(vals)
00055         if isinstance(vals, list):
00056             new_vals = []
00057             for val in vals:
00058                 new_vals.append(rewrite_basepath(val, resources, export_path,
00059                                                  loc))
00060             if isinstance(getattr(resources, key), set):
00061                 setattr(resources, key, set(new_vals))
00062             else:
00063                 setattr(resources, key, new_vals)
00064         elif vals:
00065             setattr(resources, key, rewrite_basepath(vals, resources,
00066                                                      export_path, loc))
00067 
00068 
00069 def generate_project_files (resources, export_path, target, name, toolchain, ide,
00070                            macros=None):
00071     """Generate the project files for a project
00072 
00073     Positional arguments:
00074     resources - a Resources object containing all of the files needed to build
00075       this project
00076     export_path - location to place project files
00077     name - name of the project
00078     toolchain - a toolchain class that corresponds to the toolchain used by the
00079       IDE or makefile
00080     ide - IDE name to export to
00081 
00082     Optional arguments:
00083     macros - additional macros that should be defined within the exported
00084       project
00085     """
00086     exporter_cls, _ = get_exporter_toolchain(ide)
00087     exporter = exporter_cls(target, export_path, name, toolchain,
00088                             extra_symbols=macros, resources=resources)
00089     exporter.generate()
00090     files = exporter.generated_files
00091     return files, exporter
00092 
00093 
00094 def zip_export (file_name, prefix, resources, project_files, inc_repos):
00095     """Create a zip file from an exported project.
00096 
00097     Positional Parameters:
00098     file_name - the file name of the resulting zip file
00099     prefix - a directory name that will prefix the entire zip file's contents
00100     resources - a resources object with files that must be included in the zip
00101     project_files - a list of extra files to be added to the root of the prefix
00102       directory
00103     """
00104     with zipfile.ZipFile(file_name, "w") as zip_file:
00105         for prj_file in project_files:
00106             zip_file.write(prj_file, join(prefix, basename(prj_file)))
00107         for loc, res in resources.iteritems():
00108             to_zip = (
00109                 res.headers + res.s_sources + res.c_sources +\
00110                 res.cpp_sources + res.libraries + res.hex_files + \
00111                 [res.linker_script] + res.bin_files + res.objects + \
00112                 res.json_files + res.lib_refs + res.lib_builds)
00113             if inc_repos:
00114                 for directory in res.repo_dirs:
00115                     for root, _, files in walk(directory):
00116                         for repo_file in files:
00117                             source = join(root, repo_file)
00118                             to_zip.append(source)
00119                             res.file_basepath[source] = res.base_path
00120                 to_zip += res.repo_files
00121             for source in to_zip:
00122                 if source:
00123                     zip_file.write(
00124                         source,
00125                         join(prefix, loc,
00126                              relpath(source, res.file_basepath[source])))
00127             for source in res.lib_builds:
00128                 target_dir, _ = splitext(source)
00129                 dest = join(prefix, loc,
00130                             relpath(target_dir, res.file_basepath[source]),
00131                             ".bld", "bldrc")
00132                 zip_file.write(source, dest)
00133 
00134 
00135 
00136 def export_project (src_paths, export_path, target, ide, libraries_paths=None,
00137                    linker_script=None, notify=None, verbose=False, name=None,
00138                    inc_dirs=None, jobs=1, silent=False, extra_verbose=False,
00139                    config=None, macros=None, zip_proj=None, inc_repos=False,
00140                    build_profile=None):
00141     """Generates a project file and creates a zip archive if specified
00142 
00143     Positional Arguments:
00144     src_paths - a list of paths from which to find source files
00145     export_path - a path specifying the location of generated project files
00146     target - the mbed board/mcu for which to generate the executable
00147     ide - the ide for which to generate the project fields
00148 
00149     Keyword Arguments:
00150     libraries_paths - paths to additional libraries
00151     linker_script - path to the linker script for the specified target
00152     notify - function is passed all events, and expected to handle notification
00153       of the user, emit the events to a log, etc.
00154     verbose - assigns the notify function to toolchains print_notify_verbose
00155     name - project name
00156     inc_dirs - additional include directories
00157     jobs - number of threads
00158     silent - silent build - no output
00159     extra_verbose - assigns the notify function to toolchains
00160       print_notify_verbose
00161     config - toolchain's config object
00162     macros - User-defined macros
00163     zip_proj - string name of the zip archive you wish to creat (exclude arg
00164      if you do not wish to create an archive
00165     """
00166 
00167     # Convert src_path to a list if needed
00168     if isinstance(src_paths, dict):
00169         paths = sum(src_paths.values(), [])
00170     elif isinstance(src_paths, list):
00171         paths = src_paths[:]
00172     else:
00173         paths = [src_paths]
00174 
00175     # Extend src_paths wit libraries_paths
00176     if libraries_paths is not None:
00177         paths.extend(libraries_paths)
00178 
00179     if not isinstance(src_paths, dict):
00180         src_paths = {"": paths}
00181 
00182     # Export Directory
00183     if not exists(export_path):
00184         makedirs(export_path)
00185 
00186     _, toolchain_name = get_exporter_toolchain(ide)
00187 
00188     # Pass all params to the unified prepare_resources()
00189     toolchain = prepare_toolchain(
00190         paths, "", target, toolchain_name, macros=macros, jobs=jobs,
00191         notify=notify, silent=silent, verbose=verbose,
00192         extra_verbose=extra_verbose, config=config, build_profile=build_profile)
00193     # The first path will give the name to the library
00194     if name is None:
00195         name = basename(normpath(abspath(src_paths[0])))
00196 
00197     # Call unified scan_resources
00198     resource_dict = {loc: scan_resources(path, toolchain, inc_dirs=inc_dirs)
00199                      for loc, path in src_paths.iteritems()}
00200     resources = Resources()
00201     toolchain.build_dir = export_path
00202     config_header = toolchain.get_config_header()
00203     resources.headers.append(config_header)
00204     resources.file_basepath[config_header] = dirname(config_header)
00205 
00206     if zip_proj:
00207         subtract_basepath(resources, export_path)
00208         for loc, res in resource_dict.iteritems():
00209             temp = copy.deepcopy(res)
00210             subtract_basepath(temp, export_path, loc)
00211             resources.add(temp)
00212     else:
00213         for _, res in resource_dict.iteritems():
00214             resources.add(res)
00215 
00216     # Change linker script if specified
00217     if linker_script is not None:
00218         resources.linker_script = linker_script
00219 
00220     files, exporter = generate_project_files(resources, export_path,
00221                                              target, name, toolchain, ide,
00222                                              macros=macros)
00223     files.append(config_header)
00224     if zip_proj:
00225         for resource in resource_dict.values():
00226             for label, res in resource.features.iteritems():
00227                 if label not in toolchain.target.features:
00228                     resource.add(res)
00229         if isinstance(zip_proj, basestring):
00230             zip_export(join(export_path, zip_proj), name, resource_dict, files,
00231                        inc_repos)
00232         else:
00233             zip_export(zip_proj, name, resource_dict, files, inc_repos)
00234 
00235     return exporter
00236 
00237 
00238 def print_results (successes, failures, skips=None):
00239     """ Print out the results of an export process
00240 
00241     Positional arguments:
00242     successes - The list of exports that succeeded
00243     failures - The list of exports that failed
00244 
00245     Keyword arguments:
00246     skips - The list of exports that were skipped
00247     """
00248     print
00249     if successes:
00250         print "Successful: "
00251         for success in successes:
00252             print "  * %s" % success
00253     if failures:
00254         print "Failed: "
00255         for failure in failures:
00256             print "  * %s" % failure
00257     if skips:
00258         print "Skipped: "
00259         for skip in skips:
00260             print "  * %s" % skip
00261