Skip to content

Commit

Permalink
Add release script
Browse files Browse the repository at this point in the history
  • Loading branch information
nathan818fr committed Dec 7, 2023
1 parent d4314b5 commit 52b0823
Show file tree
Hide file tree
Showing 9 changed files with 428 additions and 1 deletion.
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@
path = external/injector
url = https://github.com/rdbo/injector
branch = rdbo-flatpak-sandbox-fix
[submodule "vcvars-bash"]
path = external/vcvars-bash
url = https://github.com/nathan818fr/vcvars-bash.git
branch = master
25 changes: 24 additions & 1 deletion external/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,24 @@ set(CAPSTONE_CMAKE_ARGS
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
-DCMAKE_MSVC_RUNTIME_LIBRARY=${CMAKE_MSVC_RUNTIME_LIBRARY}
-DCAPSTONE_ARCHITECTURE_DEFAULT=ON
-DCAPSTONE_BUILD_TESTS=OFF
-DCAPSTONE_BUILD_CSTOOL=OFF
-DCAPSTONE_INSTALL=OFF
-DCAPSTONE_BUILD_SHARED=OFF
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
-DCAPSTONE_ARCHITECTURE_DEFAULT=OFF
-DCAPSTONE_BUILD_STATIC_RUNTIME=OFF
)
if(DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)
if(${CMAKE_MSVC_RUNTIME_LIBRARY} STREQUAL "MultiThreaded" OR ${CMAKE_MSVC_RUNTIME_LIBRARY} STREQUAL "MultiThreadedDebug")
set(KEYSTONE_CMAKE_ARGS ${KEYSTONE_CMAKE_ARGS} -DCAPSTONE_BUILD_STATIC_RUNTIME=ON)
else()
set(KEYSTONE_CMAKE_ARGS ${KEYSTONE_CMAKE_ARGS} -DCAPSTONE_BUILD_STATIC_RUNTIME=OFF)
endif()
else()
set(KEYSTONE_CMAKE_ARGS ${KEYSTONE_CMAKE_ARGS} -DCAPSTONE_BUILD_STATIC_RUNTIME=OFF)
endif()
if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
set(CAPSTONE_CMAKE_ARGS ${CAPSTONE_CMAKE_ARGS} -DCAPSTONE_ARM64_SUPPORT=ON)
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm")
Expand All @@ -27,9 +36,22 @@ set(KEYSTONE_CMAKE_ARGS
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
-DCMAKE_MSVC_RUNTIME_LIBRARY=${CMAKE_MSVC_RUNTIME_LIBRARY}
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
-DKEYSTONE_BUILD_STATIC_RUNTIME=OFF
)
if(DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)
string(TOUPPER "LLVM_USE_CRT_${CMAKE_BUILD_TYPE}" LLVM_USE_CRT_VAR)
if(${CMAKE_MSVC_RUNTIME_LIBRARY} STREQUAL "MultiThreaded")
set(KEYSTONE_CMAKE_ARGS ${KEYSTONE_CMAKE_ARGS} -D${LLVM_USE_CRT_VAR}=MT)
elseif(${CMAKE_MSVC_RUNTIME_LIBRARY} STREQUAL "MultiThreadedDebug")
set(KEYSTONE_CMAKE_ARGS ${KEYSTONE_CMAKE_ARGS} -D${LLVM_USE_CRT_VAR}=MTd)
elseif(${CMAKE_MSVC_RUNTIME_LIBRARY} STREQUAL "MultiThreadedDLL")
set(KEYSTONE_CMAKE_ARGS ${KEYSTONE_CMAKE_ARGS} -D${LLVM_USE_CRT_VAR}=MD)
elseif(${CMAKE_MSVC_RUNTIME_LIBRARY} STREQUAL "MultiThreadedDebugDLL")
set(KEYSTONE_CMAKE_ARGS ${KEYSTONE_CMAKE_ARGS} -D${LLVM_USE_CRT_VAR}=MDd)
endif()
endif()
if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
set(KEYSTONE_CMAKE_ARGS ${KEYSTONE_CMAKE_ARGS} -DLLVM_TARGETS_TO_BUILD=AArch64)
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm")
Expand All @@ -45,6 +67,7 @@ set(LIEF_CMAKE_ARGS
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
-DCMAKE_MSVC_RUNTIME_LIBRARY=${CMAKE_MSVC_RUNTIME_LIBRARY}
-DLIEF_USE_CCACHE=OFF
-DLIEF_ENABLE_JSON=OFF
-DLIEF_FROZEN_ENABLED=OFF
Expand Down
1 change: 1 addition & 0 deletions external/vcvars-bash
Submodule vcvars-bash added at 7041b8
310 changes: 310 additions & 0 deletions tools/build-release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,310 @@
#!/usr/bin/env bash
set -Eeuo pipefail
shopt -s inherit_errexit

declare -gr NIX_PLATFORMS=(
# Linux (GNU/glibc)
x86_64-linux-gnu
aarch64-linux-gnu
# Linux (Alpine/musl)
x86_64-linux-musl
aarch64-linux-musl
)
declare -gr NIX_VARIANTS=(
shared
static
)

declare -gr WINDOWS_PLATFORMS=(
# Windows (MSVC)
i686-windows-msvc
x86_64-windows-msvc
aarch64-windows-msvc
)
declare -gr WINDOWS_VARIANTS=(
shared-md
static-md
static-mt
)

SCRIPT_DIR=$(dirname -- "$(realpath -m -- "$0")")
declare -gr SCRIPT_DIR
PROJECT_DIR=$(dirname -- "$SCRIPT_DIR")
declare -gr PROJECT_DIR

function define_targets() {
local platform variant
TARGETS=()
for platform in "${NIX_PLATFORMS[@]}"; do
for variant in "${NIX_VARIANTS[@]}"; do
TARGETS+=("${platform}-${variant}")
done
done
for platform in "${WINDOWS_PLATFORMS[@]}"; do
for variant in "${WINDOWS_VARIANTS[@]}"; do
TARGETS+=("${platform}-${variant}")
done
done
declare -gr TARGETS
}

function print_usage() {
cat <<EOF
Usage: $(basename -- "$0") <target>
Environment variables:
LIBMEM_BUILD_OUT_DIR: The output directory (default: "build/out/libmem-local-\${target}").
LIBMEM_BUILD_SKIP_ARCHIVE: Skip the final archive creation (default: false).
Supported targets:
$(printf ' - %s\n' "${TARGETS[@]}")
EOF
}

function main() {
define_targets
echo "$TARGETS"

if [[ $# -ne 1 ]]; then
print_usage >&2
return 1
fi

local target=$1
if ! array_contains "$target" "${TARGETS[@]}"; then
printf 'error: Unknown target: %s\n' "$target" >&2
return 1
fi

local source_dir=${PROJECT_DIR}
local out_dir
if [[ -n "${LIBMEM_BUILD_OUT_DIR:-}" ]]; then
out_dir=$(realpath -m -- "$LIBMEM_BUILD_OUT_DIR")
if [[ -d "$out_dir" ]]; then
printf 'error: Output directory already exists: %s\n' "$out_dir" >&2
return 1
fi
else
out_dir=$(realpath -m -- "build/out/libmem-local-${target}")
rm -rf -- "$out_dir"
fi
mkdir -p -- "$out_dir"

printf 'Target: %s\n' "$target"
printf 'Source directory: %s\n' "$source_dir"
printf 'Output directory: %s\n' "$out_dir"
printf '\n'

case "$target" in
*-linux-*) _build_in_docker "$target" "$source_dir" "$out_dir" ;;
*) _build_locally "$target" "$source_dir" "$out_dir" ;;
esac

if [[ "${LIBMEM_BUILD_SKIP_ARCHIVE:-}" != true ]]; then
printf '[+] Create archive\n'
tar -czf "${out_dir}.tar.gz" --owner=0 --group=0 --numeric-owner -C "$(dirname -- "$out_dir")" "$(basename -- "$out_dir")"
fi

printf '[+] Done\n'
}

function _build_in_docker() {
local target=$1 source_dir=$2 out_dir=$3

local docker_os=unknown docker_platform=unknown
case "$target" in
*-linux-gnu-*) docker_os=linux-gnu ;;
*-linux-musl-*) docker_os=linux-musl ;;
esac
case "$target" in
x86_64-*) docker_platform=linux/amd64 ;;
aarch64-*) docker_platform=linux/arm64 ;;
esac

local docker_image="libmem-build-${docker_os}-${docker_platform##*/}"
docker build --platform "$docker_platform" -t "$docker_image" -f "${SCRIPT_DIR}/docker-env/${docker_os}.Dockerfile" "${SCRIPT_DIR}/docker-env"
docker run --platform "$docker_platform" --rm \
-e "PUID=$(id -u)" \
-e "PGID=$(id -g)" \
-e "_TARGET=${target}" \
-e "_SOURCE_DIR=/source" \
-e "_BUILD_DIR=/build" \
-e "_OUT_DIR=/out" \
-v "${source_dir}:/source:ro" \
-v "${out_dir}:/out:rw" \
-i "$docker_image" \
bash <<<"set -Eeuo pipefail; shopt -s inherit_errexit; $(declare -f do_build); do_build; exit 0"
}

function _build_locally() {
local target=$1 source_dir=$2 out_dir=$3

local local_env local_env_arch
local_env=$(awk -F- '{print $2"-"$3}' <<<"$target") # keep only the middle part
local_env_arch=${target%%-*} # remove everything after the first dash

init_temp_dir
_=_ \
_TARGET="$target" \
_SOURCE_DIR="$source_dir" \
_BUILD_DIR="${g_temp_dir}/build" \
_OUT_DIR="$out_dir" \
"${SCRIPT_DIR}/local-env/${local_env}.sh" "$local_env_arch" \
bash <<<"set -Eeuo pipefail; shopt -s inherit_errexit; $(declare -f do_build); do_build; exit 0"
}

# Perform the build and copy the results to the output directory.
# This function must be self-contained and exportable.
# Inputs:
# _TARGET: The target to build.
# _SOURCE_DIR: The absolute path to the source directory.
# _BUILD_DIR: The absolute path to the build directory.
# _OUT_DIR: The absolute path to the output directory.
function do_build() {
true "${_TARGET?required}" "${_SOURCE_DIR?required}" "${_BUILD_DIR?required}" "${_OUT_DIR?required}"

# Build using CMake
function build_variant() {
local variant_name=$1
local variant_build_type=$2
local variant_conf=("${@:3}")
printf '[+] Build (%s)\n' "$variant_name"

# Prepare config
case "$_TARGET" in
*-windows-msvc-*)
variant_conf+=(-G 'NMake Makefiles')
;;
*)
local flags
case "$_TARGET" in
x86_64-*) flags='-march=westmere' ;;
aarch64-*) flags='-march=armv8-a' ;;
esac
variant_conf+=(-G 'Unix Makefiles' -DCMAKE_C_FLAGS="$flags" -DCMAKE_CXX_FLAGS="$flags")
;;
esac
variant_conf+=(-DLIBMEM_BUILD_TESTS='OFF')

# Build using CMake
local variant_build_dir="${_BUILD_DIR}/${variant_name}"
set -x
cmake -S "$_SOURCE_DIR" -B "$variant_build_dir" -DCMAKE_BUILD_TYPE="$variant_build_type" "${variant_conf[@]}"
cmake --build "$variant_build_dir" --config "$variant_build_type" --parallel "$(nproc)"
{ set +x; } 2>/dev/null

# Copy libraries
local variant_out_dir="${_OUT_DIR}/lib/${variant_name}"
mkdir -p -- "$variant_out_dir"
function copy_lib() {
install -vD -m644 -- "${variant_build_dir}/${1}" "${variant_out_dir}/${2:-$(basename -- "$1")}"
}
case "$_TARGET" in
*-windows-msvc-shared*) copy_lib 'libmem.dll' ;;
*-windows-msvc-static*) copy_lib 'libmem.lib' ;;
*-shared) copy_lib 'liblibmem.so' ;;
*-static) copy_lib 'liblibmem.a' ;;
esac
}

case "$_TARGET" in
*-windows-msvc-shared-md)
build_variant release Release -DLIBMEM_BUILD_STATIC=OFF -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL
build_variant debug Debug -DLIBMEM_BUILD_STATIC=OFF -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebugDLL
;;
*-windows-msvc-static-md)
build_variant release Release -DLIBMEM_BUILD_STATIC=ON -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL
build_variant debug Debug -DLIBMEM_BUILD_STATIC=ON -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebugDLL
;;
*-windows-msvc-static-mt)
build_variant release Release -DLIBMEM_BUILD_STATIC=ON -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded
build_variant debug Debug -DLIBMEM_BUILD_STATIC=ON -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug
;;
*-shared)
build_variant ./ Release -DLIBMEM_BUILD_STATIC=OFF
;;
*-static)
build_variant ./ Release -DLIBMEM_BUILD_STATIC=ON
;;
esac

# Copy headers
printf '[+] Copy headers\n'
mkdir -p -- "${_OUT_DIR}/include"
cp -rT -- "${_SOURCE_DIR}/include" "${_OUT_DIR}/include"

# Copy licenses
printf '[+] Copy licenses\n'
mkdir -p -- "${_OUT_DIR}/licenses"
function copy_licenses() {
local name=$1
local dir="${_SOURCE_DIR}/${2:-$name}"
find "$dir" -maxdepth 1 -type f \( -iname 'license*' -o -iname 'copying*' -o -iname 'exception*' \) | while read -r file; do
local file_name
file_name=$(basename -- "$file")
file_name=${file_name%.*} # remove extension
file_name=${file_name,,} # lowercase
install -vD -m644 -- "$file" "${_OUT_DIR}/licenses/${name}-${file_name}.txt"
done
}
copy_licenses 'libmem' './'
copy_licenses 'capstone' 'external/capstone'
copy_licenses 'keystone' 'external/keystone'
copy_licenses 'LIEF' 'external/LIEF'
copy_licenses 'llvm' 'external/llvm'
copy_licenses 'injector' 'external/injector'

# Add stdlib information (glibc version, musl version)
printf '[+] Add stdlib information\n'
case "$_TARGET" in
*-linux-gnu-*)
# ldd --version can cause exit 141 when stdout is closed early.
{ ldd --version || true; } | head -n1 | awk '{print $NF}' | install -vD -m644 -- /dev/stdin "${_OUT_DIR}/GLIBC_VERSION.txt"
;;
*-linux-musl-*)
apk info musl 2>/dev/null | head -n1 | awk '{print $1}' | sed 's/^musl-//' | install -vD -m644 -- /dev/stdin "${_OUT_DIR}/MUSL_VERSION.txt"
;;
*-windows-msvc-*)
printf '%s\n' "${VCTOOLSVERSION:-${VSCMD_ARG_VCVARS_VER:-}}" | install -vD -m644 -- /dev/stdin "${_OUT_DIR}/MSVC_VERSION.txt"
printf '%s\n' "${WINDOWSSDKVERSION:-}" | install -vD -m644 -- /dev/stdin "${_OUT_DIR}/WINSDK_VERSION.txt"
;;
esac
}

# Ensure that the temporary directory exists and is set to an absolute path.
# This directory will be automatically deleted when the script exits.
# This function is idempotent.
# Outputs:
# g_temp_dir: The absolute path to the temporary directory.
function init_temp_dir() {
if [[ -v g_temp_dir ]]; then
return
fi

g_temp_dir=$(mktemp -d)
declare -gr g_temp_dir

# shellcheck disable=SC2317
function __temp_dir_cleanup() { rm -rf -- "$g_temp_dir"; }
trap __temp_dir_cleanup INT TERM EXIT
}

# Check if an array contains a value.
# Inputs:
# $1: The value to check for.
# $2+: The array to check.
# Returns:
# 0 if the array contains the value,
# 1 otherwise.
function array_contains() {
local value=$1
local element
for element in "${@:2}"; do
if [[ "$element" == "$value" ]]; then
return 0
fi
done
return 1
}

eval 'main "$@";exit "$?"'
2 changes: 2 additions & 0 deletions tools/docker-env/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.dockerignore
*.Dockerfile
18 changes: 18 additions & 0 deletions tools/docker-env/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env sh
set -eu

groupmod -o -g "${PGID:-1000}" build
usermod -o -u "${PUID:-1000}" build

if [ ! -d /build ]; then
mkdir /build
chown build:build /build
fi

command=${1:-sh}
command=$(which -- "${command}" || {
echo "${command}: not found" >&2
return 1
})
shift
exec su build -s "$command" -- "$@"
Loading

0 comments on commit 52b0823

Please sign in to comment.