package-metadata.pl 16.3 KB
Newer Older
1
#!/usr/bin/env perl
2 3
use FindBin;
use lib "$FindBin::Bin";
4
use strict;
5
use metadata;
6
use Getopt::Long;
7

8
my %board;
9

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
sub version_to_num($) {
	my $str = shift;
	my $num = 0;

	if (defined($str) && $str =~ /^\d+(?:\.\d+)+$/)
	{
		my @n = (split(/\./, $str), 0, 0, 0, 0);
		$num = ($n[0] << 24) | ($n[1] << 16) | ($n[2] << 8) | $n[3];
	}

	return $num;
}

sub version_filter_list(@) {
	my $cmpver = version_to_num(shift @_);
	my @items;

	foreach my $item (@_)
	{
		if ($item =~ s/@(lt|le|gt|ge|eq|ne)(\d+(?:\.\d+)+)\b//)
		{
			my $op = $1;
			my $symver = version_to_num($2);

			if ($symver > 0 && $cmpver > 0)
			{
				next unless (($op eq 'lt' && $cmpver <  $symver) ||
				             ($op eq 'le' && $cmpver <= $symver) ||
				             ($op eq 'gt' && $cmpver >  $symver) ||
				             ($op eq 'ge' && $cmpver >= $symver) ||
				             ($op eq 'eq' && $cmpver == $symver) ||
				             ($op eq 'ne' && $cmpver != $symver));
			}
		}

		push @items, $item;
	}

	return @items;
}

51 52
sub gen_kconfig_overrides() {
	my %config;
53
	my %kconfig;
54 55 56
	my $package;
	my $pkginfo = shift @ARGV;
	my $cfgfile = shift @ARGV;
57
	my $patchver = shift @ARGV;
58 59 60 61 62 63 64 65 66 67 68 69 70 71

	# parameter 2: build system config
	open FILE, "<$cfgfile" or return;
	while (<FILE>) {
		/^(CONFIG_.+?)=(.+)$/ and $config{$1} = 1;
	}
	close FILE;

	# parameter 1: package metadata
	open FILE, "<$pkginfo" or return;
	while (<FILE>) {
		/^Package:\s*(.+?)\s*$/ and $package = $1;
		/^Kernel-Config:\s*(.+?)\s*$/ and do {
			my @config = split /\s+/, $1;
72
			foreach my $config (version_filter_list($patchver, @config)) {
73
				my $val = 'm';
74
				my $override;
75 76
				if ($config =~ /^(.+?)=(.+)$/) {
					$config = $1;
77
					$override = 1;
78 79 80
					$val = $2;
				}
				if ($config{"CONFIG_PACKAGE_$package"} and ($config ne 'n')) {
81
					next if $kconfig{$config} eq 'y';
82 83 84
					$kconfig{$config} = $val;
				} elsif (!$override) {
					$kconfig{$config} or $kconfig{$config} = 'n';
85 86 87 88 89
				}
			}
		};
	};
	close FILE;
90 91 92 93 94 95 96 97

	foreach my $kconfig (sort keys %kconfig) {
		if ($kconfig{$kconfig} eq 'n') {
			print "# $kconfig is not set\n";
		} else {
			print "$kconfig=$kconfig{$kconfig}\n";
		}
	}
98 99
}

100 101
my %dep_check;
sub __find_package_dep($$) {
102 103
	my $pkg = shift;
	my $name = shift;
104
	my $deps = $pkg->{depends};
105 106

	return 0 unless defined $deps;
107 108 109 110 111 112 113
	foreach my $vpkg (@{$deps}) {
		foreach my $dep (@{$vpackage{$vpkg}}) {
			next if $dep_check{$dep->{name}};
			$dep_check{$dep->{name}} = 1;
			return 1 if $dep->{name} eq $name;
			return 1 if (__find_package_dep($dep, $name) == 1);
		}
114 115 116 117
	}
	return 0;
}

118 119 120 121 122 123 124 125 126
# wrapper to avoid infinite recursion
sub find_package_dep($$) {
	my $pkg = shift;
	my $name = shift;

	%dep_check = ();
	return __find_package_dep($pkg, $name);
}

127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
sub package_depends($$) {
	my $a = shift;
	my $b = shift;
	my $ret;

	return 0 if ($a->{submenu} ne $b->{submenu});
	if (find_package_dep($a, $b->{name}) == 1) {
		$ret = 1;
	} elsif (find_package_dep($b, $a->{name}) == 1) {
		$ret = -1;
	} else {
		return 0;
	}
	return $ret;
}

143 144
sub mconf_depends {
	my $pkgname = shift;
145 146 147
	my $depends = shift;
	my $only_dep = shift;
	my $res;
F
Felix Fietkau 已提交
148
	my $dep = shift;
149
	my $seen = shift;
150
	my $parent_condition = shift;
F
Felix Fietkau 已提交
151
	$dep or $dep = {};
152
	$seen or $seen = {};
153
	my @t_depends;
154 155 156 157

	$depends or return;
	my @depends = @$depends;
	foreach my $depend (@depends) {
158
		my $m = "depends on";
159 160
		my $flags = "";
		$depend =~ s/^([@\+]+)// and $flags = $1;
161
		my $condition = $parent_condition;
162

163 164
		$depend = $2 if	$depend =~ /^(.+):(.+)$/ and $dep->{$1} eq 'select';

165
		next if $condition eq $depend;
166 167 168
		next if $seen->{"$parent_condition:$depend"};
		next if $seen->{":$depend"};
		$seen->{"$parent_condition:$depend"} = 1;
169
		if ($depend =~ /^(.+):(.+)$/) {
170
			if ($1 ne "PACKAGE_$pkgname") {
171 172
				if ($condition) {
					$condition = "$condition && $1";
173 174 175 176
				} else {
					$condition = $1;
				}
			}
177 178
			$depend = $2;
		}
179
		if ($flags =~ /\+/) {
180 181
			my $vdep = $vpackage{$depend};
			if ($vdep) {
182 183 184
				my @vdeps;

				foreach my $v (@$vdep) {
185 186 187
					next if $v->{buildonly};
					if ($v->{variant_default}) {
						unshift @vdeps, $v->{name};
188
					} else {
189
						push @vdeps, $v->{name};
190 191 192
					}
				}

193
				$depend = shift @vdeps;
194

195
				if (@vdeps > 1) {
196
					$condition = ($condition ? "$condition && " : '') . join("&&", map { "PACKAGE_$_<PACKAGE_$pkgname" } @vdeps);
197
				} elsif (@vdeps > 0) {
198
					$condition = ($condition ? "$condition && " : '') . "PACKAGE_${vdeps[0]}<PACKAGE_$pkgname";
199 200
				}
			}
201 202 203 204 205 206 207 208 209

			# Menuconfig will not treat 'select FOO' as a real dependency
			# thus if FOO depends on other config options, these dependencies
			# will not be checked. To fix this, we simply emit all of FOO's
			# depends here as well.
			$package{$depend} and push @t_depends, [ $package{$depend}->{depends}, $condition ];

			$m = "select";
			next if $only_dep;
210 211

			$flags =~ /@/ or $depend = "PACKAGE_$depend";
212
		} else {
213
			my $vdep = $vpackage{$depend};
214
			if ($vdep && @$vdep > 0) {
215
				$depend = join("||", map { "PACKAGE_".$_->{name} } @$vdep);
216 217
			} else {
				$flags =~ /@/ or $depend = "PACKAGE_$depend";
218 219
			}
		}
220

221 222 223 224 225
		if ($condition) {
			if ($m =~ /select/) {
				next if $depend eq $condition;
				$depend = "$depend if $condition";
			} else {
226
				next if $dep->{"$depend if $condition"};
227 228
				$depend = "!($condition) || $depend" unless $dep->{$condition} eq 'select';
			}
229
		}
F
Felix Fietkau 已提交
230 231
		$dep->{$depend} =~ /select/ or $dep->{$depend} = $m;
	}
232 233 234 235 236

	foreach my $tdep (@t_depends) {
		mconf_depends($pkgname, $tdep->[0], 1, $dep, $seen, $tdep->[1]);
	}

237
	foreach my $depend (sort keys %$dep) {
F
Felix Fietkau 已提交
238
		my $m = $dep->{$depend};
239 240 241 242 243
		$res .= "\t\t$m $depend\n";
	}
	return $res;
}

244 245 246 247 248 249 250 251 252 253 254 255
sub mconf_conflicts {
	my $pkgname = shift;
	my $depends = shift;
	my $res = "";

	foreach my $depend (@$depends) {
		next unless $package{$depend};
		$res .= "\t\tdepends on m || (PACKAGE_$depend != y)\n";
	}
	return $res;
}

256 257 258 259
sub print_package_config_category($) {
	my $cat = shift;
	my %menus;
	my %menu_dep;
260

261
	return unless $category{$cat};
262

263 264
	print "menu \"$cat\"\n\n";
	my %spkg = %{$category{$cat}};
265

266 267
	foreach my $spkg (sort {uc($a) cmp uc($b)} keys %spkg) {
		foreach my $pkg (@{$spkg{$spkg}}) {
268
			next if $pkg->{buildonly};
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
			my $menu = $pkg->{submenu};
			if ($menu) {
				$menu_dep{$menu} or $menu_dep{$menu} = $pkg->{submenudep};
			} else {
				$menu = 'undef';
			}
			$menus{$menu} or $menus{$menu} = [];
			push @{$menus{$menu}}, $pkg;
		}
	}
	my @menus = sort {
		($a eq 'undef' ?  1 : 0) or
		($b eq 'undef' ? -1 : 0) or
		($a cmp $b)
	} keys %menus;

	foreach my $menu (@menus) {
		my @pkgs = sort {
			package_depends($a, $b) or
			($a->{name} cmp $b->{name})
		} @{$menus{$menu}};
		if ($menu ne 'undef') {
			$menu_dep{$menu} and print "if $menu_dep{$menu}\n";
			print "menu \"$menu\"\n";
		}
		foreach my $pkg (@pkgs) {
295
			next if $pkg->{src}{ignore};
296 297 298 299 300
			my $title = $pkg->{name};
			my $c = (72 - length($pkg->{name}) - length($pkg->{title}));
			if ($c > 0) {
				$title .= ("." x $c). " ". $pkg->{title};
			}
301
			$title = "\"$title\"";
302 303 304
			print "\t";
			$pkg->{menu} and print "menu";
			print "config PACKAGE_".$pkg->{name}."\n";
305 306
			$pkg->{hidden} and $title = "";
			print "\t\t".($pkg->{tristate} ? 'tristate' : 'bool')." $title\n";
307
			print "\t\tdefault y if DEFAULT_".$pkg->{name}."\n";
308
			unless ($pkg->{hidden}) {
309 310 311 312
				my @def = ("ALL");
				if (!exists($pkg->{repository})) {
					push @def, "ALL_NONSHARED";
				}
313
				if ($pkg->{name} =~ /^kmod-/) {
314
					push @def, "ALL_KMODS";
315
				}
316
				$pkg->{default} ||= "m if " . join("||", @def);
317 318 319 320 321
			}
			if ($pkg->{default}) {
				foreach my $default (split /\s*,\s*/, $pkg->{default}) {
					print "\t\tdefault $default\n";
				}
322
			}
323
			print mconf_depends($pkg->{name}, $pkg->{depends}, 0);
324
			print mconf_depends($pkg->{name}, $pkg->{mdepends}, 0);
325
			print mconf_conflicts($pkg->{name}, $pkg->{conflicts});
326 327 328 329 330 331 332 333 334 335 336 337
			print "\t\thelp\n";
			print $pkg->{description};
			print "\n";

			$pkg->{config} and print $pkg->{config}."\n";
		}
		if ($menu ne 'undef') {
			print "endmenu\n";
			$menu_dep{$menu} and print "endif\n";
		}
	}
	print "endmenu\n\n";
338

339 340 341
	undef $category{$cat};
}

342 343 344 345
sub print_package_overrides() {
	keys %overrides > 0 or return;
	print "\tconfig OVERRIDE_PKGS\n";
	print "\t\tstring\n";
346
	print "\t\tdefault \"".join(" ", sort keys %overrides)."\"\n\n";
347 348
}

349
sub gen_package_config() {
350
	parse_package_metadata($ARGV[0]) or exit 1;
351 352 353 354 355
	print "menuconfig IMAGEOPT\n\tbool \"Image configuration\"\n\tdefault n\n";
	print "source \"package/*/image-config.in\"\n";
	if (scalar glob "package/feeds/*/*/image-config.in") {
	    print "source \"package/feeds/*/*/image-config.in\"\n";
	}
356
	print_package_config_category 'Base system';
357
	foreach my $cat (sort {uc($a) cmp uc($b)} keys %category) {
358 359
		print_package_config_category $cat;
	}
360
	print_package_overrides();
361 362
}

363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
sub and_condition($) {
	my $condition = shift;
	my @spl_and = split('\&\&', $condition);
	if (@spl_and == 1) {
		return "\$(CONFIG_$spl_and[0])";
	}
	return "\$(and " . join (',', map("\$(CONFIG_$_)", @spl_and)) . ")";
}

sub gen_condition ($) {
	my $condition = shift;
	# remove '!()', just as include/package-ipkg.mk does
	$condition =~ s/[()!]//g;
	return join("", map(and_condition($_), split('\|\|', $condition)));
}

379 380 381 382 383
sub get_conditional_dep($$) {
	my $condition = shift;
	my $depstr = shift;
	if ($condition) {
		if ($condition =~ /^!(.+)/) {
384
			return "\$(if " . gen_condition($1) . ",,$depstr)";
385
		} else {
386
			return "\$(if " . gen_condition($condition) . ",$depstr)";
387 388 389 390 391 392
		}
	} else {
		return $depstr;
	}
}

393 394 395
sub gen_package_mk() {
	my $line;

396
	parse_package_metadata($ARGV[0]) or exit 1;
397 398 399
	foreach my $srcname (sort {uc($a) cmp uc($b)} keys %srcpackage) {
		my $src = $srcpackage{$srcname};
		my $variant_default;
400
		my %deplines = ('' => {});
401

402
		foreach my $pkg (@{$src->{packages}}) {
403 404 405 406 407 408 409 410 411 412 413
			foreach my $dep (@{$pkg->{depends}}) {
				next if ($dep =~ /@/);

				my $condition;

				$dep =~ s/\+//g;
				if ($dep =~ /^(.+):(.+)/) {
					$condition = $1;
					$dep = $2;
				}

414 415
				my $vpkg_dep = $vpackage{$dep};
				unless (defined $vpkg_dep) {
416 417 418 419 420
					warn sprintf "WARNING: Makefile '%s' has a dependency on '%s', which does not exist\n",
						$src->{makefile}, $dep;
					next;
				}

421 422
				# Filter out self-depends
				my @vdeps = grep { $srcname ne $_->{src}{name} } @{$vpkg_dep};
423

424
				foreach my $vdep (@vdeps) {
425
					my $depstr = sprintf '$(curdir)/%s/compile', $vdep->{src}{path};
426
					if (@vdeps > 1) {
427
						$depstr = sprintf '$(if $(CONFIG_PACKAGE_%s),%s)', $vdep->{name}, $depstr;
428 429 430 431 432 433 434 435
					}
					my $depline = get_conditional_dep($condition, $depstr);
					if ($depline) {
						$deplines{''}{$depline}++;
					}
				}
			}

436
			my $config = '';
437
			$config = sprintf '$(CONFIG_PACKAGE_%s)', $pkg->{name} unless $pkg->{buildonly};
438

439
			$pkg->{prereq} and printf "prereq-%s += %s\n", $config, $src->{path};
440 441 442

			next if $pkg->{buildonly};

443
			printf "package-%s += %s\n", $config, $src->{path};
444

445
			if ($pkg->{variant}) {
446 447
				if (!defined($variant_default) or $pkg->{variant_default}) {
					$variant_default = $pkg->{variant};
448
				}
449
				printf "\$(curdir)/%s/variants += \$(if %s,%s)\n", $src->{path}, $config, $pkg->{variant};
450
			}
451
		}
452

453
		if (defined($variant_default)) {
454
			printf "\$(curdir)/%s/default-variant := %s\n", $src->{path}, $variant_default;
455 456 457
		}

		unless (grep {!$_->{buildonly}} @{$src->{packages}}) {
458
			printf "package- += %s\n", $src->{path};
459
		}
460

461
		if (@{$src->{buildtypes}} > 0) {
462
			printf "buildtypes-%s = %s\n", $src->{path}, join(' ', @{$src->{buildtypes}});
463 464
		}

465 466
		foreach my $type ('', @{$src->{buildtypes}}) {
			my $suffix = '';
467

468 469 470 471 472 473 474 475
			$suffix = "/$type" if $type;

			next unless $src->{"builddepends$suffix"};

			defined $deplines{$suffix} or $deplines{$suffix} = {};

			foreach my $dep (@{$src->{"builddepends$suffix"}}) {
				my $depsuffix = "";
476
				my $deptype = "";
477 478 479 480 481 482
				my $condition;

				if ($dep =~ /^(.+):(.+)/) {
					$condition = $1;
					$dep = $2;
				}
483
				if ($dep =~ /^(.+)\/(.+)/) {
484
					$dep = $1;
485
					$deptype = $2;
486
					$depsuffix = "/$2";
487 488
				}

489 490 491 492
				next if $srcname.$suffix eq $dep.$depsuffix;

				my $src_dep = $srcpackage{$dep};
				unless (defined($src_dep) && (!$deptype || grep { $_ eq $deptype } @{$src_dep->{buildtypes}})) {
493 494
					warn sprintf "WARNING: Makefile '%s' has a build dependency on '%s', which does not exist\n",
						$src->{makefile}, $dep.$depsuffix;
495
					next;
496
				}
497

498
				my $depstr = sprintf '$(curdir)/%s/compile', $src_dep->{path}.$depsuffix;
499 500
				my $depline = get_conditional_dep($condition, $depstr);
				if ($depline) {
501
					$deplines{$suffix}{$depline}++;
502 503 504
				}
			}
		}
505

506 507 508
		foreach my $suffix (sort keys %deplines) {
			my $depline = join(" ", sort keys %{$deplines{$suffix}});
			if ($depline) {
509
				$line .= sprintf "\$(curdir)/%s/compile += %s\n", $src->{path}.$suffix, $depline;
510
			}
511 512
		}
	}
513

514 515 516 517 518
	if ($line ne "") {
		print "\n$line";
	}
}

519 520 521 522 523 524 525 526 527 528
sub gen_package_source() {
	parse_package_metadata($ARGV[0]) or exit 1;
	foreach my $name (sort {uc($a) cmp uc($b)} keys %package) {
		my $pkg = $package{$name};
		if ($pkg->{name} && $pkg->{source}) {
			print "$pkg->{name}: ";
			print "$pkg->{source}\n";
		}
	}
}
529

530
sub gen_package_auxiliary() {
531 532 533
	parse_package_metadata($ARGV[0]) or exit 1;
	foreach my $name (sort {uc($a) cmp uc($b)} keys %package) {
		my $pkg = $package{$name};
534 535
		if ($pkg->{name} && $pkg->{repository}) {
			print "Package/$name/subdir = $pkg->{repository}\n";
536
		}
537 538 539 540 541 542 543 544 545 546 547 548
		my %depends;
		foreach my $dep (@{$pkg->{depends} || []}) {
			if ($dep =~ m!^\+?(?:[^:]+:)?([^@]+)$!) {
				$depends{$1}++;
			}
		}
		my @depends = sort keys %depends;
		if (@depends > 0) {
			foreach my $n (@{$pkg->{provides}}) {
				print "Package/$n/depends = @depends\n";
			}
		}
549 550 551
	}
}

552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
sub gen_package_license($) {
	my $level = shift;
	parse_package_metadata($ARGV[0]) or exit 1;
	foreach my $name (sort {uc($a) cmp uc($b)} keys %package) {
		my $pkg = $package{$name};
		if ($pkg->{name}) {
			if ($pkg->{license}) {
				print "$pkg->{name}: ";
				print "$pkg->{license}\n";
				if ($pkg->{licensefiles} && $level == 0) {
					print "\tFiles: $pkg->{licensefiles}\n";
				}
			} else {
				if ($level == 1) {
					print "$pkg->{name}: Missing license! ";
567
					print "Please fix $pkg->{src}{makefile}\n";
568 569 570 571 572 573
				}
			}
		}
	}
}

574 575 576 577 578 579
sub gen_version_filtered_list() {
	foreach my $item (version_filter_list(@ARGV)) {
		print "$item\n";
	}
}

580 581 582 583 584 585 586 587 588 589
sub gen_usergroup_list() {
	parse_package_metadata($ARGV[0]) or exit 1;
	for my $name (keys %usernames) {
		print "user $name $usernames{$name}{id} $usernames{$name}{makefile}\n";
	}
	for my $name (keys %groupnames) {
		print "group $name $groupnames{$name}{id} $groupnames{$name}{makefile}\n";
	}
}

590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
sub gen_package_manifest_json() {
	my $json;
	parse_package_metadata($ARGV[0]) or exit 1;
	foreach my $name (sort {uc($a) cmp uc($b)} keys %package) {
		my %depends;
		my $pkg = $package{$name};
		foreach my $dep (@{$pkg->{depends} || []}) {
			if ($dep =~ m!^\+?(?:[^:]+:)?([^@]+)$!) {
				$depends{$1}++;
			}
		}
		my @depends = sort keys %depends;
		my $pkg_deps = join ' ', map { qq/"$_",/ } @depends;
		$pkg_deps =~ s/\,$//;

		my $pkg_maintainer = join ' ', map { qq/"$_",/ } @{$pkg->{maintainer} || []};
		$pkg_maintainer =~ s/\,$//;

		$json = <<"END_JSON";
${json}{
"name":"$name",
"version":"$pkg->{version}",
"category":"$pkg->{category}",
"license":"$pkg->{license}",
"maintainer": [$pkg_maintainer],
"depends":[$pkg_deps]},
END_JSON
	}

	$json =~ s/[\n\r]//g;
	$json =~ s/\,$//;
	print "[$json]";
}

624
sub parse_command() {
625
	GetOptions("ignore=s", \@ignore);
626 627
	my $cmd = shift @ARGV;
	for ($cmd) {
628 629
		/^mk$/ and return gen_package_mk();
		/^config$/ and return gen_package_config();
630
		/^kconfig/ and return gen_kconfig_overrides();
631
		/^source$/ and return gen_package_source();
632
		/^pkgaux$/ and return gen_package_auxiliary();
633
		/^pkgmanifestjson$/ and return gen_package_manifest_json();
634 635
		/^license$/ and return gen_package_license(0);
		/^licensefull$/ and return gen_package_license(1);
636
		/^usergroup$/ and return gen_usergroup_list();
637
		/^version_filter$/ and return gen_version_filtered_list();
638
	}
639
	die <<EOF
640
Available Commands:
641 642
	$0 mk [file]				Package metadata in makefile format
	$0 config [file] 			Package metadata in Kconfig format
643
	$0 kconfig [file] [config] [patchver]	Kernel config overrides
644
	$0 source [file] 			Package source file information
645
	$0 pkgaux [file]			Package auxiliary variables in makefile format
646
	$0 pkgmanifestjson [file]		Package manifests in JSON format
647 648
	$0 license [file] 			Package license information
	$0 licensefull [file] 			Package license information (full list)
649
	$0 usergroup [file]			Package usergroup allocation list
650
	$0 version_filter [patchver] [list...]	Filter list of version tagged strings
651

652 653
Options:
	--ignore <name>				Ignore the source package <name>
654 655 656 657
EOF
}

parse_command();