From: Ladislav Michl <oss-lists@triops.cz>
To: ptxdist@pengutronix.de
Subject: [ptxdist] [PATCH 1/6] scripts: add ptxdist_bootstrap.sh with out-of-tree build support
Date: Tue, 13 Oct 2026 13:16:52 +0200 [thread overview]
Message-ID: <as4TJOUIN2862imu@lenoch> (raw)
In-Reply-To: <as4S9kELLgKY9wdR@lenoch>
From: Ladislav Michl <ladis@triops.cz>
The bootstrap script makes ready everything PTXdist needs from the host:
- links to the GNU tools in <builddir>/bin
- kconfig in <builddir>/scripts/kconfig
All the missing prerequisites are reported at once.
Add support for out-of-tree builds to the Makefile; all generated files
ends in the build directory, 'install' and 'dist' targets are only
supported in-tree.
Signed-off-by: Ladislav Michl <ladis@triops.cz>
---
.gitignore | 1 +
Makefile.in | 65 +++-------
configure.ac | 2 +-
scripts/ptxdist_bootstrap.sh | 230 +++++++++++++++++++++++++++++++++++
4 files changed, 250 insertions(+), 48 deletions(-)
create mode 100755 scripts/ptxdist_bootstrap.sh
diff --git a/.gitignore b/.gitignore
index 1e2cd1c31..79657ecab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,3 +24,4 @@ man/ptxdist.1.gz
/env/
/scripts/report/__pycache__/
+/build.log
diff --git a/Makefile.in b/Makefile.in
index da8cb9d7c..5eb7b407b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,9 +1,10 @@
-version := $(shell . ./scripts/ptxdist_version.sh && echo $${PTXDIST_VERSION_FULL})
+version := $(shell PTXDIST_TOPDIR=@abs_srcdir@ && . @abs_srcdir@/scripts/ptxdist_version.sh && echo $${PTXDIST_VERSION_FULL})
project := ptxdist-$(version)
prefix := @prefix@
exec_prefix := @exec_prefix@
abs_srcdir := @abs_srcdir@
+abs_builddir := @abs_builddir@
libdir := @libdir@
bindir := @bindir@
instdir := $(libdir)/$(project)
@@ -13,49 +14,13 @@ RST2MAN := @RST2MAN@
export SHELL
-all: kconfig environment
- @touch .done
-
-kconfig:
- @echo "building conf and mconf ..."
- $(MAKE) -C "$(abs_srcdir)/scripts/kconfig"
+all:
+ @echo "preparing PTXdist host tools ..."
+ @CC="@CC@" CFLAGS="@CFLAGS@" CPPFLAGS="@CPPFLAGS@" LDFLAGS="@LDFLAGS@" \
+ LEX="@LEX@" YACC="@YACC@" \
+ "@BASH@" "$(abs_srcdir)/scripts/ptxdist_bootstrap.sh" "$(abs_builddir)"
@echo "done."
-environment:
- @echo -n "preparing PTXdist environment ..."
- @ln -sf @AWK@ "$(abs_srcdir)/bin/awk"
- @ln -sf @GNU_chmod@ "$(abs_srcdir)/bin/chmod"
- @ln -sf @GNU_chown@ "$(abs_srcdir)/bin/chown"
- @ln -sf @GNU_mv@ "$(abs_srcdir)/bin/mv"
- @ln -sf @GNU_cp@ "$(abs_srcdir)/bin/cp"
- @ln -sf @GNU_rm@ "$(abs_srcdir)/bin/rm"
- @ln -sf @GNU_ln@ "$(abs_srcdir)/bin/ln"
- @ln -sf @GNU_rmdir@ "$(abs_srcdir)/bin/rmdir"
- @ln -sf @GNU_md5sum@ "$(abs_srcdir)/bin/md5sum"
- @ln -sf @GNU_mkdir@ "$(abs_srcdir)/bin/mkdir"
- @ln -sf @GNU_mktemp@ "$(abs_srcdir)/bin/mktemp"
- @ln -sf @GNU_install@ "$(abs_srcdir)/bin/install"
- @ln -sf @GNU_stat@ "$(abs_srcdir)/bin/stat"
- @ln -sf @GNU_mknod@ "$(abs_srcdir)/bin/mknod"
- @ln -sf @GNU_tty@ "$(abs_srcdir)/bin/tty"
- @ln -sf @GNU_tar@ "$(abs_srcdir)/bin/tar"
- @ln -sf @GNU_find@ "$(abs_srcdir)/bin/find"
- @ln -sf @PTXDIST_FILE@ "$(abs_srcdir)/bin/file"
- @ln -sf @GNU_cat@ "$(abs_srcdir)/bin/cat"
- @ln -sf @GNU_dirname@ "$(abs_srcdir)/bin/dirname"
- @ln -sf @GNU_readlink@ "$(abs_srcdir)/bin/readlink"
- @ln -sf @GNU_realpath@ "$(abs_srcdir)/bin/realpath"
- @ln -sf @GNU_sort@ "$(abs_srcdir)/bin/sort"
- @ln -sf @SED@ "$(abs_srcdir)/bin/sed"
- @ln -sf @GNU_xargs@ "$(abs_srcdir)/bin/xargs"
- @ln -sf @BASH@ "$(abs_srcdir)/bin/bash"
- @ln -sf @SYSCTL@ "$(abs_srcdir)/bin/sysctl"
- @ln -sf @MAKE@ "$(abs_srcdir)/bin/make"
- @if [ @SPHINX@ != "sphinx-build" ]; then \
- ln -sf @SPHINX@ "$(abs_srcdir)/bin/sphinx-build"; \
- fi
- @echo " done"
-
man: man/ptxdist.1.gz
man/ptxdist.1: doc/ptxdist.man doc/ref_parameter.rst
@mkdir -pv man
@@ -66,16 +31,22 @@ man/ptxdist.1.gz: man/ptxdist.1
gzip -f $<
clean:
- @rm -f .done
- @find "$(abs_srcdir)/bin" -type l -print0 | xargs -0 rm -f
- @$(MAKE) -C "$(abs_srcdir)/scripts/kconfig" clean
+ @rm -f "$(abs_builddir)/.done"
+ @find "$(abs_builddir)/bin" -type l -print0 | xargs -0 rm -f
+ @$(MAKE) -C "$(abs_builddir)/scripts/kconfig" \
+ -f "$(abs_srcdir)/scripts/kconfig/Makefile" clean
+
+intree-check:
+ @if [ "$(abs_srcdir)" != "$(abs_builddir)" ]; then \
+ echo "install and dist are only supported for in-tree builds!" ; exit 1 ; \
+ fi
-dirty-check:
+dirty-check: intree-check
@case "$(version)" in \
*-dirty) echo "refusing to install or package a dirty git tree!" ; exit 1 ;; \
esac
-install: all dirty-check
+install: intree-check all dirty-check
@echo "installing PTXdist to $(DESTDIR)$(prefix)..."
@rm -fr "$(DESTDIR)$(instdir)"
@mkdir -p "$(DESTDIR)$(instdir)"
diff --git a/configure.ac b/configure.ac
index c368e46b1..2590ebbed 100644
--- a/configure.ac
+++ b/configure.ac
@@ -15,7 +15,7 @@ dnl
dnl Check if the user has extracted the patches archive
dnl
AC_MSG_CHECKING(for ptxdist patches)
-if test -d `dirname $0`/patches
+if test -d "$srcdir/patches"
then
AC_MSG_RESULT(yes)
else
diff --git a/scripts/ptxdist_bootstrap.sh b/scripts/ptxdist_bootstrap.sh
new file mode 100755
index 000000000..b9f4c7a5c
--- /dev/null
+++ b/scripts/ptxdist_bootstrap.sh
@@ -0,0 +1,230 @@
+#!/bin/sh
+#
+# Prepare the host tools PTXdist needs:
+# - links to sane (GNU) tools found on the host in <builddir>/bin
+# - kconfig (conf, mconf and, if possible, nconf) in <builddir>/scripts/kconfig
+#
+# All missing prerequisites are reported at once. Only tools that PTXdist
+# itself needs are checked, everything required by some packages only is
+# left to the package build.
+#
+# usage: ptxdist_bootstrap.sh <builddir>
+#
+# CC, CFLAGS, CPPFLAGS, LDFLAGS, LEX, YACC and PKG_CONFIG from the
+# environment are used if set.
+#
+
+PTXDIST_LOG_PROMPT="ptxdist: "
+
+#
+# Everything up to the bash version check must be plain POSIX sh: the
+# script may be started by any shell and re-executes itself with bash.
+#
+if [ -z "${BASH_VERSION}" ]; then
+ bash="$(command -v bash)" || {
+ echo "${PTXDIST_LOG_PROMPT}error: bash >= 4.2 is required, please install it" >&2
+ exit 1
+ }
+ exec "${bash}" "${0}" "${@}"
+fi
+
+case "${BASH_VERSION}" in
+[0-3].*|4.[01].*)
+ echo "${PTXDIST_LOG_PROMPT}error: bash >= 4.2 is required, found ${BASH_VERSION} as '${BASH}'" >&2
+ exit 1
+ ;;
+esac
+
+# e.g. when started as 'sh' with /bin/sh -> bash
+set +o posix
+
+topdir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" || exit
+builddir="${1}"
+if [ -z "${builddir}" ]; then
+ echo "usage: ${0} <builddir>" >&2
+ exit 1
+fi
+
+declare -A links
+declare -a missing
+
+#
+# $1: version found, $2: version required
+#
+version_ge() {
+ local -a have want
+ local i
+
+ IFS=. read -r -a have <<< "${1}"
+ IFS=. read -r -a want <<< "${2}"
+ for (( i = 0; i < ${#want[@]}; i++ )); do
+ if [ "${have[i]:-0}" -gt "${want[i]}" ]; then
+ return 0
+ elif [ "${have[i]:-0}" -lt "${want[i]}" ]; then
+ return 1
+ fi
+ done
+}
+
+#
+# find a GNU tool and register a link for it
+#
+# $1: link name
+# $2: expected '--version' output, e.g. 'GNU coreutils'
+# $3: minimum version, may be empty
+# $4: package that provides it (to print the hint)
+# $5...: names to look for in PATH
+#
+find_gnu() {
+ local link="${1}" id="${2}" min="${3}" pkg="${4}"
+ local name path version
+ shift 4
+
+ for name in "${@}"; do
+ path="$(type -P "${name}")" || continue
+ version="$("${path}" --version 2>/dev/null | head -n 1)"
+ [[ "${version}" =~ ${id} ]] || continue
+ if [ -n "${min}" ]; then
+ [[ "${version}" =~ ([0-9]+(\.[0-9]+)+) ]] &&
+ version_ge "${BASH_REMATCH[1]}" "${min}" || continue
+ fi
+ links[${link}]="${path}"
+ return
+ done
+ missing+=( "${id}${min:+ >= ${min}} as '${link}' (package: ${pkg})" )
+}
+
+for tool in cat chmod chown cp dirname install ln md5sum mkdir mknod \
+ mktemp mv readlink realpath rm rmdir sort stat tty; do
+ find_gnu "${tool}" "GNU coreutils" "" coreutils "g${tool}" "${tool}"
+done
+find_gnu tar "GNU tar" "" tar gtar tar
+find_gnu find "GNU findutils" 4 findutils gfind find
+find_gnu xargs "GNU findutils" 4 findutils gxargs xargs
+find_gnu sed "GNU sed" 4 sed gsed sed
+find_gnu awk "GNU Awk" "" gawk gawk awk
+find_gnu make "GNU Make" 3.81 make gmake gnumake make
+
+links[bash]="${BASH}"
+
+if path="$(type -P file)"; then
+ links[file]="${path}"
+else
+ missing+=( "'file' (package: file)" )
+fi
+
+# optional
+links[sysctl]="$(type -P sysctl || type -P false)"
+if path="$(type -P sphinx-build)"; then
+ links[sphinx-build]="${path}"
+fi
+
+#
+# kconfig
+#
+if [ -z "${CC}" ]; then
+ CC="$(type -P gcc || type -P cc)" || CC=cc
+fi
+if ! type -P "${CC%% *}" > /dev/null; then
+ missing+=( "C compiler '${CC}' (package: gcc)" )
+fi
+: ${LEX:=flex} ${YACC:=bison} ${PKG_CONFIG:=pkg-config}
+if ! type -P "${LEX%% *}" > /dev/null; then
+ missing+=( "'${LEX}' (package: flex)" )
+fi
+if ! type -P "${YACC%% *}" > /dev/null; then
+ missing+=( "'${YACC}' (package: bison)" )
+fi
+
+#
+# $1: test program; possibly followed by compiler and linker flags
+#
+try_link() {
+ local prog="${1}"
+ shift
+ echo "${prog}" |
+ ${CC} ${CFLAGS} ${CPPFLAGS} -x c - -o /dev/null ${LDFLAGS} "${@}" > /dev/null 2>&1
+}
+
+#
+# $1: pkg-config modules (space separated, all required)
+# $2: fallback libs
+# $3: test program
+# out: libs_cflags, libs_libs
+#
+find_libs() {
+ local modules="${1}" fallback="${2}" prog="${3}"
+
+ if ${PKG_CONFIG} --exists ${modules} 2>/dev/null; then
+ libs_cflags="$(${PKG_CONFIG} --cflags ${modules})"
+ libs_libs="$(${PKG_CONFIG} --libs ${modules})"
+ else
+ libs_cflags=""
+ libs_libs="${fallback}"
+ fi
+ try_link "${prog}" ${libs_cflags} ${libs_libs}
+}
+
+ncurses_prog='#include <ncurses.h>
+int main(void) { initscr(); endwin(); return 0; }'
+nconf_prog='#include <ncurses.h>
+#include <menu.h>
+#include <panel.h>
+int main(void) { initscr(); new_panel(stdscr); free_menu(NULL); return 0; }'
+
+if type -P "${CC%% *}" > /dev/null; then
+ if find_libs "ncursesw" "-lncursesw" "${ncurses_prog}" ||
+ find_libs "ncurses" "-lncurses" "${ncurses_prog}"; then
+ mconf_cflags="${libs_cflags}"
+ mconf_libs="${libs_libs}"
+ else
+ missing+=( "ncurses development files (package: libncurses-dev or ncurses-devel)" )
+ fi
+ # nconf is optional
+ if find_libs "ncursesw menuw panelw" "-lmenuw -lpanelw -lncursesw" "${nconf_prog}" ||
+ find_libs "ncurses menu panel" "-lmenu -lpanel -lncurses" "${nconf_prog}"; then
+ nconf=nconf
+ nconf_libs="${libs_libs}"
+ fi
+fi
+
+if [ ${#missing[@]} -gt 0 ]; then
+ {
+ echo
+ echo "${PTXDIST_LOG_PROMPT}error: missing host tools, please install:"
+ echo
+ printf " - %s\n" "${missing[@]}"
+ echo
+ } >&2
+ exit 1
+fi
+
+#
+# all prerequisites are there, set up the build directory
+#
+mkdir -p "${builddir}/bin" "${builddir}/scripts/kconfig" &&
+for link in "${!links[@]}"; do
+ ln -sfn "${links[${link}]}" "${builddir}/bin/${link}" || exit
+done
+
+if ! "${links[make]}" -C "${builddir}/scripts/kconfig" \
+ -f "${topdir}/scripts/kconfig/Makefile" \
+ CC="${CC}" \
+ ${CFLAGS:+CFLAGS="${CFLAGS}"} \
+ ${CPPFLAGS:+CPPFLAGS="${CPPFLAGS}"} \
+ ${LDFLAGS:+LDFLAGS="${LDFLAGS}"} \
+ LEX="${LEX}" \
+ YACC="${YACC}" \
+ MCONF_CFLAGS="${mconf_cflags}" \
+ MCONF_LIBS="${mconf_libs}" \
+ NCONF_LIBS="${nconf_libs}" \
+ NCONF="${nconf}" \
+ > "${builddir}/build.log" 2>&1; then
+ tail -n 20 "${builddir}/build.log" >&2
+ echo >&2
+ echo "${PTXDIST_LOG_PROMPT}error: building kconfig failed, see '${builddir}/build.log'" >&2
+ echo >&2
+ exit 1
+fi
+
+echo "${topdir}" > "${builddir}/.done"
--
2.47.3
next prev parent reply other threads:[~2026-10-13 11:17 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-13 11:16 [ptxdist] [PATCH 0/6] New BSP from template Ladislav Michl
2026-10-13 11:16 ` Ladislav Michl [this message]
2026-10-13 11:17 ` [ptxdist] [PATCH 2/6] ptxdist: introduce PTXDIST_HOSTTOOLS_DIR Ladislav Michl
2026-10-13 11:17 ` [ptxdist] [PATCH 3/6] ptxdist: prepare host tools on demand Ladislav Michl
2026-10-13 11:18 ` [ptxdist] [PATCH 4/6] ptxdist: don't depend on bash being /bin/bash Ladislav Michl
2026-10-13 11:18 ` [ptxdist] [PATCH 5/6] configure: use ptxdist_bootstrap.sh to check the host Ladislav Michl
2026-10-13 11:18 ` [ptxdist] [PATCH 6/6] ptxdist: let new project raise from template Ladislav Michl
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=as4TJOUIN2862imu@lenoch \
--to=oss-lists@triops.cz \
--cc=ptxdist@pengutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox