#!/usr/bin/perl -w =head1 NAME dh_illumos_gate - unpack and prepare illumos sources =cut use strict; use Debian::Debhelper::Dh_Lib; use Dpkg::Changelog::Parse; use Cwd; =head1 SYNOPSIS B [S>] [options] [-- [tar options]] [files and/or directories to pack/unpack] =head1 DESCRIPTION C is responsible for unpacking illumos sources and adjusting the sources for Debian build environment (paths to programs, command options, linker and compiler flags, etc.). C unpacks specified files or directories, if any. Otherwise it unpacks the entire F. In any case B<-X> option can be used to exclude some files or directories, and top directory F is always stripped. If files interested to C are unpacked they will be configured. See L. After executing C one can use commands like this to configure or build components of illumos gate: ksh93 usr/bldenv.sh usr/env.sh -c "cd usr/src/lib/libzfs && make --sun install" L provides more convenient way to do this. =head1 OPTIONS =over 4 =item B<--build> Unpack or pack (by B<--create-orig>) files known to be required for building illumos components. These are F, F, F. If any file under F is requested, F are [un]packed too. Same for F. This option is provided only for convenience. You are free to pack and unpack these files explicitly. =item B<-X>I B<--exclude=>I Do not pack or unpack files or directories matching I. This option can be used multiple times. I is passed as is to L via I<--exclude=PATTERN>. =item B<--destdir=>I Destination directory for B<--configure>, B<--checkout> and unpacking (default action). =item B<--create-orig> Create I<.orig> tarball out of the listed files and directories. Note that part of path before F will be stripped. =item B<--configure> Copy existing sources (F<./usr>) into the build directory specified by B<--destdir> (instead of unpacking the illumos-gate tarball) and then configure it. =item B<--unpack-only> Only unpack illumos-gate tarball, do not configure. =item B<--checkout>[I<=git-hash>] Clone illumos-gate git repository and checkout I in there. If not specified, hash is extracted from topmost version in F: C<1.2.3.git.-4>. Could be used for B<--create-orig>. Repository is https://github.com/illumos/illumos-gate.git, unless specified by B<--repository>. You should also set B<--destdir>. =item B<--repository=>I illumos-gate git repository. Default is https://github.com/illumos/illumos-gate.git. =item B<--root=>I Defines root directory where build result will be installed: executables, libraries, headers, etc. Defaults to F<./debian/tmp>. This can be overrided by L. If absent, it will be created. =back =head1 EXAMPLES =over 4 =item Unpack and configure the whole illumos source tree (F) dh_illumos_gate =item Unpack and configure whole illumos source tree, but F dh_illumos_gate -X usr/src/uts =item Unpack and configure whole illumos source tree, but F; then add F dh_illumos_gate -X usr/src/uts dh_illumos_gate usr/src/uts/common/sys =item Unpack all Makefiles under F dh_illumos_gate usr/src/Makefile\* =item Unpack all header files under F dh_illumos_gate -- --wildcards-match-slash usr/src/uts/*.h =item Create source tarball out of F excluding F<*.xml> files dh_illumos_gate --create-orig [path/to/]usr/src/cmd -X*.xml =item Prepare for debug and non-debug builds dh_illumos_gate --configure --destdir=workdir/debug dh_illumos_gate --configure --destdir=workdir/non-debug =item Migrate to 3.0 (quilt) format dh_illumos_gate --unpack-only files... dh_illumos_gate --create-orig files... =item Create new orig tarball dh_illumos_gate --checkout=a5723... --destdir=foo dh_illumos_gate --create-orig foo/usr/src =back =head1 FILES =over 4 =item /usr/src/illumos-gate/illumos-gate-$(VER).tar.xz This file contains complete and unmodified illumos sources. It is provided by package I. Version C<$(VER)> is determined from F: (\d+\.\d+).* => \1, e. g.: 2.10+3 => VER = 2.10 =back =head1 DETAILS Here are things which this helper does after unpacking illumos sources. =over 4 =cut $dh{ROOT} = 'debian/tmp'; $dh{CHECKOUT} = undef; $dh{DESTDIR} = '.'; $dh{REPOSITORY} = 'https://github.com/illumos/illumos-gate.git'; init( options => { 'build' => \$dh{BUILD}, 'checkout:s' => \$dh{CHECKOUT}, 'configure' => \$dh{CONFIGURE}, 'create-orig' => \$dh{CREATE_ORIG}, 'destdir=s' => \$dh{DESTDIR}, 'repository=s' => \$dh{REPOSITORY}, 'root=s' => \$dh{ROOT}, 'unpack-only' => \$dh{UNPACK_ONLY}, } ); my %options = ( file => 'debian/changelog' ); my $changelog = changelog_parse(%options); my $version = $changelog->{'Version'}; my $cwd = getcwd(); my @tar_X = (); if ( defined( $dh{'EXCLUDE'} ) && $dh{'EXCLUDE'} ) { foreach my $x ( @{ $dh{'EXCLUDE'} } ) { push @tar_X, '--exclude'; push @tar_X, $x; } } if ( defined $dh{CHECKOUT} ) { if ( -e $dh{DESTDIR} ) { error("Destination path `$dh{DESTDIR}' exists."); } if ( !$dh{CHECKOUT} ) { $dh{CHECKOUT} = $version =~ s!.*\Wgit\W?(\w+)-[^-]+$!$1!r; } doit( 'git', 'clone', '-n', $dh{REPOSITORY}, $dh{DESTDIR} ); doit( 'git', '-C', $dh{DESTDIR}, 'checkout', $dh{CHECKOUT} ); exit; } elsif ( $dh{CREATE_ORIG} ) { my $source = $changelog->{'Source'}; my $source_version = $version =~ s!^(.*)-[^-]+$!$1!r; my $tarball = "$cwd/../${source}_${source_version}.orig.tar.xz"; my $transform = "s,.*usr/src,$source-$source_version/usr/src,"; my @tar = ( 'tar', '-c', '-J', '--exclude-vcs', '--exclude-vcs-ignores', '--owner=0', '--group=0', '--mode', 'u=rwX,go=rX', '--transform', "'$transform'", '-f', "'$tarball'", @tar_X ); my @extra = (); if ( $dh{'BUILD'} ) { my $r = $ARGV[0] =~ s!(.*)usr/src.*!$1!r; # XXX Sloppy push @extra, ( "${r}usr/src/Makefile*", "${r}usr/src/common/mapfiles", "${r}usr/src/tools/scripts/bldenv.sh", ); if ( grep { m|(.*)usr/src/lib/.*| } @ARGV ) { push @extra, "$1usr/src/lib/Makefile*"; } if ( grep { m|(.*)usr/src/cmd/.*| } @ARGV ) { push @extra, "$1usr/src/cmd/Makefile*"; } } # We need shell wildcards here, thus complex_doit, not doit # sort - to drop dublicates (lead to hardlinks in the tarball): complex_doit("find @ARGV @extra -type f | sort -u | @tar -T -"); exit; } elsif ( $dh{CONFIGURE} ) { if ( -e $dh{DESTDIR} ) { error("Destination path `$dh{DESTDIR}' exists."); } doit( 'mkdir', '-p', $dh{DESTDIR} ); doit( 'cp', '-a', 'usr', "$dh{DESTDIR}/usr" ); # fall through } else { # Default is to unpack for backward compatibility my $ver; if ( $version =~ /^(\d+(\.\d+)+(\.git\w+)?).*$/ ) { $ver = $1; } else { error( "Could not determine illumos source version from changelog. " . "It should be like 5.10.6.gitXYZ+1, but it is '$version'" ); } my $tarball = "/usr/src/illumos-gate/illumos-gate-$ver.tar.xz"; if ( !-f $tarball ) { error( "$tarball does not exist. You might not have package illumos-source-$ver " . "installed or have a typo in debian/changelog" ); } my @to_extract = (); if (@ARGV) { if ( $dh{'BUILD'} ) { push @to_extract, ( 'usr/src/Makefile*', 'usr/src/common/mapfiles', 'usr/src/tools/scripts/bldenv.sh', ); if ( grep { m|.*usr/src/lib/.*| } @ARGV ) { push @to_extract, 'usr/src/lib/Makefile*'; } if ( grep { m|.*usr/src/cmd/.*| } @ARGV ) { push @to_extract, 'usr/src/cmd/Makefile*'; } } push @to_extract, map { m,(?:illumos-gate/)?(.*),; $1 } @ARGV; } else { push @to_extract, 'usr'; } my @to_extract_real = (); foreach my $p (@to_extract) { if ( $p =~ /^-/ ) { push @to_extract_real, $p; #XXX: tar option } else { push @to_extract_real, 'illumos-gate/' . $p; #XXX: path } } doit( 'mkdir', '-p', $dh{DESTDIR} ); doit( 'tar', '-C', $dh{DESTDIR}, '-x', '-f', $tarball, @tar_X, '--wildcards', '--strip-components=1', @to_extract_real ); if ( $dh{UNPACK_ONLY} ) { exit; } } =item Saving original files Any files from illumos sources, changed by this helper, are saved with F<.orig> suffix, so you can investigate changes. For example, you can use C to see all changes. =cut =item Changes to F (if exists): Remove option C<-s> (strip) from install command for directories and files. This options does not make sense for directories and GNU L is not tolerant here. Also replace option C<-f> with C<-t>. Append C with C<-m32> since native host compiler can produce 64-bit code by default. Set initial value of C to C<:> since it may be appended later with other commands separated by C<;>, but bash and dash do not like stand-alone C<;>. Korn shell is ok. Explicitly undefine some CPP macros related to amd64 for building 32-bit objects, e. i. options like C<-U__amd64> are appended to C and C. C flags are appended to C command. Delete (set to empty) variable C, cause we are not using shared lex library (F), but static Flex library (libl.a). In variables C and C replace variables C<$(CTFSTABS)> and C<$(CTFCONVERT)> with explicit F and F, because those variables are empty when building without CTF, but creating offsets really requires CTF data. This is used when compiling libc and illumos kernel. =cut my $multiarch = `dpkg-architecture -qDEB_HOST_MULTIARCH`; chomp $multiarch; my $bits = `dpkg-architecture -qDEB_HOST_ARCH_BITS`; chomp $bits; # In illumos source 32-bit binaries are default my ( $libdir32, $libdir64, $usrlibdir32, $usrlibdir64 ); if ( $bits == 64 ) { $libdir32 = "lib32"; $usrlibdir32 = "usr/$libdir32"; $libdir64 = "lib/$multiarch"; $usrlibdir64 = "usr/$libdir64"; } else { $libdir32 = "lib/$multiarch"; $usrlibdir32 = "usr/$libdir32"; $libdir64 = "lib64"; $usrlibdir64 = "usr/$libdir64"; } my $Makefile_master = $dh{DESTDIR} . '/usr/src/Makefile.master'; my $Makefile_master_orig = $Makefile_master . '.orig'; if ( -f $Makefile_master ) { if ( !-e $Makefile_master_orig ) { doit( 'cp', '-f', $Makefile_master, $Makefile_master_orig ); } # Be careful with modern CPP: my $i386_undef = '-Uamd64 -U__amd64 -U__amd64__ -U__x86_64__ -U__x86_64 -U_LP64'; doit( 'sed', '-r', '-i', ' /^INS\.(file|dir)/ s, -s,,; s/^POST_PROCESS_O\s*=\s*$/POST_PROCESS_O = :/; /^INS\.file/ s, -f, -t,; /^i386_XARCH\s*=/s,$, -m32 ' . $i386_undef . ',; /^i386_AS_XARCH\s*=/s,$, ' . $i386_undef . ',; /^COMPILE\.s/s,$, $($(MACH)_AS_XARCH),; /^MAPFILE.LEX/d; /^OFFSETS_CREATE/ s,\$\(CTFSTABS\),ctfstabs,; /^OFFSETS_CREATE/ s,\$\(CTFCONVERT\),ctfconvert,; ', $Makefile_master ); } =item Changes F (if exists): Append C to C command, because C by default uses C compiler to create shared library. Set C, C, C and C to match Debian multiarch layout. For example C = F and C = F on I. It cannot be done in environment file F (see below), because in some cases C will be overriden by C within makefiles. =cut my $Makefile_lib = $dh{DESTDIR} . '/usr/src/lib/Makefile.lib'; my $Makefile_lib_orig = $Makefile_lib . '.orig'; if ( -f $Makefile_lib ) { if ( !-e $Makefile_lib_orig ) { doit( 'cp', '-f', $Makefile_lib, $Makefile_lib_orig ); } doit( 'sed', '-r', '-i', ' /^BUILD.SO/ s,\$\(CC\),$(CC) $(CFLAGS),; ', $Makefile_lib ); doit( 'sed', '-r', '-i', " s,^(ROOTFS_LIBDIR)\\s*=.*,\\1=\$(ROOT)/$libdir32,; s,^(ROOTFS_LIBDIR64)\\s*=.*,\\1=\$(ROOT)/$libdir64,; s,^(ROOTLIBDIR)\\s*=.*,\\1=\$(ROOT)/$usrlibdir32,; s,^(ROOTLIBDIR64)\\s*=.*,\\1=\$(ROOT)/$usrlibdir64,; ", $Makefile_lib ); } =item Changes F (if exists): Remove trailing spaces in the line C Maybe we should patch GNU make to do it for us in SunOS mode. Remove linker flag for setting ELF interpreter (-Wl,-I/lib/ld.so.1) =cut my $Makefile_cmd = $dh{DESTDIR} . '/usr/src/cmd/Makefile.cmd'; my $Makefile_cmd_orig = $Makefile_cmd . '.orig'; if ( -f $Makefile_cmd ) { if ( !-e $Makefile_cmd_orig ) { doit( 'cp', '-f', $Makefile_cmd, $Makefile_cmd_orig ); } doit( 'sed', '-r', '-i', ' /^TEXT_DOMAIN/ s,\s+$,,g; ', $Makefile_cmd ); doit( 'sed', '-r', '-i', ' /LDFLAGS\s*\+=\s*-Wl,-I\/lib\/ld\.so\.1/d; ', $Makefile_cmd ); } =item Creates F Set C to the B<--destdir>. Set C from F<./debian/changelog>. For example it can be C<2.10-3>. Set C=F to call L instead of GNU L. Default system GCC is build to use GNU L, but L is required to build most illumos components. See L. Set proto area to be F/root>. Disable linting libraries by replacing C with ":". So it will do nothing. Successfully. Also define C to empty string to prevent installation of lint libraries (which do not exist). Disable modifying comment section of ELFs by replacing C with ":". Disable stripping by replacing C with ":". Enable GCC and GCC4 mode by defining C<__GNUC> and C<__GNUC4>. Change GCC root to F, so the default system compiler is used. Define C to be C. Export all C variables (using C) to make them available from makefiles. Unsets C, C, C. Many related variables are unset by F, but these ones. They break build. =cut chdir $dh{DESTDIR}; my $codemgr_ws = getcwd(); chdir $cwd; doit( 'mkdir', '-p', $dh{ROOT} ); chdir $dh{ROOT}; my $root = getcwd(); chdir $cwd; my $env = $dh{DESTDIR} . '/usr/env.sh'; my $mach = `uname -p`; chomp $mach; if ( open( ENV, '>', $env ) ) { print ENV "# This file was generated by dh_illumos_gate(1)\n"; print ENV "export VERSION='$version'\n"; print ENV "export CODEMGR_WS='$codemgr_ws'\n"; print ENV "export ROOT='$root'\n"; print ENV "export SRC='$codemgr_ws/usr/src'\n"; print ENV "export MULTI_PROTO='no'\n"; print ENV "export CW_NO_SHADOW=1\n"; print ENV "export LD_ALTEXEC='/usr/bin/ld-gnu-to-sun'\n"; print ENV "export BUILD_TOOLS='/opt'\n"; print ENV "export MACH='$mach'\n"; print ENV "export LINT=:\n"; print ENV "export LINTLIB=''\n"; print ENV "export __GNUC=''\n"; print ENV "export __GNUC4=''\n"; print ENV "export GCC_ROOT='/usr'\n"; print ENV "export CW_GCC=gcc\n"; print ENV "export SAVEARGS=\n"; print ENV "export LEX='/usr/bin/flex -l'\n"; print ENV "export STRIP=':'\n"; print ENV "export MCS=':'\n"; print ENV "export DEB_LIBDIR_32='/$libdir32'\n"; print ENV "export DEB_USRLIBDIR_32='/$usrlibdir32'\n"; print ENV "export DEB_LIBDIR_64='/$libdir64'\n"; print ENV "export DEB_USRLIBDIR_64='/$usrlibdir64'\n"; print ENV "unset CFLAGS\n"; print ENV "unset CPPFLAGS\n"; print ENV "unset LDFLAGS\n"; print ENV "export LDLIBS32=\"-L\$ROOT/\$DEB_LIBDIR_32 -L\$ROOT/\$DEB_USRLIBDIR_32\"\n"; print ENV "export LDLIBS64=\"-L\$ROOT/\$DEB_LIBDIR_64 -L\$ROOT/\$DEB_USRLIBDIR_64\"\n"; print ENV 'export LDLIBS_NATIVE="', ( $bits == 64 ) ? '$LDLIBS64' : '$LDLIBS32', "\"\n"; print ENV `dpkg-architecture -s`; close(ENV); } else { error("Failed to write `$env': $!"); } =item Create F (if F exists) Copy F to F. Fix definition of C variables, so this script will not override them if they are already defined. These variables can be set to ":", when executing L with option C<--without-ctf>. =cut my $bldenv_sh_orig = $dh{DESTDIR} . '/usr/src/tools/scripts/bldenv.sh'; my $bldenv_sh = $dh{DESTDIR} . '/usr/bldenv.sh'; if ( -f $bldenv_sh_orig ) { doit( 'cp', '-f', $bldenv_sh_orig, $bldenv_sh ); doit( 'sed', '-r', '-i', ' s,export +(CTF.+)="(.+)",export \1="${\1:-\2}",; s,^PATH=".+",PATH="${PATH}:/opt/onbld/bin:/opt/onbld/bin/${MACH}:.",; ', $bldenv_sh ); } =back =head1 NOTES To clean package (via C<./debian/rules clean>) you should just remove F directory, or the directory you specified by B<--destdir>: rm -rf usr C will fail when it's unpacking files which should be unpacked due to option C<--build>. This is a L issue (tar: ...: Not found in archive). For example, this will fail: dh_illumos_gate --build usr/src/cmd usr/src/lib/Makefile.lib Workaround: dh_illumos_gate --build usr/src/cmd dh_illumos_gate usr/src/lib/Makefile.lib =head1 SEE ALSO L, L. =head1 AUTHOR Igor Pashev =cut