mirror of
https://codeberg.org/libreboot/lbmk.git
synced 2026-03-26 22:09:03 +02:00
NOTE: Support added for xarch target x86_64-elf, but U-Boot failed to build with this error: OBJCOPY lib/efi_loader/helloworld.efi x86_64-elf-objcopy: lib/efi_loader/helloworld_efi.so: invalid bfd target make[2]: *** [scripts/Makefile.lib:476: lib/efi_loader/helloworld.efi] Error 1 Since I'm building U-Boot for x86_64 *on* an x86-64 host, and since that is currently the recommended type of machine to use for lbmk development, and since the other x86 payloads currently don't cross compile anyway, this is an acceptable compromise for now. This is because at present, I'm not making U-Boot the primary payload on x86, instead preferring to chain it from GRUB and SeaBIOS. The target.cfg file for x86 u-boot shows xarch/xtree commented. Uncomment these to compile on crossgcc instead of hostcc. I mention 64-bit because I initially did this first, but decided to do 32-bit first. I'll work on the 64-bit one next (SPL). It's only enabled in QEMU for now. Signed-off-by: Leah Rowe <leah@libreboot.org>
293 lines
8.9 KiB
Bash
Executable File
293 lines
8.9 KiB
Bash
Executable File
#!/usr/bin/env sh
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
# Copyright (c) 2022-2023 Alper Nebi Yasak <alpernebiyasak@gmail.com>
|
|
# Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com>
|
|
# Copyright (c) 2023-2024 Leah Rowe <leah@libreboot.org>
|
|
|
|
set -u -e
|
|
|
|
. "include/lib.sh"
|
|
. "include/git.sh"
|
|
|
|
eval `setvars "" xarch srcdir premake cmakedir xlang mode makeargs elfdir cmd \
|
|
project target target_dir targets xtree _f release bootstrapargs mkhelper \
|
|
autoconfargs listfile autogenargs btype tree rev tree_depend build_depend \
|
|
defconfig postmake mkhelpercfg dry dest_dir mdir cleanargs`; badhash="n"
|
|
|
|
main()
|
|
{
|
|
while getopts f:b:m:u:c:x:s:l:n:d: option; do
|
|
[ -n "$_f" ] && $err "only one flag is permitted"
|
|
_f="$1" && [ "$_f" = "-d" ] && dry=":"
|
|
case "$1" in
|
|
-d) mode="" ;;
|
|
-b) mode="" ;;
|
|
-u) mode="oldconfig" ;;
|
|
-m) mode="menuconfig" ;;
|
|
-c) mode="distclean" ;;
|
|
-x) mode="crossgcc-clean" ;;
|
|
-f) mode="fetch" ;;
|
|
-s) mode="savedefconfig" ;;
|
|
-l) mode="olddefconfig" ;;
|
|
-n) mode="nconfig" ;;
|
|
*) $err "invalid option '-$option'" ;;
|
|
esac
|
|
[ -z "${OPTARG+x}" ] && shift 1 && break
|
|
project="${OPTARG#src/}"; shift 2
|
|
done
|
|
[ -z "$_f" ] && $err "missing flag (-m/-u/-b/-c/-x/-f/-s/-l/-n)"
|
|
[ -z "$project" ] && mk $_f $(ls -1 config/git) && return 1
|
|
|
|
[ -f "config/git/$project/pkg.cfg" ] || $err "'$project' not defined"
|
|
|
|
for d in "elf" "config/data" "config" "src"; do
|
|
eval "${d#*/}dir=\"$d/$project\""
|
|
done; dest_dir="$elfdir"
|
|
listfile="$datadir/build.list"
|
|
[ -f "$listfile" ] || listfile="" # optional on all projects
|
|
|
|
mkhelpercfg="$datadir/mkhelper.cfg"
|
|
e "$mkhelpercfg" f missing && mkhelpercfg="$TMPDIR/mkhelper.cfg" && \
|
|
x_ touch "$mkhelpercfg"
|
|
|
|
targets="$@"; cmd="build_targets $targets"
|
|
singletree "$project" && cmd="build_project"
|
|
|
|
remkdir "${tmpgit%/*}"
|
|
}
|
|
|
|
build_project()
|
|
{
|
|
configure_project "$configdir" || return 0
|
|
[ ! -f "$listfile" ] || $dry elfcheck || return 0
|
|
|
|
[ "$mode" = "distclean" ] && mode="clean"
|
|
run_make_command || return 0
|
|
|
|
[ -n "$mode" ] || $dry copy_elf; return 0
|
|
}
|
|
|
|
build_targets()
|
|
{
|
|
[ -d "$configdir" ] || $err "directory, $configdir, does not exist"
|
|
[ $# -gt 0 ] || targets="$(ls -1 "$configdir")" || $err "!o $configdir"
|
|
|
|
for x in $targets; do
|
|
[ "$x" = "list" ] && x_ ls -1 "config/$project" && \
|
|
listfile="" && break
|
|
target="$x"
|
|
printf "'make %s', '%s', '%s'\n" "$mode" "$project" "$target"
|
|
x_ handle_defconfig
|
|
[ -n "$mode" ] || [ -z "$postmake" ] || $postmake || \
|
|
$err "$project/$target: !postmake: $postmake"; continue
|
|
done; return 0
|
|
}
|
|
|
|
handle_defconfig()
|
|
{
|
|
target_dir="$configdir/$target"
|
|
|
|
[ -f "CHANGELOG" ] || fetch_project "$project"
|
|
configure_project "$target_dir" || return 0
|
|
x_ mkdir -p "$elfdir/$target"
|
|
|
|
chkvars tree; srcdir="src/$project/$tree"
|
|
|
|
if [ "$mode" = "distclean" ] || [ "$mode" = "crossgcc-clean" ]; then
|
|
[ -d "$srcdir" ] || return 0
|
|
fi
|
|
[ -z "$mode" ] && $dry check_cross_compiler
|
|
|
|
for y in "$target_dir/config"/*; do
|
|
[ "$_f" = "-d" ] || [ -f "$y" ] || continue
|
|
[ "$_f" = "-d" ] || defconfig="$y"
|
|
|
|
[ -n "$mode" ] || check_defconfig || continue
|
|
handle_makefile
|
|
[ -n "$mode" ] || $dry copy_elf
|
|
done; return 0
|
|
}
|
|
|
|
configure_project()
|
|
{
|
|
eval `setvars "" xarch xlang build_depend autoconfargs xtree postmake \
|
|
tree_depend makeargs btype mkhelper bootstrapargs premake release \
|
|
cleanargs`
|
|
_tcfg="$1/target.cfg"; badhash="n"; [ -f "$_tcfg" ] || btype="auto"
|
|
[ -f "$datadir/mkhelper.cfg" ] && eval `setcfg "$datadir/mkhelper.cfg"`
|
|
|
|
while [ -f "$_tcfg" ] || [ "$cmd" != "build_project" ]; do
|
|
eval `setvars "" rev tree`; eval `setcfg "$_tcfg"`
|
|
printf "Loading %s config: %s\n" "$project" "$_tcfg"
|
|
|
|
[ "$_f" = "-d" ] && build_depend="" # dry run
|
|
[ "$cmd" = "build_project" ] && break
|
|
[ "$mode" = "fetch" ] || break
|
|
|
|
[ "${_tcfg%/*/target.cfg}" = "${_tcfg%"/$tree/target.cfg"}" ] \
|
|
&& break; _tcfg="${_tcfg%/*/target.cfg}/$tree/target.cfg"
|
|
done
|
|
[ "$XBMK_RELEASE" = "y" ] && [ "$release" = "n" ] && return 1
|
|
[ -z "$btype" ] || [ "${mode%config}" = "$mode" ] || return 1
|
|
[ -z "$mode" ] && build_dependencies
|
|
|
|
mdir="$PWD/config/submodule/$project"
|
|
[ -n "$tree" ] && mdir="$mdir/$tree"
|
|
[ -f "CHANGELOG" ] || check_project_hashes
|
|
|
|
[ "$mode" = "fetch" ] || x_ ./mk -f "$project" $target
|
|
[ "$mode" = "fetch" ] || return 0
|
|
[ -f "CHANGELOG" ] && return 1; fetch_${cmd#build_}; return 1
|
|
}
|
|
|
|
build_dependencies()
|
|
{
|
|
for bd in $build_depend; do
|
|
bd_p="${bd%%/*}"; bd_t="${bd##*/}"
|
|
[ -z "$bd_p" ] && $dry $err "$project/$tree: !bd '$bd'"
|
|
[ "${bd##*/}" = "$bd" ] && bd_t=""
|
|
[ -z "$bd_p" ] || $dry ./mk -b $bd_p $bd_t \
|
|
|| $err "!mk $project/$tree $bd_p/$bd_t"; continue
|
|
done; return 0
|
|
}
|
|
|
|
check_project_hashes()
|
|
{
|
|
mkdir -p "$XBMK_CACHE/hash" || $err "!mkdir '$XBMK_CACHE/hash'"
|
|
old_pjhash=""; [ ! -f "$XBMK_CACHE/hash/$project$tree" ] || \
|
|
read -r old_pjhash < "$XBMK_CACHE/hash/$project$tree"
|
|
|
|
x_ rm -f "$TMPDIR/project.list" "$TMPDIR/project.hash" \
|
|
"$TMPDIR/project.tmp"; x_ touch "$TMPDIR/project.tmp"
|
|
x_ touch "$TMPDIR/project.hash"
|
|
|
|
for rmchk in "$datadir" "$configdir/$tree" "$mdir"; do
|
|
[ -d "$rmchk" ] || continue
|
|
find "$rmchk" -type f -not -path "*/.git*/*" >> \
|
|
"$TMPDIR/project.tmp" || $err "!find $rmchk > project.tmp"
|
|
done; sort "$TMPDIR/project.tmp" > "$TMPDIR/project.list" || \
|
|
$err "!sort project tmp/list"
|
|
|
|
while read -r rmchk; do
|
|
[ ! -f "$rmchk" ] || sha512sum "$rmchk" | awk \
|
|
'{print $1}' >> "$TMPDIR/project.hash" || $err "!h $rmchk"
|
|
done < "$TMPDIR/project.list"
|
|
|
|
pjhash="$(sha512sum "$TMPDIR/project.hash" | awk '{print $1}')" || :
|
|
badhash="y" && [ "$pjhash" = "$old_pjhash" ] && badhash="n"
|
|
[ -f "$XBMK_CACHE/hash/$project$tree" ] || badhash="y"
|
|
|
|
printf "%s\n" "$pjhash" > "$XBMK_CACHE/hash/$project$tree" || \
|
|
$err "!mk $XBMK_CACHE/hash/$project$tree"
|
|
|
|
[ "$badhash" = "n" ] || rm -Rf "src/$project/$tree" \
|
|
"elf/$project/$tree" "elf/$project/$target" || \
|
|
$err "!rm $project $tree"; :
|
|
}
|
|
|
|
check_cross_compiler()
|
|
{
|
|
xgccargs="UPDATED_SUBMODULES=1 CPUS=$XBMK_THREADS"
|
|
for _xarch in $xarch; do
|
|
cbdir="src/coreboot/$tree"
|
|
[ "$project" != "coreboot" ] && cbdir="src/coreboot/default"
|
|
[ -n "$xtree" ] && cbdir="src/coreboot/$xtree"
|
|
|
|
x_ ./mk -f coreboot ${cbdir#src/coreboot/}
|
|
|
|
export PATH="$PWD/$cbdir/util/crossgcc/xgcc/bin:$PATH"
|
|
export CROSS_COMPILE="${xarch% *}-"
|
|
[ -n "$xlang" ] && export BUILD_LANGUAGES="$xlang"
|
|
|
|
xfix="${_xarch%-*}" && [ "$xfix" = "x86_64" ] && xfix="x64"
|
|
|
|
# sometimes buildgcc fails for like no reason. try twice.
|
|
make -C "$cbdir" crossgcc-$xfix $xgccargs || \
|
|
make -C "$cbdir" crossgcc-$xfix $xgccargs || \
|
|
$err "!mkxgcc $project/$xtree '$xfix' '$xgccargs'"
|
|
done; return 0
|
|
}
|
|
|
|
check_defconfig()
|
|
{
|
|
[ -f "$defconfig" ] || $dry $err "$project/$target: missing defconfig"
|
|
dest_dir="$elfdir/$target/${defconfig#"$target_dir/config/"}"
|
|
|
|
$dry elfcheck || return 1 # skip build if a previous one exists
|
|
$dry x_ mkdir -p "$dest_dir"
|
|
}
|
|
|
|
elfcheck()
|
|
{
|
|
# TODO: very hacky check. do it properly (based on build.list)
|
|
for elftest in "$dest_dir"/*; do
|
|
[ -e "$elftest" ] && e "$elftest" f && return 1
|
|
done; return 0
|
|
}
|
|
|
|
handle_makefile()
|
|
{
|
|
$dry check_makefile "$srcdir" && x_ make -C "$srcdir" $cleanargs clean
|
|
[ -f "$defconfig" ] && x_ cp "$defconfig" "$srcdir/.config"
|
|
[ -n "$mode" ] || [ -n "$btype" ] || $dry make -C \
|
|
"$srcdir" silentoldconfig || make -C "$srcdir" oldconfig || :
|
|
|
|
run_make_command || $err "handle_makefile $srcdir: no makefile!"
|
|
|
|
_copy=".config" && [ "$mode" = "savedefconfig" ] && _copy="defconfig"
|
|
[ "${mode%config}" = "$mode" ] || \
|
|
$dry x_ cp "$srcdir/$_copy" "$defconfig"
|
|
|
|
[ -e "$srcdir/.git" ] && [ "$project" = "u-boot" ] && \
|
|
[ "$mode" = "distclean" ] && $dry x_ git -C "$srcdir" $cleanargs clean -fdx; :
|
|
}
|
|
|
|
run_make_command()
|
|
{
|
|
[ -z "$premake" ] || [ -n "$mode" ] || $premake || $err "!$premake"
|
|
$dry check_cmake "$srcdir" && [ -z "$mode" ] && $dry check_autoconf \
|
|
"$srcdir"; $dry check_makefile "$srcdir" || return 1
|
|
|
|
$dry make -C "$srcdir" $mode -j$XBMK_THREADS $makeargs || $err "!$mode"
|
|
[ -z "$mkhelper" ] || [ -n "$mode" ] || $mkhelper || $err "!$mkhelper"
|
|
|
|
[ "$mode" = "clean" ] && \
|
|
$dry make -C "$srcdir" $cleanargs distclean || :; :
|
|
}
|
|
|
|
check_cmake()
|
|
{
|
|
[ -z "$cmakedir" ] || $dry check_makefile "$1" || cmake -B "$1" \
|
|
"$1/$cmakedir" || $dry check_makefile "$1" || $err \
|
|
"$1: !cmk $cmakedir"
|
|
[ -z "$cmakedir" ] || $dry check_makefile "$1" || \
|
|
$err "check_cmake $1: can't generate Makefile"; return 0
|
|
}
|
|
|
|
check_autoconf()
|
|
{
|
|
(
|
|
cd "$1" || $err "!cd $1"
|
|
[ -f "bootstrap" ] && x_ ./bootstrap $bootstrapargs
|
|
[ -f "autogen.sh" ] && x_ ./autogen.sh $autogenargs
|
|
[ -f "configure" ] && x_ ./configure $autoconfargs; return 0
|
|
) || $err "can't bootstrap project: $1"
|
|
}
|
|
|
|
check_makefile()
|
|
{
|
|
[ -f "$1/Makefile" ] || [ -f "$1/makefile" ] || \
|
|
[ -f "$1/GNUmakefile" ] || return 1; return 0
|
|
}
|
|
|
|
copy_elf()
|
|
{
|
|
[ -f "$listfile" ] && x_ mkdir -p "$dest_dir" && while read -r f; do
|
|
[ -f "$srcdir/$f" ] && x_ cp "$srcdir/$f" "$dest_dir"
|
|
done < "$listfile"; x_ make clean -C "$srcdir" $cleanargs
|
|
}
|
|
|
|
main $@ || exit 0
|
|
. "$mkhelpercfg"
|
|
$cmd
|