Skip to content

Instantly share code, notes, and snippets.

@o11c
Last active December 3, 2016 02:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save o11c/cf98115ba716ebdd1dc2cc75b290f321 to your computer and use it in GitHub Desktop.
Save o11c/cf98115ba716ebdd1dc2cc75b290f321 to your computer and use it in GitHub Desktop.
FreePascal cross hack (Debian packages)
/cache/
/tmp/
/out/
/fpc-cross-hack-config.sh
#!/bin/bash
# vim: isk+=-
# Running this script will create some hacked-up binary-only cross-FPCs.
# You'll need to install qemu-user-binfmt to run them.
# Other than in lazy-config(), no Debian-specific tools are used.
set -e
set -E
trap 'echo "Failure during startup, maybe on line $LINENO"' ERR
config()
{
default-config
# Instead of editing *this* script, edit *that* one.
# Since everything is functions, you could even overwrite them.
# (e.g. you could reimplement the `download` function using `curl`.
# You could call parse-args rather than setting config variables directly.
maybe-source fpc-cross-hack-config.sh
# Command-line arguments override the sourced file.
parse-args "$@"
# If any of the config thingies is lazy, execute it.
lazy-config
}
default-config()
{
# Where to download .
config_mirror=http://ftp.debian.org/debian
# Path to the GPG keyring used to check the Release file.
config_keyring=/usr/share/keyrings/debian-archive-keyring.gpg
# If not running on Debian, you'll need to set this explicitly.
config_native_arch=
config_dists=(
stretch
jessie-backports
jessie
wheezy-backports
wheezy
)
config_arches=(
# At first I implemented this, but it requires downloading
# a *lot* of Packages.xz files that don't have what we need.
#everything
all
amd64
arm64
armel
armhf
i386
powerpc
sparc
)
config_blacklist_arches=(
# Something fails, haven't investigated.
# Already dropped from jessie so I'm not bothering.
sparc
)
# Version numbers will be added as appropriate.
# NOTE: other code currently assumes these all start with 'fp'
config_packages=(
# TODO https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=846628
binutils-i586-linux-gnu
binutils-x86-64-linux-gnu
fp-compiler
fp-docs
fp-ide
fp-units-base
fp-units-db
fp-units-fcl
fp-units-fv
fp-units-gfx
fp-units-gnome1
fp-units-gtk
fp-units-gtk2
fp-units-i386
fp-units-math
fp-units-misc
fp-units-multimedia
fp-units-net
fp-units-rtl
fp-utils
fpc
fpc-source
)
config_blacklist_packages=(
)
config_skip_phase1=no
config_skip_phase2=no
config_skip_phase3=no
}
lazy-config()
{
local arch package
if test -z "$config_native_arch"
then
config_native_arch=$(call dpkg --print-architecture)
fi
declare -g -A config_arches_hash
for arch in "${config_arches[@]}"
do
config_arches_hash["$arch"]=yes
done
for arch in "${config_blacklist_arches[@]}"
do
config_arches_hash["$arch"]=no
done
# Not supporting "everything" makes this *way* easier.
declare -g -A config_packages_hash
for package in "${config_packages[@]}"
do
config_packages_hash["$package"]=x
done
for package in "${config_blacklist_packages[@]}"
do
unset config_packages_hash["$package"]
done
config_packages=("${!config_packages_hash[@]}")
}
parse-args()
{
for arg
do
case "$arg" in
-h | --help)
: '
This help.
'
declare -f parse-args | sed -n '/--[a-z]/,/;/{s/^ \( \(-\)\)\?/\2/; /^-/s/)$//; s/.*[:;].*//; p}' # What?
exit
;;
--mirror=*)
: '
URL to download the original .deb files from.
This is probably the same as in sources.list
'
config_mirror=${arg#*=}
;;
--keyring=*)
: '
Path to GPG keyring that can verify the Release file.
On Debian, this is shipped by the `debian-archive-keyring` package.
'
config_keyring=${arg#*=}
;;
--native-arch=*)
: '
Preferred architecture for this that only need to exist once.
'
config_native_arch=${arg#*=}
;;
--dist=* | --dists=*)
: '
Comma-separated list of distributions to download and repack.
By default, all of the following are repacked:
stretch
jessie-backports
jessie
wheezy-backports
wheezy
Each one requires about 150MB of initial download, and another
150MB of output.
'
config_dists=($(echo "${arg#*=}" | sed 's/,/ /g'))
;;
--arch=* | --arches=*)
: '
Comma-separated list of architectures to repack.
Any architecture not in the Release file, or which does not
have fp-compiler in its Packages file, will be silently ignored.
By default, all architectures in the Release file are used.
'
config_arches=($(echo "${arg#*=}" | sed 's/,/ /g'))
;;
--blacklist-arch=* | --blacklist-arches=*)
: '
Comma-separated list of architectures NOT to repack.
This overrides --arches=
'
config_blacklist_arches=($(echo "${arg#*=}" | sed 's/,/ /g'))
;;
--package=* | --packages=*)
: '
Comma-separated list of packages to repack.
Any package not in the Packages file will be silently ignored.
By default, all packages in the Release file are used.
'
config_packages=($(echo "${arg#*=}" | sed 's/,/ /g'))
;;
--blacklist-package=* | --blacklist-packages=*)
: '
Comma-separated list of packages NOT to repack.
This overrides --packages=
'
config_blacklist_packages=($(echo "${arg#*=}" | sed 's/,/ /g'))
;;
--skip-phase1)
config_skip_phase1=yes
;;
--skip-phase2)
config_skip_phase2=yes
;;
--skip-phase3)
config_skip_phase3=yes
;;
*)
die 'No such argument: %q' "$arg"
;;
esac
done
}
# No user-serviceable parts beyond this point (probably).
### Basic functions
die()
{
local fmt
fmt="$1"; shift
printf 'FATAL: '"$fmt"'\n' "$@" >&2
kill -KILL -$$
}
quiet()
{
"$@" >/dev/null
}
silent()
{
"$@" >/dev/null 2>&1
}
indirect-get()
{
echo "${!1}"
}
indirect-set()
{
eval "$1"='$2'
}
maybe-source()
{
if test -f "$1"
then
source "$1"
fi
}
have()
{
silent which "$1"
}
need()
{
if ! have "$1"
then
die '%q is not installed' "$1"
fi
}
call()
{
need "$1"
"$@"
}
### Debugging
colorize()
{
# This is slow, it should be cached.
# But, it only happens if something goes wrong, so ...
if have pygmentize
then
pygmentize -O linenos=True "$1"
return
fi
cat -n "$1"
}
get-context()
{
local s e x c
(( x = "$2" ))
(( c = "$3" )) || true
(( s = x<=c ? 1 : x-c ))
(( e = x+c ))
colorize "$1" | sed -n "$s,$e"'{ s/[0-9]\+/\x1b[32m&\x1b[m/; s/^/ /; '"${x}"'s/^ / ==>/; p; }'
}
backtrace_wd="$(pwd)"
backtrace()
{
cd "$backtrace_wd"
{
local max file line func argc argvi i j
echo
echo 'Panic! Something failed unexpectedly.'
echo 'While executing' "$BASH_COMMAND"
echo
echo Backtrace:
echo
max=${#BASH_LINENO[@]}
let max-- # The top-most frame is "special".
argvi=${BASH_ARGC[0]}
for ((i=1;i<max;++i))
do
file=${BASH_SOURCE[i]}
line=${BASH_LINENO[i-1]}
func=${FUNCNAME[i]}
argc=${BASH_ARGC[i]}
printf '%s:%d: ... in %q' "$file" "$line" "$func"
# BASH_ARGV: ... bar foo ...
# argvi ^
# argvi+argc ^
for ((j=argc-1; j>=0; --j))
do
printf ' %q' ${BASH_ARGV[argvi+j]}
done
let argvi+=argc || true
printf '\n'
get-context "$file" "$line" 3
done
if true
then
file=${BASH_SOURCE[i]}
line=${BASH_LINENO[i-1]}
printf '%s:%d: ... at top level\n' "$file" "$line"
get-context "$file" "$line" 3
fi
} >&2
kill -KILL -$$
}
### Core logic
download()
{
test -n "$1"
# It would simplify all callers a lot if $1 already included cache/
local url out
url="$config_mirror"/"$1"
out=cache/"$1"
if test -f "$out"
then
return
fi
mkdir -p "$(dirname "$out")"
call wget -q -c -O "$out".part "$url" || die 'GET %s' "$url"
mv "$out".part "$out"
}
get-field()
{
local field
field="$1"
sed -n '
# Do not print anything until the field name is found.
s/^'"$field"': *//
T
/^$/!p
# Also print followng lines that start with a space.
: more
n
s/^ //
T exit
p
b more
: exit
q
'
}
get-active-arches()
{
local dist release avail_arches enabled
dist="$1"
release=cache/dists/"$dist"/Release
avail_arches=($(cat "$release" | get-field Architectures))
for arch in all "${avail_arches[@]}"
do
enabled="${config_arches_hash[$arch]}"
if test -z "$enabled"
then
enabled="${config_arches_hash[everything]}"
fi
if test "$enabled" = yes
then
echo "$arch"
fi
done
}
volatile-dist()
{
local dist release release_gpg enabled_arches
dist="$1"
release=dists/"$dist"/Release
release_gpg=dists/"$dist"/Release.gpg
download "$release"; release=cache/"$release"
download "$release_gpg"; release_gpg=cache/"$release_gpg"
silent gpgv --keyring "$config_keyring" "$release_gpg" "$release" || die 'GPG %q' "$release"
echo "OK: $release"
enabled_arches=($(get-active-arches "$dist"))
for arch in "${enabled_arches[@]}"
do
volatile-arch "$dist" "$arch"
done
}
get-smallest-packages-file()
{
local arch
arch="$1"
grep ' main/binary-'"$arch"'/Packages[^ /]*$' | sort -k 2,2 -n | head -n 1
}
check-sha()
{
local sha file
sha="$1"
file="$2"
echo "$sha $file" | sha256sum -c --status || die 'SHA %q' "$file"
}
volatile-arch()
{
local dist arch release sha size packages_file packages_file_u
dist="$1"
arch="$2"
release=cache/dists/"$dist"/Release
read -r sha size packages_file < <(cat "$release" | get-field SHA256 | get-smallest-packages-file "$arch")
packages_file=dists/"$dist"/"$packages_file"
download "$packages_file"; packages_file=cache/"$packages_file"
check-sha "$sha" "$packages_file"
packages_file_u=cache/dists/"$dist"/main/binary-"$arch"/Packages.prefix
if ! test "$packages_file_u" -nt "$packages_file"
then
# 'Packages' is sorted by *source* name, not *binary* name. Ick.
auto-cat "$packages_file" | sed -n '/^Package: \(fp\|binu\)/,/^Package: \([^fb]\|f[^p]\|b[^i]\|bi[^n]\|bin[^u]\)/{/Package: \([^fb]\|f[^p]\|b[^i]\|bi[^n]\|bin[^u]\)/!p}' > "$packages_file_u".tmp
mv "$packages_file_u".tmp "$packages_file_u"
fi
echo "OK: $packages_file"
}
auto-cat()
{
local input
input="$1"
# How many decompression programs do *you* have installed?
case "$input" in
*.Z) call uncompress -c "$input";;
*.bz2) call bzcat "$input";;
*.dz) call dictzcat "$input";;
*.gz) call zcat "$input";;
*.lrz) call lrzcat "$input";;
*.lz4) call lz4cat "$input";;
*.lzma) call lzcat "$input";;
*.pz) call precat "$input";;
*.rz) call runzip < "$input";;
*.xz) call xzcat "$input";;
*.zst) call zstdcat "$input";;
*.nyan) call nyancat;;
*.*) die 'Unknown extension %q' "${input##*.}";;
*) cat "$input";;
esac
}
auto-uncat()
{
local output tmp
output="$1"
tmp="$output".tmp
# How many compression programs do *you* have installed?
case "$output" in
*.Z) call compress > "$tmp";;
*.bz2) call bzip2 > "$tmp";;
*.dz) call dictzip > "$tmp";;
*.gz) call gzip > "$tmp";;
*.lrz) call lrzip > "$tmp";;
*.lz4) call lz4 > "$tmp";;
*.lzma) call lzma > "$tmp";;
*.pz) call prezip > "$tmp";;
*.rz) call rzip > "$tmp";;
*.xz) call xz > "$tmp";;
*.zst) call zstd > "$tmp";;
*.*) die 'Unknown extension %q' "${output##*.}";;
*) cat > "$tmp";;
esac
mv "$tmp" "$output"
}
fixed-dist()
{
local dist release enabled_arches
dist="$1"
release=cache/dists/"$dist"/Release
enabled_arches=($(get-active-arches "$dist"))
for arch in "${enabled_arches[@]}"
do
fixed-arch "$dist" "$arch"
done
}
fixed-arch()
{
local dist arch packages_file_u package url sha REPLY
dist="$1"
arch="$2"
packages_file_u=cache/dists/"$dist"/main/binary-"$arch"/Packages.prefix
package=
url=
sha=
while IFS= read -r
do
case "$REPLY" in
'')
if test -n "${config_packages_hash[${package%-[0-9]*}]}"
then
download "$url"; url=cache/"$url"
check-sha "$sha" "$url"
echo "OK: $url"
fi
package=
url=
sha=
;;
Package:*)
package="${REPLY#*:\ }"
;;
Filename:*)
url="${REPLY#*:\ }"
;;
SHA256:*)
sha="${REPLY#*:\ }"
;;
*)
;;
esac
done < "$packages_file_u"
}
repack-dist()
{
local dist release enabled_arches
dist="$1"
release=cache/dists/"$dist"/Release
enabled_arches=($(get-active-arches "$dist"))
need realpath
for arch in "${enabled_arches[@]}"
do
repack-arch "$dist" "$arch"
done
}
repack-arch()
{
local dist arch packages_file_u package version pkg_arch url REPLY
dist="$1"
arch="$2"
packages_file_u=cache/dists/"$dist"/main/binary-"$arch"/Packages.prefix
package=
version=
pkg_arch=
url=
while IFS= read -r
do
case "$REPLY" in
'')
if test "$pkg_arch" != "$arch"
then
# `Architecture: all` are repeated in multiple Packages files.
test "$pkg_arch" = all
elif test -n "${config_packages_hash[${package%-[0-9]*}]}"
then
url=cache/"$url"
repack-deb "$package" "$version" "$arch" "$url"
fi
package=
version=
pkg_arch=
url=
;;
Package:*)
package="${REPLY#*:\ }"
;;
Version:*)
version="${REPLY#*:\ }"
;;
Architecture:*)
pkg_arch="${REPLY#*:\ }"
;;
Filename:*)
url="${REPLY#*:\ }"
;;
*)
;;
esac
done < "$packages_file_u"
}
unpack-deb()
{
local wip_dir in_deb
wip_dir="$1"
in_deb="$2"
in_deb="$(realpath "$in_deb")"
ar t "$in_deb" > "$wip_dir"/top.list
mkdir "$wip_dir"/top
( cd "$wip_dir"/top; ar x "$in_deb" )
tar tf "$wip_dir"/top/control.tar.* > "$wip_dir"/control.list
mkdir "$wip_dir"/control
( cd "$wip_dir"/control; tar xaf ../top/control.tar.* )
tar tf "$wip_dir"/top/data.tar.* > "$wip_dir"/data.list
# do *not* extract, it takes a while and is often unnecessary
}
deb-modify-data()
{
local wip_dir
wip_dir=.
mkdir "$wip_dir"/data
( cd "$wip_dir"/data; tar xaf ../top/data.tar.* )
}
pack-deb()
{
local wip_dir out_deb
wip_dir="$1"
out_deb="$2"
out_deb="$(realpath "$out_deb")"
if test -d "$wip_dir"/data
then
(cd "$wip_dir"/data; tar caf ../top/data.tar.* .)
fi
(cd "$wip_dir"/control; tar caf ../top/control.tar.* .)
(cd "$wip_dir"/top; ar rc "$out_deb" $(cat ../top.list))
}
set-control()
{
local field value
field="$1"
value="$2"
sed -i control/control -e "/^$field:/d"
echo "$field: $value" >> control/control
}
try-arch-vars()
{
test "$#" -eq 4 || test "$#" -eq 6 || die 'Unsupported number of arguments'
#nonlocal fpc_target fpc_bin deb_arch binutils_triple deb_triple binutils_package
# Currently, we're doing "fake" cross-compilers. Once real ones
# are built, named fp-compiler-$fpc_target, switch on $1 instead.
if test "$deb_arch" = "$3"
then
fpc_target="$1"
fpc_bin="$2"
deb_arch="$3"
binutils_triple="$4"
deb_triple="${5:-$binutils_triple}"
binutils_package=binutils-"${6:-$binutils_triple}"
fi
}
set-arch-vars()
{
#nonlocal fpc_target fpc_bin deb_arch binutils_triple deb_triple binutils_package
deb_arch="$1"
test -n "$deb_arch"
test "$deb_arch" != all
# Sane
try-arch-vars aarch64-linux ppca64 arm64 aarch64-linux-gnu
# TODO Is FPC really treating these identically? Thats not good.
# I think this will break when "real" cross-compilers are used.
try-arch-vars arm-linux ppcarm armel arm-linux-gnueabi
try-arch-vars arm-linux ppcarm armhf arm-linux-gnueabihf
# TODO does fpc support a "no OS" -T flag?
try-arch-vars avr-TODO ppcavr '' avr
# Sane
try-arch-vars i386-linux ppc386 i386 i586-linux-gnu i386-linux-gnu ''
# TODO: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=846184
try-arch-vars i386-win32 ppc386 '' i686-w64-mingw32 '' mingw-w64-i686
# TODO does fpc support a "no OS" -T flag? Also, no binutils.
try-arch-vars i8086-TODO ppc8086 '' ''
# TODO does fpc support a "no OS" -T flag? Also, no binutils.
try-arch-vars jvm-TODO ppcjvm '' ''
# Retired to ports, but binutils is still here.
try-arch-vars m68k-linux ppc68k 'm68k' m68k-linux-gnu
# Mips is nasty about GNU triples, hopefully these work.
try-arch-vars mips-linux ppcmips mips mips-linux-gnu
try-arch-vars mipsel-linux ppcmipsel mipsel mipsel-linux-gnu
# Sane, though everyone is moving to ppc64el.
try-arch-vars powerpc-linux ppcppc powerpc powerpc-linux-gnu
try-arch-vars powerpc64-linux ppcppc64 'ppc64' powerpc64-linux-gnu
# TODO everyone is moving to sparc64; no binutils (or can sparc64-linux-gnu work without help?).
try-arch-vars sparc-linux ppcsparc 'sparc' ''
# Sane (but note that _ is not valid in package names)
try-arch-vars x86_64-linux ppcx64 amd64 x86_64-linux-gnu x86-64-linux-gnu ''
# TODO: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=846184
try-arch-vars x86_64-win64 ppcx64 '' x86_64-w64-mingw32 '' mingw-w64-x86_64
if test -z "$fpc_target"
then
die "Unsupported target!"
fi
test -n "$fpc_target"
test -n "$fpc_bin"
test -n "$deb_arch"
test -n "$binutils_triple"
test -n "$deb_triple"
test -n "$binutils_package"
}
hack-deb()
{
# nonlocal is_foreign
local package version arch old_version any_version
package="$1"
version="$2"
arch="$3"
# Set the new package version.
set-control Version "$version"
if test "$arch" = all
then
set-control Multi-Arch foreign
else
set-control Multi-Arch same
fi
old_version="${version%+crosshack}"
sed -i control/control -e "s/(= ${old_version//./\\.})/(= ${version})/g"
any_version='[0-9]*'
case "$package" in
# tools, can be used from host arch
fp-utils | fp-utils-$any_version | \
fp-ide | fp-ide-$any_version | \
binutils-i586-linux-gnu | binutils-x86-64-linux-gnu)
set-control Multi-Arch foreign
is_foreign=yes
;;
fp-units-gtk2 | fp-units-gtk2-$any_version)
# Not really. TODO https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=689097
# But since *our* part is fine, leave it as `Multi-Arch: same`.
# All this does is avoid copying the .deb from tmp/ to out/
is_foreign=yes
;;
fpc-source | fpc-source-$any_version | \
fp-docs | fp-docs-$any_version | \
fpc | fpc-$any_version | fp-compiler | \
fp-units-*)
# These support Multi-Arch without any effort on our part
# (either because they are empty, or already use arch-specific paths).
# Just skip the warning below.
;;
fp-compiler-$any_version)
fp-compiler-is-complicated
;;
*)
echo "WARNING: unhandled package $package";;
esac
}
fp-compiler-is-complicated()
{
local fpc_target fpc_bin deb_arch binutils_triple deb_triple binutils_package
set-arch-vars "$arch"
local fpc_version
fpc_version=${package##*-}
sed -i control/control -e "s/binutils/binutils:$deb_arch | $binutils_package/"
rm control/preinst # long obsolete
rm control/postinst # now simplified, moved to fp-compiler-config
rm control/prerm # already simple, moved to fp-compiler-config
rm control/postrm # now obsolete (yay)
deb-modify-data
# Users should only call /usr/bin/fpc or /usr/bin/$fpc_version.
# TODO And internally, we should be calling /usr/lib/fpc/$fpc_version/$fpc_bin anyway ...
# (previous behavior was very wrong - calling /usr/bin/fpc-FOO
# would read /etc/fpc-BAR.cfg and then execute /usr/bin/ppcx86-QUX)
rm data/usr/bin/$fpc_bin-$fpc_version
rm data/usr/share/man/man1/$fpc_bin-$fpc_version.1.gz
# Put new config files under a directory,
# so that *only* /etc/fpc.cfg pollutes the top-level namespace.
mkdir data/etc
mkdir data/etc/fpc
mkdir data/etc/fpc/$fpc_target
cat > data/etc/fpc/$fpc_target/target.cfg << EOF
# multiarch library search path
-Fl/usr/lib/$deb_triple
-Fl/lib/$deb_triple
# TODO /usr/lib32 /lib32 etc.
# Location of ld/as for cross-compiling.
# Will be silently ignored if it doesn't exist,
# in which case the native ones in /usr/bin/ will be used.
-FD/usr/$binutils_triple/bin
EOF
if test "$arch" != "$config_native_arch"
then
# TODO: Move to new `Multi-Arch: foreign` fp-compiler-driver.
rm data/usr/bin/grab_vcsa-$fpc_version
rm data/usr/bin/fpc-$fpc_version
rm data/usr/bin/fpc-depends-$fpc_version
rm data/usr/bin/fpcmkcfg-$fpc_version
rm data/usr/bin/fpcres-$fpc_version
else # "$arch" = "$config_native_arch"
# This symlinks is necessary to make fpc use the right $fpc_bin.
mv -T data/usr/bin/fpc-$fpc_version data/usr/lib/fpc/$fpc_version/fpc
ln -s /usr/lib/fpc/$fpc_version/fpc data/usr/bin/fpc-$fpc_version
mkdir data/etc/fpc/$fpc_version
# TODO: Move to new `Architecture: all` fp-compiler-config.
# Note that fpcmkcfg is dynamically linked, but only against libc.
data/usr/bin/fpcmkcfg-$fpc_version -d "basepath=/usr/lib/fpc/\$fpcversion" -o data/etc/fpc/$fpc_version/mkcfg.cfg
cat > data/etc/fpc/debian.cfg << EOF
# Now a single file instead of needing to be managed by update-alternatives,
# which would result in wrong behavior in several cases.
# (Until after stretch, update-alternatives must still be in charge of
# creating the symlink to this file though).
# This file is still slightly nasty because variables are expanded only
# under #CFGDIR, but not under #INCLUDE. Still better than before though.
# This is generated by fpcmkcfg during package build.
#CFGDIR /etc/fpc/\$fpcversion
#INCLUDE mkcfg.cfg
# This contains Debian-specific customizations for multiarch.
#CFGDIR /etc/fpc/\$fpctarget
#INCLUDE target.cfg
# For local administrator customizations.
#INCLUDE /etc/fpc/local.cfg
#CFGDIR /etc/fpc/\$fpcversion
#INCLUDE local.cfg
#CFGDIR /etc/fpc/\$fpctarget
#INCLUDE local.cfg
EOF
cat > data/etc/fpc/local.cfg << EOF
# Customizations by the local administator, for all versions and target.
# This file will be untouched by upgrades of any fp-compiler-* package.
EOF
cat > data/etc/fpc/$fpc_version/local.cfg << EOF
# Customizations by the local administator, specific to version $fpc_version.
# This file will be untouched by upgrades of any fp-compiler-* package.
EOF
cat > data/etc/fpc/$fpc_target/local.cfg << EOF
# Customizations by the local administator, specific to target $fpc_target.
# This file will be untouched by upgrades of any fp-compiler-* package.
EOF
cat > control/postinst << EOF
#! /bin/sh
set -e
fpcver=$fpc_version
fpc_major=\${fpcver%%.*}
fpc_minor=\${fpcver%.*}; fpc_minor=\${fpc_minor#*.};
fpc_patch=\${fpcver##*.}
fpc_priority=\$((fpc_major*1000000 + fpc_minor*1000 + fpc_patch))
man_dir=/usr/share/man/man1
update-alternatives \
--install /usr/bin/fpc fpc /usr/bin/fpc-\$fpcver \$fpc_priority \
--slave /usr/bin/fpc-depends fpc-depends /usr/bin/fpc-depends-\$fpcver \
--slave /usr/bin/fpcres fpcres /usr/bin/fpcres-\$fpcver \
--slave \$man_dir/fpc.1.gz fpc.1.gz \$man_dir/fpc-\$fpcver.1.gz \
--slave \$man_dir/fpc-depends.1.gz fpc-depends.1.gz \$man_dir/fpc-depends-\$fpcver.1.gz \
--slave \$man_dir/fpcres.1.gz fpcres.1.gz \$man_dir/fpcres-\$fpcver.1.gz
update-alternatives \
--install /etc/fpc.cfg fpc.cfg /etc/fpc/debian.cfg \$fpc_priority
update-alternatives \
--install /usr/bin/pc pc /usr/bin/fpc-\$fpcver 20
EOF
cat > control/prerm << EOF
#! /bin/sh
set -e
fpcver=$fpc_version
update-alternatives --remove fpc /usr/bin/fpc-\$fpcver
update-alternatives --remove fpc.cfg /etc/fpc/debian.cfg
update-alternatives --remove pc /usr/bin/fpc-\$fpcver
EOF
fi
}
repack-deb()
{
local is_foreign # but "returned" from sub-functions
local package version arch in_deb out_deb wip_dir
package="$1"
version="$2"
arch="$3"
in_deb="$4"
is_foreign=no
version="$version+crosshack"
out_deb=out/"${package}_${version}_${arch}.deb"
wip_dir=tmp/"${package}_${version}_${arch}"
# Not required, but hopefully the Debian repo is usually sane.
if test "$out_deb" -nt "$in_deb"
then
return
fi
# Possibly some earlier run aborted.
rm -rf "$wip_dir"
rm -rf "$wip_dir".deb
mkdir "$wip_dir"
unpack-deb "$wip_dir" "$in_deb"
{
pushd "$wip_dir" >/dev/null
hack-deb "$package" "$version" "$arch"
popd >/dev/null
}
pack-deb "$wip_dir" "$wip_dir".deb
rm -rf "$wip_dir"
if test "$is_foreign" = yes && test "$arch" != "$config_native_arch"
then
# Don't place `Multi-Arch: foreign` packages in out/
# so that `dpkg -i out/*.deb` works.
echo FOREIGN: "$out_deb"
else
mv "$wip_dir".deb "$out_deb"
echo OUT: "$out_deb"
fi
}
### Entry point
volatile()
{
local dist
for dist in "${config_dists[@]}"
do
volatile-dist "$dist"
done
}
fixed()
{
local dist
for dist in "${config_dists[@]}"
do
fixed-dist "$dist"
done
}
repack()
{
local dist
for dist in "${config_dists[@]}"
do
repack-dist "$dist"
done
}
main()
{
shopt -s extdebug
trap 'backtrace' ERR
# This doesn't work very well actually.
#
# The fact that the ERR trap is inherited will kill us anyway,
# for the times we actually care. (for e.g. `cat | sed 1q` we don't).
#set -o pipefail
mkdir -p tmp cache out
echo 'ENTER: Phase 0: config'
config "$@"
if test "$config_skip_phase1" = yes
then
echo 'SKIP: Phase 1: download Release and Package files'
else
echo 'ENTER: Phase 1: download Release and Package files'
volatile
fi
if test "$config_skip_phase2" = yes
then
echo 'SKIP: Phase 2: download .deb files'
else
echo 'ENTER: Phase 2: download .deb files'
fixed
fi
if test "$config_skip_phase3" = yes
then
echo 'SKIP: Phase 3: repack .deb files'
else
echo 'ENTER: Phase 3: repack .deb files'
repack
fi
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment