Arch.pm 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  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. my @tuple = split /-/, $tuple, 4;
  313. return @tuple if wantarray;
  314. return {
  315. abi => $tuple[0],
  316. libc => $tuple[1],
  317. os => $tuple[2],
  318. cpu => $tuple[3],
  319. };
  320. } else {
  321. return;
  322. }
  323. }
  324. =item $gnutriplet = debarch_to_gnutriplet($arch)
  325. Map a Debian architecture into a GNU triplet.
  326. =cut
  327. sub debarch_to_gnutriplet($)
  328. {
  329. my $arch = shift;
  330. return debtuple_to_gnutriplet(debarch_to_debtuple($arch));
  331. }
  332. =item $arch = gnutriplet_to_debarch($gnutriplet)
  333. Map a GNU triplet into a Debian architecture.
  334. =cut
  335. sub gnutriplet_to_debarch($)
  336. {
  337. my $gnu = shift;
  338. return debtuple_to_debarch(gnutriplet_to_debtuple($gnu));
  339. }
  340. sub debwildcard_to_debtuple($)
  341. {
  342. my $arch = shift;
  343. my @tuple = split /-/, $arch, 3;
  344. if (any { $_ eq 'any' } @tuple) {
  345. if (scalar @tuple == 4) {
  346. return @tuple;
  347. } elsif (scalar @tuple == 3) {
  348. return ('any', @tuple);
  349. } elsif (scalar @tuple == 2) {
  350. return ('any', 'any', @tuple);
  351. } else {
  352. return ('any', 'any', 'any', 'any');
  353. }
  354. } else {
  355. return debarch_to_debtuple($arch);
  356. }
  357. }
  358. sub debarch_to_cpuattrs($)
  359. {
  360. my $arch = shift;
  361. my ($abi, $libc, $os, $cpu) = debarch_to_debtuple($arch);
  362. if (defined($cpu)) {
  363. _load_abitable();
  364. return ($abibits{$abi} // $cpubits{$cpu}, $cpuendian{$cpu});
  365. } else {
  366. return;
  367. }
  368. }
  369. =item $bool = debarch_eq($arch_a, $arch_b)
  370. Evaluate the equality of a Debian architecture, by comparing with another
  371. Debian architecture. No wildcard matching is performed.
  372. =cut
  373. sub debarch_eq($$)
  374. {
  375. my ($a, $b) = @_;
  376. return 1 if ($a eq $b);
  377. my @a = debarch_to_debtuple($a);
  378. my @b = debarch_to_debtuple($b);
  379. return 0 if scalar @a != 4 or scalar @b != 4;
  380. return $a[0] eq $b[0] && $a[1] eq $b[1] && $a[2] eq $b[2] && $a[3] eq $b[3];
  381. }
  382. =item $bool = debarch_is($arch, $arch_wildcard)
  383. Evaluate the identity of a Debian architecture, by matching with an
  384. architecture wildcard.
  385. =cut
  386. sub debarch_is($$)
  387. {
  388. my ($real, $alias) = @_;
  389. return 1 if ($alias eq $real or $alias eq 'any');
  390. my @real = debarch_to_debtuple($real);
  391. my @alias = debwildcard_to_debtuple($alias);
  392. return 0 if scalar @real != 4 or scalar @alias != 4;
  393. if (($alias[0] eq $real[0] || $alias[0] eq 'any') &&
  394. ($alias[1] eq $real[1] || $alias[1] eq 'any') &&
  395. ($alias[2] eq $real[2] || $alias[2] eq 'any') &&
  396. ($alias[3] eq $real[3] || $alias[3] eq 'any')) {
  397. return 1;
  398. }
  399. return 0;
  400. }
  401. =item $bool = debarch_is_wildcard($arch)
  402. Evaluate whether a Debian architecture is an architecture wildcard.
  403. =cut
  404. sub debarch_is_wildcard($)
  405. {
  406. my $arch = shift;
  407. return 0 if $arch eq 'all';
  408. my @tuple = debwildcard_to_debtuple($arch);
  409. return 0 if scalar @tuple != 4;
  410. return 1 if any { $_ eq 'any' } @tuple;
  411. return 0;
  412. }
  413. =item $bool = debarch_is_illegal($arch)
  414. Validate an architecture name.
  415. =cut
  416. sub debarch_is_illegal
  417. {
  418. my ($arch) = @_;
  419. return $arch !~ m/^!?[a-zA-Z0-9][a-zA-Z0-9-]*$/;
  420. }
  421. =item $bool = debarch_is_concerned($arch, @arches)
  422. Evaluate whether a Debian architecture applies to the list of architecture
  423. restrictions, as usually found in dependencies inside square brackets.
  424. =cut
  425. sub debarch_is_concerned
  426. {
  427. my ($host_arch, @arches) = @_;
  428. my $seen_arch = 0;
  429. foreach my $arch (@arches) {
  430. $arch = lc $arch;
  431. if ($arch =~ /^!/) {
  432. my $not_arch = $arch;
  433. $not_arch =~ s/^!//;
  434. if (debarch_is($host_arch, $not_arch)) {
  435. $seen_arch = 0;
  436. last;
  437. } else {
  438. # !arch includes by default all other arches
  439. # unless they also appear in a !otherarch
  440. $seen_arch = 1;
  441. }
  442. } elsif (debarch_is($host_arch, $arch)) {
  443. $seen_arch = 1;
  444. last;
  445. }
  446. }
  447. return $seen_arch;
  448. }
  449. =item @array = debarch_list_parse($arch_list, %options)
  450. Parse an architecture list.
  451. =cut
  452. sub debarch_list_parse
  453. {
  454. my $arch_list = shift;
  455. my @arch_list = split /\s+/, $arch_list;
  456. foreach my $arch (@arch_list) {
  457. if (debarch_is_illegal($arch)) {
  458. error(g_("'%s' is not a legal architecture in list '%s'"),
  459. $arch, $arch_list);
  460. }
  461. }
  462. return @arch_list;
  463. }
  464. 1;
  465. __END__
  466. =back
  467. =head1 CHANGES
  468. =head2 Version 1.01 (dpkg 1.18.5)
  469. New functions: debarch_is_illegal(), debarch_list_parse().
  470. =head2 Version 1.00 (dpkg 1.18.2)
  471. Mark the module as public.
  472. =head1 SEE ALSO
  473. dpkg-architecture(1).