Arch.pm 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. # Copyright © 2006-2015 Guillem Jover <guillem@debian.org>
  2. #
  3. # This program is free software; you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License as published by
  5. # the Free Software Foundation; either version 2 of the License, or
  6. # (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  15. package Dpkg::Arch;
  16. =encoding utf8
  17. =head1 NAME
  18. Dpkg::Arch - handle architectures
  19. =head1 DESCRIPTION
  20. The Dpkg::Arch module provides functions to handle Debian architectures,
  21. wildcards, and mapping from and to GNU triplets.
  22. =cut
  23. use strict;
  24. use warnings;
  25. use feature qw(state);
  26. our $VERSION = '1.01';
  27. our @EXPORT_OK = qw(
  28. get_raw_build_arch
  29. get_raw_host_arch
  30. get_build_arch
  31. get_host_arch
  32. get_host_gnu_type
  33. get_valid_arches
  34. debarch_eq
  35. debarch_is
  36. debarch_is_wildcard
  37. debarch_is_illegal
  38. debarch_is_concerned
  39. debarch_to_cpuattrs
  40. debarch_to_gnutriplet
  41. debarch_to_debtuple
  42. debarch_to_multiarch
  43. debarch_list_parse
  44. debtuple_to_debarch
  45. debtuple_to_gnutriplet
  46. gnutriplet_to_debarch
  47. gnutriplet_to_debtuple
  48. gnutriplet_to_multiarch
  49. );
  50. use Exporter qw(import);
  51. use POSIX qw(:errno_h);
  52. use Dpkg ();
  53. use Dpkg::Gettext;
  54. use Dpkg::ErrorHandling;
  55. use Dpkg::Util qw(:list);
  56. use Dpkg::Build::Env;
  57. my (@cpu, @os);
  58. my (%cputable, %ostable);
  59. my (%cputable_re, %ostable_re);
  60. my (%cpubits, %cpuendian);
  61. my %abibits;
  62. my %debtuple_to_debarch;
  63. my %debarch_to_debtuple;
  64. =head1 FUNCTIONS
  65. =over 4
  66. =item $arch = get_raw_build_arch()
  67. Get the raw build Debian architecture, without taking into account variables
  68. from the environment.
  69. =cut
  70. sub get_raw_build_arch()
  71. {
  72. state $build_arch;
  73. return $build_arch if defined $build_arch;
  74. # Note: We *always* require an installed dpkg when inferring the
  75. # build architecture. The bootstrapping case is handled by
  76. # dpkg-architecture itself, by avoiding computing the DEB_BUILD_
  77. # variables when they are not requested.
  78. $build_arch = qx(dpkg --print-architecture);
  79. syserr('dpkg --print-architecture failed') if $? >> 8;
  80. chomp $build_arch;
  81. return $build_arch;
  82. }
  83. =item $arch = get_build_arch()
  84. Get the build Debian architecture, using DEB_BUILD_ARCH from the environment
  85. if available.
  86. =cut
  87. sub get_build_arch()
  88. {
  89. return Dpkg::Build::Env::get('DEB_BUILD_ARCH') || get_raw_build_arch();
  90. }
  91. {
  92. my %cc_host_gnu_type;
  93. sub get_host_gnu_type()
  94. {
  95. my $CC = $ENV{CC} || 'gcc';
  96. return $cc_host_gnu_type{$CC} if defined $cc_host_gnu_type{$CC};
  97. $cc_host_gnu_type{$CC} = qx($CC -dumpmachine);
  98. if ($? >> 8) {
  99. $cc_host_gnu_type{$CC} = '';
  100. } else {
  101. chomp $cc_host_gnu_type{$CC};
  102. }
  103. return $cc_host_gnu_type{$CC};
  104. }
  105. sub set_host_gnu_type
  106. {
  107. my ($host_gnu_type) = @_;
  108. my $CC = $ENV{CC} || 'gcc';
  109. $cc_host_gnu_type{$CC} = $host_gnu_type;
  110. }
  111. }
  112. =item $arch = get_raw_host_arch()
  113. Get the raw host Debian architecture, without taking into account variables
  114. from the environment.
  115. =cut
  116. sub get_raw_host_arch()
  117. {
  118. state $host_arch;
  119. return $host_arch if defined $host_arch;
  120. my $host_gnu_type = get_host_gnu_type();
  121. if ($host_gnu_type eq '') {
  122. warning(g_('cannot determine CC system type, falling back to ' .
  123. 'default (native compilation)'));
  124. } else {
  125. my (@host_archtuple) = gnutriplet_to_debtuple($host_gnu_type);
  126. $host_arch = debtuple_to_debarch(@host_archtuple);
  127. if (defined $host_arch) {
  128. $host_gnu_type = debtuple_to_gnutriplet(@host_archtuple);
  129. } else {
  130. warning(g_('unknown CC system type %s, falling back to ' .
  131. 'default (native compilation)'), $host_gnu_type);
  132. $host_gnu_type = '';
  133. }
  134. set_host_gnu_type($host_gnu_type);
  135. }
  136. if (!defined($host_arch)) {
  137. # Switch to native compilation.
  138. $host_arch = get_raw_build_arch();
  139. }
  140. return $host_arch;
  141. }
  142. =item $arch = get_host_arch()
  143. Get the host Debian architecture, using DEB_HOST_ARCH from the environment
  144. if available.
  145. =cut
  146. sub get_host_arch()
  147. {
  148. return Dpkg::Build::Env::get('DEB_HOST_ARCH') || get_raw_host_arch();
  149. }
  150. =item @arch_list = get_valid_arches()
  151. Get an array with all currently known Debian architectures.
  152. =cut
  153. sub get_valid_arches()
  154. {
  155. _load_cputable();
  156. _load_ostable();
  157. my @arches;
  158. foreach my $os (@os) {
  159. foreach my $cpu (@cpu) {
  160. my $arch = debtuple_to_debarch(split(/-/, $os, 3), $cpu);
  161. push @arches, $arch if defined($arch);
  162. }
  163. }
  164. return @arches;
  165. }
  166. my %table_loaded;
  167. sub _load_table
  168. {
  169. my ($table, $loader) = @_;
  170. return if $table_loaded{$table};
  171. local $_;
  172. local $/ = "\n";
  173. open my $table_fh, '<', "$Dpkg::DATADIR/$table"
  174. or syserr(g_('cannot open %s'), $table);
  175. while (<$table_fh>) {
  176. $loader->($_);
  177. }
  178. close $table_fh;
  179. $table_loaded{$table} = 1;
  180. }
  181. sub _load_cputable
  182. {
  183. _load_table('cputable', sub {
  184. if (m/^(?!\#)(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/) {
  185. $cputable{$1} = $2;
  186. $cputable_re{$1} = $3;
  187. $cpubits{$1} = $4;
  188. $cpuendian{$1} = $5;
  189. push @cpu, $1;
  190. }
  191. });
  192. }
  193. sub _load_ostable
  194. {
  195. _load_table('ostable', sub {
  196. if (m/^(?!\#)(\S+)\s+(\S+)\s+(\S+)/) {
  197. $ostable{$1} = $2;
  198. $ostable_re{$1} = $3;
  199. push @os, $1;
  200. }
  201. });
  202. }
  203. sub _load_abitable()
  204. {
  205. _load_table('abitable', sub {
  206. if (m/^(?!\#)(\S+)\s+(\S+)/) {
  207. $abibits{$1} = $2;
  208. }
  209. });
  210. }
  211. sub _load_tupletable()
  212. {
  213. _load_cputable();
  214. _load_table('tupletable', sub {
  215. if (m/^(?!\#)(\S+)\s+(\S+)/) {
  216. my $debtuple = $1;
  217. my $debarch = $2;
  218. if ($debtuple =~ /<cpu>/) {
  219. foreach my $_cpu (@cpu) {
  220. (my $dt = $debtuple) =~ s/<cpu>/$_cpu/;
  221. (my $da = $debarch) =~ s/<cpu>/$_cpu/;
  222. next if exists $debarch_to_debtuple{$da}
  223. or exists $debtuple_to_debarch{$dt};
  224. $debarch_to_debtuple{$da} = $dt;
  225. $debtuple_to_debarch{$dt} = $da;
  226. }
  227. } else {
  228. $debarch_to_debtuple{$2} = $1;
  229. $debtuple_to_debarch{$1} = $2;
  230. }
  231. }
  232. });
  233. }
  234. sub debtuple_to_gnutriplet(@)
  235. {
  236. my ($abi, $libc, $os, $cpu) = @_;
  237. _load_cputable();
  238. _load_ostable();
  239. return unless
  240. defined $abi && defined $libc && defined $os && defined $cpu &&
  241. exists $cputable{$cpu} && exists $ostable{"$abi-$libc-$os"};
  242. return join('-', $cputable{$cpu}, $ostable{"$abi-$libc-$os"});
  243. }
  244. sub gnutriplet_to_debtuple($)
  245. {
  246. my $gnu = shift;
  247. return unless defined($gnu);
  248. my ($gnu_cpu, $gnu_os) = split(/-/, $gnu, 2);
  249. return unless defined($gnu_cpu) && defined($gnu_os);
  250. _load_cputable();
  251. _load_ostable();
  252. my ($os, $cpu);
  253. foreach my $_cpu (@cpu) {
  254. if ($gnu_cpu =~ /^$cputable_re{$_cpu}$/) {
  255. $cpu = $_cpu;
  256. last;
  257. }
  258. }
  259. foreach my $_os (@os) {
  260. if ($gnu_os =~ /^(.*-)?$ostable_re{$_os}$/) {
  261. $os = $_os;
  262. last;
  263. }
  264. }
  265. return if !defined($cpu) || !defined($os);
  266. return (split(/-/, $os, 3), $cpu);
  267. }
  268. =item $multiarch = gnutriplet_to_multiarch($gnutriplet)
  269. Map a GNU triplet into a Debian multiarch triplet.
  270. =cut
  271. sub gnutriplet_to_multiarch($)
  272. {
  273. my $gnu = shift;
  274. my ($cpu, $cdr) = split(/-/, $gnu, 2);
  275. if ($cpu =~ /^i[4567]86$/) {
  276. return "i386-$cdr";
  277. } else {
  278. return $gnu;
  279. }
  280. }
  281. =item $multiarch = debarch_to_multiarch($arch)
  282. Map a Debian architecture into a Debian multiarch triplet.
  283. =cut
  284. sub debarch_to_multiarch($)
  285. {
  286. my $arch = shift;
  287. return gnutriplet_to_multiarch(debarch_to_gnutriplet($arch));
  288. }
  289. sub debtuple_to_debarch(@)
  290. {
  291. my ($abi, $libc, $os, $cpu) = @_;
  292. _load_tupletable();
  293. if (!defined $abi || !defined $libc || !defined $os || !defined $cpu) {
  294. return;
  295. } elsif (exists $debtuple_to_debarch{"$abi-$libc-$os-$cpu"}) {
  296. return $debtuple_to_debarch{"$abi-$libc-$os-$cpu"};
  297. } else {
  298. return;
  299. }
  300. }
  301. sub debarch_to_debtuple($)
  302. {
  303. my $arch = shift;
  304. return if not defined $arch;
  305. _load_tupletable();
  306. if ($arch =~ /^linux-([^-]*)/) {
  307. # XXX: Might disappear in the future, not sure yet.
  308. $arch = $1;
  309. }
  310. my $tuple = $debarch_to_debtuple{$arch};
  311. if (defined($tuple)) {
  312. return split(/-/, $tuple, 4);
  313. } else {
  314. return;
  315. }
  316. }
  317. =item $gnutriplet = debarch_to_gnutriplet($arch)
  318. Map a Debian architecture into a GNU triplet.
  319. =cut
  320. sub debarch_to_gnutriplet($)
  321. {
  322. my $arch = shift;
  323. return debtuple_to_gnutriplet(debarch_to_debtuple($arch));
  324. }
  325. =item $arch = gnutriplet_to_debarch($gnutriplet)
  326. Map a GNU triplet into a Debian architecture.
  327. =cut
  328. sub gnutriplet_to_debarch($)
  329. {
  330. my $gnu = shift;
  331. return debtuple_to_debarch(gnutriplet_to_debtuple($gnu));
  332. }
  333. sub debwildcard_to_debtuple($)
  334. {
  335. my $arch = shift;
  336. my @tuple = split /-/, $arch, 3;
  337. if (any { $_ eq 'any' } @tuple) {
  338. if (scalar @tuple == 4) {
  339. return @tuple;
  340. } elsif (scalar @tuple == 3) {
  341. return ('any', @tuple);
  342. } elsif (scalar @tuple == 2) {
  343. return ('any', 'any', @tuple);
  344. } else {
  345. return ('any', 'any', 'any', 'any');
  346. }
  347. } else {
  348. return debarch_to_debtuple($arch);
  349. }
  350. }
  351. sub debarch_to_cpuattrs($)
  352. {
  353. my $arch = shift;
  354. my ($abi, $libc, $os, $cpu) = debarch_to_debtuple($arch);
  355. if (defined($cpu)) {
  356. _load_abitable();
  357. return ($abibits{$abi} // $cpubits{$cpu}, $cpuendian{$cpu});
  358. } else {
  359. return;
  360. }
  361. }
  362. =item $bool = debarch_eq($arch_a, $arch_b)
  363. Evaluate the equality of a Debian architecture, by comparing with another
  364. Debian architecture. No wildcard matching is performed.
  365. =cut
  366. sub debarch_eq($$)
  367. {
  368. my ($a, $b) = @_;
  369. return 1 if ($a eq $b);
  370. my @a = debarch_to_debtuple($a);
  371. my @b = debarch_to_debtuple($b);
  372. return 0 if scalar @a != 4 or scalar @b != 4;
  373. return $a[0] eq $b[0] && $a[1] eq $b[1] && $a[2] eq $b[2] && $a[3] eq $b[3];
  374. }
  375. =item $bool = debarch_is($arch, $arch_wildcard)
  376. Evaluate the identity of a Debian architecture, by matching with an
  377. architecture wildcard.
  378. =cut
  379. sub debarch_is($$)
  380. {
  381. my ($real, $alias) = @_;
  382. return 1 if ($alias eq $real or $alias eq 'any');
  383. my @real = debarch_to_debtuple($real);
  384. my @alias = debwildcard_to_debtuple($alias);
  385. return 0 if scalar @real != 4 or scalar @alias != 4;
  386. if (($alias[0] eq $real[0] || $alias[0] eq 'any') &&
  387. ($alias[1] eq $real[1] || $alias[1] eq 'any') &&
  388. ($alias[2] eq $real[2] || $alias[2] eq 'any') &&
  389. ($alias[3] eq $real[3] || $alias[3] eq 'any')) {
  390. return 1;
  391. }
  392. return 0;
  393. }
  394. =item $bool = debarch_is_wildcard($arch)
  395. Evaluate whether a Debian architecture is an architecture wildcard.
  396. =cut
  397. sub debarch_is_wildcard($)
  398. {
  399. my $arch = shift;
  400. return 0 if $arch eq 'all';
  401. my @tuple = debwildcard_to_debtuple($arch);
  402. return 0 if scalar @tuple != 4;
  403. return 1 if any { $_ eq 'any' } @tuple;
  404. return 0;
  405. }
  406. =item $bool = debarch_is_illegal($arch)
  407. Validate an architecture name.
  408. =cut
  409. sub debarch_is_illegal
  410. {
  411. my ($arch) = @_;
  412. return $arch !~ m/^!?[a-zA-Z0-9][a-zA-Z0-9-]*$/;
  413. }
  414. =item $bool = debarch_is_concerned($arch, @arches)
  415. Evaluate whether a Debian architecture applies to the list of architecture
  416. restrictions, as usually found in dependencies inside square brackets.
  417. =cut
  418. sub debarch_is_concerned
  419. {
  420. my ($host_arch, @arches) = @_;
  421. my $seen_arch = 0;
  422. foreach my $arch (@arches) {
  423. $arch = lc $arch;
  424. if ($arch =~ /^!/) {
  425. my $not_arch = $arch;
  426. $not_arch =~ s/^!//;
  427. if (debarch_is($host_arch, $not_arch)) {
  428. $seen_arch = 0;
  429. last;
  430. } else {
  431. # !arch includes by default all other arches
  432. # unless they also appear in a !otherarch
  433. $seen_arch = 1;
  434. }
  435. } elsif (debarch_is($host_arch, $arch)) {
  436. $seen_arch = 1;
  437. last;
  438. }
  439. }
  440. return $seen_arch;
  441. }
  442. =item @array = debarch_list_parse($arch_list, %options)
  443. Parse an architecture list.
  444. =cut
  445. sub debarch_list_parse
  446. {
  447. my $arch_list = shift;
  448. my @arch_list = split /\s+/, $arch_list;
  449. foreach my $arch (@arch_list) {
  450. if (debarch_is_illegal($arch)) {
  451. error(g_("'%s' is not a legal architecture in list '%s'"),
  452. $arch, $arch_list);
  453. }
  454. }
  455. return @arch_list;
  456. }
  457. 1;
  458. __END__
  459. =back
  460. =head1 CHANGES
  461. =head2 Version 1.01 (dpkg 1.18.5)
  462. New functions: debarch_is_illegal(), debarch_list_parse().
  463. =head2 Version 1.00 (dpkg 1.18.2)
  464. Mark the module as public.
  465. =head1 SEE ALSO
  466. dpkg-architecture(1).