Rizky Ardi Maulana / mbed-os
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.check_supported()
00090     exporter.generate()
00091     files = exporter.generated_files
00092     return files, exporter
00093 
00094 
00095 def zip_export (file_name, prefix, resources, project_files, inc_repos):
00096     """Create a zip file from an exported project.
00097 
00098     Positional Parameters:
00099     file_name - the file name of the resulting zip file
00100     prefix - a directory name that will prefix the entire zip file's contents
00101     resources - a resources object with files that must be included in the zip
00102     project_files - a list of extra files to be added to the root of the prefix
00103       directory
00104     """
00105     with zipfile.ZipFile(file_name, "w") as zip_file:
00106         for prj_file in project_files:
00107             zip_file.write(prj_file, join(prefix, basename(prj_file)))
00108         for loc, resource in resources.iteritems():
00109             for res in [resource] + resource.features.values():
00110                 to_zip = (
00111                     res.headers + res.s_sources + res.c_sources +\
00112                     res.cpp_sources + res.libraries + res.hex_files + \
00113                     [res.linker_script] + res.bin_files + res.objects + \
00114                     res.json_files + res.lib_refs + res.lib_builds)
00115                 if inc_repos:
00116                     for directory in res.repo_dirs:
00117                         for root, _, files in walk(directory):
00118                             for repo_file in files:
00119                                 source = join(root, repo_file)
00120                                 to_zip.append(source)
00121                                 res.file_basepath[source] = res.base_path
00122                     to_zip += res.repo_files
00123                 for source in to_zip:
00124                     if source:
00125                         zip_file.write(
00126                             source,
00127                             join(prefix, loc,
00128                                  relpath(source, res.file_basepath[source])))
00129                 for source in res.lib_builds:
00130                     target_dir, _ = splitext(source)
00131                     dest = join(prefix, loc,
00132                                 relpath(target_dir, res.file_basepath[source]),
00133                                 ".bld", "bldrc")
00134                     zip_file.write(source, dest)
00135 
00136 
00137 
00138 def export_project (src_paths, export_path, target, ide,
00139                    libraries_paths=None, linker_script=None, clean=False,
00140                    notify=None, verbose=False, name=None, inc_dirs=None,
00141                    jobs=1, silent=False, extra_verbose=False, config=None,
00142                    macros=None, zip_proj=None, inc_repos=False,
00143                    build_profile=None):
00144     """Generates a project file and creates a zip archive if specified
00145 
00146     Positional Arguments:
00147     src_paths - a list of paths from which to find source files
00148     export_path - a path specifying the location of generated project files
00149     target - the mbed board/mcu for which to generate the executable
00150     ide - the ide for which to generate the project fields
00151 
00152     Keyword Arguments:
00153     libraries_paths - paths to additional libraries
00154     linker_script - path to the linker script for the specified target
00155     clean - removes the export_path if it exists
00156     notify - function is passed all events, and expected to handle notification
00157       of the user, emit the events to a log, etc.
00158     verbose - assigns the notify function to toolchains print_notify_verbose
00159     name - project name
00160     inc_dirs - additional include directories
00161     jobs - number of threads
00162     silent - silent build - no output
00163     extra_verbose - assigns the notify function to toolchains
00164       print_notify_verbose
00165     config - toolchain's config object
00166     macros - User-defined macros
00167     zip_proj - string name of the zip archive you wish to creat (exclude arg
00168      if you do not wish to create an archive
00169     """
00170 
00171     # Convert src_path to a list if needed
00172     if isinstance(src_paths, dict):
00173         paths = sum(src_paths.values(), [])
00174     elif isinstance(src_paths, list):
00175         paths = src_paths[:]
00176     else:
00177         paths = [src_paths]
00178 
00179     # Extend src_paths wit libraries_paths
00180     if libraries_paths is not None:
00181         paths.extend(libraries_paths)
00182 
00183     if not isinstance(src_paths, dict):
00184         src_paths = {"": paths}
00185 
00186     # Export Directory
00187     if exists(export_path) and clean:
00188         rmtree(export_path)
00189     if not exists(export_path):
00190         makedirs(export_path)
00191 
00192     _, toolchain_name = get_exporter_toolchain(ide)
00193 
00194     # Pass all params to the unified prepare_resources()
00195     toolchain = prepare_toolchain(paths, target, toolchain_name,
00196                                   macros=macros, clean=clean, jobs=jobs,
00197                                   notify=notify, silent=silent, verbose=verbose,
00198                                   extra_verbose=extra_verbose, config=config,
00199                                   build_profile=build_profile)
00200     # The first path will give the name to the library
00201     if name is None:
00202         name = basename(normpath(abspath(src_paths[0])))
00203 
00204     # Call unified scan_resources
00205     resource_dict = {loc: scan_resources(path, toolchain, inc_dirs=inc_dirs)
00206                      for loc, path in src_paths.iteritems()}
00207     resources = Resources()
00208     toolchain.build_dir = export_path
00209     config_header = toolchain.get_config_header()
00210     resources.headers.append(config_header)
00211     resources.file_basepath[config_header] = dirname(config_header)
00212 
00213     if zip_proj:
00214         subtract_basepath(resources, export_path)
00215         for loc, res in resource_dict.iteritems():
00216             temp = copy.deepcopy(res)
00217             subtract_basepath(temp, export_path, loc)
00218             resources.add(temp)
00219     else:
00220         for _, res in resource_dict.iteritems():
00221             resources.add(res)
00222 
00223     # Change linker script if specified
00224     if linker_script is not None:
00225         resources.linker_script = linker_script
00226 
00227     files, exporter = generate_project_files(resources, export_path,
00228                                              target, name, toolchain, ide,
00229                                              macros=macros)
00230     files.append(config_header)
00231     if zip_proj:
00232         if isinstance(zip_proj, basestring):
00233             zip_export(join(export_path, zip_proj), name, resource_dict, files, inc_repos)
00234         else:
00235             zip_export(zip_proj, name, resource_dict, files, inc_repos)
00236 
00237     return exporter
00238 
00239 
00240 def print_results (successes, failures, skips=None):
00241     """ Print out the results of an export process
00242 
00243     Positional arguments:
00244     successes - The list of exports that succeeded
00245     failures - The list of exports that failed
00246 
00247     Keyword arguments:
00248     skips - The list of exports that were skipped
00249     """
00250     print
00251     if successes:
00252         print "Successful: "
00253         for success in successes:
00254             print "  * %s" % success
00255     if failures:
00256         print "Failed: "
00257         for failure in failures:
00258             print "  * %s" % failure
00259     if skips:
00260         print "Skipped: "
00261         for skip in skips:
00262             print "  * %s" % skip
00263