]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - tools/moveconfig.py
karo: tx28: supply a valid stack pointer to early SPL code
[karo-tx-uboot.git] / tools / moveconfig.py
index d775cf80c2056481bf547bec0570bdcaa588776e..496c90a9dc81dc70ff705bea9c1a727d8175ed16 100755 (executable)
@@ -46,6 +46,9 @@ should look like this:
   CONFIG_CMD_USB bool n
   CONFIG_SYS_TEXT_BASE hex 0x00000000
 
+Next you must edit the Kconfig to add the menu entries for the configs
+you are moving.
+
 And then run this tool giving the file name of the recipe
 
   $ tools/moveconfig.py recipe
@@ -132,6 +135,9 @@ Available options
    Surround each portion of the log with escape sequences to display it
    in color on the terminal.
 
+ -d, --defconfigs
+  Specify a file containing a list of defconfigs to move
+
  -n, --dry-run
    Peform a trial run that does not make any changes.  It is useful to
    see what is going to happen before one actually runs it.
@@ -140,10 +146,16 @@ Available options
    Exit immediately if Make exits with a non-zero status while processing
    a defconfig file.
 
+ -H, --headers-only
+   Only cleanup the headers; skip the defconfig processing
+
  -j, --jobs
    Specify the number of threads to run simultaneously.  If not specified,
    the number of threads is the same as the number of CPU cores.
 
+ -v, --verbose
+   Show any build errors as boards are built
+
 To see the complete list of supported options, run
 
   $ tools/moveconfig.py -h
@@ -193,6 +205,7 @@ CROSS_COMPILE = {
 STATE_IDLE = 0
 STATE_DEFCONFIG = 1
 STATE_AUTOCONF = 2
+STATE_SAVEDEFCONFIG = 3
 
 ACTION_MOVE = 0
 ACTION_DEFAULT_VALUE = 1
@@ -338,11 +351,12 @@ def cleanup_headers(config_attrs, dry_run):
         patterns.append(re.compile(r'#\s*define\s+%s\W' % config))
         patterns.append(re.compile(r'#\s*undef\s+%s\W' % config))
 
-    for (dirpath, dirnames, filenames) in os.walk('include'):
-        for filename in filenames:
-            if not fnmatch.fnmatch(filename, '*~'):
-                cleanup_one_header(os.path.join(dirpath, filename), patterns,
-                                   dry_run)
+    for dir in 'include', 'arch', 'board':
+        for (dirpath, dirnames, filenames) in os.walk(dir):
+            for filename in filenames:
+                if not fnmatch.fnmatch(filename, '*~'):
+                    cleanup_one_header(os.path.join(dirpath, filename),
+                                       patterns, dry_run)
 
 ### classes ###
 class KconfigParser:
@@ -391,8 +405,7 @@ class KconfigParser:
 
         return CROSS_COMPILE.get(arch, '')
 
-    def parse_one_config(self, config_attr, defconfig_lines,
-                         dotconfig_lines, autoconf_lines):
+    def parse_one_config(self, config_attr, defconfig_lines, autoconf_lines):
         """Parse .config, defconfig, include/autoconf.mk for one config.
 
         This function looks for the config options in the lines from
@@ -403,7 +416,6 @@ class KconfigParser:
           config_attr: A dictionary including the name, the type,
                        and the default value of the target config.
           defconfig_lines: lines from the original defconfig file.
-          dotconfig_lines: lines from the .config file.
           autoconf_lines: lines from the include/autoconf.mk file.
 
         Returns:
@@ -419,7 +431,7 @@ class KconfigParser:
         else:
             default = config + '=' + config_attr['default']
 
-        for line in defconfig_lines + dotconfig_lines:
+        for line in defconfig_lines:
             line = line.rstrip()
             if line.startswith(config + '=') or line == not_set:
                 return (ACTION_ALREADY_EXIST, line)
@@ -464,15 +476,12 @@ class KconfigParser:
         with open(defconfig_path) as f:
             defconfig_lines = f.readlines()
 
-        with open(dotconfig_path) as f:
-            dotconfig_lines = f.readlines()
-
         with open(autoconf_path) as f:
             autoconf_lines = f.readlines()
 
         for config_attr in self.config_attrs:
             result = self.parse_one_config(config_attr, defconfig_lines,
-                                           dotconfig_lines, autoconf_lines)
+                                           autoconf_lines)
             results.append(result)
 
         log = ''
@@ -500,7 +509,7 @@ class KconfigParser:
         print log,
 
         if not self.options.dry_run:
-            with open(defconfig_path, 'a') as f:
+            with open(dotconfig_path, 'a') as f:
                 for (action, value) in results:
                     if action == ACTION_MOVE:
                         f.write(value + '\n')
@@ -550,7 +559,7 @@ class Slot:
                 pass
         shutil.rmtree(self.build_dir)
 
-    def add(self, defconfig):
+    def add(self, defconfig, num, total):
         """Assign a new subprocess for defconfig and add it to the slot.
 
         If the slot is vacant, create a new subprocess for processing the
@@ -567,9 +576,12 @@ class Slot:
             return False
         cmd = list(self.make_cmd)
         cmd.append(defconfig)
-        self.ps = subprocess.Popen(cmd, stdout=self.devnull)
+        self.ps = subprocess.Popen(cmd, stdout=self.devnull,
+                                   stderr=subprocess.PIPE)
         self.defconfig = defconfig
         self.state = STATE_DEFCONFIG
+        self.num = num
+        self.total = total
         return True
 
     def poll(self):
@@ -592,11 +604,21 @@ class Slot:
             return False
 
         if self.ps.poll() != 0:
-
+            errmsg = 'Failed to process.'
+            errout = self.ps.stderr.read()
+            if errout.find('gcc: command not found') != -1:
+                errmsg = 'Compiler not found ('
+                errmsg += color_text(self.options.color, COLOR_YELLOW,
+                                     self.cross_compile)
+                errmsg += color_text(self.options.color, COLOR_LIGHT_RED,
+                                     ')')
             print >> sys.stderr, log_msg(self.options.color,
                                          COLOR_LIGHT_RED,
                                          self.defconfig,
-                                         "failed to process.")
+                                         errmsg),
+            if self.options.verbose:
+                print >> sys.stderr, color_text(self.options.color,
+                                                COLOR_LIGHT_CYAN, errout)
             if self.options.exit_on_error:
                 sys.exit("Exit on error.")
             else:
@@ -609,15 +631,36 @@ class Slot:
 
         if self.state == STATE_AUTOCONF:
             self.parser.update_defconfig(self.defconfig)
+
+            print ' %d defconfigs out of %d\r' % (self.num + 1, self.total),
+            sys.stdout.flush()
+
+            """Save off the defconfig in a consistent way"""
+            cmd = list(self.make_cmd)
+            cmd.append('savedefconfig')
+            self.ps = subprocess.Popen(cmd, stdout=self.devnull,
+                                       stderr=subprocess.PIPE)
+            self.state = STATE_SAVEDEFCONFIG
+            return False
+
+        if self.state == STATE_SAVEDEFCONFIG:
+            defconfig_path = os.path.join(self.build_dir, 'defconfig')
+            shutil.move(defconfig_path,
+                        os.path.join('configs', self.defconfig))
             self.state = STATE_IDLE
             return True
 
-        cross_compile = self.parser.get_cross_compile()
+        self.cross_compile = self.parser.get_cross_compile()
         cmd = list(self.make_cmd)
-        if cross_compile:
-            cmd.append('CROSS_COMPILE=%s' % cross_compile)
+        if self.cross_compile:
+            cmd.append('CROSS_COMPILE=%s' % self.cross_compile)
+        cmd.append('KCONFIG_IGNORE_DUPLICATES=1')
         cmd.append('include/config/auto.conf')
-        self.ps = subprocess.Popen(cmd, stdout=self.devnull)
+        """This will be screen-scraped, so be sure the expected text will be
+        returned consistently on every machine by setting LANG=C"""
+        self.ps = subprocess.Popen(cmd, stdout=self.devnull,
+                                   env=dict(os.environ, LANG='C'),
+                                   stderr=subprocess.PIPE)
         self.state = STATE_AUTOCONF
         return False
 
@@ -645,7 +688,7 @@ class Slots:
         for i in range(options.jobs):
             self.slots.append(Slot(config_attrs, options, devnull, make_cmd))
 
-    def add(self, defconfig):
+    def add(self, defconfig, num, total):
         """Add a new subprocess if a vacant slot is found.
 
         Arguments:
@@ -655,7 +698,7 @@ class Slots:
           Return True on success or False on failure
         """
         for slot in self.slots:
-            if slot.add(defconfig):
+            if slot.add(defconfig, num, total):
                 return True
         return False
 
@@ -696,6 +739,10 @@ class Slots:
                 print >> sys.stderr, color_text(self.options.color,
                                                 COLOR_LIGHT_RED, line)
 
+            with open('moveconfig.failed', 'w') as f:
+                for board in failed_boards:
+                    f.write(board + '\n')
+
 def move_config(config_attrs, options):
     """Move config options to defconfig files.
 
@@ -704,8 +751,6 @@ def move_config(config_attrs, options):
                     the type, and the default value of the target config.
       options: option flags
     """
-    check_top_directory()
-
     if len(config_attrs) == 0:
         print 'Nothing to do. exit.'
         sys.exit(0)
@@ -716,20 +761,29 @@ def move_config(config_attrs, options):
                                                 config_attr['type'],
                                                 config_attr['default'])
 
-    # All the defconfig files to be processed
-    defconfigs = []
-    for (dirpath, dirnames, filenames) in os.walk('configs'):
-        dirpath = dirpath[len('configs') + 1:]
-        for filename in fnmatch.filter(filenames, '*_defconfig'):
-            defconfigs.append(os.path.join(dirpath, filename))
+    if options.defconfigs:
+        defconfigs = [line.strip() for line in open(options.defconfigs)]
+        for i, defconfig in enumerate(defconfigs):
+            if not defconfig.endswith('_defconfig'):
+                defconfigs[i] = defconfig + '_defconfig'
+            if not os.path.exists(os.path.join('configs', defconfigs[i])):
+                sys.exit('%s - defconfig does not exist. Stopping.' %
+                         defconfigs[i])
+    else:
+        # All the defconfig files to be processed
+        defconfigs = []
+        for (dirpath, dirnames, filenames) in os.walk('configs'):
+            dirpath = dirpath[len('configs') + 1:]
+            for filename in fnmatch.filter(filenames, '*_defconfig'):
+                defconfigs.append(os.path.join(dirpath, filename))
 
     slots = Slots(config_attrs, options)
 
     # Main loop to process defconfig files:
     #  Add a new subprocess into a vacant slot.
     #  Sleep if there is no available slot.
-    for defconfig in defconfigs:
-        while not slots.add(defconfig):
+    for i, defconfig in enumerate(defconfigs):
+        while not slots.add(defconfig, i, len(defconfigs)):
             while not slots.available():
                 # No available slot: sleep for a while
                 time.sleep(SLEEP_TIME)
@@ -738,10 +792,9 @@ def move_config(config_attrs, options):
     while not slots.empty():
         time.sleep(SLEEP_TIME)
 
+    print ''
     slots.show_failed_boards()
 
-    cleanup_headers(config_attrs, options.dry_run)
-
 def bad_recipe(filename, linenum, msg):
     """Print error message with the file name and the line number and exit."""
     sys.exit("%s: line %d: error : " % (filename, linenum) + msg)
@@ -822,13 +875,20 @@ def main():
     # Add options here
     parser.add_option('-c', '--color', action='store_true', default=False,
                       help='display the log in color')
+    parser.add_option('-d', '--defconfigs', type='string',
+                      help='a file containing a list of defconfigs to move')
     parser.add_option('-n', '--dry-run', action='store_true', default=False,
                       help='perform a trial run (show log with no changes)')
     parser.add_option('-e', '--exit-on-error', action='store_true',
                       default=False,
                       help='exit immediately on any error')
+    parser.add_option('-H', '--headers-only', dest='cleanup_headers_only',
+                      action='store_true', default=False,
+                      help='only cleanup the headers')
     parser.add_option('-j', '--jobs', type='int', default=cpu_count,
                       help='the number of jobs to run simultaneously')
+    parser.add_option('-v', '--verbose', action='store_true', default=False,
+                      help='show any build errors as boards are built')
     parser.usage += ' recipe_file\n\n' + \
                     'The recipe_file should describe config options you want to move.\n' + \
                     'Each line should contain config_name, type, default_value\n\n' + \
@@ -847,7 +907,12 @@ def main():
 
     update_cross_compile()
 
-    move_config(config_attrs, options)
+    check_top_directory()
+
+    if not options.cleanup_headers_only:
+        move_config(config_attrs, options)
+
+    cleanup_headers(config_attrs, options.dry_run)
 
 if __name__ == '__main__':
     main()