#!/usr/bin/perl ########################################################################### # Makefile for API Sanity Checker # Install/remove the tool for GNU/Linux, FreeBSD and Mac OS X # # Copyright (C) 2009-2010 The Linux Foundation # Copyright (C) 2009-2011 Institute for System Programming, RAS # Copyright (C) 2011-2013 ROSA Lab # # Written by Andrey Ponomarenko # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License or the GNU Lesser # General Public License as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # and the GNU Lesser General Public License along with this program. # If not, see . ########################################################################### use Getopt::Long; Getopt::Long::Configure ("posix_default", "no_ignore_case"); use File::Path qw(mkpath rmtree); use File::Spec qw(catfile file_name_is_absolute); use File::Copy qw(copy); use File::Basename qw(dirname); use Cwd qw(abs_path); use File::Find; use Config; use strict; my $TOOL_SNAME = "api-sanity-checker"; my $ARCHIVE_DIR = abs_path(dirname($0)); my $ABICC = "/usr/local/bin/abi-compliance-checker.pl"; my $ABICC_VERSION = "1.98.7"; my $HELP_MSG = " NAME: Makefile for API Sanity Checker DESCRIPTION: Install $TOOL_SNAME command and private modules. USAGE: sudo perl $0 -install -prefix /usr sudo perl $0 -update -prefix /usr sudo perl $0 -remove -prefix /usr OPTIONS: -h|-help Print this help. --prefix=PREFIX Install files in PREFIX [/usr/local]. -install Command to install the tool. -update Command to update existing installation. -remove Command to remove the tool. EXTRA OPTIONS: --destdir=DESTDIR This option is for maintainers to build RPM or DEB packages inside the build root. The environment variable DESTDIR is also supported. \n"; if(not @ARGV) { print $HELP_MSG; exit(0); } my ($PREFIX, $DESTDIR, $Help, $Install, $Update, $Remove); GetOptions( "h|help!" => \$Help, "prefix=s" => \$PREFIX, "destdir=s" => \$DESTDIR, "install!" => \$Install, "update!" => \$Update, "remove!" => \$Remove ) or exit(1); sub scenario() { if($Help) { print $HELP_MSG; exit(0); } if(not $Install and not $Update and not $Remove) { print STDERR "ERROR: command is not selected (-install, -update or -remove)\n"; exit(1); } if(my $Version = `$ABICC -dumpversion`) { if(cmpVersions($Version, $ABICC_VERSION)<0) { print STDERR "ERROR: requires $ABICC_VERSION or newer version of \'$ABICC\'\n"; exit(1); } } else { print STDERR "ERROR: cannot find \'$ABICC\'\n"; exit(1); } if($PREFIX ne "/") { $PREFIX=~s/[\/]+\Z//g; } if(not $PREFIX) { # default prefix if($Config{"osname"}!~/win/i) { $PREFIX = "/usr/local"; } } if(my $Var = $ENV{"DESTDIR"}) { print "Using DESTDIR environment variable\n"; $DESTDIR = $Var; } if($DESTDIR) { if($DESTDIR ne "/") { $DESTDIR=~s/[\/]+\Z//g; } if(not isAbs($DESTDIR)) { print STDERR "ERROR: destdir is not absolute path\n"; exit(1); } if(not -d $DESTDIR) { print STDERR "ERROR: you should create destdir directory first\n"; exit(1); } $PREFIX = $DESTDIR.$PREFIX; if(not -d $PREFIX) { print STDERR "ERROR: you should create installation directory first (destdir + prefix):\n mkdir -p $PREFIX\n"; exit(1); } } else { if(not isAbs($PREFIX)) { print STDERR "ERROR: prefix is not absolute path\n"; exit(1); } if(not -d $PREFIX) { print STDERR "ERROR: you should create prefix directory first\n"; exit(1); } } print "INSTALL PREFIX: $PREFIX\n"; # paths my $EXE_PATH = catFile($PREFIX, "bin"); my $MODULES_PATH = catFile($PREFIX, "share", $TOOL_SNAME); my $REL_PATH = catFile("..", "share", $TOOL_SNAME); my $TOOL_PATH = catFile($EXE_PATH, $TOOL_SNAME); if(not -w $PREFIX) { print STDERR "ERROR: you should be root\n"; exit(1); } if($Remove or $Update) { if(-e $EXE_PATH."/".$TOOL_SNAME) { # remove executable print "-- Removing $TOOL_PATH\n"; unlink($EXE_PATH."/".$TOOL_SNAME); } if(-d $MODULES_PATH) { # remove modules print "-- Removing $MODULES_PATH\n"; rmtree($MODULES_PATH); } } if($Install or $Update) { if(-e $EXE_PATH."/".$TOOL_SNAME or -e $MODULES_PATH) { # check installed if(not $Remove) { print STDERR "ERROR: you should remove old version first (`perl $0 -remove --prefix=$PREFIX`)\n"; exit(1); } } # configure my $Content = readFile($ARCHIVE_DIR."/".$TOOL_SNAME.".pl"); if($DESTDIR) { # relative path $Content=~s/MODULES_INSTALL_PATH/$REL_PATH/; } else { # absolute path $Content=~s/MODULES_INSTALL_PATH/$MODULES_PATH/; } # copy executable print "-- Installing $TOOL_PATH\n"; mkpath($EXE_PATH); writeFile($EXE_PATH."/".$TOOL_SNAME, $Content); chmod(0775, $EXE_PATH."/".$TOOL_SNAME); if($Config{"osname"}=~/win/i) { writeFile($EXE_PATH."/".$TOOL_SNAME.".cmd", "\@perl \"$TOOL_PATH\" \%*"); } # copy modules if(-d $ARCHIVE_DIR."/modules") { print "-- Installing $MODULES_PATH\n"; mkpath($MODULES_PATH); copyDir($ARCHIVE_DIR."/modules", $MODULES_PATH); } # check PATH my $Warn = "WARNING: your PATH variable doesn't include \'$EXE_PATH\'\n"; if($Config{"osname"}=~/win/i) { if($ENV{"PATH"}!~/(\A|[:;])\Q$EXE_PATH\E[\/\\]?(\Z|[:;])/i) { print $Warn; } } else { if($ENV{"PATH"}!~/(\A|[:;])\Q$EXE_PATH\E[\/\\]?(\Z|[:;])/) { print $Warn; } } } exit(0); } sub cmpVersions($$) { # compare two versions in dotted-numeric format my ($V1, $V2) = @_; return 0 if($V1 eq $V2); my @V1Parts = split(/\./, $V1); my @V2Parts = split(/\./, $V2); for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) { return -1 if(int($V1Parts[$i]) < int($V2Parts[$i])); return 1 if(int($V1Parts[$i]) > int($V2Parts[$i])); } return -1 if($#V1Parts < $#V2Parts); return 1 if($#V1Parts > $#V2Parts); return 0; } sub catFile(@) { return File::Spec->catfile(@_); } sub isAbs($) { return File::Spec->file_name_is_absolute($_[0]); } sub copyDir($$) { my ($From, $To) = @_; my %Files; find(\&wanted, $From); sub wanted { $Files{$File::Find::dir."/$_"} = 1 if($_ ne "."); } foreach my $Path (sort keys(%Files)) { my $Inst = $Path; $Inst=~s/\A\Q$ARCHIVE_DIR\E/$To/; if(-d $Path) { # directories mkpath($Inst); } else { # files mkpath(dirname($Inst)); copy($Path, $Inst); } } } sub readFile($) { my $Path = $_[0]; return "" if(not $Path or not -f $Path); open(FILE, $Path) || die ("can't open file \'$Path\': $!\n"); local $/ = undef; my $Content = ; close(FILE); return $Content; } sub writeFile($$) { my ($Path, $Content) = @_; return if(not $Path); open(FILE, ">".$Path) || die ("can't open file \'$Path\': $!\n"); print FILE $Content; close(FILE); } scenario();