Last active
December 3, 2016 02:32
-
-
Save o11c/cf98115ba716ebdd1dc2cc75b290f321 to your computer and use it in GitHub Desktop.
FreePascal cross hack (Debian packages)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/cache/ | |
/tmp/ | |
/out/ | |
/fpc-cross-hack-config.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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