OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2015 The Chromium Authors. All rights reserved. | 2 # Copyright 2015 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """MB - the Meta-Build wrapper around GYP and GN | 6 """MB - the Meta-Build wrapper around GYP and GN |
7 | 7 |
8 MB is a wrapper script for GYP and GN that can be used to generate build files | 8 MB is a wrapper script for GYP and GN that can be used to generate build files |
9 for sets of canned configurations and analyze them. | 9 for sets of canned configurations and analyze them. |
10 """ | 10 """ |
(...skipping 755 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
766 env['GYP_CROSSCOMPILE'] = '1' | 766 env['GYP_CROSSCOMPILE'] = '1' |
767 return cmd, env | 767 return cmd, env |
768 | 768 |
769 def RunGNAnalyze(self, vals): | 769 def RunGNAnalyze(self, vals): |
770 # analyze runs before 'gn gen' now, so we need to run gn gen | 770 # analyze runs before 'gn gen' now, so we need to run gn gen |
771 # in order to ensure that we have a build directory. | 771 # in order to ensure that we have a build directory. |
772 ret = self.RunGNGen(vals) | 772 ret = self.RunGNGen(vals) |
773 if ret: | 773 if ret: |
774 return ret | 774 return ret |
775 | 775 |
776 inp = self.ReadInputJSON(['files', 'targets']) | 776 # TODO(dpranke): add 'test_targets' and 'additional_compile_targets' |
| 777 # as required keys once the recipe has been converted over. |
| 778 # See crbug.com/552146. |
| 779 inp = self.ReadInputJSON(['files']) |
777 if self.args.verbose: | 780 if self.args.verbose: |
778 self.Print() | 781 self.Print() |
779 self.Print('analyze input:') | 782 self.Print('analyze input:') |
780 self.PrintJSON(inp) | 783 self.PrintJSON(inp) |
781 self.Print() | 784 self.Print() |
782 | 785 |
| 786 use_new_logic = ('test_targets' in inp and |
| 787 'additional_compile_targets' in inp) |
| 788 if use_new_logic: |
| 789 # TODO(crbug.com/555273) - currently GN treats targets and |
| 790 # additional_compile_targets identically since we can't tell the |
| 791 # difference between a target that is a group in GN and one that isn't. |
| 792 # We should eventually fix this and treat the two types differently. |
| 793 targets = (set(inp['test_targets']) | |
| 794 set(inp['additional_compile_targets'])) |
| 795 else: |
| 796 targets = set(inp['targets']) |
| 797 |
783 output_path = self.args.output_path[0] | 798 output_path = self.args.output_path[0] |
784 | 799 |
785 # Bail out early if a GN file was modified, since 'gn refs' won't know | 800 # Bail out early if a GN file was modified, since 'gn refs' won't know |
786 # what to do about it. | 801 # what to do about it. Also, bail out early if 'all' was asked for, |
787 if any(f.endswith('.gn') or f.endswith('.gni') for f in inp['files']): | 802 # since we can't deal with it yet. |
788 self.WriteJSON({'status': 'Found dependency (all)'}, output_path) | 803 if (any(f.endswith('.gn') or f.endswith('.gni') for f in inp['files']) or |
789 return 0 | 804 'all' in targets): |
790 | 805 if use_new_logic: |
791 # Bail out early if 'all' was asked for, since 'gn refs' won't recognize it. | 806 self.WriteJSON({ |
792 if 'all' in inp['targets']: | 807 'status': 'Found dependency (all)', |
793 self.WriteJSON({'status': 'Found dependency (all)'}, output_path) | 808 'compile_targets': sorted(targets), |
| 809 'test_targets': sorted(targets & set(inp['test_targets'])), |
| 810 }, output_path) |
| 811 else: |
| 812 self.WriteJSON({'status': 'Found dependency (all)'}, output_path) |
794 return 0 | 813 return 0 |
795 | 814 |
796 # This shouldn't normally happen, but could due to unusual race conditions, | 815 # This shouldn't normally happen, but could due to unusual race conditions, |
797 # like a try job that gets scheduled before a patch lands but runs after | 816 # like a try job that gets scheduled before a patch lands but runs after |
798 # the patch has landed. | 817 # the patch has landed. |
799 if not inp['files']: | 818 if not inp['files']: |
800 self.Print('Warning: No files modified in patch, bailing out early.') | 819 self.Print('Warning: No files modified in patch, bailing out early.') |
801 self.WriteJSON({'targets': [], | 820 if use_new_logic: |
802 'build_targets': [], | 821 self.WriteJSON({ |
803 'status': 'No dependency'}, output_path) | 822 'status': 'No dependency', |
| 823 'compile_targets': [], |
| 824 'test_targets': [], |
| 825 }, output_path) |
| 826 else: |
| 827 self.WriteJSON({ |
| 828 'status': 'No dependency', |
| 829 'targets': [], |
| 830 'build_targets': [], |
| 831 }, output_path) |
804 return 0 | 832 return 0 |
805 | 833 |
806 ret = 0 | 834 ret = 0 |
807 response_file = self.TempFile() | 835 response_file = self.TempFile() |
808 response_file.write('\n'.join(inp['files']) + '\n') | 836 response_file.write('\n'.join(inp['files']) + '\n') |
809 response_file.close() | 837 response_file.close() |
810 | 838 |
811 matching_targets = [] | 839 matching_targets = set() |
812 try: | 840 try: |
813 cmd = self.GNCmd('refs', self.args.path[0]) + [ | 841 cmd = self.GNCmd('refs', self.args.path[0]) + [ |
814 '@%s' % response_file.name, '--all', '--as=output'] | 842 '@%s' % response_file.name, '--all', '--as=output'] |
815 ret, out, _ = self.Run(cmd, force_verbose=False) | 843 ret, out, _ = self.Run(cmd, force_verbose=False) |
816 if ret and not 'The input matches no targets' in out: | 844 if ret and not 'The input matches no targets' in out: |
817 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out), | 845 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out), |
818 output_path) | 846 output_path) |
819 build_dir = self.ToSrcRelPath(self.args.path[0]) + self.sep | 847 build_dir = self.ToSrcRelPath(self.args.path[0]) + self.sep |
820 for output in out.splitlines(): | 848 for output in out.splitlines(): |
821 build_output = output.replace(build_dir, '') | 849 build_output = output.replace(build_dir, '') |
822 if build_output in inp['targets']: | 850 if build_output in targets: |
823 matching_targets.append(build_output) | 851 matching_targets.add(build_output) |
824 | 852 |
825 cmd = self.GNCmd('refs', self.args.path[0]) + [ | 853 cmd = self.GNCmd('refs', self.args.path[0]) + [ |
826 '@%s' % response_file.name, '--all'] | 854 '@%s' % response_file.name, '--all'] |
827 ret, out, _ = self.Run(cmd, force_verbose=False) | 855 ret, out, _ = self.Run(cmd, force_verbose=False) |
828 if ret and not 'The input matches no targets' in out: | 856 if ret and not 'The input matches no targets' in out: |
829 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out), | 857 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out), |
830 output_path) | 858 output_path) |
831 for label in out.splitlines(): | 859 for label in out.splitlines(): |
832 build_target = label[2:] | 860 build_target = label[2:] |
833 # We want to accept 'chrome/android:chrome_public_apk' and | 861 # We want to accept 'chrome/android:chrome_public_apk' and |
834 # just 'chrome_public_apk'. This may result in too many targets | 862 # just 'chrome_public_apk'. This may result in too many targets |
835 # getting built, but we can adjust that later if need be. | 863 # getting built, but we can adjust that later if need be. |
836 for input_target in inp['targets']: | 864 for input_target in targets: |
837 if (input_target == build_target or | 865 if (input_target == build_target or |
838 build_target.endswith(':' + input_target)): | 866 build_target.endswith(':' + input_target)): |
839 matching_targets.append(input_target) | 867 matching_targets.add(input_target) |
840 finally: | 868 finally: |
841 self.RemoveFile(response_file.name) | 869 self.RemoveFile(response_file.name) |
842 | 870 |
843 if matching_targets: | 871 if matching_targets: |
844 # TODO: it could be that a target X might depend on a target Y | 872 if use_new_logic: |
845 # and both would be listed in the input, but we would only need | 873 self.WriteJSON({ |
846 # to specify target X as a build_target (whereas both X and Y are | 874 'status': 'Found dependency', |
847 # targets). I'm not sure if that optimization is generally worth it. | 875 'compile_targets': sorted(matching_targets), |
848 self.WriteJSON({'targets': sorted(set(matching_targets)), | 876 'test_targets': sorted(matching_targets & |
849 'build_targets': sorted(set(matching_targets)), | 877 set(inp['test_targets'])), |
850 'status': 'Found dependency'}, output_path) | 878 }, output_path) |
| 879 else: |
| 880 self.WriteJSON({ |
| 881 'status': 'Found dependency', |
| 882 'targets': sorted(matching_targets), |
| 883 'build_targets': sorted(matching_targets), |
| 884 }, output_path) |
851 else: | 885 else: |
852 self.WriteJSON({'targets': [], | 886 if use_new_logic: |
853 'build_targets': [], | 887 self.WriteJSON({ |
854 'status': 'No dependency'}, output_path) | 888 'status': 'No dependency', |
| 889 'compile_targets': [], |
| 890 'test_targets': [], |
| 891 }, output_path) |
| 892 else: |
| 893 self.WriteJSON({ |
| 894 'status': 'No dependency', |
| 895 'targets': [], |
| 896 'build_targets': [], |
| 897 }, output_path) |
855 | 898 |
856 if self.args.verbose: | 899 if self.args.verbose: |
857 outp = json.loads(self.ReadFile(output_path)) | 900 outp = json.loads(self.ReadFile(output_path)) |
858 self.Print() | 901 self.Print() |
859 self.Print('analyze output:') | 902 self.Print('analyze output:') |
860 self.PrintJSON(outp) | 903 self.PrintJSON(outp) |
861 self.Print() | 904 self.Print() |
862 | 905 |
863 return 0 | 906 return 0 |
864 | 907 |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1047 | 1090 |
1048 if __name__ == '__main__': | 1091 if __name__ == '__main__': |
1049 try: | 1092 try: |
1050 sys.exit(main(sys.argv[1:])) | 1093 sys.exit(main(sys.argv[1:])) |
1051 except MBErr as e: | 1094 except MBErr as e: |
1052 print(e) | 1095 print(e) |
1053 sys.exit(1) | 1096 sys.exit(1) |
1054 except KeyboardInterrupt: | 1097 except KeyboardInterrupt: |
1055 print("interrupted, exiting", stream=sys.stderr) | 1098 print("interrupted, exiting", stream=sys.stderr) |
1056 sys.exit(130) | 1099 sys.exit(130) |
OLD | NEW |