b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | #!/usr/bin/env perl |
| 2 | |
| 3 | use strict; |
| 4 | use warnings; |
| 5 | use Cwd; |
| 6 | |
| 7 | my (%targets, %architectures, %kernels, %devices); |
| 8 | |
| 9 | $ENV{'TOPDIR'} = Cwd::getcwd(); |
| 10 | |
| 11 | |
| 12 | sub parse_targetinfo { |
| 13 | my ($target_dir, $subtarget) = @_; |
| 14 | |
| 15 | if (open M, "make -C '$target_dir' --no-print-directory DUMP=1 TARGET_BUILD=1 SUBTARGET='$subtarget' |") { |
| 16 | my ($target_name, $target_arch, $target_kernel, $target_testing_kernel, @target_features); |
| 17 | while (defined(my $line = readline M)) { |
| 18 | chomp $line; |
| 19 | |
| 20 | if ($line =~ /^Target: (.+)$/) { |
| 21 | $target_name = $1; |
| 22 | } |
| 23 | elsif ($line =~ /^Target-Arch-Packages: (.+)$/) { |
| 24 | $target_arch = $1; |
| 25 | } |
| 26 | elsif ($line =~ /^Linux-Version: (\d\.\d+)\.\d+$/) { |
| 27 | $target_kernel = $1; |
| 28 | } |
| 29 | elsif ($line =~ /^Linux-Testing-Version: (\d\.\d+)\.\d+$/) { |
| 30 | $target_testing_kernel = $1; |
| 31 | } |
| 32 | elsif ($line =~ /^Target-Features: (.+)$/) { |
| 33 | @target_features = split /\s+/, $1; |
| 34 | } |
| 35 | elsif ($line =~ /^@\@$/) { |
| 36 | if ($target_name && $target_arch && $target_kernel && |
| 37 | !grep { $_ eq 'broken' or $_ eq 'source-only' } @target_features) { |
| 38 | $targets{$target_name} = $target_arch; |
| 39 | $architectures{$target_arch} ||= []; |
| 40 | push @{$architectures{$target_arch}}, $target_name; |
| 41 | $kernels{$target_name} ||= []; |
| 42 | push @{$kernels{$target_name}}, $target_kernel; |
| 43 | if ($target_testing_kernel) { |
| 44 | push @{$kernels{$target_name}}, $target_testing_kernel; |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | undef $target_name; |
| 49 | undef $target_arch; |
| 50 | undef $target_kernel; |
| 51 | undef $target_testing_kernel; |
| 52 | @target_features = (); |
| 53 | } |
| 54 | } |
| 55 | close M; |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | sub parse_devices { |
| 60 | my ($target_dir, $subtarget) = @_; |
| 61 | |
| 62 | if (open M, "make -C '$target_dir' --no-print-directory DUMP=1 TARGET_BUILD=1 SUBTARGET='$subtarget' V=s |") { |
| 63 | my ($device_profile, $device_name, @device_alt_names, $device_is_alt); |
| 64 | while (defined(my $line = readline M)) { |
| 65 | chomp $line; |
| 66 | |
| 67 | if ($line =~ /^Target-Profile-Name: (.+)$/) { |
| 68 | $device_name = $1; |
| 69 | } |
| 70 | elsif ($line =~ /^Target-Profile: DEVICE_(.+)$/) { |
| 71 | $device_profile = $1; |
| 72 | } |
| 73 | # Logic behind this. |
| 74 | # DUMP duplicate info for each alternative device name and |
| 75 | # the alternative device name are printed first before the |
| 76 | # primary device name |
| 77 | # Alternative device titles always have the full list of |
| 78 | # all the alternative device name. |
| 79 | # The device name pattern for an alternative device name is |
| 80 | # Target-Profile-Name: ALT_NAME (PRIMARY_NAME) |
| 81 | # We compare the detected device name and check if it does |
| 82 | # match the alternative device name pattern with one of |
| 83 | # the alternative device name in Alternative device titles: |
| 84 | # If an alternative device name is detected, |
| 85 | # alternative device is skipped. |
| 86 | elsif ($line =~ /^Alternative device titles:$/) { |
| 87 | while (defined($line = readline M)) { |
| 88 | if ($line =~ /^- (.+)$/) { |
| 89 | if ($device_name =~ /^\Q$1\E \((.+)\)$/) { |
| 90 | $device_is_alt = 1; |
| 91 | last; |
| 92 | } |
| 93 | push @device_alt_names, $1; |
| 94 | } |
| 95 | else { |
| 96 | last; |
| 97 | } |
| 98 | } |
| 99 | } |
| 100 | if ($line =~ /^@\@$/) { |
| 101 | if ($device_name && $device_profile && ! $device_is_alt) { |
| 102 | push @{$devices{$device_profile}}, $device_name; |
| 103 | |
| 104 | if (scalar @device_alt_names) { |
| 105 | foreach my $device_alt_name (sort values @device_alt_names) { |
| 106 | push @{$devices{$device_profile}}, $device_alt_name; |
| 107 | } |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | undef $device_name; |
| 112 | undef $device_profile; |
| 113 | undef $device_is_alt; |
| 114 | @device_alt_names = (); |
| 115 | } |
| 116 | } |
| 117 | close M; |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | sub get_targetinfo { |
| 122 | foreach my $target_makefile (glob "target/linux/*/Makefile") { |
| 123 | my ($target_dir) = $target_makefile =~ m!^(.+)/Makefile$!; |
| 124 | my @subtargets; |
| 125 | |
| 126 | if (open M, "make -C '$target_dir' --no-print-directory DUMP=1 TARGET_BUILD=1 val.FEATURES V=s 2>/dev/null |") { |
| 127 | if (defined(my $line = readline M)) { |
| 128 | chomp $line; |
| 129 | if (grep { $_ eq 'broken' or $_ eq 'source-only' } split /\s+/, $line) { |
| 130 | next; |
| 131 | } |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | if (open M, "make -C '$target_dir' --no-print-directory DUMP=1 TARGET_BUILD=1 val.SUBTARGETS V=s 2>/dev/null |") { |
| 136 | if (defined(my $line = readline M)) { |
| 137 | chomp $line; |
| 138 | @subtargets = split /\s+/, $line; |
| 139 | } |
| 140 | close M; |
| 141 | } |
| 142 | |
| 143 | push @subtargets, 'generic' if @subtargets == 0; |
| 144 | |
| 145 | foreach my $subtarget (@subtargets) { |
| 146 | parse_targetinfo($target_dir, $subtarget); |
| 147 | } |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | sub get_devices { |
| 152 | my ($target_subtarget) = @_; |
| 153 | my ($target, $subtarget) = split /\//, $target_subtarget; |
| 154 | |
| 155 | my ($target_dir) = "target/linux/" . $target; |
| 156 | |
| 157 | parse_devices($target_dir, $subtarget) |
| 158 | } |
| 159 | |
| 160 | if (@ARGV == 1 && $ARGV[0] eq 'targets') { |
| 161 | get_targetinfo(); |
| 162 | foreach my $target_name (sort keys %targets) { |
| 163 | printf "%s %s\n", $target_name, $targets{$target_name}; |
| 164 | } |
| 165 | } |
| 166 | elsif (@ARGV == 1 && $ARGV[0] eq 'architectures') { |
| 167 | get_targetinfo(); |
| 168 | foreach my $target_arch (sort keys %architectures) { |
| 169 | printf "%s %s\n", $target_arch, join ' ', @{$architectures{$target_arch}}; |
| 170 | } |
| 171 | } |
| 172 | elsif (@ARGV == 1 && $ARGV[0] eq 'kernels') { |
| 173 | get_targetinfo(); |
| 174 | foreach my $target_name (sort keys %targets) { |
| 175 | printf "%s %s\n", $target_name, join ' ', @{$kernels{$target_name}}; |
| 176 | } |
| 177 | } |
| 178 | elsif (@ARGV == 2 && $ARGV[0] eq 'devices') { |
| 179 | get_devices($ARGV[1]); |
| 180 | foreach my $device (sort keys %devices) { |
| 181 | printf "%s \"%s\"\n", $device, join '" "', @{$devices{$device}}; |
| 182 | } |
| 183 | } |
| 184 | else { |
| 185 | print "Usage: $0 targets\n"; |
| 186 | print "Usage: $0 architectures\n"; |
| 187 | print "Usage: $0 kernels\n"; |
| 188 | print "Usage: $0 devices <target/subtarget>\n"; |
| 189 | } |