|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | + |
| 3 | +''' |
| 4 | +
|
| 5 | +Copyright(c) 2017 Cedric Jimenez |
| 6 | +
|
| 7 | +This file is part of Nano-OS. |
| 8 | +
|
| 9 | +Nano-OS is free software: you can redistribute it and/or modify |
| 10 | +it under the terms of the GNU Lesser General Public License as published by |
| 11 | +the Free Software Foundation, either version 3 of the License, or |
| 12 | +(at your option) any later version. |
| 13 | +
|
| 14 | +Nano-OS is distributed in the hope that it will be useful, |
| 15 | +but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | +GNU Lesser General Public License for more details. |
| 18 | +
|
| 19 | +You should have received a copy of the GNU Lesser General Public License |
| 20 | +along with Nano-OS. If not, see <http://www.gnu.org/licenses/>. |
| 21 | +
|
| 22 | +''' |
| 23 | + |
| 24 | + |
| 25 | +#################################################### |
| 26 | +####Imports |
| 27 | +import sys, os |
| 28 | +from argparse import ArgumentParser |
| 29 | + |
| 30 | + |
| 31 | +#################################################### |
| 32 | +####Data types |
| 33 | + |
| 34 | + |
| 35 | +class BuildParameters(object): |
| 36 | + ''' |
| 37 | + Contains the software parameters |
| 38 | + ''' |
| 39 | + |
| 40 | + def __init__(self): |
| 41 | + ''' |
| 42 | + Constructor |
| 43 | + ''' |
| 44 | + |
| 45 | + self.root_dir = "" |
| 46 | + ''' Root directory ''' |
| 47 | + |
| 48 | + self.target = "" |
| 49 | + ''' Build target ''' |
| 50 | + |
| 51 | + self.packages = [] |
| 52 | + ''' Packages to build ''' |
| 53 | + |
| 54 | + self.list_packages = False |
| 55 | + ''' Indicate if the packages must be listed ''' |
| 56 | + |
| 57 | + self.build_cmd = [] |
| 58 | + ''' Build command ''' |
| 59 | + |
| 60 | + self.header_dep = True |
| 61 | + ''' Header dependency check ''' |
| 62 | + |
| 63 | + self.verbose = False |
| 64 | + ''' Verbose mode ''' |
| 65 | + |
| 66 | + self.build_jobs = 1 |
| 67 | + ''' Number of build jobs ''' |
| 68 | + |
| 69 | + return |
| 70 | + |
| 71 | + |
| 72 | + |
| 73 | +#################################################### |
| 74 | +####Functions |
| 75 | + |
| 76 | +def checkargs(args, params): |
| 77 | + ''' |
| 78 | + Check the command line parameters |
| 79 | +
|
| 80 | + @param args: command line parameters |
| 81 | + @type args: string[] |
| 82 | + |
| 83 | + @param params: parameter storage class |
| 84 | + @type params: BuildParameters |
| 85 | +
|
| 86 | + @return: if the parameters are valid : True, if not : False |
| 87 | + @rtype: boolean |
| 88 | +
|
| 89 | + ''' |
| 90 | + |
| 91 | + # Retrieve the parameters |
| 92 | + parser_description = "Build tool v1.0" |
| 93 | + parser = ArgumentParser(description=parser_description) |
| 94 | + parser.add_argument('-t', nargs=1, metavar='target', required=True, |
| 95 | + help='[string] Target name') |
| 96 | + parser.add_argument('-p', nargs='+', metavar='package', |
| 97 | + required=True, help='[string] Packages to build') |
| 98 | + parser.add_argument('-c', nargs='+', metavar='command', |
| 99 | + required=True, help='[string] Build command, ex: all|all+|clean|clean+') |
| 100 | + parser.add_argument('-j', nargs=1, metavar='jobs', |
| 101 | + required=False, help='[int] Number of build jobs') |
| 102 | + parser.add_argument('-l', action='store_true', |
| 103 | + required=False, help='List all available packages and targets') |
| 104 | + parser.add_argument('-v', action='store_true', |
| 105 | + required=False, help='Verbose mode') |
| 106 | + parser.add_argument('-d', action='store_true', |
| 107 | + required=False, help='Header dependency check') |
| 108 | + |
| 109 | + # Check the parameters count |
| 110 | + if len(args) < 2: |
| 111 | + print "No input parameters specified" |
| 112 | + parser.print_help() |
| 113 | + return False |
| 114 | + |
| 115 | + # Display the software inline help |
| 116 | + if (("-h" in args) or ("--help" in args)): |
| 117 | + parser.print_help() |
| 118 | + return False |
| 119 | + |
| 120 | + # Parse the parameters |
| 121 | + if ("-l" in args): |
| 122 | + params.list_packages = True |
| 123 | + else: |
| 124 | + args = parser.parse_args() |
| 125 | + params.target = args.t[0] |
| 126 | + params.packages = args.p |
| 127 | + params.build_cmd = args.c |
| 128 | + if args.j != None: |
| 129 | + params.build_jobs = int(args.j[0]) |
| 130 | + params.list_packages = args.l |
| 131 | + params.verbose = args.v |
| 132 | + params.header_dep = args.d |
| 133 | + |
| 134 | + |
| 135 | + # All parameters are valid |
| 136 | + return True |
| 137 | + |
| 138 | +def listPackages(params, print_result): |
| 139 | + ''' |
| 140 | + List available packages |
| 141 | + |
| 142 | + @param params: parameter storage class |
| 143 | + @type params: BuildParameters |
| 144 | + |
| 145 | + @param print_result: indicate if the package list must be displayed |
| 146 | + @type print_result: bool |
| 147 | + |
| 148 | + ''' |
| 149 | + |
| 150 | + # List all packages |
| 151 | + build_dir = os.path.join(params.root_dir, "build") |
| 152 | + packages = [] |
| 153 | + package_name = "" |
| 154 | + recursiveListPackages(packages, package_name, build_dir) |
| 155 | + |
| 156 | + # List all targets |
| 157 | + targets = [] |
| 158 | + for dirname, dirnames, filenames in os.walk(build_dir): |
| 159 | + for filename in filenames: |
| 160 | + if filename.endswith(".target"): |
| 161 | + targets.append(filename[:len(filename)-7]) |
| 162 | + |
| 163 | + # Print results |
| 164 | + if print_result: |
| 165 | + print "" |
| 166 | + print "Packages list:" |
| 167 | + for package in packages: |
| 168 | + print " - " + package |
| 169 | + print "" |
| 170 | + print "Target list:" |
| 171 | + for target in targets: |
| 172 | + print " - " + target |
| 173 | + |
| 174 | + return (packages, targets) |
| 175 | + |
| 176 | +def recursiveListPackages(packages, package_name, current_dir): |
| 177 | + ''' |
| 178 | + List the packages recursively |
| 179 | + |
| 180 | + @param packages: list of the packages |
| 181 | + @type packages: string[] |
| 182 | + @param package_name: current package name |
| 183 | + @type package_name: string |
| 184 | + @param current_dir: current directory |
| 185 | + @type current_dir: string |
| 186 | + |
| 187 | + ''' |
| 188 | + |
| 189 | + for dirname, dirnames, filenames in os.walk(current_dir): |
| 190 | + if( ("makefile" in filenames) and ("makefile.inc" in filenames) ): |
| 191 | + packages.append(package_name[1:]) |
| 192 | + else: |
| 193 | + if len(dirnames) != 0: |
| 194 | + for dir in dirnames: |
| 195 | + package = package_name + "." + dir |
| 196 | + recursiveListPackages(packages, package, os.path.join(dirname, dir)) |
| 197 | + break |
| 198 | + |
| 199 | + return |
| 200 | + |
| 201 | +def buildPackages(params): |
| 202 | + ''' |
| 203 | + Build selected packages |
| 204 | + |
| 205 | + @param params: parameter storage class |
| 206 | + @type params: BuildParameters |
| 207 | + |
| 208 | + ''' |
| 209 | + |
| 210 | + successful_build_count = 0 |
| 211 | + total_build_count = 0 |
| 212 | + |
| 213 | + for package in params.packages: |
| 214 | + |
| 215 | + # Check if package name contains wildcard |
| 216 | + packages_to_build = [] |
| 217 | + if package.endswith("*"): |
| 218 | + (packages, targets) = listPackages(params, False) |
| 219 | + package = package[:len(package) - 1] |
| 220 | + for pack in packages: |
| 221 | + if pack.startswith(package): |
| 222 | + packages_to_build.append(pack) |
| 223 | + else: |
| 224 | + packages_to_build.append(package) |
| 225 | + |
| 226 | + # Build packages |
| 227 | + for package_to_build in packages_to_build: |
| 228 | + total_build_count = total_build_count + 1 |
| 229 | + print "" |
| 230 | + try: |
| 231 | + |
| 232 | + # Set build directory |
| 233 | + dir = os.path.join(params.root_dir, "build", package_to_build.replace('.', os.sep)) |
| 234 | + |
| 235 | + # Construct the build command |
| 236 | + command = "make -C " + dir + " -k" + " TARGET=" + params.target |
| 237 | + if params.build_jobs > 1: |
| 238 | + command = command + " -j " + str(params.build_jobs) + " --output-sync=target" |
| 239 | + for cmd in params.build_cmd: |
| 240 | + command = command + " " + cmd |
| 241 | + if params.header_dep: |
| 242 | + command = command + " HEADER_DEP=yes" |
| 243 | + if params.verbose: |
| 244 | + command = command + " DISPLAY=yes" |
| 245 | + print command |
| 246 | + else: |
| 247 | + command = command + " --no-print-directory" |
| 248 | + ret = os.system(command) |
| 249 | + if ret == 0: |
| 250 | + successful_build_count = successful_build_count + 1 |
| 251 | + |
| 252 | + except: |
| 253 | + print "" |
| 254 | + print "=> Invalid package : " + package |
| 255 | + |
| 256 | + print "" |
| 257 | + print "=> Success : " + str(successful_build_count) + "/" + str(total_build_count) |
| 258 | + |
| 259 | + if( successful_build_count == total_build_count ): |
| 260 | + ret = True |
| 261 | + else: |
| 262 | + ret = False |
| 263 | + |
| 264 | + return ret |
| 265 | + |
| 266 | +#################################################### |
| 267 | +####Software entry point |
| 268 | + |
| 269 | +if __name__ == '__main__': |
| 270 | + |
| 271 | + params = BuildParameters() |
| 272 | + params.root_dir = os.path.dirname(os.path.abspath(__file__)) |
| 273 | + |
| 274 | + # Check the command line parameters |
| 275 | + if not checkargs(sys.argv, params): |
| 276 | + sys.exit(-1) |
| 277 | + |
| 278 | + # Check action |
| 279 | + if params.list_packages: |
| 280 | + |
| 281 | + listPackages(params, True) |
| 282 | + ret = True |
| 283 | + |
| 284 | + else: |
| 285 | + |
| 286 | + ret = buildPackages(params) |
| 287 | + |
| 288 | + if ret: |
| 289 | + sys.exit(0) |
| 290 | + else: |
| 291 | + sys.exit(-1) |
| 292 | + |
| 293 | + |
| 294 | + |
0 commit comments