diff options
Diffstat (limited to 'libpsn00b/cmake')
| -rw-r--r-- | libpsn00b/cmake/internal_setup.cmake | 161 | ||||
| -rw-r--r-- | libpsn00b/cmake/sdk.cmake | 89 | ||||
| -rw-r--r-- | libpsn00b/cmake/virtual_targets.cmake | 109 |
3 files changed, 359 insertions, 0 deletions
diff --git a/libpsn00b/cmake/internal_setup.cmake b/libpsn00b/cmake/internal_setup.cmake new file mode 100644 index 0000000..e3d4be7 --- /dev/null +++ b/libpsn00b/cmake/internal_setup.cmake @@ -0,0 +1,161 @@ +# PSn00bSDK internal setup script for CMake +# (C) 2021 spicyjpeg - MPL licensed + +# This script is included automatically when using the toolchain file and +# defines helper functions. + +cmake_minimum_required(VERSION 3.21) +include(GNUInstallDirs) + +# IMPORTANT TODO: set a version number +set(PSN00BSDK_VERSION 0.1.0) + +## Settings (can be overridden by projects) + +set(PSN00BSDK_EXECUTABLE_SUFFIX ".exe") +set(PSN00BSDK_SHARED_LIBRARY_SUFFIX ".dll") +set(PSN00BSDK_SYMBOL_MAP_SUFFIX ".map") + +## SDK libraries + +# DON'T CHANGE THE ORDER or you'll break the libraries' internal dependencies. +set(PSN00BSDK_LIBRARIES psxgpu psxgte psxspu psxcd psxsio psxetc psxapi lzp c) + +include(${CMAKE_CURRENT_LIST_DIR}/libpsn00b.cmake OPTIONAL) +if(NOT TARGET psn00bsdk_common) + include(${CMAKE_CURRENT_LIST_DIR}/virtual_targets.cmake) +endif() + +# Use the toolchain path to find libgcc (used to build libpsn00b). Of course +# different installers, packages and distros have different opinions when it +# comes to deciding where to install toolchains, so we have to bruteforce +# multiple combinations of paths. +if(CMAKE_C_COMPILER_VERSION) + string(REGEX MATCH "^([0-9]+)\." _dummy ${CMAKE_C_COMPILER_VERSION}) + + find_library( + PSN00BSDK_LIBGCC gcc + HINTS + ${PSN00BSDK_TC}/lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} + ${PSN00BSDK_TC}/lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} + ${PSN00BSDK_TC}/lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} + ${PSN00BSDK_TC}/lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} + ${PSN00BSDK_TC}/../lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} + ${PSN00BSDK_TC}/../lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} + ${PSN00BSDK_TC}/../lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} + ${PSN00BSDK_TC}/../lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} + NO_DEFAULT_PATH + DOC "Path to libgcc (bundled with the GCC toolchain)" + ) +endif() + +## Tools + +set( + PSN00BSDK_TOOLS + ${CMAKE_CURRENT_LIST_DIR}/../../../${CMAKE_INSTALL_BINDIR} + ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR} +) + +find_program(ELF2X elf2x HINTS ${PSN00BSDK_TOOLS}) +find_program(ELF2CPE elf2cpe HINTS ${PSN00BSDK_TOOLS}) +find_program(SMXLINK elf2x HINTS ${PSN00BSDK_TOOLS}) +find_program(LZPACK lzpack HINTS ${PSN00BSDK_TOOLS}) +find_program(MKPSXISO mkpsxiso HINTS ${PSN00BSDK_TOOLS}) + +## Helper functions for executables + +set(PSN00BSDK_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/../include) +set(PSN00BSDK_LDSCRIPTS ${CMAKE_CURRENT_LIST_DIR}/../ldscripts) + +# psn00bsdk_add_executable( +# <target name> <STATIC|DYNAMIC> +# [EXCLUDE_FROM_ALL] +# <sources> ... +# ) +function(psn00bsdk_add_executable name type) + string(TOLOWER ${type} _type) + if(NOT ${_type} MATCHES "^(static|dynamic)$") + message(FATAL_ERROR "Invalid executable type: ${type} (must be STATIC or DYNAMIC)") + endif() + + add_executable (${name} ${ARGN}) + target_link_libraries(${name} psn00bsdk_${_type}_exe) + set_target_properties(${name} PROPERTIES PREFIX "" SUFFIX ".elf") + target_link_options (${name} PRIVATE -T${PSN00BSDK_LDSCRIPTS}/exe.ld) + + target_include_directories(${name} PRIVATE ${PSN00BSDK_INCLUDE}) + + # Add post-build steps to generate the .exe and symbol map once the + # executable is built. CMake 3.21 added support for target-dependent + # generator expressions (catchy name lol) in add_custom_command(), so I'm + # making heavy use of those here. + add_custom_command( + TARGET ${name} POST_BUILD + COMMAND ${ELF2X} -q ${name}.elf ${name}${PSN00BSDK_EXECUTABLE_SUFFIX} + COMMAND ${TOOLCHAIN_NM} -f posix -l -n ${name}.elf $<ANGLE-R>${name}${PSN00BSDK_SYMBOL_MAP_SUFFIX} + BYPRODUCTS ${name}${PSN00BSDK_EXECUTABLE_SUFFIX} ${name}${PSN00BSDK_SYMBOL_MAP_SUFFIX} + ) +endfunction() + +# psn00bsdk_add_library( +# <target name> <STATIC|SHARED|MODULE> +# [EXCLUDE_FROM_ALL] +# <sources> ... +# ) +# Note that SHARED and MODULE have the same meaning (both will create a DLL). +# SDK libraries are NOT statically linked in by default; if you need to link +# something, use target_link_libraries() manually. +function(psn00bsdk_add_library name type) + string(TOUPPER ${type} _type_upper) + string(TOLOWER ${type} _type) + if(NOT ${_type} MATCHES "^(static|object|shared|module)$") + message(FATAL_ERROR "Invalid library type: ${type} (must be STATIC, OBJECT, SHARED or MODULE)") + endif() + + add_library (${name} ${_type_upper} ${ARGN}) + target_link_libraries(${name} psn00bsdk_${_type}_lib) + + target_include_directories(${name} PRIVATE ${PSN00BSDK_INCLUDE}) + + if(${_type} MATCHES "^(shared|module)$") + set_target_properties(${name} PROPERTIES PREFIX "" SUFFIX ".so") + target_link_options (${name} PRIVATE -T${PSN00BSDK_LDSCRIPTS}/dll.ld) + + # Add a post-build step to dump the DLL's raw contents into a new file + # separate from the built ELF. + add_custom_command( + TARGET ${name} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} -O binary ${name}.so ${name}${PSN00BSDK_SHARED_LIBRARY_SUFFIX} + BYPRODUCTS ${name}${PSN00BSDK_SHARED_LIBRARY_SUFFIX} + ) + else() + set_target_properties(${name} PROPERTIES PREFIX "lib" SUFFIX ".a") + + # Remove virtual target dependencies to make sure linking against the + # library does not also propagate static library flags. + set_target_properties(${name} PROPERTIES INTERFACE_LINK_LIBRARIES "") + endif() +endfunction() + +# psn00bsdk_add_cd_image( +# <target name> +# <image file name> +# <mkpsxiso config template> +# [DEPENDS <dependencies> ...] +# [additional options passed to add_custom_target()] +# ) +function(psn00bsdk_add_cd_image name image_name config_file) + set(CD_IMAGE_NAME ${image_name}) + configure_file(${config_file} _gen_${config_file}) + + add_custom_target( + ${name} ALL + COMMAND ${MKPSXISO} -y -q _gen_${config_file} + BYPRODUCTS ${image_name}.bin ${image_name}.cue + COMMENT "Building CD image ${image_name}" + ${ARGN} + ) +endfunction() + +## Helper functions for assets (TODO) diff --git a/libpsn00b/cmake/sdk.cmake b/libpsn00b/cmake/sdk.cmake new file mode 100644 index 0000000..4c2f330 --- /dev/null +++ b/libpsn00b/cmake/sdk.cmake @@ -0,0 +1,89 @@ +# PSn00bSDK toolchain setup file for CMake +# (C) 2021 spicyjpeg - MPL licensed + +cmake_minimum_required(VERSION 3.21) + +set( + PSN00BSDK_TC $ENV{PSN00BSDK_TC} + CACHE PATH "Path to the GCC toolchain's installation directory" +) +set( + PSN00BSDK_TARGET mipsel-unknown-elf + CACHE STRING "GCC toolchain target triplet" +) + +## CMake configuration + +set(CMAKE_SYSTEM_NAME PlayStation) +set(CMAKE_SYSTEM_PROCESSOR mipsel) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +#set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +# Tell CMake not to run the linker when compiling test programs, and to pass +# toolchain settings to the generated test projects. This dodges missing C++ +# standard library errors. +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES PSN00BSDK_TC PSN00BSDK_TARGET) + +## Toolchain path setup + +# Attempt to find GCC using a list of common installation locations. +# PSN00BSDK_TC can be left unset if the toolchain can be found in any of these +# or in the PATH environment variable. +find_program( + _gcc ${PSN00BSDK_TARGET}-gcc + HINTS + ${PSN00BSDK_TC}/bin + ${PSN00BSDK_TC}/../bin + # Same as ${CMAKE_INSTALL_PREFIX}/${PSN00BSDK_TARGET}/bin + ${CMAKE_CURRENT_LIST_DIR}/../../../${PSN00BSDK_TARGET}/bin + PATHS + "C:/Program Files/${PSN00BSDK_TARGET}/bin" + "C:/Program Files (x86)/${PSN00BSDK_TARGET}/bin" + "C:/${PSN00BSDK_TARGET}/bin" + /opt/${PSN00BSDK_TARGET}/bin + /usr/local/${PSN00BSDK_TARGET}/bin + /usr/${PSN00BSDK_TARGET}/bin + NO_CACHE REQUIRED +) +cmake_path(GET _gcc PARENT_PATH _bin) +cmake_path(GET _bin PARENT_PATH _toolchain) + +# Overwrite the empty cache entry, so it won't have to be found again. +if(NOT IS_DIRECTORY PSN00BSDK_TC) + set( + PSN00BSDK_TC ${_toolchain} + CACHE PATH "Path to the GCC toolchain's installation directory" + FORCE + ) +endif() + +## Toolchain executables + +# ${CMAKE_EXECUTABLE_SUFFIX} seems not to work in toolchain scripts, so we +# can't rely on it to determine the host OS extension for executables. The best +# workaround I found is to extract the extension from the path returned by +# find_program() using a regex. +set(_prefix ${_bin}/${PSN00BSDK_TARGET}) +string(REGEX MATCH ".+-gcc(.*)$" _dummy ${_gcc}) + +set(CMAKE_ASM_COMPILER ${_prefix}-gcc${CMAKE_MATCH_1}) +set(CMAKE_C_COMPILER ${_prefix}-gcc${CMAKE_MATCH_1}) +set(CMAKE_CXX_COMPILER ${_prefix}-g++${CMAKE_MATCH_1}) +set(CMAKE_AR ${_prefix}-ar${CMAKE_MATCH_1}) +set(CMAKE_LINKER ${_prefix}-ld${CMAKE_MATCH_1}) +set(CMAKE_RANLIB ${_prefix}-ranlib${CMAKE_MATCH_1}) +set(CMAKE_OBJCOPY ${_prefix}-objcopy${CMAKE_MATCH_1}) +set(CMAKE_SIZE ${_prefix}-size${CMAKE_MATCH_1}) +set(CMAKE_STRIP ${_prefix}-strip${CMAKE_MATCH_1}) +set(TOOLCHAIN_NM ${_prefix}-nm${CMAKE_MATCH_1}) + +## SDK setup + +# We can't set up the SDK here as the find_*() functions may fail if they are +# called before project(). We can however set a script to be executed right +# after project() is invoked. +set(CMAKE_PROJECT_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/internal_setup.cmake) diff --git a/libpsn00b/cmake/virtual_targets.cmake b/libpsn00b/cmake/virtual_targets.cmake new file mode 100644 index 0000000..df1df79 --- /dev/null +++ b/libpsn00b/cmake/virtual_targets.cmake @@ -0,0 +1,109 @@ +# libpsn00b interface targets +# (C) 2021 spicyjpeg - MPL licensed + +# This script creates several "virtual" targets (psn00bsdk_*) that set include +# directories and compiler flags when a target is linked against them. These +# all end up in the autogenerated libpsn00b setup script after installation, +# so this file is only included when building libpsn00b. + +# The following targets are currently defined: +# - psn00bsdk_common +# - psn00bsdk_object_lib (same as psn00bsdk_common) +# - psn00bsdk_static_exe +# - psn00bsdk_dynamic_exe +# - psn00bsdk_static_lib +# - psn00bsdk_shared_lib +# - psn00bsdk_module_lib (same as psn00bsdk_shared_lib) + +include(GNUInstallDirs) + +set(PSN00BSDK_VIRTUAL_TARGETS "") + +macro(_add_interface_target name) + add_library(${name} INTERFACE) + list(APPEND PSN00BSDK_VIRTUAL_TARGETS ${name}) + + target_compile_options( + ${name} INTERFACE + ${_aflags} + $<$<COMPILE_LANGUAGE:C,CXX>:${_cflags}> + $<$<COMPILE_LANGUAGE:CXX>:${_cxxflags}> + ) + target_link_options (${name} INTERFACE ${_ldflags}) + target_link_libraries(${name} INTERFACE ${ARGN}) +endmacro() + +macro(_add_alias_target name) + #add_library(${name} ALIAS ${ARGN}) + add_library(${name} INTERFACE) + list(APPEND PSN00BSDK_VIRTUAL_TARGETS ${name}) + + target_link_libraries(${name} INTERFACE ${ARGN}) +endmacro() + +# Options common to all target types: +# - Define PLAYSTATION=1 and set include directories +# - Optimize for MIPS R3000 +# - Inject zero checks into division operations (will throw breaks) +# - All standard libraries (including libgcc) disabled +# - Put all symbols into separate sections when building +# - C++ features that require runtime support disabled +# - Unused section stripping enabled +set(_aflags -msoft-float -march=r3000 -mtune=r3000 -mabi=32) +set(_cflags -mdivide-breaks -O2 -ffreestanding -fno-builtin -nostdlib -fdata-sections -ffunction-sections -fsigned-char -fno-strict-overflow -fdiagnostics-color=always) +set(_cxxflags -fno-exceptions -fno-rtti -fno-unwind-tables -fno-threadsafe-statics -fno-use-cxa-atexit) +set(_ldflags -nostdlib -Wl,-gc-sections) + +_add_interface_target(psn00bsdk_common) +_add_alias_target (psn00bsdk_object_lib psn00bsdk_common) + +target_compile_definitions( + psn00bsdk_common INTERFACE + PLAYSTATION=1 + $<$<CONFIG:DEBUG>:DEBUG=1> +) + +# Options for executables without support for dynamic linking: +# - Position-independent code disabled +# - GP-relative addressing enabled only for local symbols +# - ABI-compatible calls disabled (incompatible with GP-relative addr) +set(_aflags -G8) +set(_cflags -mno-abicalls -mgpopt -mno-extern-sdata) +set(_cxxflags) +set(_ldflags -G8 -static) + +_add_interface_target(psn00bsdk_static_exe psn00bsdk_common ${PSN00BSDK_LIBRARIES}) + +# Options for executables with support for dynamic linking: +# - Position-independent code disabled +# - GP-relative addressing disabled +# - ABI-compatible calls disabled (must be performed manually) +set(_aflags -G0) +set(_cflags -mno-abicalls -mno-gpopt) +set(_cxxflags) +set(_ldflags -G0 -static) + +_add_interface_target(psn00bsdk_dynamic_exe psn00bsdk_common ${PSN00BSDK_LIBRARIES}) + +# Options for static libraries: +# - GP-relative addressing disabled +# - ABI-compatible calls disabled +# - Local stripping enabled +set(_aflags -G0 -Wa,--strip-local-absolute) +set(_cflags -mno-abicalls -mno-gpopt) +set(_cxxflags) +set(_ldflags) + +_add_interface_target(psn00bsdk_static_lib psn00bsdk_common) + +# Options for dynamically-loaded libraries: +# - Position-independent code enabled +# - GP-relative addressing disabled (incompatible with ABI calls) +# - ABI-compatible calls enabled +set(_aflags -G0) +set(_cflags -mabicalls -mshared -mno-gpopt -fPIC) +set(_cxxflags) +set(_ldflags -G0 -shared) + +_add_interface_target(psn00bsdk_shared_lib psn00bsdk_common) +_add_alias_target (psn00bsdk_module_lib psn00bsdk_shared_lib) |
