Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/build_linux
/build_linux_softfp
/build_mingw
/.idea
/build
__pycache__/
/softfp-shim/wrappers
41 changes: 41 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,47 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")

# Toolchain arch target
set(target_arch arm-vita-eabi)

# Float ABI baked into the toolchain: a build parameter, never a branch (see
# PLAN-softfp.md). Selects --with-float in the GCC configure; world_arch is
# the identity stamped into the core (pacman Architecture, makepkg CARCH,
# version_info.txt) so a softfp core can never be mistaken for the default one.
set(VITASDK_FLOAT_ABI "hard" CACHE STRING
"Float ABI baked into the toolchain: hard (default) or softfp")
set_property(CACHE VITASDK_FLOAT_ABI PROPERTY STRINGS hard softfp)

# A profile names a world, and the world decides the ABI rather than the other
# way round: CI asks for a profile because that is what the lock carries, and
# describe already refuses one this repository does not publish.
#
# A profile wins over VITASDK_FLOAT_ABI, and does so silently. CMake cannot
# tell a cache entry left at its default from one somebody passed, so a check
# that the two agree would either miss -DVITASDK_FLOAT_ABI=hard or refuse
# every re-configure of an existing build directory. Passing both is passing
# the same thing twice; the profile is the one that says which world this is.
include(Profiles)
set(VITASDK_PROFILE "" CACHE STRING "World to build; selects the float ABI")
if(VITASDK_PROFILE)
if(NOT VITASDK_PROFILE IN_LIST VITASDK_PROFILES)
message(FATAL_ERROR
"unknown profile '${VITASDK_PROFILE}'; this tree publishes: ${VITASDK_PROFILES}")
endif()
set(profile_float_abi ${VITASDK_PROFILE_FLOAT_ABI_${VITASDK_PROFILE}})
if(NOT profile_float_abi)
message(FATAL_ERROR "profile '${VITASDK_PROFILE}' declares no float ABI")
endif()
set(VITASDK_FLOAT_ABI ${profile_float_abi} CACHE STRING "" FORCE)
endif()

if(NOT VITASDK_FLOAT_ABI STREQUAL "hard" AND NOT VITASDK_FLOAT_ABI STREQUAL "softfp")
message(FATAL_ERROR "VITASDK_FLOAT_ABI must be 'hard' or 'softfp', got '${VITASDK_FLOAT_ABI}'")
endif()
if(VITASDK_FLOAT_ABI STREQUAL "softfp")
set(world_arch "vita-softfp")
else()
set(world_arch "vita")
endif()

# Build date
string(TIMESTAMP build_date "%Y-%m-%d_%H-%M-%S")
string(TIMESTAMP default_package_version "0.%Y%m%d.%H%M%S" UTC)
Expand Down
6 changes: 6 additions & 0 deletions cmake/Profiles.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@ include_guard(GLOBAL)

# Published profile (world) names; describe rejects anything else.
set(VITASDK_PROFILES vita vita-softfp)

# The float ABI each profile bakes into the toolchain. A profile is a world and
# a world is named by the architecture its packages carry, so the name is the
# same on both sides of the build.
set(VITASDK_PROFILE_FLOAT_ABI_vita hard)
set(VITASDK_PROFILE_FLOAT_ABI_vita-softfp softfp)
19 changes: 19 additions & 0 deletions cmake/WriteMakepkgConf.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#
# Stamps the world's CARCH into the makepkg.conf shipped inside the SDK.
# vita-makepkg's own makepkg.conf.sample always says CARCH="vita": this is
# the one place that turns it into the world the core was actually built for.
#

if(NOT DEFINED INPUT OR NOT DEFINED OUTPUT OR NOT DEFINED WORLD_ARCH)
message(FATAL_ERROR "INPUT, OUTPUT and WORLD_ARCH are required")
endif()

file(READ "${INPUT}" contents)
string(REGEX REPLACE "\nCARCH=\"[^\"]*\"\n" "\nCARCH=\"${WORLD_ARCH}\"\n"
contents "${contents}")

get_filename_component(output_directory "${OUTPUT}" DIRECTORY)
file(MAKE_DIRECTORY "${output_directory}")
set(temporary "${OUTPUT}.tmp")
file(WRITE "${temporary}" "${contents}")
file(RENAME "${temporary}" "${OUTPUT}")
6 changes: 3 additions & 3 deletions cmake/WritePacmanConfig.cmake
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
if(NOT DEFINED OUTPUT OR NOT DEFINED HOST_ARCHITECTURE)
message(FATAL_ERROR "OUTPUT and HOST_ARCHITECTURE are required")
if(NOT DEFINED OUTPUT OR NOT DEFINED HOST_ARCHITECTURE OR NOT DEFINED WORLD_ARCH)
message(FATAL_ERROR "OUTPUT, HOST_ARCHITECTURE and WORLD_ARCH are required")
endif()

get_filename_component(output_directory "${OUTPUT}" DIRECTORY)
file(MAKE_DIRECTORY "${output_directory}")
set(temporary "${OUTPUT}.tmp")
file(WRITE "${temporary}"
"[options]\n"
"Architecture = ${HOST_ARCHITECTURE} vita\n"
"Architecture = ${HOST_ARCHITECTURE} ${WORLD_ARCH}\n"
"# vdpm verifies signed channel metadata and the selected database hash before use.\n"
"SigLevel = Never\n")
file(RENAME "${temporary}" "${OUTPUT}")
1 change: 1 addition & 0 deletions cmake/create_version.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ file(READ ${INPUT_DIR}/pthread-embedded-version.txt _pthread_sha1)
file(READ ${INPUT_DIR}/samples-version.txt _samples_sha1)

file(WRITE ${OUTPUT_FILE} "Built at ${BUILD_DATE}\n")
file(APPEND ${OUTPUT_FILE} "world ${WORLD_ARCH} (float-abi=${VITASDK_FLOAT_ABI})\n")
file(APPEND ${OUTPUT_FILE} "newlib ${_newlib_sha1}")
file(APPEND ${OUTPUT_FILE} "pthread-embedded ${_pthread_sha1}")
file(APPEND ${OUTPUT_FILE} "samples ${_samples_sha1}")
Expand Down
6 changes: 5 additions & 1 deletion cmake/recipes/BuildHostTools.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ ExternalProject_Add(vita-makepkg
INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_INSTALL_PREFIX}/bin/
COMMAND ${CMAKE_COMMAND} -E copy_directory <SOURCE_DIR>/libmakepkg ${CMAKE_INSTALL_PREFIX}/bin/libmakepkg
COMMAND ${CMAKE_COMMAND} -E copy <SOURCE_DIR>/vita-makepkg ${CMAKE_INSTALL_PREFIX}/bin/
COMMAND ${CMAKE_COMMAND} -E copy <SOURCE_DIR>/makepkg.conf.sample ${CMAKE_INSTALL_PREFIX}/bin/makepkg.conf
COMMAND ${CMAKE_COMMAND}
-DINPUT=<SOURCE_DIR>/makepkg.conf.sample
-DOUTPUT=${CMAKE_INSTALL_PREFIX}/bin/makepkg.conf
-DWORLD_ARCH=${world_arch}
-P ${PROJECT_SOURCE_DIR}/cmake/WriteMakepkgConf.cmake
${UPDATE_DISCONNECTED_SUPPORT}
)
25 changes: 24 additions & 1 deletion cmake/recipes/BuildSdkComponents.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,30 @@ ExternalProject_add(vita-headers
${UPDATE_DISCONNECTED_SUPPORT}
)

# The softfp world calls the same hard-float Sce* stubs vita-headers just
# installed, but with float/double arguments and return values sitting in
# the wrong registers (AAPCS-base vs AAPCS-VFP). Splice the 23 shims from
# softfp-shim/ into the affected stub archives in place -- see
# PLAN-softfp.md, "Fase 1 - los 23 shims de serie" and
# scripts/patch-softfp-stub-archives.sh for why this is an archive rewrite
# and not a -lvita_softfp_shim added to LIB_SPEC.
if(VITASDK_FLOAT_ABI STREQUAL "softfp")
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/softfp-shim.stamp
COMMAND ${PROJECT_SOURCE_DIR}/scripts/build-softfp-shim.sh
${binutils_prefix}-gcc ${binutils_prefix}-ar ${binutils_prefix}-objcopy
${PROJECT_SOURCE_DIR}/softfp-shim
${CMAKE_INSTALL_PREFIX}/${target_arch}/include
${CMAKE_INSTALL_PREFIX}/${target_arch}/lib
${toolchain_build_install_dir}/${target_arch}/lib
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/softfp-shim.stamp
DEPENDS vita-headers gcc-base binutils_${build_suffix}
COMMENT "Splicing the softfp ABI shims into the stub archives"
VERBATIM
)
add_custom_target(softfp-shim ALL DEPENDS ${CMAKE_BINARY_DIR}/softfp-shim.stamp)
endif()

ExternalProject_Add(newlib
DEPENDS binutils_${target_suffix} vita-headers
GIT_REPOSITORY ${NEWLIB_REPOSITORY}
Expand Down Expand Up @@ -82,4 +106,3 @@ ExternalProject_Add(samples
COMMAND ${GIT_EXECUTABLE} -C <SOURCE_DIR> rev-parse HEAD > ${CMAKE_BINARY_DIR}/samples-version.txt
${UPDATE_DISCONNECTED_SUPPORT}
)

6 changes: 6 additions & 0 deletions cmake/recipes/FinalizeSdk.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ if(BUILD_PACMAN_CLIENT)
COMMAND ${CMAKE_COMMAND}
-DOUTPUT=${CMAKE_INSTALL_PREFIX}/etc/pacman.conf
-DHOST_ARCHITECTURE=${host_published}
-DWORLD_ARCH=${world_arch}
-P ${PROJECT_SOURCE_DIR}/cmake/WritePacmanConfig.cmake
DEPENDS vdpm
VERBATIM)
Expand All @@ -43,6 +44,11 @@ set(finalize_sdk_dependencies
if(BUILD_PACMAN_CLIENT)
list(APPEND finalize_sdk_dependencies package-client-configuration)
endif()
if(VITASDK_FLOAT_ABI STREQUAL "softfp")
# Splice the softfp shims into the stub archives before finalize-sdk
# strips them (cmake/strip_target_objects.cmake), not after.
list(APPEND finalize_sdk_dependencies softfp-shim)
endif()

# Target objects are stripped where they are produced. In stage 2 they arrive
# already stripped from stage 1, and the objcopy that would do it belongs to
Expand Down
2 changes: 1 addition & 1 deletion cmake/recipes/GccCommonArgs.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ set(common_gcc_configure_args
--with-arch=armv7-a
--with-tune=cortex-a9
--with-fpu=neon
--with-float=hard
--with-float=${VITASDK_FLOAT_ABI}
--with-mode=thumb
"--with-pkgversion=${pkgversion}"
)
Expand Down
1 change: 1 addition & 0 deletions cmake/recipes/Provenance.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ if(VITASDK_STAGE1_DIR)
else()
add_custom_command(OUTPUT ${version_info_file}
COMMAND ${CMAKE_COMMAND} -DINPUT_DIR=${CMAKE_BINARY_DIR} -DOUTPUT_FILE=${version_info_file}
-DWORLD_ARCH=${world_arch} -DVITASDK_FLOAT_ABI=${VITASDK_FLOAT_ABI}
-P ${CMAKE_SOURCE_DIR}/cmake/create_version.cmake
DEPENDS vita-headers vita-toolchain_${target_suffix} newlib pthread-embedded samples
COMMENT "Creating version_info.txt"
Expand Down
38 changes: 38 additions & 0 deletions scripts/build-softfp-shim.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
#
# Generate softfp-shim/wrappers/*.S from the vita-headers this build just
# installed, assemble them, and splice them into every stub archive they
# touch, in every given lib dir. See patch-softfp-stub-archives.sh for what
# "splice" means; generation is cheap enough (a handful of regex passes over
# a few headers) to redo on every softfp build rather than trust a checked-in
# copy to still match vita-headers -- see softfp-shim/README.md.

set -euo pipefail

if [[ $# -lt 6 ]]; then
printf 'usage: %s <cc> <ar> <objcopy> <shim-dir> <vita-headers-include-dir> <lib-dir>...\n' "$0" >&2
exit 2
fi

cc=$1
ar=$2
objcopy=$3
shim_dir=$4
headers_dir=$5
shift 5

work_dir=$(mktemp -d)
trap 'rm -rf "$work_dir"' EXIT

python3 "$shim_dir/generate.py" "$headers_dir" --out "$work_dir/wrappers"

for src in "$work_dir"/wrappers/*.S; do
name=$(basename "$src" .S)
"$cc" -c -mfpu=neon -mfloat-abi=softfp "$src" -o "$work_dir/$name.o"
done

script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
for lib_dir in "$@"; do
"$script_dir/patch-softfp-stub-archives.sh" "$lib_dir" "$ar" "$objcopy" \
"$work_dir" "$shim_dir/functions.tsv"
done
7 changes: 4 additions & 3 deletions scripts/ci/build-host.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,6 @@ for required in host stage artifacts_dir out_dir build_id version revision profi
exit 2
}
done
# profile is required but not yet consumed: no profile -> VITASDK_FLOAT_ABI
# mapping exists in CMakeLists.txt yet.
: "$profile"

actual_revision=$(git -C "$repo_root" rev-parse HEAD)
[[ $actual_revision == "$revision" ]] || {
Expand Down Expand Up @@ -175,6 +172,9 @@ build_and_stage() {
local -a extra_args=("$@")
local -a cmake_args=(
-S "$repo_root" -B build ${extra_args[@]+"${extra_args[@]}"}
# The lock says which world this is; the profile is how the tree is
# told, and it is what decides the float ABI baked into the toolchain.
-DVITASDK_PROFILE="$profile"
-DVITASDK_SOURCE_REVISION="$revision"
-DVITASDK_SOURCE_DATE_EPOCH="$source_date_epoch"
# The lock names the host; artifacts published under any other name
Expand Down Expand Up @@ -363,6 +363,7 @@ if [[ $stage == 1 ]]; then
enable_ccache
cmake -S "$repo_root" -B build \
-DVITASDK_TARGET_ONLY=ON \
-DVITASDK_PROFILE="$profile" \
-DVITASDK_SOURCE_REVISION="$revision" \
-DVITASDK_SOURCE_DATE_EPOCH="$source_date_epoch"
cmake --build build --target sysroot --parallel "$(ci_nproc)"
Expand Down
64 changes: 64 additions & 0 deletions scripts/patch-softfp-stub-archives.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env bash
#
# Splice the softfp ABI shims (softfp-shim/wrappers/*.S, already assembled to
# *.o) into the stub archives vita-headers just installed, for the 23
# functions listed in softfp-shim/functions.tsv (see PLAN-softfp.md, "Fase 1
# - los 23 shims de serie").
#
# For each function this renames the real stub object's exported symbol to
# __vita_softfp_target_<name> (objcopy --redefine-sym) and adds the matching
# wrapper object as a new archive member under the original name. A static
# archive resolves symbols through its member index, not by member order, so
# after the rename there is exactly one provider of <name> left in the
# archive and no link-order dependency is introduced -- packages keep linking
# -lSceGxm_stub, -lScePvf_stub, etc. exactly as before.

set -euo pipefail

if [[ $# -ne 5 ]]; then
printf 'usage: %s <lib-dir> <ar> <objcopy> <wrapper-obj-dir> <functions.tsv>\n' "$0" >&2
exit 2
fi

lib_dir=$1
ar=$2
objcopy=$3
wrapper_dir=$4
functions_tsv=$5

[[ -d $lib_dir ]] || { printf 'lib dir not found: %s\n' "$lib_dir" >&2; exit 1; }

work_dir=$(mktemp -d)
trap 'rm -rf "$work_dir"' EXIT

patch_archive() {
local archive=$1 name=$2
[[ -f $archive ]] || return 0

local member
member=$("$ar" t "$archive" | grep -E "_${name}\.(o|wo)\$" || true)
if [[ -z $member ]]; then
printf 'symbol %s not found in %s\n' "$name" "$archive" >&2
exit 1
fi

local extract_dir="$work_dir/$(basename "$archive")-$name"
mkdir -p "$extract_dir"
(cd "$extract_dir" && "$ar" x "$archive" "$member")
"$objcopy" --redefine-sym "${name}=__vita_softfp_target_${name}" \
"$extract_dir/$member"

"$ar" r "$archive" "$extract_dir/$member"
"$ar" r "$archive" "$wrapper_dir/$name.o"
"$ar" s "$archive"
}

while IFS=$'\t' read -r name header module; do
[[ -n $name ]] || continue
[[ -f "$wrapper_dir/$name.o" ]] || {
printf 'wrapper object not found: %s/%s.o\n' "$wrapper_dir" "$name" >&2
exit 1
}
patch_archive "$lib_dir/lib${module}_stub.a" "$name"
patch_archive "$lib_dir/lib${module}_stub_weak.a" "$name"
done < "$functions_tsv"
9 changes: 9 additions & 0 deletions scripts/repack-core.sh
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,10 @@ cp -a "$vita_makepkg/libmakepkg" "$sdk_root/bin/libmakepkg"
cp -a "$vita_makepkg/vita-makepkg" "$sdk_root/bin/vita-makepkg"
cp -a "$vita_makepkg/makepkg.conf.sample" "$sdk_root/bin/makepkg.conf"

# Repacking only ever handles releases of the default world: softfp cores
# are never repacked by this script.
cmake -DOUTPUT="$sdk_root/etc/pacman.conf" -DHOST_ARCHITECTURE="$host" \
-DWORLD_ARCH=vita \
-P "$script_directory/../cmake/WritePacmanConfig.cmake"

vdpm_version=$(awk -F= '$1 == "version" { print $2; exit }' \
Expand All @@ -167,6 +170,12 @@ fi
# The component lines above this block still describe what produced the
# binaries. These say who repacked them and with what, and name the source
# archive by digest so the claim can be checked against what is published.
# Archives from before the world was stamped in version_info.txt never carry
# a "world" line; backfill it here since this script only ever repacks the
# default world (see the pacman.conf write above).
if ! grep -q '^world ' "$version_info"; then
printf 'world vita (float-abi=hard)\n' >> "$version_info"
fi
{
printf 'repacked from %s\n' "$(basename "$archive")"
printf 'source sha256 %s\n' "${archive_digest%% *}"
Expand Down
27 changes: 27 additions & 0 deletions scripts/validate-core-package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,33 @@ if [[ $pkgname == vitasdk-core ]]; then
printf 'core package does not contain provenance information\n' >&2
exit 1
}

# The world (vita, vita-softfp, ...) is stamped in two independent places;
# a mismatch means the build tagged the release for one world while
# actually configuring the toolchain, or makepkg, for another.
world_from_version=$(bsdtar -xOf "$package" version_info.txt |
awk '$1 == "world" { print $2; exit }')
[[ -n $world_from_version ]] || {
printf 'version_info.txt does not declare a world\n' >&2
exit 1
}

grep -qx 'bin/makepkg.conf' <<< "$archive_entries" || {
printf 'core package does not contain bin/makepkg.conf\n' >&2
exit 1
}
world_from_makepkg=$(bsdtar -xOf "$package" bin/makepkg.conf |
awk -F '"' '/^CARCH=/ { print $2; exit }')
[[ -n $world_from_makepkg ]] || {
printf 'bin/makepkg.conf does not declare CARCH\n' >&2
exit 1
}

[[ $world_from_version == "$world_from_makepkg" ]] || {
printf 'world mismatch: version_info.txt says %s, bin/makepkg.conf CARCH says %s\n' \
"$world_from_version" "$world_from_makepkg" >&2
exit 1
}
else
grep -Eq '^bin/vdpm(\.exe)?$' <<< "$archive_entries" || {
printf 'client package does not contain the package client\n' >&2
Expand Down
Loading
Loading