blob: 68868af333d4278cd7b065540217258bb02b4a26 [file]
#!/usr/bin/env bash
set -u
set -e
USE_PARALLEL=false
if command -v env_parallel &> /dev/null
then
# The env_parallel command stores ignored values in this variable
# so it needs to be defined for the `set -u` flag to not error
PARALLEL_IGNORED_NAMES=""
# Source the env_parallel init script
. env_parallel.bash
# If the `--session` start fails it mean that the installed
# version of GNU parallel is too old to have the features we need
if env_parallel --session &> /dev/null
then
USE_PARALLEL=true
fi
fi
ROOT_PATH="$(cd "$(dirname $0)"; echo $PWD)"
export ROOT_PATH
OUTPUT_DIRECTORY="$ROOT_PATH/output"
UPDATE_SUBMODULES=false
CONFIGURATION="Release"
BUILD_PLATFORM="Any CPU"
CLEAN=false
PACKAGES=false
NIGHTLY=false
PORTABLE=false
UI=false
SOURCE_PACKAGE=false
HEADLESS=false
SKIP_FETCH=false
EXTERNAL_LIB_ONLY=false
TLIB_EXPORT_COMPILE_COMMANDS=false
SHARED=false
EXTERNAL_LIB_ARCH=""
TFM="net8.0"
GENERATE_DOTNET_BUILD_TARGET=true
PARAMS=()
RID="linux-x64"
MULTIPLATFORM=false
HOST_ARCH=
# Common cmake flags
CMAKE_COMMON="${RENODE_EXTRA_CMAKE_ARGS:-}"
function print_help() {
echo "Usage: $0 [-cdvspntm] [--no-gui] [--skip-fetch] [--profile-build] [--external-lib-only] [--tlib-export-compile-commands] [--external-lib-arch <arch>] [--host-arch i386|aarch64] [--source-package] [--ui] [-- <ARGS>]"
echo
echo "-c clean instead of building"
echo "-d build Debug configuration"
echo "-v verbose output"
echo "-p create packages after building"
echo "-t create a portable package"
echo "-m create a multi-platform package"
echo "--source-package build a source package (dotnet on Linux only)"
echo "-n tag built packages as nightly"
echo "-s update submodules"
echo "-b custom build properties file"
echo "--skip-fetch skip fetching submodules and additional resources"
echo "--no-gui build with GUI disabled"
echo "-B bundle target runtime (default value: $RID, requires -t)"
echo "-F select the target framework for which Renode should be built (default value: $TFM)"
echo "--profile-build build optimized for profiling"
echo "--tlib-coverage build tlib with coverage reporting"
echo "--external-lib-only only build external libraries"
echo "--external-lib-arch build only single arch (implies --external-lib-only)"
echo "--tlib-export-compile-commands build tlibs with 'compile_commands.json' (requires --external-lib-arch)"
echo "--host-arch build with a specific tcg host architecture (default: i386)"
echo "--skip-dotnet-target-generation don't generate 'Directory.Build.targets' file, useful when experimenting with different build settings"
echo "--tcg-opcode-backtrace collect a backtrace for each emitted TCG opcode, to track internal TCG errors (implies Debug configuration)"
echo "--shared build the librenode native library"
echo "--ui rebuild the web-based UI"
echo "--werror treat warnings as errors in both CMake and Dotnet builds"
echo "<ARGS> arguments to pass to the dotnet build system"
}
while getopts "cdvpnstmB:F:-:" opt
do
case $opt in
c)
CLEAN=true
;;
d)
CONFIGURATION="Debug"
;;
v)
PARAMS+=(verbosity:detailed)
;;
p)
PACKAGES=true
;;
n)
NIGHTLY=true
;;
t)
PORTABLE=true
;;
m)
MULTIPLATFORM=true
;;
s)
UPDATE_SUBMODULES=true
;;
B)
RID=$OPTARG
;;
F)
TFM=$OPTARG
;;
-)
case $OPTARG in
"no-gui")
HEADLESS=true
;;
"skip-fetch")
SKIP_FETCH=true
;;
"net")
echo "'--net' flag is a no-op and will be removed in the future" >&1
;;
"source-package")
SOURCE_PACKAGE=true
;;
"profile-build")
CMAKE_COMMON+=" -DPROFILING_BUILD=ON"
;;
"external-lib-only")
EXTERNAL_LIB_ONLY=true
;;
"external-lib-arch")
# This only makes sense with '--external-lib-only' set; it might as well imply it
EXTERNAL_LIB_ONLY=true
shift $((OPTIND-1))
EXTERNAL_LIB_ARCH=$1
OPTIND=2
;;
"tlib-export-compile-commands")
if [ -z $EXTERNAL_LIB_ARCH ]; then
echo "--tlib-export-compile-commands requires --external-lib-arch being set"
exit 1
fi
TLIB_EXPORT_COMPILE_COMMANDS=true
;;
"tlib-coverage")
CMAKE_COMMON+=" -DCOVERAGE_REPORTING=ON"
;;
"host-arch")
shift $((OPTIND-1))
if [ $1 == "aarch64" ] || [ $1 == "arm64" ]; then
HOST_ARCH="aarch64"
elif [ $1 == "i386" ] || [ $1 == "x86" ] || [ $1 == "x86_64" ]; then
HOST_ARCH="i386"
else
echo "host architecture $1 not supported. Supported architectures are i386 and aarch64"
exit 1
fi
OPTIND=2
;;
"skip-dotnet-target-generation")
GENERATE_DOTNET_BUILD_TARGET=false
;;
"tcg-opcode-backtrace")
# Doesn't make sense without debug.
CONFIGURATION="Debug"
CMAKE_COMMON+=" -DTCG_OPCODE_BACKTRACE=ON"
;;
"shared")
SHARED=true
;;
"ui")
UI=true
;;
"werror" | "Werror")
CMAKE_COMMON+=" -DFAIL_ON_WARNINGS=ON"
PARAMS+=(p:TreatWarningsAsErrors=true)
;;
*)
print_help
exit 1
;;
esac
;;
\?)
print_help
exit 1
;;
esac
done
shift "$((OPTIND-1))"
PARAMS+=(
"$@"
)
# Export so that packaging scripts can name headless artifacts accordingly
export HEADLESS
if $HEADLESS && { $PACKAGES || $MULTIPLATFORM; }
then
echo "--no-gui currently supports portable packages only, use -t without -p or -m."
exit 1
fi
if [ -n "${PLATFORM:-}" ]
then
echo "PLATFORM environment variable is currently set to: >>$PLATFORM<<"
echo "This might cause problems during the build."
echo "Please clear it with:"
echo ""
echo " unset PLATFORM"
echo ""
echo " and run the build script again."
exit 1
fi
# We can only update parts of this repository if Renode is built from within the git tree
if [ ! -e .git ]
then
SKIP_FETCH=true
UPDATE_SUBMODULES=false
COMMIT_STRING="notgit"
else
COMMIT_STRING="git$(git rev-parse --short=9 HEAD)"
fi
if $SKIP_FETCH
then
echo "Skipping init/update of submodules"
else
# Update submodules if not initialized or if requested by the user
# Warn if not updating, but unclean
# Disabling -e to allow grep to fail
set +e
git submodule status --recursive | grep -q "^-"
SUBMODULES_NOT_INITED=$?
git submodule status --recursive | grep -q "^+"
SUBMODULES_NOT_CLEAN=$?
set -e
if $UPDATE_SUBMODULES || [ $SUBMODULES_NOT_INITED -eq 0 ]
then
echo "Updating submodules..."
git submodule update --init --recursive
elif [ $SUBMODULES_NOT_CLEAN -eq 0 ]
then
echo "Submodules are not updated. Use -s to force update."
fi
fi
. "${ROOT_PATH}/tools/common.sh"
. "${ROOT_PATH}/tools/building/native_interface_runtime_config.sh"
. "${ROOT_PATH}/tools/building/prepare_portable_native_interface_runtime.sh"
if $SKIP_FETCH
then
echo "Skipping library fetch"
else
"${ROOT_PATH}"/tools/building/fetch_libraries.sh
fi
if $HEADLESS
then
BUILD_TARGET=Headless
PARAMS+=(p:GUI_DISABLED=true)
# Custom configurations (like ReleaseHeadless) do not inherit the SDK's optimization defaults
# for Release, so enable optimization explicitly here.
if [ "$CONFIGURATION" = "Release" ]; then
PARAMS+=(p:Optimize=true)
fi
else
BUILD_TARGET=""
fi
if [[ -z "$HOST_ARCH" ]]; then
HOST_ARCH="$DETECTED_ARCH"
fi
# Set correct RID
if $ON_LINUX; then
RID="linux-x64"
if [[ $HOST_ARCH == "aarch64" ]]; then
RID="linux-arm64"
fi
elif $ON_OSX; then
RID="osx-x64"
if [[ $HOST_ARCH == "aarch64" ]]; then
RID="osx-arm64"
fi
elif $ON_WINDOWS; then
RID="win-x64"
fi
SUPPORTED_RIDS=(
"linux-x64"
"linux-arm64"
"osx-x64"
"osx-arm64"
"win-x64"
)
SUPPORTED_UI_RIDS=(
"linux_x64"
"linux_arm64"
"mac_x64"
"mac_arm64"
"win_x64"
)
# macos `cp` does not have the -u flag
if $ON_OSX; then
cp_u() {
cp $@
}
sed_inplace() {
sed -i '' "$@"
}
else
cp_u() {
cp -u $@
}
sed_inplace() {
sed -i "$@"
}
fi
export -f cp_u sed_inplace
function generate_build_target() {
if ! $GENERATE_DOTNET_BUILD_TARGET; then
return
fi
if $ON_WINDOWS; then
# CsWinRTAotOptimizerEnabled is disabled due to a bug in dotnet-sdk.
# See: https://github.com/dotnet/sdk/issues/44026
OS_SPECIFIC_TARGET_OPTS='<CsWinRTAotOptimizerEnabled>false</CsWinRTAotOptimizerEnabled>'
fi
BUILD_TARGETS_FILE=$(mktemp)
BUILD_TARGETS_PATH="$(get_path "$PWD/Directory.Build.targets")"
# For Xwt.WPF specifically this has to be `.props` rather than `.targets` because we need to override these values in the csproj
BUILD_PROPS_PATH_WPF="$(get_path "$PWD/lib/termsharp/xwt/Xwt.WPF/Directory.Build.props")"
cat <<EOF > "$BUILD_TARGETS_FILE"
<Project>
<PropertyGroup>
<TargetFrameworks>$TFM</TargetFrameworks>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
${OS_SPECIFIC_TARGET_OPTS:+${OS_SPECIFIC_TARGET_OPTS}}
</PropertyGroup>
</Project>
EOF
cp_u "$BUILD_TARGETS_FILE" "$BUILD_PROPS_PATH_WPF"
cp_u "$BUILD_TARGETS_FILE" "$BUILD_TARGETS_PATH"
rm "$BUILD_TARGETS_FILE"
}
generate_build_target
export DOTNET_CLI_TELEMETRY_OPTOUT=1
TARGET="`get_path \"$PWD/Renode.sln\"`"
if $ON_LINUX; then
PARAMS+=(p:WPFPath=$ROOT_PATH/lib/resources/libraries/WPF/$RID)
fi
OUT_BIN_DIR="$(get_path "output/bin/${CONFIGURATION}")"
# Copy properties file according to the running OS
mkdir -p "$OUTPUT_DIRECTORY"
CORES_PATH="$ROOT_PATH/src/Infrastructure/src/Emulator/Cores"
UI_PATH="$ROOT_PATH/src/UI"
# clean instead of building
if $CLEAN
then
remove_dir() {
output_dir="$(get_path "$1")"
if [[ -d "${output_dir}" ]]
then
echo "Removing: ${output_dir}"
rm -rf "${output_dir}"
fi
}
for project_dir in $(find "$(get_path "${ROOT_PATH}")" -iname '*.csproj' -exec dirname '{}' \;)
do
for dir in {bin,obj}/{Debug,Release}{,Headless}
do
remove_dir "${project_dir}/${dir}"
done
done
# Manually clean the main output directories as it's location is non-standard
remove_dir "${OUTPUT_DIRECTORY}/bin"
remove_dir "${OUTPUT_DIRECTORY}/publish"
# Tlib shared libraries
remove_dir "${CORES_PATH}/bin"
remove_dir "${CORES_PATH}/obj"
exit 0
fi
# check weak implementations of core libraries
pushd "$ROOT_PATH/tools/building" > /dev/null
./check_weak_implementations.sh
popd > /dev/null
PARAMS+=(p:Configuration="${CONFIGURATION}${BUILD_TARGET}" p:GenerateFullPaths=true p:Platform="\"$BUILD_PLATFORM\"" p:Architecture="$HOST_ARCH" p:CommitString="$COMMIT_STRING")
# Paths for tlib
CORES_BIN_PATH="$CORES_PATH/bin/$CONFIGURATION"
NATIVE_CORES_BUILD_PATH="$CORES_PATH/obj/$CONFIGURATION/$RID"
NATIVE_CORES_BIN_PATH="$CORES_BIN_PATH/$RID"
# Cmake generator, handled in their own variable since the names contain spaces
if $ON_WINDOWS
then
CMAKE_GEN="-GMinGW Makefiles"
else
CMAKE_GEN="-GUnix Makefiles"
fi
# Macos architecture flags, to make rosetta work properly
if $ON_OSX
then
CMAKE_COMMON+=" -DCMAKE_OSX_ARCHITECTURES=x86_64"
if [ $HOST_ARCH == "aarch64" ]; then
CMAKE_COMMON+=" -DCMAKE_OSX_ARCHITECTURES=arm64"
fi
fi
# This list contains all cores that will be built.
# If you are adding a new core or endianness add it here to have the correct tlib built
CORES=(arm.le arm.be arm64.le arm-m.le arm-m.be ppc.le ppc.be ppc64.le ppc64.be i386.le x86_64.le riscv.le riscv64.le sparc.le sparc.be xtensa.le)
# if '--external-lib-arch' was used - pick the first matching one
if [[ ! -z $EXTERNAL_LIB_ARCH ]]; then
NONE_MATCHED=true
for potential_match in "${CORES[@]}"; do
if [[ $potential_match == "$EXTERNAL_LIB_ARCH"* ]]; then
CORES=("$potential_match")
echo "Compiling external lib for $potential_match"
NONE_MATCHED=false
break
fi
done
if $NONE_MATCHED ; then
echo "Failed to match any external lib arch"
exit 1
fi
fi
# build KVM - currently it's supported only on Linux
if $ON_LINUX && [[ "$HOST_ARCH" == "i386" ]] && [[ -z $EXTERNAL_LIB_ARCH || "${CORES[@]}" == "i386kvm.le" ]]; then
KVM_CORE_DIR="$NATIVE_CORES_BUILD_PATH/virt"
mkdir -p $KVM_CORE_DIR
pushd "$KVM_CORE_DIR" > /dev/null
cmake "$CORES_PATH/virt"
cmake --build . -j$(nproc)
mkdir -p $NATIVE_CORES_BIN_PATH
cp_u -v *.so $NATIVE_CORES_BIN_PATH/
popd > /dev/null
fi
build_core () {
set -e
core_config=$1
if [[ $core_config == *"kvm"* ]]; then
continue
fi
CORE="$(echo $core_config | cut -d '.' -f 1)"
ENDIAN="$(echo $core_config | cut -d '.' -f 2)"
BITS=32
# Check if core is 64-bit
if [[ $CORE =~ "64" ]]; then
BITS=64
fi
# Core specific flags to cmake
CMAKE_CONF_FLAGS="-DTARGET_ARCH=$CORE -DTARGET_WORD_SIZE=$BITS -DCMAKE_BUILD_TYPE=$CONFIGURATION"
CORE_DIR=$NATIVE_CORES_BUILD_PATH/$CORE/$ENDIAN
mkdir -p $CORE_DIR
pushd "$CORE_DIR" > /dev/null
if [[ $ENDIAN == "be" ]]; then
CMAKE_CONF_FLAGS+=" -DTARGET_WORDS_BIGENDIAN=1"
fi
if [[ "$TLIB_EXPORT_COMPILE_COMMANDS" = true ]]; then
CMAKE_CONF_FLAGS+=" -DCMAKE_EXPORT_COMPILE_COMMANDS=1"
fi
cmake "$CMAKE_GEN" $CMAKE_COMMON $CMAKE_CONF_FLAGS -DHOST_ARCH=$HOST_ARCH $CORES_PATH
cmake --build . -j"$(nproc)"
mkdir -p $NATIVE_CORES_BIN_PATH
cp_u -v tlib/*.so $NATIVE_CORES_BIN_PATH/
# copy compile_commands.json to tlib directory
if [[ "$TLIB_EXPORT_COMPILE_COMMANDS" = true ]]; then
command cp -v -f $CORE_DIR/compile_commands.json $CORES_PATH/tlib/
fi
popd > /dev/null
}
# build tlib
if $USE_PARALLEL
then
echo "Starting parallel tlib build"
env_parallel build_core ::: "${CORES[@]}"
env_parallel --end-session
else
for core_config in "${CORES[@]}"
do
build_core $core_config
done
fi
# Remove pre-multiplatform tlib `lib` directory
rm -rf "$CORES_BIN_PATH/lib"
# Copy tlib
mkdir -p "$OUT_BIN_DIR/platform-lib"
cp_u -r $CORES_BIN_PATH/. $OUT_BIN_DIR/platform-lib
if $EXTERNAL_LIB_ONLY
then
exit 0
fi
# Remove pre-deterministic versioning `Properties` directory
rm -rf "$ROOT_PATH/src/Renode/Properties"
# build
dotnet build "${PARAMS[@]/#/-}" $TARGET
if $ON_WINDOWS; then
python3() {
PY_PYTHON=3 py "$@"
}
fi
if ! $HEADLESS
then
python3 ./tools/add-wpf-dep.py "$OUT_BIN_DIR/Renode.runtimeconfig.json" "$OUT_BIN_DIR/RenodeWPF.runtimeconfig.json"
ln -fs Renode.dll "$OUT_BIN_DIR/RenodeWPF.dll"
else
rm -f "$OUT_BIN_DIR/RenodeWPF.runtimeconfig.json" "$OUT_BIN_DIR/RenodeWPF.dll"
fi
# on arm64 macOS System.Drawing.Common can't find libgdiplus so we symlink it to the output directory
# this is only used for `FrameBufferTester`
if [[ $RID == "osx-arm64" ]]; then
GDIPLUS_PATH="/opt/homebrew/lib/libgdiplus.dylib"
if [ -e $GDIPLUS_PATH ]; then
# For some reason System.Drawing.Common does not search the binary root when running from a source build
# but does for a package, so just link it to both locations so the packaging scripts do not have to be updated
mkdir -p $OUT_BIN_DIR/runtimes/unix/lib/netcoreapp3.0
ln -s -f $GDIPLUS_PATH $OUT_BIN_DIR/runtimes/unix/lib/netcoreapp3.0/libgdiplus.dylib
mkdir -p $OUT_BIN_DIR/unix/lib/netcoreapp3.0/
ln -s -f $GDIPLUS_PATH $OUT_BIN_DIR/unix/lib/netcoreapp3.0/libgdiplus.dylib
else
echo "libgdiplus.dylib not found by build.sh, FrameBufferTester might not work"
fi
fi
# `OUT_BIN_DIR`'s goes through `cygwin -aw` on Windows, so it's already absolute
# The path starts with a drive letter on Windows, so we have to special-case it
if [[ "$OUT_BIN_DIR" != "/"* ]] && ! $ON_WINDOWS; then
OUT_BIN_DIR="$PWD/$OUT_BIN_DIR"
fi
# NOTE: This has to be consistent with `SUPPORTED_RIDS`
LLVM_DISAS_EXTS=(
.so
-aarch64.so
.dylib
-aarch64.dylib
.dll
)
# Copy libllvm-disas
for idx in "${!SUPPORTED_RIDS[@]}"; do
PLAT_RID=${SUPPORTED_RIDS[idx]}
DISAS_FILE=$ROOT_PATH/lib/resources/llvm/libllvm-disas${LLVM_DISAS_EXTS[$idx]}
if [[ ! -f "$DISAS_FILE" ]]; then
continue
fi
if ! $MULTIPLATFORM && [[ "$PLAT_RID" != "$RID" ]]; then
continue
fi
mkdir -p "$OUT_BIN_DIR/platform-lib/$PLAT_RID"
cp_u "$DISAS_FILE" "$OUT_BIN_DIR/platform-lib/$PLAT_RID/libllvm-disas.so"
done
# Build and copy UI
if $UI; then
NO_COLOR=true "$UI_PATH/scripts/build_neutralino.sh"
for idx in "${!SUPPORTED_RIDS[@]}"; do
PLAT_RID=${SUPPORTED_RIDS[idx]}
if ! $MULTIPLATFORM && [[ "$PLAT_RID" != "$RID" ]]; then
continue
fi
PLAT_UI_RID=${SUPPORTED_UI_RIDS[idx]}
BIN_EXT=""
if [[ "$PLAT_RID" == win* ]]; then
BIN_EXT=".exe"
fi
mkdir -p "$OUT_BIN_DIR/platform-lib/$PLAT_RID"
cp_u "$UI_PATH/neutralino/dist/renode-ui/renode-ui-$PLAT_UI_RID$BIN_EXT" "$OUT_BIN_DIR/platform-lib/$PLAT_RID/renode-ui$BIN_EXT"
done
fi
if $SHARED
then
echo "Building DNNE package..."
dotnet build "$(get_path "$ROOT_PATH/tools/NativeInterface/third-party/DNNE/src/create_package.proj")" -c "$CONFIGURATION"
echo "Building librenode..."
dotnet build "$(get_path "$ROOT_PATH/tools/NativeInterface/csharp/NativeInterface.csproj")" -c "$CONFIGURATION" -f "$TFM" -p:PlatformOutputDir="$OUT_BIN_DIR/platform-lib/$RID"
copy_native_interface_runtime_config "$OUT_BIN_DIR" "$OUT_BIN_DIR/platform-lib/$RID"
fi
# build packages after successful compilation
params=""
if [ $CONFIGURATION == "Debug" ]
then
params="$params -d"
fi
if $NIGHTLY
then
params="$params -n"
fi
if $SOURCE_PACKAGE
then
if $ON_LINUX
then
# Source package bundles nuget dependencies required for building Renode
# Source packages are best built first, so it does not have to copy and then delete the packages from the `output` directory
$ROOT_PATH/tools/packaging/make_source_package.sh $params
else
echo "Source package can only be built on Linux. Exiting!"
exit 1
fi
fi
OG_TFM="$TFM"
# `dotnet publish` is all-or-nothing in terms of TFM - we can't have mixed net8.0 for normal code and net8.0-windows10 for WPF
if $PACKAGES || $PORTABLE; then
if $ON_WINDOWS && ! $HEADLESS; then
# For Windows (since we have to actually build Xwt.WPF), we switch the whole build to a Windows-only TFM and make Renode actually require WPF
TFM="$TFM-windows10.0.17763.0"
generate_build_target
PARAMS+=(p:RequireWPF=true)
elif ! $ON_WINDOWS; then
# For non-Windows, we have modified `Xwt.WPF.csproj` to remove their dependency on WPF if `RemoveWPF` is set
PARAMS+=(p:RemoveWPF=true)
fi
fi
if $PACKAGES
then
if $ON_LINUX
then
export RID TFM
$ROOT_PATH/tools/packaging/make_linux_package.sh $params
elif $ON_WINDOWS
then
# No Non portable dotnet package on windows yet
echo "Only portable dotnet packages are supported on windows. Rerun build.sh with -t flag to build portable"
exit 1
elif $ON_OSX
then
# No Non portable dotnet package on macOS
echo "Only portable dotnet packages are supported on macOS. Rerun build.sh with -t flag to build portable"
exit 1
fi
fi
if $MULTIPLATFORM
then
$ROOT_PATH/tools/packaging/make_multi_package.sh $params
fi
if $PORTABLE
then
PUBLISH_PARAMS=()
# The solution "Any CPU" platform is mapped to "AnyCPU" for projects.
# Publishing Renode.csproj directly bypasses that mapping, so without
# normalizing it here, conditional settings in projects such as Xwt.Gtk
# would be skipped.
for p in "${PARAMS[@]}"; do
if [[ "$p" == p:Platform=* ]]; then
PUBLISH_PARAMS+=(p:Platform=AnyCPU)
else
PUBLISH_PARAMS+=("$p")
fi
done
PUBLISH_PARAMS+=(p:PORTABLE=true)
PUBLISH_PARAMS+=(p:SatelliteResourceLanguages=en)
# maxcpucount:1 to avoid an error with multithreaded publish
echo "RID = $RID"
PUBLISH_OUTPUT="$OUTPUT_DIRECTORY/publish/$CONFIGURATION/$RID"
# dotnet publish does not remove files left by a previous variant. In
# particular, a normal build followed by a headless one can otherwise
# retain GUI assemblies in the headless package.
rm -rf "$PUBLISH_OUTPUT"
dotnet publish -maxcpucount:1 -r $RID -f $TFM "${PUBLISH_PARAMS[@]/#/-}" --output "$PUBLISH_OUTPUT" "$(get_path "$PWD/src/Renode/Renode.csproj")"
# Prepare for use with NativeInterface even if SHARED is not enabled as this is just one file and it means that librenode can be added later
prepare_portable_native_interface_runtime "$PUBLISH_OUTPUT" "$OUT_BIN_DIR"
export RID TFM
$ROOT_PATH/tools/packaging/make_${DETECTED_OS}_portable.sh $params
fi
TFM="$OG_TFM"
generate_build_target