Arch.pm 14 KB

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