add a new mode to build in docker

This commit is contained in:
SoftFever
2026-04-03 23:14:15 +08:00
parent 2d83918fc5
commit 0e1896e3f1

View File

@@ -8,7 +8,7 @@ SCRIPT_PATH=$(dirname "$(readlink -f "${0}")")
pushd "${SCRIPT_PATH}" > /dev/null pushd "${SCRIPT_PATH}" > /dev/null
function usage() { function usage() {
echo "Usage: ./${SCRIPT_NAME} [-1][-b][-c][-d][-D][-e][-h][-i][-j N][-p][-r][-s][-t][-u][-l][-L]" echo "Usage: ./${SCRIPT_NAME} [-1][-b][-c][-d][-D][-e][-F][-g][-h][-i][-j N][-p][-r][-s][-t][-u][-l][-L]"
echo " -1: limit builds to one core (where possible)" echo " -1: limit builds to one core (where possible)"
echo " -j N: limit builds to N cores (where possible)" echo " -j N: limit builds to N cores (where possible)"
echo " -b: build in Debug mode" echo " -b: build in Debug mode"
@@ -17,6 +17,8 @@ function usage() {
echo " -d: download and build dependencies in ./deps/ (build prerequisite)" echo " -d: download and build dependencies in ./deps/ (build prerequisite)"
echo " -D: dry run" echo " -D: dry run"
echo " -e: build in RelWithDebInfo mode" echo " -e: build in RelWithDebInfo mode"
echo " -F: rebuild the cached Docker/Podman runner image from scratch when used with -g"
echo " -g: run the requested build steps inside a Docker/Podman Ubuntu 24.04 container similar to the GitHub Actions Linux runner"
echo " -h: prints this help text" echo " -h: prints this help text"
echo " -i: build the Orca Slicer AppImage (optional)" echo " -i: build the Orca Slicer AppImage (optional)"
echo " -p: boost ccache hit rate by disabling precompiled headers (default: ON)" echo " -p: boost ccache hit rate by disabling precompiled headers (default: ON)"
@@ -28,6 +30,9 @@ function usage() {
echo " -L: use ld.lld as linker (if available)" echo " -L: use ld.lld as linker (if available)"
echo "For a first use, you want to './${SCRIPT_NAME} -u'" echo "For a first use, you want to './${SCRIPT_NAME} -u'"
echo " and then './${SCRIPT_NAME} -dsi'" echo " and then './${SCRIPT_NAME} -dsi'"
echo "For a GitHub Actions-like Linux build locally, use './${SCRIPT_NAME} -g -istrlL'"
echo "Use './${SCRIPT_NAME} -gF -istrlL' to rebuild the cached runner image first."
echo "Set ORCA_CONTAINER_CLI, ORCA_DOCKER_IMAGE, ORCA_DOCKER_BASE_IMAGE, or ORCA_DOCKER_CMAKE_VERSION to override the container runtime, cached image tag, base image, or CMake version."
} }
SLIC3R_PRECOMPILED_HEADERS="ON" SLIC3R_PRECOMPILED_HEADERS="ON"
@@ -35,60 +40,83 @@ SLIC3R_PRECOMPILED_HEADERS="ON"
unset name unset name
BUILD_DIR=build BUILD_DIR=build
BUILD_CONFIG=Release BUILD_CONFIG=Release
while getopts ":1j:bcCdDehiprstulL" opt ; do FORWARDED_ARGS=()
while getopts ":1j:bcCdDeFghiprstulL" opt ; do
case ${opt} in case ${opt} in
1 ) 1 )
export CMAKE_BUILD_PARALLEL_LEVEL=1 export CMAKE_BUILD_PARALLEL_LEVEL=1
FORWARDED_ARGS+=("-1")
;; ;;
j ) j )
export CMAKE_BUILD_PARALLEL_LEVEL=$OPTARG export CMAKE_BUILD_PARALLEL_LEVEL=$OPTARG
FORWARDED_ARGS+=("-j" "$OPTARG")
;; ;;
b ) b )
BUILD_DIR=build-dbg BUILD_DIR=build-dbg
BUILD_CONFIG=Debug BUILD_CONFIG=Debug
FORWARDED_ARGS+=("-b")
;; ;;
c ) c )
CLEAN_BUILD=1 CLEAN_BUILD=1
FORWARDED_ARGS+=("-c")
;; ;;
C ) C )
COLORED_OUTPUT="-DCOLORED_OUTPUT=ON" COLORED_OUTPUT="-DCOLORED_OUTPUT=ON"
FORWARDED_ARGS+=("-C")
;; ;;
d ) d )
BUILD_DEPS="1" BUILD_DEPS="1"
FORWARDED_ARGS+=("-d")
;; ;;
D ) D )
DRY_RUN="1" DRY_RUN="1"
FORWARDED_ARGS+=("-D")
;; ;;
e ) e )
BUILD_DIR=build-dbginfo BUILD_DIR=build-dbginfo
BUILD_CONFIG=RelWithDebInfo BUILD_CONFIG=RelWithDebInfo
FORWARDED_ARGS+=("-e")
;;
F )
CLEAN_DOCKER_IMAGE="1"
;;
g )
USE_DOCKER="1"
;; ;;
h ) usage h ) usage
exit 1 exit 1
;; ;;
i ) i )
BUILD_IMAGE="1" BUILD_IMAGE="1"
FORWARDED_ARGS+=("-i")
;; ;;
p ) p )
SLIC3R_PRECOMPILED_HEADERS="OFF" SLIC3R_PRECOMPILED_HEADERS="OFF"
FORWARDED_ARGS+=("-p")
;; ;;
r ) r )
SKIP_RAM_CHECK="1" SKIP_RAM_CHECK="1"
FORWARDED_ARGS+=("-r")
;; ;;
s ) s )
BUILD_ORCA="1" BUILD_ORCA="1"
FORWARDED_ARGS+=("-s")
;; ;;
t ) t )
BUILD_TESTS="1" BUILD_TESTS="1"
FORWARDED_ARGS+=("-t")
;; ;;
u ) u )
export UPDATE_LIB="1" export UPDATE_LIB="1"
FORWARDED_ARGS+=("-u")
;; ;;
l ) l )
USE_CLANG="1" USE_CLANG="1"
FORWARDED_ARGS+=("-l")
;; ;;
L ) L )
USE_LLD="1" USE_LLD="1"
FORWARDED_ARGS+=("-L")
;; ;;
* ) * )
echo "Unknown argument '${opt}', aborting." echo "Unknown argument '${opt}', aborting."
@@ -102,6 +130,11 @@ if [ ${OPTIND} -eq 1 ] ; then
exit 1 exit 1
fi fi
if [[ -n "${CLEAN_DOCKER_IMAGE}" ]] && [[ -z "${USE_DOCKER}" ]] ; then
echo "Error: -F requires -g."
exit 1
fi
function check_available_memory_and_disk() { function check_available_memory_and_disk() {
FREE_MEM_GB=$(free --gibi --total | grep 'Mem' | rev | cut --delimiter=" " --fields=1 | rev) FREE_MEM_GB=$(free --gibi --total | grep 'Mem' | rev | cut --delimiter=" " --fields=1 | rev)
MIN_MEM_GB=10 MIN_MEM_GB=10
@@ -139,6 +172,277 @@ function print_and_run() {
fi fi
} }
function resolve_container_cli() {
if [[ -n "${ORCA_CONTAINER_CLI}" ]] ; then
if ! command -v "${ORCA_CONTAINER_CLI}" >/dev/null 2>&1 ; then
echo "Error: container runtime '${ORCA_CONTAINER_CLI}' was not found." >&2
exit 1
fi
echo "${ORCA_CONTAINER_CLI}"
return
fi
if command -v docker >/dev/null 2>&1 ; then
echo "docker"
return
fi
if command -v podman >/dev/null 2>&1 ; then
echo "podman"
return
fi
echo "Error: neither docker nor podman is available. Install one of them or set ORCA_CONTAINER_CLI." >&2
exit 1
}
function get_docker_runner_image() {
local base_image
local docker_cmake_version
local recipe_hash
local sanitized_base_image
local sanitized_cmake_version
if [[ -n "${ORCA_DOCKER_IMAGE}" ]] ; then
echo "${ORCA_DOCKER_IMAGE}"
return
fi
base_image="${ORCA_DOCKER_BASE_IMAGE:-ubuntu:24.04}"
docker_cmake_version="${ORCA_DOCKER_CMAKE_VERSION-4.3.0}"
recipe_hash=$(find "${SCRIPT_PATH}/build_linux.sh" "${SCRIPT_PATH}/scripts/linux.d" -type f -print0 | sort -z | xargs -0 cat | sha256sum | cut -c1-12)
sanitized_base_image=$(echo "${base_image}" | tr '/:@' '---' | tr -cs 'A-Za-z0-9_.-' '-')
sanitized_cmake_version=$(echo "${docker_cmake_version:-system}" | tr -cs 'A-Za-z0-9_.-' '-')
echo "orcaslicer-linux-builder:${sanitized_base_image}-cmake-${sanitized_cmake_version}-${recipe_hash}"
}
function docker_runner_dockerfile() {
cat <<'EOF'
ARG BASE_IMAGE=ubuntu:24.04
FROM ${BASE_IMAGE}
ARG CMAKE_VERSION=4.3.0
ENV DEBIAN_FRONTEND=noninteractive
SHELL ["/bin/bash", "-c"]
RUN apt-get update && apt-get install -y sudo ca-certificates curl tar
COPY build_linux.sh /tmp/orcaslicer/build_linux.sh
COPY scripts/linux.d /tmp/orcaslicer/scripts/linux.d
WORKDIR /tmp/orcaslicer
RUN chmod +x ./build_linux.sh
RUN ./build_linux.sh -ur
RUN if [[ -n "${CMAKE_VERSION}" ]] ; then \
case "$(uname -m)" in \
x86_64|amd64) cmake_arch="x86_64" ;; \
aarch64|arm64) cmake_arch="aarch64" ;; \
*) cmake_arch="" ;; \
esac ; \
if [[ -n "${cmake_arch}" ]] ; then \
cmake_root="/opt/cmake-${CMAKE_VERSION}-linux-${cmake_arch}" ; \
if ! curl -fsSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-${cmake_arch}.tar.gz" | tar -xz -C /opt ; then \
echo "Warning: failed to install CMake ${CMAKE_VERSION}; falling back to the distro cmake package." ; \
elif [[ -d "${cmake_root}" ]] ; then \
ln -sf "${cmake_root}/bin/"* /usr/local/bin/ ; \
fi ; \
else \
echo "Skipping GitHub Actions CMake install for unsupported architecture $(uname -m)." ; \
fi ; \
fi
RUN rm -rf /var/lib/apt/lists/* /tmp/orcaslicer
EOF
}
function ensure_docker_runner_image() {
local container_cli
local base_image
local runner_image
local docker_cmake_version
local image_exists="0"
local force_rebuild="0"
local -a build_cmd
container_cli="$1"
runner_image="$2"
base_image="${ORCA_DOCKER_BASE_IMAGE:-ubuntu:24.04}"
docker_cmake_version="${ORCA_DOCKER_CMAKE_VERSION-4.3.0}"
if "${container_cli}" image inspect "${runner_image}" >/dev/null 2>&1 ; then
image_exists="1"
fi
if [[ -n "${CLEAN_DOCKER_IMAGE}" ]] ; then
force_rebuild="1"
if [[ "${image_exists}" == "1" ]] ; then
echo "Removing cached container image ${runner_image} ..."
if [[ -z "${DRY_RUN}" ]] ; then
"${container_cli}" image rm -f "${runner_image}" >/dev/null
else
printf '%q ' "${container_cli}" image rm -f "${runner_image}"
echo
fi
image_exists="0"
fi
fi
if [[ "${image_exists}" == "1" ]] ; then
echo "Using cached container image ${runner_image}"
return
fi
build_cmd=(
"${container_cli}" build --pull
-t "${runner_image}"
--build-arg "BASE_IMAGE=${base_image}"
--build-arg "CMAKE_VERSION=${docker_cmake_version}"
)
if [[ "${force_rebuild}" == "1" ]] ; then
build_cmd+=(--no-cache)
fi
build_cmd+=(-f - "${SCRIPT_PATH}")
printf '%q ' "${build_cmd[@]}"
echo
if [[ -n "${DRY_RUN}" ]] ; then
return
fi
docker_runner_dockerfile | "${build_cmd[@]}"
}
function run_in_docker() {
local container_cli
local runner_image
local container_workspace
local host_uid
local host_gid
local host_user
local -a build_args
local -a container_env
container_cli=$(resolve_container_cli)
runner_image=$(get_docker_runner_image)
host_uid=$(id -u)
host_gid=$(id -g)
host_user="${USER:-orca}"
container_workspace="/__w/OrcaSlicer/OrcaSlicer"
build_args=()
for item in "${FORWARDED_ARGS[@]}" ; do
if [[ "${item}" == "-u" ]] || [[ "${item}" == "-D" ]] ; then
continue
fi
build_args+=("${item}")
done
container_env=(
-e "CI=true"
-e "GITHUB_ACTIONS=true"
-e "GITHUB_WORKSPACE=${container_workspace}"
-e "GIT_CEILING_DIRECTORIES=${container_workspace}/deps/build"
-e "RUNNER_OS=Linux"
-e "RUNNER_TEMP=/tmp"
-e "HOST_UID=${host_uid}"
-e "HOST_GID=${host_gid}"
-e "HOST_USER=${host_user}"
)
if [[ -n "${CMAKE_BUILD_PARALLEL_LEVEL}" ]] ; then
container_env+=( -e "CMAKE_BUILD_PARALLEL_LEVEL=${CMAKE_BUILD_PARALLEL_LEVEL}" )
fi
if [[ -n "${ORCA_UPDATER_SIG_KEY}" ]] ; then
container_env+=( -e "ORCA_UPDATER_SIG_KEY=${ORCA_UPDATER_SIG_KEY}" )
fi
ensure_docker_runner_image "${container_cli}" "${runner_image}"
printf '%q ' "${container_cli}" run --rm -i \
-v "${SCRIPT_PATH}:${container_workspace}" \
-w "${container_workspace}" \
"${container_env[@]}" \
"${runner_image}" \
bash -s -- "${build_args[@]}"
echo
if [[ -n "${DRY_RUN}" ]] ; then
return
fi
"${container_cli}" run --rm -i \
-v "${SCRIPT_PATH}:${container_workspace}" \
-w "${container_workspace}" \
"${container_env[@]}" \
"${runner_image}" \
bash -s -- "${build_args[@]}" <<'EOF'
set -e
function create_builder_user() {
if [[ "${HOST_UID}" == "0" ]] ; then
HOST_USER=root
return
fi
if getent group "${HOST_GID}" >/dev/null 2>&1 ; then
HOST_GROUP=$(getent group "${HOST_GID}" | cut -d: -f1)
else
HOST_GROUP="orca-builder"
if getent group "${HOST_GROUP}" >/dev/null 2>&1 ; then
HOST_GROUP="orca-builder-${HOST_GID}"
fi
groupadd -g "${HOST_GID}" "${HOST_GROUP}"
fi
if getent passwd "${HOST_UID}" >/dev/null 2>&1 ; then
HOST_USER=$(getent passwd "${HOST_UID}" | cut -d: -f1)
usermod -g "${HOST_GROUP}" "${HOST_USER}"
elif id -u "${HOST_USER}" >/dev/null 2>&1 ; then
usermod -u "${HOST_UID}" -g "${HOST_GROUP}" "${HOST_USER}"
else
useradd -m -u "${HOST_UID}" -g "${HOST_GROUP}" -s /bin/bash "${HOST_USER}"
fi
echo "${HOST_USER} ALL=(ALL) NOPASSWD:ALL" >/etc/sudoers.d/orcaslicer-builder
chmod 0440 /etc/sudoers.d/orcaslicer-builder
}
create_builder_user
mkdir -p "${GITHUB_WORKSPACE}/deps/build/destdir"
chown -R "${HOST_UID}:${HOST_GID}" "${GITHUB_WORKSPACE}/deps/build"
if [[ -d "${GITHUB_WORKSPACE}/build" ]] ; then
chown -R "${HOST_UID}:${HOST_GID}" "${GITHUB_WORKSPACE}/build"
fi
if [[ -d "${GITHUB_WORKSPACE}/build-dbg" ]] ; then
chown -R "${HOST_UID}:${HOST_GID}" "${GITHUB_WORKSPACE}/build-dbg"
fi
if [[ -d "${GITHUB_WORKSPACE}/build-dbginfo" ]] ; then
chown -R "${HOST_UID}:${HOST_GID}" "${GITHUB_WORKSPACE}/build-dbginfo"
fi
sudo -H -u "${HOST_USER}" env \
CMAKE_BUILD_PARALLEL_LEVEL="${CMAKE_BUILD_PARALLEL_LEVEL-}" \
GITHUB_WORKSPACE="${GITHUB_WORKSPACE}" \
GIT_CEILING_DIRECTORIES="${GIT_CEILING_DIRECTORIES-}" \
ORCA_UPDATER_SIG_KEY="${ORCA_UPDATER_SIG_KEY-}" \
bash -c '
set -e
cd "${GITHUB_WORKSPACE}"
if [[ "$#" -gt 0 ]] ; then
./build_linux.sh "$@"
else
echo "No build steps were requested after container setup."
fi
' bash "$@"
EOF
}
if [[ -n "${USE_DOCKER}" ]] ; then
run_in_docker
popd > /dev/null # ${SCRIPT_PATH}
exit 0
fi
# cmake 4.x compatibility workaround # cmake 4.x compatibility workaround
export CMAKE_POLICY_VERSION_MINIMUM=3.5 export CMAKE_POLICY_VERSION_MINIMUM=3.5