diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ecb936..213b699 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -303,6 +303,27 @@ if(NOT VITASDK_TARGET_ONLY) endif() include(cmake/recipes/BuildGccFinal.cmake) include(cmake/recipes/Provenance.cmake) + +# What the target half is made of, named once because two things wait for it: +# the export that hands stage 2 a sysroot, and the finalize barrier of a build +# that keeps its own. One of them forgetting a piece is invisible until +# something reads the result -- the softfp shims were spliced by finalize-sdk +# and not by the export, so a staged build shipped stage 2 a sysroot whose +# stub archives had never been patched, and the ABI contract test found it +# there rather than here. +set(target_half_dependencies + ${gcc_final_barrier} + vita-headers + newlib + pthread-embedded + samples + ${version_info_file}) +if(VITASDK_FLOAT_ABI STREQUAL "softfp" AND NOT VITASDK_STAGE1_DIR) + # Stage 2 imports the archives already spliced; there is nothing to splice + # and no softfp-shim target, since the components are not built there. + list(APPEND target_half_dependencies softfp-shim) +endif() + if(VITASDK_TARGET_ONLY) include(cmake/recipes/ExportSysroot.cmake) else() diff --git a/cmake/recipes/ExportSysroot.cmake b/cmake/recipes/ExportSysroot.cmake index dda169d..1b07d77 100644 --- a/cmake/recipes/ExportSysroot.cmake +++ b/cmake/recipes/ExportSysroot.cmake @@ -43,8 +43,7 @@ add_custom_target(sysroot -P ${CMAKE_SOURCE_DIR}/cmake/CopySysroot.cmake COMMAND ${CMAKE_COMMAND} -E tar "cfj" ${CMAKE_BINARY_DIR}/${sysroot_tarball} vitasdk WORKING_DIRECTORY ${sysroot_root} - DEPENDS ${gcc_final_barrier} vita-headers newlib pthread-embedded samples - ${version_info_file} + DEPENDS ${target_half_dependencies} COMMENT "Exporting the target half to ${sysroot_tarball}" VERBATIM ) diff --git a/cmake/recipes/FinalizeSdk.cmake b/cmake/recipes/FinalizeSdk.cmake index 589eaf5..aec562b 100644 --- a/cmake/recipes/FinalizeSdk.cmake +++ b/cmake/recipes/FinalizeSdk.cmake @@ -33,22 +33,12 @@ set(finalize_sdk_dependencies vita-toolchain_${target_suffix} binutils_${target_suffix} gdb_${target_suffix} - vita-headers - newlib - pthread-embedded - samples vdpm vita-makepkg - ${gcc_final_barrier} - ${version_info_file}) + ${target_half_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 diff --git a/tests/cmake/target-half-dependencies.cmake b/tests/cmake/target-half-dependencies.cmake new file mode 100644 index 0000000..8101315 --- /dev/null +++ b/tests/cmake/target-half-dependencies.cmake @@ -0,0 +1,56 @@ +# The export and the finalize barrier wait for the same target half. +# +# They are mutually exclusive -- a producer exports a sysroot for stage 2, any +# other build finalizes its own -- so a piece added to one and forgotten in the +# other is invisible until something reads the result. The softfp shims were +# spliced by finalize-sdk and not by the export, so a staged build handed +# stage 2 a sysroot whose stub archives had never been patched, and the ABI +# contract test found it two jobs later. + +cmake_minimum_required(VERSION 3.16) + +get_filename_component(repository_root "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE) +set(failures 0) + +function(expect_contains path needle description) + file(READ "${repository_root}/${path}" contents) + string(FIND "${contents}" "${needle}" position) + if(position EQUAL -1) + message(SEND_ERROR "FAIL: ${description}") + math(EXPR failures "${failures} + 1") + set(failures ${failures} PARENT_SCOPE) + endif() +endfunction() + +function(expect_absent path needle description) + file(READ "${repository_root}/${path}" contents) + string(FIND "${contents}" "${needle}" position) + if(NOT position EQUAL -1) + message(SEND_ERROR "FAIL: ${description}") + endif() +endfunction() + +# Both consumers take the list; neither spells the target half out again. +expect_contains("cmake/recipes/ExportSysroot.cmake" + "DEPENDS \${target_half_dependencies}" + "the sysroot export does not wait for the target half") +expect_contains("cmake/recipes/FinalizeSdk.cmake" + "\${target_half_dependencies})" + "finalize-sdk does not wait for the target half") + +# The splice belongs to the list and nowhere else, or the two drift again. +expect_absent("cmake/recipes/ExportSysroot.cmake" "softfp-shim" + "ExportSysroot.cmake names softfp-shim itself instead of taking the list") +expect_absent("cmake/recipes/FinalizeSdk.cmake" "softfp-shim" + "FinalizeSdk.cmake names softfp-shim itself instead of taking the list") + +# A softfp world whose shims were never spliced is a toolchain that +# miscompiles quietly, so the list carries them exactly when the world is one. +expect_contains("CMakeLists.txt" + "list(APPEND target_half_dependencies softfp-shim)" + "the softfp splice is not part of the target half") +expect_contains("CMakeLists.txt" + "VITASDK_FLOAT_ABI STREQUAL \"softfp\"" + "nothing decides when the splice belongs to the target half") + +message(STATUS "target half dependency tests passed")