| #!/usr/bin/env perl |
| use FindBin; |
| use lib "$FindBin::Bin"; |
| use strict; |
| use metadata; |
| use Getopt::Long; |
| |
| sub target_config_features(@) { |
| my $ret; |
| |
| while ($_ = shift @_) { |
| /^arm_v(\w+)$/ and $ret .= "\tselect arm_v$1\n"; |
| /^audio$/ and $ret .= "\tselect AUDIO_SUPPORT\n"; |
| /^boot-part$/ and $ret .= "\tselect USES_BOOT_PART\n"; |
| /^broken$/ and $ret .= "\tdepends on BROKEN\n"; |
| /^cpiogz$/ and $ret .= "\tselect USES_CPIOGZ\n"; |
| /^display$/ and $ret .= "\tselect DISPLAY_SUPPORT\n"; |
| /^dt$/ and $ret .= "\tselect USES_DEVICETREE\n"; |
| /^dt-overlay$/ and $ret .= "\tselect HAS_DT_OVERLAY_SUPPORT\n"; |
| /^emmc$/ and $ret .= "\tselect EMMC_SUPPORT\n"; |
| /^ext4$/ and $ret .= "\tselect USES_EXT4\n"; |
| /^fpu$/ and $ret .= "\tselect HAS_FPU\n"; |
| /^gpio$/ and $ret .= "\tselect GPIO_SUPPORT\n"; |
| /^jffs2$/ and $ret .= "\tselect USES_JFFS2\n"; |
| /^jffs2_nand$/ and $ret .= "\tselect USES_JFFS2_NAND\n"; |
| /^legacy-sdcard$/ and $ret .= "\tselect LEGACY_SDCARD_SUPPORT\n"; |
| /^low_mem$/ and $ret .= "\tselect LOW_MEMORY_FOOTPRINT\n"; |
| /^minor$/ and $ret .= "\tselect USES_MINOR\n"; |
| /^mips16$/ and $ret .= "\tselect HAS_MIPS16\n"; |
| /^nand$/ and $ret .= "\tselect NAND_SUPPORT\n"; |
| /^nommu$/ and $ret .= "\tselect NOMMU\n"; |
| /^pci$/ and $ret .= "\tselect PCI_SUPPORT\n"; |
| /^pcie$/ and $ret .= "\tselect PCIE_SUPPORT\n"; |
| /^pcmcia$/ and $ret .= "\tselect PCMCIA_SUPPORT\n"; |
| /^powerpc64$/ and $ret .= "\tselect powerpc64\n"; |
| /^pwm$/ and $ret .= "\select PWM_SUPPORT\n"; |
| /^ramdisk$/ and $ret .= "\tselect USES_INITRAMFS\n"; |
| /^rfkill$/ and $ret .= "\tselect RFKILL_SUPPORT\n"; |
| /^rootfs-part$/ and $ret .= "\tselect USES_ROOTFS_PART\n"; |
| /^rtc$/ and $ret .= "\tselect RTC_SUPPORT\n"; |
| /^separate_ramdisk$/ and $ret .= "\tselect USES_INITRAMFS\n\tselect USES_SEPARATE_INITRAMFS\n"; |
| /^small_flash$/ and $ret .= "\tselect SMALL_FLASH\n"; |
| /^spe_fpu$/ and $ret .= "\tselect HAS_SPE_FPU\n"; |
| /^squashfs$/ and $ret .= "\tselect USES_SQUASHFS\n"; |
| /^targz$/ and $ret .= "\tselect USES_TARGZ\n"; |
| /^testing-kernel$/ and $ret .= "\tselect HAS_TESTING_KERNEL\n"; |
| /^ubifs$/ and $ret .= "\tselect USES_UBIFS\n"; |
| /^usb$/ and $ret .= "\tselect USB_SUPPORT\n"; |
| /^usbgadget$/ and $ret .= "\tselect USB_GADGET_SUPPORT\n"; |
| /^virtio$/ and $ret .= "\tselect VIRTIO_SUPPORT\n"; |
| } |
| return $ret; |
| } |
| |
| sub target_name($) { |
| my $target = shift; |
| my $parent = $target->{parent}; |
| if ($parent) { |
| return $target->{parent}->{name}." - ".$target->{name}; |
| } else { |
| return $target->{name}; |
| } |
| } |
| |
| sub kver($) { |
| my $v = shift; |
| $v =~ tr/\./_/; |
| if (substr($v,0,2) eq "2_") { |
| $v =~ /(\d+_\d+_\d+)(_\d+)?/ and $v = $1; |
| } else { |
| $v =~ /(\d+_\d+)(_\d+)?/ and $v = $1; |
| } |
| return $v; |
| } |
| |
| sub print_target($) { |
| my $target = shift; |
| my $features = target_config_features(@{$target->{features}}); |
| my $help = $target->{desc}; |
| my $confstr; |
| |
| chomp $features; |
| $features .= "\n"; |
| if ($help =~ /\w+/) { |
| $help =~ s/^\s*/\t /mg; |
| $help = "\thelp\n$help"; |
| } else { |
| undef $help; |
| } |
| |
| my $v = kver($target->{version}); |
| my $tv = kver($target->{testing_version}); |
| $tv or $tv = $v; |
| if (@{$target->{subtargets}} == 0) { |
| $confstr = <<EOF; |
| config TARGET_$target->{conf} |
| bool "$target->{name}" |
| select LINUX_$v if !TESTING_KERNEL |
| select LINUX_$tv if TESTING_KERNEL |
| EOF |
| } |
| else { |
| $confstr = <<EOF; |
| config TARGET_$target->{conf} |
| bool "$target->{name}" |
| EOF |
| } |
| if ($target->{subtarget}) { |
| $confstr .= "\tdepends on TARGET_$target->{boardconf}\n"; |
| } |
| if (@{$target->{subtargets}} > 0) { |
| $confstr .= "\tselect HAS_SUBTARGETS\n"; |
| grep { /broken/ } @{$target->{features}} and $confstr .= "\tdepends on BROKEN\n"; |
| } else { |
| $confstr .= $features; |
| if ($target->{arch} =~ /\w/) { |
| $confstr .= "\tselect $target->{arch}\n"; |
| } |
| if ($target->{has_devices}) { |
| $confstr .= "\tselect HAS_DEVICES\n"; |
| } |
| } |
| |
| foreach my $dep (@{$target->{depends}}) { |
| my $mode = "depends on"; |
| my $flags; |
| my $name; |
| |
| $dep =~ /^([@\+\-]+)(.+)$/; |
| $flags = $1; |
| $name = $2; |
| |
| next if $name =~ /:/; |
| $flags =~ /-/ and $mode = "deselect"; |
| $flags =~ /\+/ and $mode = "select"; |
| $flags =~ /@/ and $confstr .= "\t$mode $name\n"; |
| } |
| $confstr .= "$help\n\n"; |
| print $confstr; |
| } |
| |
| sub merge_package_lists($$) { |
| my $list1 = shift; |
| my $list2 = shift; |
| my @l = (); |
| my %pkgs; |
| |
| foreach my $pkg (@$list1, @$list2) { |
| $pkgs{$pkg =~ s/^~//r} = 1; |
| } |
| foreach my $pkg (keys %pkgs) { |
| push @l, $pkg unless ($pkg =~ /^-/ or $pkgs{"-$pkg"}); |
| } |
| return sort(@l); |
| } |
| |
| sub gen_target_config() { |
| my $file = shift @ARGV; |
| my @target = parse_target_metadata($file); |
| my %defaults; |
| |
| my @target_sort = sort { |
| target_name($a) cmp target_name($b); |
| } @target; |
| |
| foreach my $target (@target_sort) { |
| next if @{$target->{subtargets}} > 0; |
| print <<EOF; |
| config DEFAULT_TARGET_$target->{conf} |
| bool |
| depends on TARGET_PER_DEVICE_ROOTFS |
| default y if TARGET_$target->{conf} |
| EOF |
| foreach my $pkg (@{$target->{packages}}) { |
| print "\tselect DEFAULT_$pkg if TARGET_PER_DEVICE_ROOTFS\n"; |
| } |
| } |
| |
| print <<EOF; |
| choice |
| prompt "Target System" |
| default TARGET_mmp |
| reset if !DEVEL |
| |
| EOF |
| |
| foreach my $target (@target_sort) { |
| next if $target->{subtarget}; |
| print_target($target); |
| } |
| |
| print <<EOF; |
| endchoice |
| |
| choice |
| prompt "Subtarget" if HAS_SUBTARGETS |
| EOF |
| foreach my $target (@target) { |
| next unless $target->{def_subtarget}; |
| print <<EOF; |
| default TARGET_$target->{conf}_$target->{def_subtarget} if TARGET_$target->{conf} |
| EOF |
| } |
| print <<EOF; |
| |
| EOF |
| foreach my $target (@target) { |
| next unless $target->{subtarget}; |
| print_target($target); |
| } |
| |
| print <<EOF; |
| endchoice |
| |
| choice |
| prompt "Target Profile" |
| default TARGET_MULTI_PROFILE if BUILDBOT |
| |
| EOF |
| foreach my $target (@target) { |
| my $profile = $target->{profiles}->[0]; |
| $profile or next; |
| print <<EOF; |
| default TARGET_$target->{conf}_$profile->{id} if TARGET_$target->{conf} && !BUILDBOT |
| EOF |
| } |
| |
| print <<EOF; |
| |
| config TARGET_MULTI_PROFILE |
| bool "Multiple devices" |
| depends on HAS_DEVICES |
| help |
| Instead of only building a single image, or all images, this allows you |
| to select images to be built for multiple devices in one build. |
| |
| EOF |
| |
| foreach my $target (@target) { |
| my $profiles = $target->{profiles}; |
| foreach my $profile (@{$target->{profiles}}) { |
| print <<EOF; |
| config TARGET_$target->{conf}_$profile->{id} |
| bool "$profile->{name}" |
| depends on TARGET_$target->{conf} |
| EOF |
| $profile->{broken} and print "\tdepends on BROKEN\n"; |
| my @pkglist = merge_package_lists($target->{packages}, $profile->{packages}); |
| foreach my $pkg (@pkglist) { |
| print "\tselect DEFAULT_$pkg\n"; |
| $defaults{$pkg} = 1; |
| } |
| my $help = $profile->{desc}; |
| if ($help =~ /\w+/) { |
| $help =~ s/^\s*/\t /mg; |
| $help = "\thelp\n$help"; |
| } else { |
| undef $help; |
| } |
| print "$help\n"; |
| } |
| } |
| |
| print <<EOF; |
| endchoice |
| |
| menu "Target Devices" |
| depends on TARGET_MULTI_PROFILE |
| |
| config TARGET_ALL_PROFILES |
| bool "Enable all profiles by default" |
| default BUILDBOT |
| |
| config TARGET_PER_DEVICE_ROOTFS |
| bool "Use a per-device root filesystem that adds profile packages" |
| default BUILDBOT |
| help |
| When disabled, all device packages from all selected devices |
| will be included in all images by default. (Marked as <*>) You will |
| still be able to manually deselect any/all packages. |
| When enabled, each device builds it's own image, including only the |
| profile packages for that device. (Marked as {M}) You will be able |
| to change a package to included in all images by marking as {*}, but |
| will not be able to disable a profile package completely. |
| |
| To get the most use of this setting, you must set in a .config stub |
| before calling "make defconfig". Selecting TARGET_MULTI_PROFILE and |
| then manually selecting (via menuconfig for instance) this option |
| will have pre-defaulted all profile packages to included, making this |
| option appear to have had no effect. |
| |
| EOF |
| foreach my $target (@target) { |
| my @profiles = sort { |
| my $x = $a->{name}; |
| my $y = $b->{name}; |
| "\L$x" cmp "\L$y"; |
| } @{$target->{profiles}}; |
| foreach my $profile (@profiles) { |
| next unless $profile->{id} =~ /^DEVICE_/; |
| print <<EOF; |
| menuconfig TARGET_DEVICE_$target->{conf}_$profile->{id} |
| bool "$profile->{name}" |
| depends on TARGET_$target->{conf} |
| default $profile->{default} |
| EOF |
| $profile->{broken} and print "\tdepends on BROKEN\n"; |
| my @pkglist = merge_package_lists($target->{packages}, $profile->{packages}); |
| foreach my $pkg (@pkglist) { |
| print "\tselect DEFAULT_$pkg if !TARGET_PER_DEVICE_ROOTFS\n"; |
| print "\tselect MODULE_DEFAULT_$pkg if TARGET_PER_DEVICE_ROOTFS\n"; |
| $defaults{$pkg} = 1; |
| } |
| |
| print <<EOF; |
| |
| |
| config TARGET_DEVICE_PACKAGES_$target->{conf}_$profile->{id} |
| string "$profile->{name} additional packages" |
| default "" |
| depends on TARGET_PER_DEVICE_ROOTFS |
| depends on TARGET_DEVICE_$target->{conf}_$profile->{id} |
| |
| EOF |
| } |
| } |
| |
| print <<EOF; |
| |
| endmenu |
| |
| config HAS_SUBTARGETS |
| bool |
| |
| config HAS_DEVICES |
| bool |
| |
| config TARGET_BOARD |
| string |
| |
| EOF |
| foreach my $target (@target) { |
| $target->{subtarget} or print "\t\tdefault \"".$target->{board}."\" if TARGET_".$target->{conf}."\n"; |
| } |
| print <<EOF; |
| config TARGET_SUBTARGET |
| string |
| default "generic" if !HAS_SUBTARGETS |
| |
| EOF |
| |
| foreach my $target (@target) { |
| foreach my $subtarget (@{$target->{subtargets}}) { |
| print "\t\tdefault \"$subtarget\" if TARGET_".$target->{conf}."_$subtarget\n"; |
| } |
| } |
| print <<EOF; |
| config TARGET_PROFILE |
| string |
| EOF |
| foreach my $target (@target) { |
| my $profiles = $target->{profiles}; |
| foreach my $profile (@$profiles) { |
| print "\tdefault \"$profile->{id}\" if TARGET_$target->{conf}_$profile->{id}\n"; |
| } |
| } |
| |
| print <<EOF; |
| |
| config TARGET_ARCH_PACKAGES |
| string |
| |
| EOF |
| foreach my $target (@target) { |
| next if @{$target->{subtargets}} > 0; |
| print "\t\tdefault \"".($target->{arch_packages} || $target->{board})."\" if TARGET_".$target->{conf}."\n"; |
| } |
| print <<EOF; |
| |
| config DEFAULT_TARGET_OPTIMIZATION |
| string |
| EOF |
| foreach my $target (@target) { |
| next if @{$target->{subtargets}} > 0; |
| print "\tdefault \"".$target->{cflags}."\" if TARGET_".$target->{conf}."\n"; |
| } |
| print "\tdefault \"-Os -pipe -funit-at-a-time\"\n"; |
| print <<EOF; |
| |
| config CPU_TYPE |
| string |
| EOF |
| foreach my $target (@target) { |
| next if @{$target->{subtargets}} > 0; |
| print "\tdefault \"".$target->{cputype}."\" if TARGET_".$target->{conf}."\n"; |
| } |
| print "\tdefault \"\"\n"; |
| |
| my %kver; |
| foreach my $target (@target) { |
| foreach my $tv ($target->{version}, $target->{testing_version}) { |
| next unless $tv; |
| my $v = kver($tv); |
| next if $kver{$v}; |
| $kver{$v} = 1; |
| print <<EOF; |
| |
| config LINUX_$v |
| bool |
| |
| EOF |
| } |
| } |
| foreach my $def (sort keys %defaults) { |
| print <<EOF; |
| config DEFAULT_$def |
| bool |
| |
| config MODULE_DEFAULT_$def |
| tristate |
| depends on TARGET_PER_DEVICE_ROOTFS |
| depends on m |
| default m if DEFAULT_$def |
| select PACKAGE_$def |
| |
| EOF |
| } |
| } |
| |
| sub gen_profile_mk() { |
| my $file = shift @ARGV; |
| my $target = shift @ARGV; |
| my @targets = parse_target_metadata($file); |
| foreach my $cur (@targets) { |
| next unless $cur->{id} eq $target; |
| my @profile_ids_unique = do { my %seen; grep { !$seen{$_}++} map { $_->{id} } @{$cur->{profiles}}}; |
| print "PROFILE_NAMES = ".join(" ", @profile_ids_unique)."\n"; |
| foreach my $profile (@{$cur->{profiles}}) { |
| print $profile->{id}.'_NAME:='.$profile->{name}."\n"; |
| print $profile->{id}.'_HAS_IMAGE_METADATA:='.$profile->{has_image_metadata}."\n"; |
| if (defined($profile->{supported_devices}) and @{$profile->{supported_devices}} > 0) { |
| print $profile->{id}.'_SUPPORTED_DEVICES:='.join(' ', @{$profile->{supported_devices}})."\n"; |
| } |
| print $profile->{id}.'_PACKAGES:='.join(' ', @{$profile->{packages}})."\n"; |
| } |
| } |
| } |
| |
| sub parse_command() { |
| GetOptions("ignore=s", \@ignore); |
| my $cmd = shift @ARGV; |
| for ($cmd) { |
| /^config$/ and return gen_target_config(); |
| /^profile_mk$/ and return gen_profile_mk(); |
| } |
| die <<EOF |
| Available Commands: |
| $0 config [file] Target metadata in Kconfig format |
| $0 profile_mk [file] [target] Profile metadata in makefile format |
| |
| EOF |
| } |
| |
| parse_command(); |