Blob Blame History Raw
#! /bin/sh

# Fix multilib issue for header files.
# Copyright (C) 2015-2016 Red Hat, Inc.
# Written by Pavel Raiskup <praiskup@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# 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 along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.


# Replace the multilib-unclean file with multilib-clean stub, while the
# original file is moved to unique architecture-specific location.

@LIB@

opt_buildroot=$(pwd)
opt_field_separator=-

# TODO: we could pretty easily implement other then 'cpp-header' stubs, if the
# target file type allows some kind of "transparent" file inclusion.  For
# example shell scripts might use '. "${destdir}/${filename}_x86_64.sh'.
# The solution is taken from Fedora PostgreSQL RPM package.
print_stub ()
{
    # The '#else' branch here is not needed!  We never install this header on
    # systems where this set of '#ifdef's is not enough (adding suggested e.g.
    # in rhbz#1242873).

    # TODO: Shorten the #ifdef hell.  There's no need to have e.g. ifdef for
    # x86_64 in ppc64's wrapper.

    replacement=$filename$opt_field_separator
cat <<EOF
/*
 * Kluge to support multilib installation of both 32- and 64-bit RPMS:
 * we need to arrange that header files that appear in both RPMs are
 * identical.  Hence, this file is architecture-independent and calls
 * in an arch-dependent file that will appear in just one RPM.
 *
 * To avoid breaking arches not explicitly supported by Red Hat, we
 * use this indirection file *only* on known multilib arches.
 *
 * We pay attention to include _only_ the original multilib-unclean
 * header file.  Including any other system-header file could cause
 * unpredictable include-ordering issues (rhbz#1412274, comment #16).
 *
 * Note: this may well fail if user tries to use gcc's -I- option.
 * But that option is deprecated anyway.
 */
#if defined(__x86_64__)
#include "${replacement}x86_64.h"
#elif defined(__i386__)
#include "${replacement}i386.h"
#elif defined(__ppc64__) || defined(__powerpc64__)
#include "${replacement}ppc64.h"
#elif defined(__ppc__) || defined(__powerpc__)
#include "${replacement}ppc.h"
#elif defined(__s390x__)
#include "${replacement}s390x.h"
#elif defined(__s390__)
#include "${replacement}s390.h"
#elif defined(__sparc__) && defined(__arch64__)
#include "${replacement}sparc64.h"
#elif defined(__sparc__)
#include "${replacement}sparc.h"
#endif
EOF
}

print_help ()
{
    _h_exit=false
    test -n "$1" && _h_exit=:

    cat <<EOF
Usage: $progname [OPTIONS]

Replace the multilib-unclean header file with multilib-clean stub, while the
original file is moved to unique architecture-specific location.  This should be
absolutely safe operation (effects of '#include <HEADER.h>' are unchanged.

To allow us to do incompatible changes in this script, packagers should use this
script only through available RPM macros.

--buildroot     prefix (directory where we play with installed files, usually
                after 'make install DESTDIR=buildroot')
--file          for example /some/path/test.h
--field-separator   by default we move filename.h to filename<SEP><ARCH>.h; this
                option allows you to override the <SEP> part
--verbose       print some useful information
--arch          override arch detection (mostly for testing purposes)
--help          show this help
EOF

    $_h_exit && exit "$1"
}

while test $# -gt 0
do
    _opt=$1 ; shift
    case $_opt in
        --buildroot|--arch|--file|--field-separator)
            _raw_opt=$(echo "$_opt" | sed -e 's/^--//' -e 's/-/_/g')
            eval "opt_$_raw_opt=\$1"
            shift || die "$_opt requires argument"
            ;;
        --help)
            print_help 0
            ;;
        *)
            error "unexpected '$_opt' program argument"
            ;;
    esac
done
$error_occurred && print_help 1
fix_arch opt_arch

for i in arch buildroot file
do
    eval "test -z \"\$opt_$i\"" && error "--$i needs to be set"
done
$error_occurred && print_help 1

# --> /buildroot/usr/include/test.h
original_file="$opt_buildroot$opt_file"

# --> /buildroot/usr/include
destdir=$(dirname "$original_file")

# --> test.h
orig_basename=$(basename "$original_file")

# --> test
filename=${orig_basename%%.[a-zA-Z0-9_]}

# --> .h
suffix=${orig_basename##${filename}}

# --> ../test_x86_64.h (on x86_64)
multilib_file="$destdir/$filename$opt_field_separator$opt_arch$suffix"

test -f "$original_file" || die "can't find '$original_file'"

is_multilib "$opt_arch"  || {
  verbose "we don't need multilib haeder hack for '$opt_arch' architecture (no-op)"
  exit 0
}

verbose "moving: '$original_file' to '$multilib_file'"

mv "$original_file" "$multilib_file" || exit 1
if print_stub > "$original_file" && chmod 644 "$original_file"; then
    :
else
    die "can't write into '$original_file'"
fi

: