Arch.pm 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  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_debtriplet
  42. debarch_to_multiarch
  43. debarch_list_parse
  44. debtriplet_to_debarch
  45. debtriplet_to_gnutriplet
  46. gnutriplet_to_debarch
  47. gnutriplet_to_debtriplet
  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 %debtriplet_to_debarch;
  63. my %debarch_to_debtriplet;
  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_archtriplet) = gnutriplet_to_debtriplet($host_gnu_type);
  126. $host_arch = debtriplet_to_debarch(@host_archtriplet);
  127. if (defined $host_arch) {
  128. $host_gnu_type = debtriplet_to_gnutriplet(@host_archtriplet);
  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. read_cputable();
  156. read_ostable();
  157. my @arches;
  158. foreach my $os (@os) {
  159. foreach my $cpu (@cpu) {
  160. my $arch = debtriplet_to_debarch(split(/-/, $os, 2), $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 read_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 read_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 abitable_load()
  204. {
  205. load_table('abitable', sub {
  206. if (m/^(?!\#)(\S+)\s+(\S+)/) {
  207. $abibits{$1} = $2;
  208. }
  209. });
  210. }
  211. sub read_triplettable()
  212. {
  213. read_cputable();
  214. load_table('triplettable', sub {
  215. if (m/^(?!\#)(\S+)\s+(\S+)/) {
  216. my $debtriplet = $1;
  217. my $debarch = $2;
  218. if ($debtriplet =~ /<cpu>/) {
  219. foreach my $_cpu (@cpu) {
  220. (my $dt = $debtriplet) =~ s/<cpu>/$_cpu/;
  221. (my $da = $debarch) =~ s/<cpu>/$_cpu/;
  222. next if exists $debarch_to_debtriplet{$da}
  223. or exists $debtriplet_to_debarch{$dt};
  224. $debarch_to_debtriplet{$da} = $dt;
  225. $debtriplet_to_debarch{$dt} = $da;
  226. }
  227. } else {
  228. $debarch_to_debtriplet{$2} = $1;
  229. $debtriplet_to_debarch{$1} = $2;
  230. }
  231. }
  232. });
  233. }
  234. sub debtriplet_to_gnutriplet(@)
  235. {
  236. my ($abi, $os, $cpu) = @_;
  237. read_cputable();
  238. read_ostable();
  239. return unless defined($abi) && defined($os) && defined($cpu) &&
  240. exists($cputable{$cpu}) && exists($ostable{"$abi-$os"});
  241. return join('-', $cputable{$cpu}, $ostable{"$abi-$os"});
  242. }
  243. sub gnutriplet_to_debtriplet($)
  244. {
  245. my $gnu = shift;
  246. return unless defined($gnu);
  247. my ($gnu_cpu, $gnu_os) = split(/-/, $gnu, 2);
  248. return unless defined($gnu_cpu) && defined($gnu_os);
  249. read_cputable();
  250. read_ostable();
  251. my ($os, $cpu);
  252. foreach my $_cpu (@cpu) {
  253. if ($gnu_cpu =~ /^$cputable_re{$_cpu}$/) {
  254. $cpu = $_cpu;
  255. last;
  256. }
  257. }
  258. foreach my $_os (@os) {
  259. if ($gnu_os =~ /^(.*-)?$ostable_re{$_os}$/) {
  260. $os = $_os;
  261. last;
  262. }
  263. }
  264. return if !defined($cpu) || !defined($os);
  265. return (split(/-/, $os, 2), $cpu);
  266. }
  267. =item $multiarch = gnutriplet_to_multiarch($gnutriplet)
  268. Map a GNU triplet into a Debian multiarch triplet.
  269. =cut
  270. sub gnutriplet_to_multiarch($)
  271. {
  272. my $gnu = shift;
  273. my ($cpu, $cdr) = split(/-/, $gnu, 2);
  274. if ($cpu =~ /^i[4567]86$/) {
  275. return "i386-$cdr";
  276. } else {
  277. return $gnu;
  278. }
  279. }
  280. =item $multiarch = debarch_to_multiarch($arch)
  281. Map a Debian architecture into a Debian multiarch triplet.
  282. =cut
  283. sub debarch_to_multiarch($)
  284. {
  285. my $arch = shift;
  286. return gnutriplet_to_multiarch(debarch_to_gnutriplet($arch));
  287. }
  288. sub debtriplet_to_debarch(@)
  289. {
  290. my ($abi, $os, $cpu) = @_;
  291. read_triplettable();
  292. if (!defined($abi) || !defined($os) || !defined($cpu)) {
  293. return;
  294. } elsif (exists $debtriplet_to_debarch{"$abi-$os-$cpu"}) {
  295. return $debtriplet_to_debarch{"$abi-$os-$cpu"};
  296. } else {
  297. return;
  298. }
  299. }
  300. sub debarch_to_debtriplet($)
  301. {
  302. my $arch = shift;
  303. return if not defined $arch;
  304. read_triplettable();
  305. if ($arch =~ /^linux-([^-]*)/) {
  306. # XXX: Might disappear in the future, not sure yet.
  307. $arch = $1;
  308. }
  309. my $triplet = $debarch_to_debtriplet{$arch};
  310. if (defined($triplet)) {
  311. return split(/-/, $triplet, 3);
  312. } else {
  313. return;
  314. }
  315. }
  316. =item $gnutriplet = debarch_to_gnutriplet($arch)
  317. Map a Debian architecture into a GNU triplet.
  318. =cut
  319. sub debarch_to_gnutriplet($)
  320. {
  321. my $arch = shift;
  322. return debtriplet_to_gnutriplet(debarch_to_debtriplet($arch));
  323. }
  324. =item $arch = gnutriplet_to_debarch($gnutriplet)
  325. Map a GNU triplet into a Debian architecture.
  326. =cut
  327. sub gnutriplet_to_debarch($)
  328. {
  329. my $gnu = shift;
  330. return debtriplet_to_debarch(gnutriplet_to_debtriplet($gnu));
  331. }
  332. sub debwildcard_to_debtriplet($)
  333. {
  334. my $arch = shift;
  335. my @tuple = split /-/, $arch, 3;
  336. if (any { $_ eq 'any' } @tuple) {
  337. if (scalar @tuple == 3) {
  338. return @tuple;
  339. } elsif (scalar @tuple == 2) {
  340. return ('any', @tuple);
  341. } else {
  342. return ('any', 'any', 'any');
  343. }
  344. } else {
  345. return debarch_to_debtriplet($arch);
  346. }
  347. }
  348. sub debarch_to_cpuattrs($)
  349. {
  350. my $arch = shift;
  351. my ($abi, $os, $cpu) = debarch_to_debtriplet($arch);
  352. if (defined($cpu)) {
  353. abitable_load();
  354. return ($abibits{$abi} // $cpubits{$cpu}, $cpuendian{$cpu});
  355. } else {
  356. return;
  357. }
  358. }
  359. =item $bool = debarch_eq($arch_a, $arch_b)
  360. Evaluate the equality of a Debian architecture, by comparing with another
  361. Debian architecture. No wildcard matching is performed.
  362. =cut
  363. sub debarch_eq($$)
  364. {
  365. my ($a, $b) = @_;
  366. return 1 if ($a eq $b);
  367. my @a = debarch_to_debtriplet($a);
  368. my @b = debarch_to_debtriplet($b);
  369. return 0 if scalar @a != 3 or scalar @b != 3;
  370. return ($a[0] eq $b[0] && $a[1] eq $b[1] && $a[2] eq $b[2]);
  371. }
  372. =item $bool = debarch_is($arch, $arch_wildcard)
  373. Evaluate the identity of a Debian architecture, by matching with an
  374. architecture wildcard.
  375. =cut
  376. sub debarch_is($$)
  377. {
  378. my ($real, $alias) = @_;
  379. return 1 if ($alias eq $real or $alias eq 'any');
  380. my @real = debarch_to_debtriplet($real);
  381. my @alias = debwildcard_to_debtriplet($alias);
  382. return 0 if scalar @real != 3 or scalar @alias != 3;
  383. if (($alias[0] eq $real[0] || $alias[0] eq 'any') &&
  384. ($alias[1] eq $real[1] || $alias[1] eq 'any') &&
  385. ($alias[2] eq $real[2] || $alias[2] eq 'any')) {
  386. return 1;
  387. }
  388. return 0;
  389. }
  390. =item $bool = debarch_is_wildcard($arch)
  391. Evaluate whether a Debian architecture is an architecture wildcard.
  392. =cut
  393. sub debarch_is_wildcard($)
  394. {
  395. my $arch = shift;
  396. return 0 if $arch eq 'all';
  397. my @triplet = debwildcard_to_debtriplet($arch);
  398. return 0 if scalar @triplet != 3;
  399. return 1 if any { $_ eq 'any' } @triplet;
  400. return 0;
  401. }
  402. =item $bool = debarch_is_illegal($arch)
  403. Validate an architecture name.
  404. =cut
  405. sub debarch_is_illegal
  406. {
  407. my ($arch) = @_;
  408. return $arch !~ m/^!?[a-zA-Z0-9][a-zA-Z0-9-]*$/;
  409. }
  410. =item $bool = debarch_is_concerned($arch, @arches)
  411. Evaluate whether a Debian architecture applies to the list of architecture
  412. restrictions, as usually found in dependencies inside square brackets.
  413. =cut
  414. sub debarch_is_concerned
  415. {
  416. my ($host_arch, @arches) = @_;
  417. my $seen_arch = 0;
  418. foreach my $arch (@arches) {
  419. $arch = lc $arch;
  420. if ($arch =~ /^!/) {
  421. my $not_arch = $arch;
  422. $not_arch =~ s/^!//;
  423. if (debarch_is($host_arch, $not_arch)) {
  424. $seen_arch = 0;
  425. last;
  426. } else {
  427. # !arch includes by default all other arches
  428. # unless they also appear in a !otherarch
  429. $seen_arch = 1;
  430. }
  431. } elsif (debarch_is($host_arch, $arch)) {
  432. $seen_arch = 1;
  433. last;
  434. }
  435. }
  436. return $seen_arch;
  437. }
  438. =item @array = debarch_list_parse($arch_list, %options)
  439. Parse an architecture list.
  440. =cut
  441. sub debarch_list_parse
  442. {
  443. my $arch_list = shift;
  444. my @arch_list = split /\s+/, $arch_list;
  445. foreach my $arch (@arch_list) {
  446. if (debarch_is_illegal($arch)) {
  447. error(g_("'%s' is not a legal architecture in list '%s'"),
  448. $arch, $arch_list);
  449. }
  450. }
  451. return @arch_list;
  452. }
  453. 1;
  454. __END__
  455. =back
  456. =head1 CHANGES
  457. =head2 Version 1.01 (dpkg 1.18.5)
  458. New functions: debarch_is_illegal(), debarch_list_parse().
  459. =head2 Version 1.00 (dpkg 1.18.2)
  460. Mark the module as public.
  461. =head1 SEE ALSO
  462. dpkg-architecture(1).