aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn "Lameguy" Wilbert Villamor <lameguy64@gmail.com>2021-10-25 08:18:23 +0800
committerGitHub <noreply@github.com>2021-10-25 08:18:23 +0800
commit8d17a5abe3c600b603f1910239d5df0fff9f4eed (patch)
tree20d3110363ab468e99502337c0a46852662bb365
parent0a7f59de1eb079930e7c25ad35adc39c9946958c (diff)
parent4e0d5bceb24042a6d31c76958ce2c6157369ac68 (diff)
downloadpsn00bsdk-8d17a5abe3c600b603f1910239d5df0fff9f4eed.tar.gz
Merge pull request #41 from spicyjpeg/cmake
CMake fixes, Windows build instructions
-rw-r--r--CMakeLists.txt106
-rw-r--r--INSTALL.md124
-rw-r--r--TOOLCHAIN.md223
-rw-r--r--changelog.txt16
-rw-r--r--cpack/setup.cmake184
-rw-r--r--doc/dev notes.txt20
-rw-r--r--examples/sound/vagsample/CMakeLists.txt22
-rw-r--r--examples/sound/vagsample/makefile65
-rw-r--r--examples/system/dynlink/main.c10
-rw-r--r--libpsn00b/CMakeLists.txt9
-rw-r--r--libpsn00b/cmake/internal_setup.cmake17
-rw-r--r--libpsn00b/include/dlfcn.h25
-rw-r--r--libpsn00b/psxetc/dl.c206
-rw-r--r--libpsn00b/readme.txt32
-rw-r--r--toolchain.txt171
15 files changed, 771 insertions, 459 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5097a50..431e95b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,6 +22,8 @@ project(
# there's no way to mute it.
include(GNUInstallDirs)
+## Settings
+
# These are passed through to libpsn00b and the examples (they are defined in
# the toolchain file).
set(
@@ -34,8 +36,12 @@ set(
)
set(
- SKIP_DOWNLOAD OFF
- CACHE BOOL "Skip downloading and building tinyxml2 and mkpsxiso"
+ SKIP_TINYXML2 OFF
+ CACHE BOOL "Skip downloading and building tinyxml2 (if already installed)"
+)
+set(
+ SKIP_MKPSXISO OFF
+ CACHE BOOL "Skip downloading and building mkpsxiso (if already installed)"
)
set(
SKIP_EXAMPLES OFF
@@ -49,50 +55,55 @@ set(
# invoked (ExternalProject_Add() runs the subprojects' install step at build
# time).
set(
- SUBPROJECT_ARGS
+ COMMON_ARGS
-DPSN00BSDK_TC:PATH=${PSN00BSDK_TC}
-DPSN00BSDK_TARGET:STRING=${PSN00BSDK_TARGET}
+ -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+)
+set(
+ EXT_LIBRARY_ARGS
+ -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}
+ -DCMAKE_INSTALL_PREFIX:PATH=${PROJECT_BINARY_DIR}/install_temp
+ -DCMAKE_MSVC_RUNTIME_LIBRARY:STRING=MultiThreaded$<$<CONFIG:Debug>:Debug>
+)
+set(
+ SUBPROJECT_ARGS
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}
-DCMAKE_INSTALL_PREFIX:PATH=${PROJECT_BINARY_DIR}/install_tree
- -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
)
set(
EXAMPLES_ARGS
- -DPSN00BSDK_TC:PATH=${PSN00BSDK_TC}
- -DPSN00BSDK_TARGET:STRING=${PSN00BSDK_TARGET}
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${PROJECT_BINARY_DIR}/install_tree/${CMAKE_INSTALL_LIBDIR}/libpsn00b/cmake/sdk.cmake
-DCMAKE_INSTALL_PREFIX:PATH=${PROJECT_BINARY_DIR}/examples
- -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
)
## External dependencies
-if(NOT SKIP_DOWNLOAD)
+if(NOT SKIP_TINYXML2)
list(APPEND SUBPROJECT_ARGS -Dtinyxml2_ROOT:PATH=${PROJECT_BINARY_DIR}/install_temp)
ExternalProject_Add(
tinyxml2
GIT_REPOSITORY "https://github.com/leethomason/tinyxml2"
- CMAKE_CACHE_ARGS
- -DCMAKE_INSTALL_PREFIX:PATH=${PROJECT_BINARY_DIR}/install_temp
- -DCMAKE_MSVC_RUNTIME_LIBRARY:STRING=MultiThreaded$<$<CONFIG:Debug>:Debug>
+ CMAKE_CACHE_ARGS ${COMMON_ARGS} ${EXT_LIBRARY_ARGS}
INSTALL_DIR install_temp
)
+else()
+ list(APPEND SUBPROJECT_ARGS -Dtinyxml2_ROOT:PATH=${tinyxml2_ROOT})
+
+ # Create a dummy target so CMake doesn't throw missing dependency errors.
+ add_library(tinyxml2 INTERFACE)
+endif()
+
+if(NOT SKIP_MKPSXISO)
ExternalProject_Add(
mkpsxiso
- # IMPORTANT TODO: migrate to Lameguy64/mkpsxiso once PR #18 is merged
GIT_REPOSITORY "https://github.com/Lameguy64/mkpsxiso"
- GIT_TAG cmake
- #GIT_REPOSITORY "https://github.com/Lameguy64/mkpsxiso"
- CMAKE_CACHE_ARGS ${SUBPROJECT_ARGS}
+ CMAKE_CACHE_ARGS ${COMMON_ARGS} ${SUBPROJECT_ARGS}
INSTALL_DIR install_tree
DEPENDS tinyxml2
)
else()
- list(APPEND SUBPROJECT_ARGS -Dtinyxml2_ROOT:PATH=${tinyxml2_ROOT})
-
- # Create dummy targets so CMake doesn't throw missing dependency errors.
- add_library(tinyxml2 INTERFACE)
add_library(mkpsxiso INTERFACE)
endif()
@@ -101,21 +112,21 @@ endif()
ExternalProject_Add(
libpsn00b
SOURCE_DIR ${PROJECT_SOURCE_DIR}/libpsn00b
- CMAKE_CACHE_ARGS ${SUBPROJECT_ARGS}
+ CMAKE_CACHE_ARGS ${COMMON_ARGS} ${SUBPROJECT_ARGS}
INSTALL_DIR install_tree
)
ExternalProject_Add(
tools
SOURCE_DIR ${PROJECT_SOURCE_DIR}/tools
- CMAKE_CACHE_ARGS ${SUBPROJECT_ARGS}
+ CMAKE_CACHE_ARGS ${COMMON_ARGS} ${SUBPROJECT_ARGS}
INSTALL_DIR install_tree
DEPENDS tinyxml2
)
ExternalProject_Add(
examples
SOURCE_DIR ${PROJECT_SOURCE_DIR}/examples
- CMAKE_CACHE_ARGS ${EXAMPLES_ARGS}
- INSTALL_DIR install_tree
+ CMAKE_CACHE_ARGS ${COMMON_ARGS} ${EXAMPLES_ARGS}
+ INSTALL_DIR examples
DEPENDS libpsn00b tools mkpsxiso
EXCLUDE_FROM_ALL ${SKIP_EXAMPLES}
)
@@ -125,58 +136,15 @@ ExternalProject_Add(
install(
DIRECTORY ${PROJECT_BINARY_DIR}/install_tree/ # THE TRAILING SLASH IS IMPORTANT
DESTINATION .
+ COMPONENT sdk
USE_SOURCE_PERMISSIONS
)
install(
DIRECTORY doc template
DESTINATION ${CMAKE_INSTALL_DATADIR}/psn00bsdk
+ COMPONENT docs
)
## CPack configuration
-if(WIN32)
- set(CPACK_GENERATOR ZIP NSIS)
-elseif(APPLE)
- # TODO: add a macOS installer and related options
- set(CPACK_GENERATOR ZIP)
-elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
- set(CPACK_GENERATOR ZIP DEB RPM)
-else()
- set(CPACK_GENERATOR ZIP)
-endif()
-
-set(CPACK_PACKAGE_DIRECTORY ${PROJECT_BINARY_DIR}/cpack)
-set(CPACK_PACKAGE_NAME PSn00bSDK)
-set(CPACK_PACKAGE_VENDOR Lameguy64)
-set(CPACK_PACKAGE_CONTACT Lameguy64)
-set(CPACK_PACKAGE_ICON ${PROJECT_SOURCE_DIR}/cpack/icon.ico)
-set(CPACK_PACKAGE_DESCRIPTION_FILE ${PROJECT_SOURCE_DIR}/cpack/description.txt)
-set(CPACK_RESOURCE_FILE_WELCOME ${PROJECT_SOURCE_DIR}/cpack/welcome.txt)
-set(CPACK_RESOURCE_FILE_README ${PROJECT_SOURCE_DIR}/README.md)
-set(CPACK_RESOURCE_FILE_LICENSE ${PROJECT_SOURCE_DIR}/LICENSE.md)
-set(CPACK_PRE_BUILD_SCRIPTS ${PROJECT_SOURCE_DIR}/cpack/fakeroot_fix.cmake)
-
-set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.28), cmake (>= 3.21), gcc-mipsel-unknown-elf")
-set(CPACK_DEBIAN_PACKAGE_SUGGESTS "git")
-set(CPACK_DEBIAN_PACKAGE_SECTION devel)
-set(CPACK_RPM_PACKAGE_REQUIRES "cmake >= 3.21, gcc-mipsel-unknown-elf")
-set(CPACK_RPM_PACKAGE_SUGGESTS "git")
-#set(CPACK_RPM_PACKAGE_RELOCATABLE ON)
-
-set(CPACK_NSIS_MUI_ICON ${PROJECT_SOURCE_DIR}/cpack/icon.ico)
-set(CPACK_NSIS_MUI_UNIICON ${PROJECT_SOURCE_DIR}/cpack/uninstall.ico)
-set(CPACK_NSIS_MUI_HEADERIMAGE ${PROJECT_SOURCE_DIR}/cpack/nsis_header.bmp)
-set(CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP ${PROJECT_SOURCE_DIR}/cpack/nsis_banner.bmp)
-set(CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP ${PROJECT_SOURCE_DIR}/cpack/nsis_banner.bmp)
-set(CPACK_NSIS_BRANDING_TEXT "PSn00bSDK - Meido-Tek Productions")
-set(CPACK_NSIS_URL_INFO_ABOUT "${PROJECT_HOMEPAGE_URL}")
-set(CPACK_NSIS_MODIFY_PATH ON)
-set(
- CPACK_NSIS_MENU_LINKS
- "${PROJECT_HOMEPAGE_URL}" "About PSn00bSDK"
- "https://github.com/Lameguy64/PSn00bSDK" "GitHub repo"
-)
-
-# This will generate a CPack configuration file and add a "package" target to
-# launch CPack.
-include(CPack)
+include(cpack/setup.cmake)
diff --git a/INSTALL.md b/INSTALL.md
index 6547c2b..6fac934 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -6,27 +6,33 @@
The instructions below are for Windows and Linux. Building on macOS hasn't been
tested but should work.
-1. Install a host C compiler toolchain if you don't already have one (this is
- required to build the tools). You can use MSVC or MinGW on Windows, or
- install the `build-essential` package provided by most Linux distros.
-
-2. Install Git and CMake. Note that some Linux distros ship relatively old
- versions of CMake, so make sure you have at least CMake 3.21. You will also
- need [Ninja](https://ninja-build.org) (it is a single executable, you have to
- copy it to any directory listed in the `PATH` environment variable) on
- Windows as there is no preinstalled build system; on Linux you can use `make`
- instead, but Ninja is still recommended.
-
-3. Build and install a GCC toolchain for `mipsel-unknown-elf`. As GCC is
- notoriously hard to compile under Windows, you may download a precompiled
+1. Set up a host compiler. Most Linux distros provide a `build-essential`,
+ `base-devel` or similar all-in-one package. You'll also need to install the
+ [Ninja](https://ninja-build.org) build engine (it's usually in a package
+ called `ninja-build`). On Windows install [MSys2](https://www.msys2.org),
+ then run the following command in the MSys2 shell to install MinGW and Ninja:
+
+ ```bash
+ pacman -Syu mingw-w64-x86_64-gcc mingw-w64-x86_64-ninja
+ ```
+
+ Add `C:\msys64\mingw64\bin` (replace `C:\msys64` if you installed MSys2 to a
+ different location) to the `PATH` environment variable using System
+ Properties.
+
+2. Install Git and CMake. Note that MSys2 and some Linux distros ship relatively
+ old versions (PSn00bSDK requires 3.21+), so grab the latest CMake release
+ from [here](https://cmake.org) instead of through your package manager.
+
+3. Build and install a GCC toolchain for `mipsel-unknown-elf`, as detailed in
+ [TOOLCHAIN.md](TOOLCHAIN.md). On Windows, you may download a precompiled
version from [Lameguy64's website](http://lameguy64.net?page=psn00bsdk) and
- and extract it into Program Files instead. See [toolchain.txt](toolchain.txt)
- for details on compiling GCC.
+ extract it into one of the directories listed below instead.
-4. If you chose a non-standard install location for the toolchain, set the
- `PSN00BSDK_TC` environment variable to point to the toolchain's root
- directory. This step is unnecessary if you installed/extracted the toolchain
- into any of these directories:
+4. If you chose a non-standard install location for the toolchain, add the `bin`
+ subfolder (inside the top-level toolchain directory) to the `PATH`
+ environment variable. This step is unnecessary if you installed/extracted the
+ toolchain into any of these directories:
- `C:\Program Files\mipsel-unknown-elf`
- `C:\Program Files (x86)\mipsel-unknown-elf`
@@ -35,49 +41,84 @@ tested but should work.
- `/usr/mipsel-unknown-elf`
- `/opt/mipsel-unknown-elf`
-5. Clone/download the PSn00bSDK repo and run the following commands:
+5. Clone/download the PSn00bSDK repo and run the following commands from its
+ directory:
```bash
- cmake -S . -B ./build -G Ninja --install-prefix INSTALL_PATH
+ cmake -S . -B ./build -G Ninja
cmake --build ./build
+ ```
+
+ If you want to install the SDK to a custom location rather than the default
+ one (`C:\Program Files\PSn00bSDK` or `/usr/local` depending on your OS), add
+ `--install-prefix <INSTALL_PATH>` to the first command. Remove `-G Ninja` to
+ use `make` instead of Ninja (slower, not recommended).
+
+ If you run into errors, try passing `-DSKIP_TINYXML2=ON` to the first command
+ after installing `tinyxml2` manually. [See below](#advanced-build-options)
+ for more details.
+
+6. Install the SDK to the path you chose by running this command (add `sudo` if
+ necessary):
+
+ ```bash
cmake --install ./build
```
- Replace `INSTALL_PATH` with the directory you want PSn00bSDK to be installed
- to (default is `C:\Program Files\PSn00bSDK` or `/usr/local`), and remove
- `-G Ninja` if you want to use `make` instead (not recommended). The following
- subdirectories will be created:
+ This will create and populate the following directories:
- - `INSTALL_PATH/bin`
- - `INSTALL_PATH/lib/libpsn00b`
- - `INSTALL_PATH/share/psn00bsdk`
+ - `<INSTALL_PATH>/bin`
+ - `<INSTALL_PATH>/lib/libpsn00b`
+ - `<INSTALL_PATH>/share/psn00bsdk`
-6. Set the `PSN00BSDK_LIBS` environment variable to
- `INSTALL_PATH/lib/libpsn00b` and add `INSTALL_PATH/bin` to `PATH`.
+7. Set the `PSN00BSDK_LIBS` environment variable to point to the `lib/libpsn00b`
+ subfolder inside the install directory. You might also want to add the `bin`
+ folder to `PATH` if it's not listed already.
Although not strictly required, you'll probably want to install a PS1 emulator
with debugging capabilities such as [no$psx](https://problemkaputt.de/psx.htm)
-(Windows only) or [pcsx-redux](https://github.com/grumpycoders/pcsx-redux).
+(Windows only), [DuckStation](https://github.com/stenzek/duckstation) or
+[pcsx-redux](https://github.com/grumpycoders/pcsx-redux).
**Avoid ePSXe and anything based on MAME** as they are inaccurate.
-## Building installer packages
+## Advanced build options
+
+### Skipping external dependency downloads
+
+By default [mkpsxiso](https://github.com/Lameguy64/mkpsxiso) (required for
+building CD images) and [tinyxml2](https://github.com/leethomason/tinyxml2)
+(required to build mkpsxiso and other SDK tools) are automatically cloned from
+their respective repos and built as part of the PSn00bSDK build process,
+*even if they are already installed*.
+
+If you wish to disable this behavior (e.g. because it leads to errors, or to
+perform an offline build), invoke CMake with the `-DSKIP_MKPSXISO=ON` and/or
+`-DSKIP_TINYXML2=ON` options when configuring the SDK. Note that you must have
+`mkpsxiso` and/or `tinyxml2` already installed (either manually or via vcpkg or
+your distro's package manager) to be able to skip them.
+
+### Building installer packages
CPack can be used to build NSIS-based installers, DEB/RPM packages and zipped
-releases. Note that currently none of the built packages include the toolchain,
-thus their usefulness is limited. Distributing prebuilt releases is discouraged
-anyway since PSn00bSDK is still far from being feature-complete.
+releases that include built SDK libraries, headers as well as the GCC toolchain.
+Distributing prebuilt releases is however discouraged since PSn00bSDK is still
+far from being feature-complete.
-1. Follow steps 1-4 above to set up the toolchain, then install NSIS on Windows
- or `dpkg` and `rpm` on Linux.
+1. Follow steps 1-4 above to set up the toolchain, then install
+ [NSIS](https://nsis.sourceforge.io/Download) on Windows or `dpkg` and `rpm`
+ on Linux.
2. Run the following commands from the PSn00bSDK directory:
```bash
- cmake -S . -B ./build -G Ninja
+ cmake -S . -B ./build -G Ninja -DBUNDLE_TOOLCHAIN=ON
cmake --build ./build -t package
```
- All built packages will be copied to the `build/cpack` folder.
+ All built packages will be copied to the `build/packages` folder.
+
+ **NOTE**: do not use `-DSKIP_MKPSXISO=ON`, otherwise the mkpsxiso binary will
+ not be included in the packages.
## Creating a project
@@ -89,7 +130,6 @@ anyway since PSn00bSDK is still far from being feature-complete.
```bash
cmake -S . -B ./build -G Ninja
cmake --build ./build
- cmake --install ./build
```
If you did everything correctly there should be a `template.bin` CD image in
@@ -99,10 +139,10 @@ Note that, even though the template relies on the `PSN00BSDK_LIBS` environment
variable to locate the SDK by default, you can also specify the path directly
on the CMake command line by adding
`-DCMAKE_TOOLCHAIN_FILE=INSTALL_PATH/lib/libpsn00b/cmake/sdk.cmake` (replace
-`INSTALL_PATH` as usual) to the first command.
+`INSTALL_PATH`) to the first command.
The toolchain script defines a few CMake macros to create PS1 executables, DLLs
and CD images. See the [reference](doc/cmake_reference.md) for details.
-----------------------------------------
-_Last updated on 2021-09-26 by spicyjpeg_
+_Last updated on 2021-10-18 by spicyjpeg_
diff --git a/TOOLCHAIN.md b/TOOLCHAIN.md
new file mode 100644
index 0000000..8ecee38
--- /dev/null
+++ b/TOOLCHAIN.md
@@ -0,0 +1,223 @@
+
+# Building the GCC toolchain
+
+If you wish to build the toolchain yourself, beware that this process can get
+pretty tedious if your machine is not fairly recent. Ensure you have at least a
+quad-core processor and 4 GB of free space before continuing.
+
+You'll need a Linux environment, even if you want to build a Windows toolchain
+(as GCC is basically impossible to build under Windows but can be cross-compiled
+via MinGW). Due to how the GCC build process works, you'll have to build a Linux
+version of the toolchain first to be able to compile it for Windows. This
+basically means you will have to build the whole toolchain twice if you want to
+target Windows.
+
+These instructions are for Debian/Ubuntu, however it should be relatively easy
+to follow them if you are using another distro. If you do not have access to a
+Linux system already, consider spinning up a VM (a headless Debian or Ubuntu
+Server install is recommended) or using WSL, whose setup is out of the scope of
+this guide.
+
+## Choosing a GCC version
+
+PSn00bSDK *should* work with any GCC version. In most cases you'll want to get
+the latest stable release of GCC and binutils. If for some reason you are having
+problems you may try building one of the following versions, which have been
+tested extensively:
+
+- GCC **7.4.0** with binutils **2.31**
+- GCC **11.2.0** with binutils **2.37**
+
+If you wish to pick an older GCC release but don't know which binutils version
+it requires, see [here](https://wiki.osdev.org/Cross-Compiler_Successful_Builds)
+for a compatibility table.
+
+## Downloading GCC
+
+1. Run the following commands to install a host toolchain and prerequisites
+ (adapt them for non-Debian distros if necessary):
+
+ ```bash
+ sudo apt update
+ sudo apt install -y build-essential make wget
+ ```
+
+2. Create an empty directory to store build artifacts in. You'll be able to
+ delete it once the toolchain is installed.
+
+3. Download the GCC and binutils source packages from
+ [here](https://ftpmirror.gnu.org/gnu) and unzip them into the folder you
+ created, or run the following commands to do the same (replace `<VERSION>`
+ with the versions you chose):
+
+ ```bash
+ wget https://ftpmirror.gnu.org/gnu/binutils/binutils-<VERSION>.tar.xz
+ wget https://ftpmirror.gnu.org/gnu/gcc/gcc-<VERSION>/gcc-<VERSION>.tar.xz
+ tar xvf binutils-<VERSION>.tar.xz
+ tar xvf gcc-<VERSION>.tar.xz
+ rm -f *.tar.xz
+ ```
+
+4. From the extracted GCC directory run the `download_prerequisites` script to
+ download additional dependencies:
+
+ ```bash
+ cd gcc-<VERSION>
+ ./contrib/download_prerequisites
+ ```
+
+## Building binutils
+
+1. Go back to the folder you made earlier and create a new subdirectory to build
+ binutils in (don't create it inside the extracted binutils source directory).
+ Call it `binutils-build` or whatever.
+
+2. Run the binutils configuration script from that folder:
+
+ ```bash
+ ../binutils-<VERSION>/configure \
+ --prefix=/usr/local/mipsel-unknown-elf --target=mipsel-unknown-elf \
+ --disable-docs --disable-nls --with-float=soft
+ ```
+
+ Replace `<VERSION>` as usual. If you don't want to install the toolchain into
+ `/usr/local/mipsel-unknown-elf` you can change the `--prefix` option.
+
+3. Compile and install binutils (this will take a few minutes to finish):
+
+ ```bash
+ make -j 4
+ sudo make install-strip
+ ```
+
+ Increase `-j 4` to speed up the build if your machine or VM has more than 4
+ CPU cores.
+
+ **NOTE**: if the build fails with a "`uint` undeclared" or similar error, try
+ editing the source file that caused the error and pasting this line at the
+ beginning:
+
+ ```c
+ typedef unsigned int uint;
+ ```
+
+ Rerun `make` to resume the build after saving the file.
+
+## Building GCC
+
+The process is mostly the same as binutils, just with different configuration
+options.
+
+1. Go back to the main directory and create an empty `gcc-build` (or whatever)
+ subfolder.
+
+2. Run the GCC configuration script from there:
+
+ ```bash
+ ../gcc-<VERSION>/configure \
+ --prefix=/usr/local/mipsel-unknown-elf --target=mipsel-unknown-elf \
+ --disable-docs --disable-nls --disable-libada --disable-libssp \
+ --disable-libquadmath --disable-libstdc++-v3 --with-float=soft \
+ --enable-languages=c,c++ --with-gnu-as --with-gnu-ld
+ ```
+
+ If you previously set a custom installation path, remember to set it here as
+ well (it must be the same).
+
+3. Compile and install GCC (will take a long time, usually around half an hour):
+
+ ```bash
+ make -j 4
+ sudo make install-strip
+ ```
+
+ Increase `-j 4` to speed up the build if your machine or VM has more than 4
+ threads.
+
+4. Add the toolchain to the `PATH` environment variable. This is required to
+ rebuild the toolchain for Windows (see below), but it will also allow
+ PSn00bSDK to find the toolchain if you installed it in a custom location.
+
+ Edit the `.bashrc` or `.bash_profile` file in your home directory and add
+ this line at the end (replace the path with the install location you chose
+ earlier, but keep the `/bin` at the end):
+
+ ```bash
+ export PATH=$PATH:/usr/local/mipsel-unknown-elf/bin
+ ```
+
+ Restart the shell by closing and reopening the terminal window or SSH
+ connection afterwards.
+
+## Rebuilding for Windows
+
+At this point you should be able to build and install PSn00bSDK on your Linux
+system. The instructions below are for building a second copy of the toolchain
+that runs on Windows.
+
+1. Install the MinGW host toolchain:
+
+ ```bash
+ sudo apt install -y g++-mingw-w64-x86-64
+ ```
+
+2. Create two new `binutils-win` and `gcc-win` folders in the directory you
+ extracted/built everything in.
+
+3. From the `binutils-win` directory, rerun the binutils configuration script
+ with the following options (do not change the installation path):
+
+ ```bash
+ ../binutils-<VERSION>/configure \
+ --build=x86_64-linux-gnu --host=x86_64-w64-mingw32 \
+ --prefix=/tmp/mipsel-unknown-elf --target=mipsel-unknown-elf \
+ --disable-docs --disable-nls --with-float=soft
+ ```
+
+ Then build binutils again:
+
+ ```bash
+ make -j 4
+ make install-strip
+ ```
+
+4. Do the same for GCC from the `gcc-win` directory:
+
+ ```bash
+ ../gcc-<VERSION>/configure \
+ --build=x86_64-linux-gnu --host=x86_64-w64-mingw32 \
+ --prefix=/tmp/mipsel-unknown-elf --target=mipsel-unknown-elf \
+ --disable-docs --disable-nls --disable-libada --disable-libssp \
+ --disable-libquadmath --disable-libstdc++-v3 --with-float=soft \
+ --enable-languages=c,c++ --with-gnu-as --with-gnu-ld
+ ```
+
+ And build it as usual:
+
+ ```bash
+ make -j 4
+ make install-strip
+ ```
+
+5. Copy the entire `/tmp/mipsel-unknown-elf` directory over to your Windows
+ machine using VM shared folders, a network share, `scp` or whichever method
+ you prefer. It's recommended to put the toolchain in
+ `C:\Program Files\mipsel-unknown-elf` or `C:\mipsel-unknown-elf`.
+
+6. If you want to keep the toolchain in another location and/or use it from the
+ command line, add the `bin` subdirectory inside `mipsel-unknown-elf` to the
+ `PATH` environment variable (as you did on Linux) using System Properties.
+
+## Note regarding C++ support
+
+C++ support in PSn00bSDK, besides compile-time features like `constexpr`, only
+goes as far as basic classes, namespaces and the ability to dynamically create
+and delete class objects at any point of the program. The required dependencies
+(which are just wrappers around `malloc()` and `free()`) are supplied by `libc`.
+
+Standard C++ libraries are not implemented and likely never going to be
+implemented due to bloat concerns that it may introduce. Besides, the official
+SDK lacks full C++ support as well.
+
+-----------------------------------------
+_Last updated on 2021-10-18 by spicyjpeg_
diff --git a/changelog.txt b/changelog.txt
index 7f141f6..3d7ee97 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -3,6 +3,22 @@ PSn00bSDK changelog
Items that are lower in the log are more recently implemented.
+10-17-2021 by spicyjpeg:
+
+* Added SKIP_TINYXML2 and SKIP_MKPSXISO build options in place of the old
+ SKIP_DOWNLOAD option, and a new BUNDLE_TOOLCHAIN option for building packages.
+ Updated INSTALL.md accordingly and fixed git branch error when downloading
+ mkpsxiso during build.
+
+* Rewritten toolchain.txt (which is now TOOLCHAIN.md) and added proper Windows
+ toolchain build instructions.
+
+* Added safety checks in CMake scripts to ensure elf2x/mkpsxiso are installed
+ before attempting to build an executable or CD image.
+
+* examples: Added CMake build script to (and removed makefile from) vagsample.
+
+
10-06-2021 by Lameguy64:
* psxspu: Fixed register typo in SpyKeyOn causing unpredictable instability.
diff --git a/cpack/setup.cmake b/cpack/setup.cmake
new file mode 100644
index 0000000..a483462
--- /dev/null
+++ b/cpack/setup.cmake
@@ -0,0 +1,184 @@
+# This script sets up all CPack-related variables and generates installation
+# rules to bundle the GCC toolchain and CMake in packages. It is included by
+# the main CMakeLists.txt script.
+
+cmake_minimum_required(VERSION 3.21)
+
+## Settings
+
+# These can be set from the command line to completely disable bundling CMake
+# and GCC in packages built by CPack. They have no effect on installing the SDK
+# normally.
+# TODO: BUNDLE_CMAKE should not be used, needs more testing
+set(
+ BUNDLE_TOOLCHAIN OFF
+ CACHE BOOL "Include the GCC toolchain in installer packages"
+)
+set(
+ BUNDLE_CMAKE OFF
+ CACHE BOOL "Include CMake in installer packages (Windows only)"
+)
+
+## Bundled components
+
+# "Install" the toolchain and CMake (by pulling files from its their install
+# locations). This is only useful when building installers, as CPack will pick
+# up these installation rules and bundle the toolchain in the installers.
+# NOTE: unfortunately there is no easy way to reuse the toolchain finding logic
+# in sdk.cmake, so I had to copypaste it here.
+if(BUNDLE_TOOLCHAIN)
+ find_program(
+ _gcc ${PSN00BSDK_TARGET}-gcc
+ HINTS
+ ${PSN00BSDK_TC}/bin
+ ${PSN00BSDK_TC}/../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)
+
+ # Check if the toolchain is actually part of an existing PSn00bSDK install.
+ # If so, disable bundling as we can't determine which files are part of the
+ # toolchain and which ones are part of the SDK.
+ if(EXISTS ${_bin}/elf2x${CMAKE_EXECUTABLE_SUFFIX})
+ message(FATAL_ERROR "${_toolchain} contains a full PSn00bSDK installation. To bundle the toolchain, set PSN00BSDK_TC to point to a directory containing only the toolchain files.")
+ else()
+ install(
+ DIRECTORY ${_toolchain}/
+ DESTINATION .
+ COMPONENT toolchain
+ USE_SOURCE_PERMISSIONS
+ #EXCLUDE_FROM_ALL
+ )
+ endif()
+endif()
+
+if(BUNDLE_CMAKE)
+ cmake_path(GET CMAKE_COMMAND PARENT_PATH _bin)
+ cmake_path(GET _bin PARENT_PATH _cmakedir)
+
+ # Bundling CMake is only allowed on Windows, both because finding CMake
+ # installation files is difficult on Linux and because it's better to
+ # specify CMake as a DEB/RPM dependency anyway.
+ if(NOT WIN32)
+ message(FATAL_ERROR "Bundling CMake into installers is only supported (and should only be done) on Windows.")
+ else()
+ install(
+ DIRECTORY ${_cmakedir}/
+ DESTINATION .
+ COMPONENT cmake
+ USE_SOURCE_PERMISSIONS
+ #EXCLUDE_FROM_ALL
+ )
+ endif()
+endif()
+
+## Variables common to all package types
+
+if(NOT DEFINED CPACK_GENERATOR)
+ if(WIN32)
+ set(CPACK_GENERATOR ZIP NSIS)
+ elseif(APPLE)
+ # TODO: add a macOS installer and related options
+ set(CPACK_GENERATOR ZIP)
+ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ set(CPACK_GENERATOR ZIP DEB RPM)
+ else()
+ set(CPACK_GENERATOR ZIP)
+ endif()
+endif()
+
+set(CPACK_VERBATIM_VARIABLES ON)
+set(CPACK_ARCHIVE_THREADS 0)
+set(CPACK_PACKAGE_DIRECTORY ${PROJECT_BINARY_DIR}/packages)
+set(CPACK_PACKAGE_NAME PSn00bSDK)
+set(CPACK_PACKAGE_VENDOR Lameguy64)
+set(CPACK_PACKAGE_CONTACT Lameguy64)
+set(CPACK_RESOURCE_FILE_README ${PROJECT_SOURCE_DIR}/README.md)
+set(CPACK_RESOURCE_FILE_LICENSE ${PROJECT_SOURCE_DIR}/LICENSE.md)
+set(CPACK_PACKAGE_ICON ${CMAKE_CURRENT_LIST_DIR}/icon.ico)
+set(CPACK_PACKAGE_DESCRIPTION_FILE ${CMAKE_CURRENT_LIST_DIR}/description.txt)
+set(CPACK_RESOURCE_FILE_WELCOME ${CMAKE_CURRENT_LIST_DIR}/welcome.txt)
+set(CPACK_PRE_BUILD_SCRIPTS ${CMAKE_CURRENT_LIST_DIR}/fakeroot_fix.cmake)
+set(CPACK_PACKAGE_INSTALL_DIRECTORY PSn00bSDK)
+
+## DEB/RPM variables
+
+set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.28), cmake (>= 3.21)")
+set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "ninja-build (>= 1.10)")
+set(CPACK_DEBIAN_PACKAGE_SUGGESTS "git (>= 2.25)")
+set(CPACK_DEBIAN_PACKAGE_SECTION devel)
+set(CPACK_RPM_PACKAGE_REQUIRES "cmake >= 3.21")
+set(CPACK_RPM_PACKAGE_SUGGESTS "ninja-build >= 1.10, git >= 2.25")
+#set(CPACK_RPM_PACKAGE_RELOCATABLE ON)
+
+## NSIS variables
+
+set(CPACK_NSIS_MUI_ICON ${CMAKE_CURRENT_LIST_DIR}/icon.ico)
+set(CPACK_NSIS_MUI_UNIICON ${CMAKE_CURRENT_LIST_DIR}/uninstall.ico)
+set(CPACK_NSIS_MUI_HEADERIMAGE ${CMAKE_CURRENT_LIST_DIR}/nsis_header.bmp)
+set(CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP ${CMAKE_CURRENT_LIST_DIR}/nsis_banner.bmp)
+set(CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP ${CMAKE_CURRENT_LIST_DIR}/nsis_banner.bmp)
+set(CPACK_NSIS_BRANDING_TEXT "PSn00bSDK - Meido-Tek Productions")
+set(CPACK_NSIS_URL_INFO_ABOUT "${PROJECT_HOMEPAGE_URL}")
+set(CPACK_NSIS_MODIFY_PATH ON)
+set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
+set(
+ CPACK_NSIS_MENU_LINKS
+ "${PROJECT_HOMEPAGE_URL}" "About PSn00bSDK"
+ "https://github.com/Lameguy64/PSn00bSDK" "GitHub repo"
+)
+
+# Paths in CPACK_NSIS_* variables are not converted to native paths by CMake
+# for some reason (and NSIS doesn't like paths with forward slashes), so we
+# have to do it manually.
+foreach(
+ _var IN ITEMS
+ CPACK_NSIS_MUI_ICON
+ CPACK_NSIS_MUI_UNIICON
+ CPACK_NSIS_MUI_HEADERIMAGE
+ CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP
+ CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP
+)
+ cmake_path(NATIVE_PATH ${_var} ${_var})
+endforeach()
+
+## Component setup
+
+# This must be done after setting CPack-related variables.
+include(CPack)
+
+cpack_add_component(
+ sdk
+ DISPLAY_NAME "SDK libraries and tools"
+ DESCRIPTION "These files are always required and their installation cannot be skipped."
+ REQUIRED
+)
+cpack_add_component(
+ docs
+ DISPLAY_NAME "SDK documentation"
+ DESCRIPTION "Select to install additional documentation files and a project template (recommended)."
+)
+
+if(BUNDLE_TOOLCHAIN)
+ cpack_add_component(
+ toolchain
+ DISPLAY_NAME "GCC MIPS toolchain"
+ DESCRIPTION "Do not skip unless you already have a toolchain that targets ${PSN00BSDK_TARGET} installed."
+ )
+endif()
+if(BUNDLE_CMAKE)
+ cpack_add_component(
+ cmake
+ DISPLAY_NAME "CMake ${CMAKE_VERSION}"
+ DESCRIPTION "Select this if you do not have CMake installed already. Note that CMake will be installed in the same directory as PSn00bSDK."
+ DISABLED
+ )
+endif()
diff --git a/doc/dev notes.txt b/doc/dev notes.txt
index 8fd8d7f..1bc9ccd 100644
--- a/doc/dev notes.txt
+++ b/doc/dev notes.txt
@@ -153,6 +153,26 @@ ignore -isystem completely). I eventually gave up and just set the include
directories manually for each target, and for some reason CMake actually
started passing -I instead of -isystem to GCC.
+* When using CPack with NSIS, all CPACK_NSIS_* variables are passed to NSIS
+verbatim, i.e. without the usual slash-to-backslash path conversion that CMake
+does on Windows. Most Windows programs accept paths with slashes without issue,
+unfortunately the NSIS builder is not one of those. To add insult to injury,
+CMake doesn't even escape backslashes by default when quoting strings in the
+generated CPack config file! So you have to convert the paths manually *and*
+tell CMake to enable escaping by setting CPACK_VERBATIM_VARIABLES, like this:
+
+ set(CPACK_VERBATIM_VARIABLES ON)
+ foreach(
+ _var IN ITEMS
+ CPACK_NSIS_MUI_ICON
+ CPACK_NSIS_MUI_UNIICON
+ CPACK_NSIS_MUI_HEADERIMAGE
+ CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP
+ CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP
+ )
+ cmake_path(NATIVE_PATH ${_var} ${_var})
+ endforeach()
+
* Not a CMake/CPack bug per se, but NSIS is picky about the banner and header
images shown in generated installers. They must be Windows BMP version 3 files
with no alpha channel, no compression and no metadata. They can either be
diff --git a/examples/sound/vagsample/CMakeLists.txt b/examples/sound/vagsample/CMakeLists.txt
new file mode 100644
index 0000000..1f42608
--- /dev/null
+++ b/examples/sound/vagsample/CMakeLists.txt
@@ -0,0 +1,22 @@
+# PSn00bSDK example CMake script
+# (C) 2021 spicyjpeg - MPL licensed
+
+cmake_minimum_required(VERSION 3.21)
+
+if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS})
+ set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake)
+endif()
+
+project(
+ vagsample
+ LANGUAGES C
+ VERSION 1.0.0
+ DESCRIPTION "PSn00bSDK SPU sound playback example"
+ HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk"
+)
+
+file(GLOB _sources *.c)
+psn00bsdk_add_executable(vagsample STATIC ${_sources})
+#psn00bsdk_add_cd_image(vagsample_iso vagsample iso.xml DEPENDS vagsample)
+
+install(FILES ${PROJECT_BINARY_DIR}/vagsample.exe DESTINATION .)
diff --git a/examples/sound/vagsample/makefile b/examples/sound/vagsample/makefile
deleted file mode 100644
index acbaaad..0000000
--- a/examples/sound/vagsample/makefile
+++ /dev/null
@@ -1,65 +0,0 @@
-# PSn00bSDK makefile template
-# Part of the PSn00bSDK Project
-# 2019 - 2021 Lameguy64 / Meido-Tek Productions
-
-## Settings
-
-PSN00BSDK_LIBS ?= ../../../libpsn00b
-
-# Edit this to point to psn00bsdk-setup.mk, or copy that over to your project's
-# root folder (it only depends on environment variables).
-include ../../../psn00bsdk-setup.mk
-
-# Project target name
-TARGET = vagsample
-
-## Files
-
-# Searches for C, C++ and S (assembler) files in local directory
-CFILES = $(notdir $(wildcard *.c))
-CPPFILES= $(notdir $(wildcard *.cpp))
-AFILES = $(notdir $(wildcard *.s))
-
-# Create names for object files
-OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
- $(addprefix build/,$(CPPFILES:.cpp=.o)) \
- $(addprefix build/,$(AFILES:.s=.o))
-
-# Project specific includes and libraries
-# (use -I for include dirs, -L for library dirs, -l for static libraries)
-INCLUDE +=
-LIBDIRS +=
-LIBS +=
-
-## Build rules
-
-#all: iso
-all: build/$(TARGET)
-
-iso: build/$(TARGET) resources
- $(MKPSXISO) -y -q iso.xml
-
-resources:
- # Add commands to build/convert your assets here
- #$(LZPACK) data.xml
-
-build/$(TARGET): $(OFILES)
- @mkdir -p $(dir $@)
- $(LD) $(LDFLAGS_EXE) $(LIBDIRS) $^ $(LIBS) -o $@
- $(NM) -f posix -l -n $@ >$@.map
- $(ELF2X) -q $@ $@.exe
-
-build/%.o: %.c
- @mkdir -p $(dir $@)
- $(CC) $(CFLAGS_EXE) $(INCLUDE) -c $< -o $@
-
-build/%.o: %.cpp
- @mkdir -p $(dir $@)
- $(CXX) $(CPPFLAGS_EXE) $(INCLUDE) -c $< -o $@
-
-build/%.o: %.s
- @mkdir -p $(dir $@)
- $(CC) $(AFLAGS_EXE) $(INCLUDE) -c $< -o $@
-
-clean:
- rm -rf build
diff --git a/examples/system/dynlink/main.c b/examples/system/dynlink/main.c
index 70314da..33f6f44 100644
--- a/examples/system/dynlink/main.c
+++ b/examples/system/dynlink/main.c
@@ -62,7 +62,9 @@ const void *const DO_NOT_STRIP[] __attribute__((section(".dummy"))) = {
&InitGeom,
&RotMatrix,
&TransMatrix,
- &MulMatrix0
+ &MulMatrix0,
+ &GetTimInfo,
+ &LoadImage
};
static const char *const DLL_FILENAMES[] = {
@@ -141,7 +143,7 @@ void load_dll(const char *filename) {
dll = dlopen(filename, RTLD_LAZY);
if (!dll)
- SHOW_ERROR("FAILED TO LOAD %s\n%s\n", filename, dlerror());
+ SHOW_ERROR("FAILED TO LOAD %s\nERROR=%d\n", filename, (int32_t) dlerror());
dll_api.init = dlsym(dll, "init");
dll_api.render = dlsym(dll, "render");
@@ -168,12 +170,12 @@ int main(int argc, const char* argv[]) {
SHOW_STATUS("LOADING SYMBOL MAP\n");
if (!DL_LoadSymbolMap("cdrom:MAIN.MAP;1"))
- SHOW_ERROR("FAILED TO LOAD SYMBOL MAP\n%s\n", dlerror());
+ SHOW_ERROR("FAILED TO LOAD SYMBOL MAP\nERROR=%d\n", (int32_t) dlerror());
// Try to obtain a reference to a local function.
void (*_display)() = DL_GetSymbolByName("display");
if (!_display)
- SHOW_ERROR("FAILED TO LOOK UP LOCAL FUNCTION\n%s\n", dlerror());
+ SHOW_ERROR("FAILED TO LOOK UP LOCAL FUNCTION\nERROR=%d\n", (int32_t) dlerror());
printf("Symbol map test, display() @ %08x\n", _display);
diff --git a/libpsn00b/CMakeLists.txt b/libpsn00b/CMakeLists.txt
index 52914d3..083208a 100644
--- a/libpsn00b/CMakeLists.txt
+++ b/libpsn00b/CMakeLists.txt
@@ -41,10 +41,17 @@ foreach(_library IN LISTS PSN00BSDK_LIBRARIES)
endforeach()
# Extract libgcc's contents and merge them into libc after building.
+# Unfortunately glob expressions won't work on Windows, so we have to manually
+# enumerate the contents of libgcc and save the list to a temporary file (as it
+# is too long to be passed directly on the command line). This is actually the
+# most reliable way I found to do this (I tried $<TARGET_OBJECTS> to no avail).
add_custom_command(
TARGET c POST_BUILD
+ COMMAND ${CMAKE_AR} t ${PSN00BSDK_LIBGCC} $<ANGLE-R>_libgcc.txt
COMMAND ${CMAKE_AR} x ${PSN00BSDK_LIBGCC}
- COMMAND ${CMAKE_AR} rsuU $<TARGET_FILE:c> *.o
+ COMMAND ${CMAKE_AR} q $<TARGET_FILE:c> \@_libgcc.txt
+ COMMAND ${CMAKE_AR} s $<TARGET_FILE:c>
+ #COMMAND ${CMAKE_AR} rsuU $<TARGET_FILE:c> *.o
COMMENT "Merging libgcc contents into SDK libc"
)
diff --git a/libpsn00b/cmake/internal_setup.cmake b/libpsn00b/cmake/internal_setup.cmake
index e3d4be7..377afbc 100644
--- a/libpsn00b/cmake/internal_setup.cmake
+++ b/libpsn00b/cmake/internal_setup.cmake
@@ -79,6 +79,12 @@ function(psn00bsdk_add_executable name type)
message(FATAL_ERROR "Invalid executable type: ${type} (must be STATIC or DYNAMIC)")
endif()
+ # Throw an error if elf2x was not found (which should never happen if the
+ # SDK is installed properly).
+ if(ELF2X STREQUAL "ELF2X-NOTFOUND")
+ message(FATAL_ERROR "Failed to locate elf2x. Check your PATH environment variable.")
+ endif()
+
add_executable (${name} ${ARGN})
target_link_libraries(${name} psn00bsdk_${_type}_exe)
set_target_properties(${name} PROPERTIES PREFIX "" SUFFIX ".elf")
@@ -146,6 +152,13 @@ endfunction()
# [additional options passed to add_custom_target()]
# )
function(psn00bsdk_add_cd_image name image_name config_file)
+ # Throw an error if mkpsxiso was not found. Performing this check manually
+ # (instead of just marking mkpsxiso as required) allows simple projects to
+ # be built even if mkpsxiso is not installed.
+ if(MKPSXISO STREQUAL "MKPSXISO-NOTFOUND")
+ message(FATAL_ERROR "Failed to locate mkpsxiso. If mkpsxiso wasn't installed alongside the SDK, check your PATH environment variable.")
+ endif()
+
set(CD_IMAGE_NAME ${image_name})
configure_file(${config_file} _gen_${config_file})
@@ -158,4 +171,6 @@ function(psn00bsdk_add_cd_image name image_name config_file)
)
endfunction()
-## Helper functions for assets (TODO)
+## Helper functions for assets
+
+# TODO: add them
diff --git a/libpsn00b/include/dlfcn.h b/libpsn00b/include/dlfcn.h
index 0c51821..b3a5cec 100644
--- a/libpsn00b/include/dlfcn.h
+++ b/libpsn00b/include/dlfcn.h
@@ -20,6 +20,23 @@
#define RTLD_DEFAULT ((DLL *) 0)
+typedef enum _DL_Error {
+ RTLD_E_NONE = 0, // No error
+ RTLD_E_FILE_OPEN = 1, // Unable to find or open file
+ RTLD_E_FILE_ALLOC = 2, // Unable to allocate buffer to load file into
+ RTLD_E_FILE_READ = 3, // Failed to read file
+ RTLD_E_NO_MAP = 4, // No symbol map has been loaded yet
+ RTLD_E_MAP_ALLOC = 5, // Unable to allocate symbol map structures
+ RTLD_E_NO_SYMBOLS = 6, // No symbols found in symbol map
+ RTLD_E_DLL_NULL = 7, // Unable to initialize DLL from null pointer
+ RTLD_E_DLL_ALLOC = 8, // Unable to allocate DLL metadata structures
+ RTLD_E_DLL_FORMAT = 9, // Unsupported DLL type or format
+ RTLD_E_NO_FILE_API = 10, // psxetc has been built without file support
+ RTLD_E_MAP_SYMBOL = 11, // Symbol not found in symbol map
+ RTLD_E_DLL_SYMBOL = 12, // Symbol not found in DLL
+ RTLD_E_HASH_LOOKUP = 13 // Hash table lookup failed due to internal error
+} DL_Error;
+
typedef enum _DL_ResolveMode {
RTLD_LAZY = 1, // Resolve functions when they are first called (default)
RTLD_NOW = 2 // Resolve all symbols immediately on load
@@ -161,13 +178,13 @@ void dlclose(DLL *dll);
*/
void *dlsym(DLL *dll, const char *name);
/**
- * @brief Returns a string describing the last error that occurred, or null if
- * no error has occurred since the last call to dlerror() (i.e. calling this
+ * @brief Returns a code describing the last error that occurred, or DL_E_NONE
+ * if no error has occurred since the last call to dlerror() (i.e. calling this
* also resets the internal error flags).
*
- * @return NULL or pointer to const string
+ * @return NULL or member of DL_Error enum
*/
-const char *const dlerror(void);
+DL_Error dlerror(void);
#ifdef __cplusplus
}
diff --git a/libpsn00b/psxetc/dl.c b/libpsn00b/psxetc/dl.c
index e405efc..586e7e1 100644
--- a/libpsn00b/psxetc/dl.c
+++ b/libpsn00b/psxetc/dl.c
@@ -48,42 +48,19 @@ typedef struct {
void *ptr;
} MapEntry;
-typedef enum {
- ERR_NONE,
- ERR_FILE,
- ERR_FILE_MALLOC,
- ERR_FILE_READ,
- ERR_NO_MAP,
- ERR_MAP_MALLOC,
- ERR_NO_SYMBOLS,
- ERR_DLL_NULL,
- ERR_DLL_MALLOC,
- ERR_DLL_FORMAT,
- ERR_NO_FILE_API,
- ERR_MAP_SYMBOL,
- ERR_DLL_SYMBOL
-} ErrorCode;
+typedef struct {
+ uint32_t nbucket;
+ uint32_t nchain;
+
+ MapEntry *entries;
+ uint32_t *bucket;
+ uint32_t *chain;
+} SymbolMap;
/* Data */
-static const char *const DL_ERROR_MESSAGES[] = {
- "Unable to find file",
- "Unable to allocate buffer to load file into",
- "Failed to read file",
- "No symbol map has been loaded yet",
- "Unable to allocate symbol map structures",
- "No symbols found in symbol map",
- "Unable to initialize DLL from null pointer",
- "Unable to allocate DLL metadata structures",
- "Unsupported DLL type or format",
- "psxetc has been built without file support",
- "Symbol not found in symbol map",
- "Symbol not found in DLL"
-};
-
-static ErrorCode _error_code = ERR_NONE;
-static uint32_t *_map_hash_table = 0;
-static MapEntry *_map_entry_table = 0;
+static DL_Error _error_code = RTLD_E_NONE;
+static SymbolMap _symbol_map;
// Accessed by _dl_resolve_helper, stores the pointer to the current resolver
// function. Can be changed using DL_SetResolveCallback().
@@ -93,18 +70,14 @@ void *(*_dl_resolve_callback)(DLL *, const char *) = 0;
#ifdef DEBUG
#define _LOG(...) printf(__VA_ARGS__)
-#define _ERROR(code, ret) { \
- _LOG("psxetc: ERROR! %s\n", DL_ERROR_MESSAGES[code - 1]); \
- _error_code = code; \
- return ret; \
-}
#else
#define _LOG(...)
+#endif
+
#define _ERROR(code, ret) { \
_error_code = code; \
return ret; \
}
-#endif
void _dl_resolve_wrapper(void);
@@ -161,8 +134,10 @@ static uint32_t _elf_hash(const char *str) {
#ifdef USE_FILE_API
static uint8_t *_load_file(const char *filename, size_t *size_output) {
int32_t fd = open(filename, 1);
- if (fd < 0)
- _ERROR(ERR_FILE, 0);
+ if (fd < 0) {
+ _LOG("psxetc: Can't open %s, error = %d\n", filename, fd);
+ _ERROR(RTLD_E_FILE_OPEN, 0);
+ }
// Extract file size from the file's associated control block.
// https://problemkaputt.de/psx-spx.htm#biosmemorymap
@@ -170,8 +145,10 @@ static uint8_t *_load_file(const char *filename, size_t *size_output) {
size_t size = fcb[fd].filesize;
uint8_t *buffer = malloc(size);
- if (!buffer)
- _ERROR(ERR_FILE_MALLOC, 0);
+ if (!buffer) {
+ _LOG("psxetc: Unable to allocate %d bytes for %s\n", size, filename);
+ _ERROR(RTLD_E_FILE_ALLOC, 0);
+ }
_LOG("psxetc: Loading %s (%d bytes)..", filename, size);
@@ -181,7 +158,9 @@ static uint8_t *_load_file(const char *filename, size_t *size_output) {
if (length <= 0) {
close(fd);
free(buffer);
- _ERROR(ERR_FILE_READ, 0);
+
+ _LOG("failed, error = %d\n", length);
+ _ERROR(RTLD_E_FILE_READ, 0);
}
_LOG(".");
@@ -213,20 +192,29 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size) {
// TODO: find a way to calculate the optimal number of hash table "buckets"
// in order to minimize hash table size
- uint32_t nbucket = entries;
- _LOG("psxetc: Predicted %d entries, %d hash buckets\n", entries, nbucket);
+ _symbol_map.nbucket = entries;
+ _symbol_map.nchain = entries;
+ _LOG(
+ "psxetc: Allocating nbucket = %d, nchain = %d\n",
+ _symbol_map.nbucket,
+ entries
+ );
// Allocate an entry table to store parsed symbols in, and an associated
// hash table (same format as .hash section, with 8-byte header).
- _map_hash_table = malloc(sizeof(uint32_t) * (2 + nbucket + entries));
- _map_entry_table = malloc(sizeof(MapEntry) * entries);
- if (!_map_hash_table || !_map_entry_table)
- _ERROR(ERR_MAP_MALLOC, -1);
+ _symbol_map.entries = malloc(sizeof(MapEntry) * entries);
+ _symbol_map.bucket = malloc(sizeof(uint32_t) * _symbol_map.nbucket);
+ _symbol_map.chain = malloc(sizeof(uint32_t) * entries);
- _map_hash_table[0] = nbucket;
- _map_hash_table[1] = entries;
- for (uint32_t i = 0; i < (nbucket + entries); i++)
- _map_hash_table[2 + i] = 0xffffffff;
+ if (!_symbol_map.entries || !_symbol_map.bucket || !_symbol_map.chain) {
+ _LOG("psxetc: Unable to allocate symbol map table\n");
+ _ERROR(RTLD_E_MAP_ALLOC, -1);
+ }
+
+ for (uint32_t i = 0; i < _symbol_map.nbucket; i++)
+ _symbol_map.bucket[i] = 0xffffffff;
+ for (uint32_t i = 0; i < entries; i++)
+ _symbol_map.chain[i] = 0xffffffff;
// Go again through the symbol map and fill in the hash table.
uint32_t index = 0;
@@ -254,7 +242,7 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size) {
void *address = (void *) address64;
char _type = toupper(type_string[0]);
uint32_t hash = _elf_hash(name);
- uint32_t hash_mod = hash % nbucket;
+ uint32_t hash_mod = hash % _symbol_map.nbucket;
if (address && (
(_type == 'T') || // .text
@@ -270,15 +258,15 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size) {
name
);
- MapEntry *entry = &(_map_entry_table[index]);
+ MapEntry *entry = &(_symbol_map.entries[index]);
entry->hash = hash;
entry->ptr = address;
// Append a reference to the entry to the hash table's chain
// for the current hash_mod. I can't explain this properly.
- uint32_t *hash_entry = &(_map_hash_table[2 + hash_mod]);
+ uint32_t *hash_entry = &(_symbol_map.bucket[hash_mod]);
while (*hash_entry != 0xffffffff)
- hash_entry = &(_map_hash_table[2 + nbucket + *hash_entry]);
+ hash_entry = &(_symbol_map.chain[*hash_entry]);
*hash_entry = index;
index++;
@@ -291,9 +279,9 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size) {
pos++;
}
- _LOG("psxetc: Parsed %d symbols from map\n", entries);
+ _LOG("psxetc: Parsed %d symbols\n", entries);
if (!entries)
- _ERROR(ERR_NO_SYMBOLS, -1);
+ _ERROR(RTLD_E_NO_SYMBOLS, -1);
return entries;
}
@@ -310,42 +298,54 @@ int32_t DL_LoadSymbolMap(const char *filename) {
return entries;
#else
- _ERROR(ERR_NO_FILE_API, -1);
+ _ERROR(RTLD_E_NO_FILE_API, -1);
#endif
}
void DL_UnloadSymbolMap(void) {
- if (!_map_hash_table)
+ if (!_symbol_map.entries)
return;
- free(_map_hash_table);
- free(_map_entry_table);
- _map_hash_table = 0;
+ free(_symbol_map.entries);
+ free(_symbol_map.bucket);
+ free(_symbol_map.chain);
+ _symbol_map.entries = 0;
}
void *DL_GetSymbolByName(const char *name) {
- if (!_map_hash_table)
- _ERROR(ERR_NO_MAP, 0);
+ if (!_symbol_map.entries) {
+ _LOG("psxetc: Attempted lookup with no map loaded\n");
+ _ERROR(RTLD_E_NO_MAP, 0);
+ }
// https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-48031.html
- uint32_t nbucket = _map_hash_table[0];
uint32_t hash = _elf_hash(name);
- uint32_t hash_mod = hash % nbucket;
+ uint32_t hash_mod = hash % _symbol_map.nbucket;
// Go through the hash table's chain until the symbol hash matches the one
// calculated.
- for (uint32_t i = _map_hash_table[2 + hash_mod]; i;) {
- MapEntry *entry = &(_map_entry_table[i]);
+ for (uint32_t i = _symbol_map.bucket[hash_mod]; i != 0xffffffff;) {
+ if (i >= _symbol_map.nchain) {
+ _LOG(
+ "psxetc: GetSymbolByName() index out of bounds (i = %d, n = %d)\n",
+ i,
+ _symbol_map.nchain
+ );
+ _ERROR(RTLD_E_HASH_LOOKUP, 0);
+ }
+
+ MapEntry *entry = &(_symbol_map.entries[i]);
if (hash == entry->hash) {
_LOG("psxetc: Map lookup [%s = %08x]\n", name, entry->ptr);
return entry->ptr;
}
- i = _map_hash_table[2 + nbucket + i];
+ i = _symbol_map.chain[i];
}
- _ERROR(ERR_MAP_SYMBOL, 0);
+ _LOG("psxetc: Map lookup [%s not found]\n", name);
+ _ERROR(RTLD_E_MAP_SYMBOL, 0);
}
void DL_SetResolveCallback(void *(*callback)(DLL *, const char *)) {
@@ -356,11 +356,13 @@ void DL_SetResolveCallback(void *(*callback)(DLL *, const char *)) {
DLL *dlinit(void *ptr, size_t size, DL_ResolveMode mode) {
if (!ptr)
- _ERROR(ERR_DLL_NULL, 0);
+ _ERROR(RTLD_E_DLL_NULL, 0);
DLL *dll = malloc(sizeof(DLL));
- if (!dll)
- _ERROR(ERR_DLL_MALLOC, 0);
+ if (!dll) {
+ _LOG("psxetc: Unable to allocate DLL struct\n");
+ _ERROR(RTLD_E_DLL_ALLOC, 0);
+ }
dll->ptr = ptr;
dll->malloc_ptr = 0;
@@ -417,7 +419,9 @@ DLL *dlinit(void *ptr, size_t size, DL_ResolveMode mode) {
// Only 16-byte symbol table entries are supported.
if (dyn->d_un.d_val != sizeof(Elf32_Sym)) {
free(dll);
- _ERROR(ERR_DLL_FORMAT, 0);
+
+ _LOG("psxetc: Invalid symtab entry size %d\n", dyn->d_un.d_val);
+ _ERROR(RTLD_E_DLL_FORMAT, 0);
}
break;
@@ -428,7 +432,9 @@ DLL *dlinit(void *ptr, size_t size, DL_ResolveMode mode) {
// Versions other than 1 are unsupported (do they even exist?).
if (dyn->d_un.d_val != 1) {
free(dll);
- _ERROR(ERR_DLL_FORMAT, 0);
+
+ _LOG("psxetc: Invalid DLL version %d\n", dyn->d_un.d_val);
+ _ERROR(RTLD_E_DLL_FORMAT, 0);
}
break;
@@ -439,7 +445,9 @@ DLL *dlinit(void *ptr, size_t size, DL_ResolveMode mode) {
// Shortcut pointers (whatever they are) are not supported.
if (dyn->d_un.d_val & RHF_QUICKSTART) {
free(dll);
- _ERROR(ERR_DLL_FORMAT, 0);
+
+ _LOG("psxetc: Invalid flags\n");
+ _ERROR(RTLD_E_DLL_FORMAT, 0);
}
break;
@@ -458,7 +466,9 @@ DLL *dlinit(void *ptr, size_t size, DL_ResolveMode mode) {
// be easy enough to support them, but why?
if (dyn->d_un.d_val) {
free(dll);
- _ERROR(ERR_DLL_FORMAT, 0);
+
+ _LOG("psxetc: Invalid base address %08x\n", dyn->d_un.d_val);
+ _ERROR(RTLD_E_DLL_FORMAT, 0);
}
break;
@@ -558,7 +568,7 @@ DLL *dlinit(void *ptr, size_t size, DL_ResolveMode mode) {
if (!dll->got[2 + j]) {
free(dll);
- _ERROR(ERR_MAP_SYMBOL, 0);
+ _ERROR(RTLD_E_MAP_SYMBOL, 0);
}
}
@@ -600,7 +610,7 @@ DLL *dlopen(const char *filename, DL_ResolveMode mode) {
return dll;
#else
- _ERROR(ERR_NO_FILE_API, 0);
+ _ERROR(RTLD_E_NO_FILE_API, 0);
#endif
}
@@ -633,13 +643,21 @@ void *dlsym(DLL *dll, const char *name) {
//return _dl_resolve_callback(RTLD_DEFAULT, name);
// https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-48031.html
- const uint32_t *hash_table = dll->hash;
- uint32_t nbucket = hash_table[0];
- uint32_t hash_mod = _elf_hash(name) % nbucket;
+ uint32_t nbucket = dll->hash[0];
+ uint32_t nchain = dll->hash[1];
+ const uint32_t *bucket = &(dll->hash[2]);
+ const uint32_t *chain = &(dll->hash[2 + nbucket]);
+
+ uint32_t hash_mod = _elf_hash(name) % nbucket;
// Go through the hash table's chain until the symbol name matches the one
// provided.
- for (uint32_t i = hash_table[2 + hash_mod]; i;) {
+ for (uint32_t i = bucket[hash_mod]; i != 0xffffffff;) {
+ if (i >= nchain) {
+ _LOG("psxetc: dlsym() index out of bounds (i = %d, n = %d)\n", i, nchain);
+ _ERROR(RTLD_E_HASH_LOOKUP, 0);
+ }
+
Elf32_Sym *sym = &(dll->symtab[i]);
const char *_name = &(dll->strtab[sym->st_name]);
@@ -648,18 +666,16 @@ void *dlsym(DLL *dll, const char *name) {
return sym->st_value;
}
- i = hash_table[2 + nbucket + i];
+ i = chain[i];
}
- _ERROR(ERR_DLL_SYMBOL, 0);
+ _LOG("psxetc: DLL lookup [%s not found]\n", name);
+ _ERROR(RTLD_E_DLL_SYMBOL, 0);
}
-const char *const dlerror(void) {
- uint32_t last = _error_code;
- _error_code = ERR_NONE;
-
- if (last)
- return DL_ERROR_MESSAGES[last - 1];
+DL_Error dlerror(void) {
+ DL_Error last = _error_code;
+ _error_code = RTLD_E_NONE;
- return 0;
+ return last;
}
diff --git a/libpsn00b/readme.txt b/libpsn00b/readme.txt
index 9f6ebc6..cfff733 100644
--- a/libpsn00b/readme.txt
+++ b/libpsn00b/readme.txt
@@ -11,11 +11,11 @@ from scratch in a mix of C and hand optimized assembly language for optimal
software performance.
These libraries can only be compiled using a build of GCC that targets
-mipsel-unknown-elf. Compiler version shouldn't matter much and it should work
-fine with GCC 9.1.0, though 7.4.0 is the recommended version as that is what
-LibPSn00b is most tested most on.
+mipsel-unknown-elf (or mipsel-none-elf). Compiler version shouldn't matter
+much and it should work fine with the latest GCC release, though 7.4.0 is the
+recommended version as that is what LibPSn00b is most tested most on.
+
-
Brief summary of libraries:
libc - Standard C library. Covers only a small subset of the full
@@ -33,7 +33,8 @@ Brief summary of libraries:
psxapi - Provides function calls for using functions provided by the PS1
BIOS.
- psxetc - Provides some miscellaneous features such as debug font.
+ psxetc - Provides some miscellaneous features used by the other libraries
+ as well as a dynamic linker for loading DLLs at runtime.
psxspu - SPU library (work in progress). Currently supports hardware
init, sample data upload via DMA and playing sound samples.
@@ -49,7 +50,12 @@ Brief summary of libraries:
must be covered in the changelog.txt file.
-Compiling (OUTDATED):
+Compiling:
+
+ Refer to INSTALL.md in the parent directory for up-to-date installation
+ instructions.
+
+ --- THE SECTION BELOW IS OUTDATED AND ONLY KEPT FOR REFERENCE ---
To compile the LibPSn00b libraries, you will first need a working GCC
toolchain which you can either build yourself as described in the
@@ -94,6 +100,10 @@ Documentation:
library documents. It may be wise to export the document as a PDF
document for easier viewing.
+ The PSn00bSDK CMake toolchain script also defines several macros and
+ helpers that can be used in project build scripts, documented in
+ cmake_reference.md.
+
Contributing:
@@ -138,4 +148,12 @@ LibPSn00b Library to-do list:
psxpress - MDEC and data decompression library. May use DEFLATE or LZ77
for compressing MDEC data instead of Huffman as used in the
official libraries. It may yield better compression which may
- potentially result in higher quality FMVs. \ No newline at end of file
+ potentially result in higher quality FMVs.
+
+ psxexp - Support library for various devices connected to the serial or
+ expansion port, including both official ones (e.g. PCMCIA cards
+ and IDE drives used by some PS1-based arcade systems) as well
+ as cheat devices, RAM expanders or even ESP8266/ESP32 wireless
+ modules. May also include APIs for accessing the filesystem on
+ a connected drive (possibly by overriding psxcd and psxmcrd
+ functions) or reliably transferring data from/to a PC.
diff --git a/toolchain.txt b/toolchain.txt
deleted file mode 100644
index d34d54b..0000000
--- a/toolchain.txt
+++ /dev/null
@@ -1,171 +0,0 @@
-If you wish to build the toolchain yourself, beware that this process can get
-pretty tedious unless you have a powerful enough computer with plenty of
-threads to spare. A system with at least 4 to 8 total threads or more is
-recommended. You may have better success building the toolchain in ArchLinux
-especially if you want to build the most recent versions of GCC. Debian
-Buster however, may have about the same chance of success in building as
-using ArchLinux.
-
-It is recommended to stick with GCC 7.4.0 and Binutils 2.31 as this is the
-version PSn00bSDK is most tested with. Though generally, it doesn't hurt to
-try out newer versions and has been known to work flawlessly without issue.
-
-These instructions are only for Linux, though they can be adapted for
-building in Windows using MSys2 or Cygwin64. Beware that libgcc cannot
-be built under Windows as the libgcc build process depends on symlinks
-which is not supported by the operating system and is not wrapped by Msys2
-and Cygwin64. The only workaround is to first build GCC in Linux then copy
-the libgcc.a library from it to the Windows build.
-
-
-Make sure the following packages are installed prior to building:
-* make
-* build-essential or build-essentials, if you don't have GCC installed yet
- (a host toolchain is required to build the rest of the SDK anyway).
-
-
-Building binutils:
-
-Binutils must be built first as GCC depends on binutils built for the same
-target architecture. In this case, building binutils and GCC to target
-mipsel-unknown-elf.
-
-* Download binutils source files at ftp://ftp.gnu.org. Choose a version you
- wish to use with PSn00bSDK. The reference version that PSn00bSDK is tested
- with most is 2.31.
-
-* Extract the contents of the archive, preferably in a directory named
- "toolchain" (or whatever).
-
-* Create a directory named binutils-build inside the toolchain directory. Do
- not create it inside the binutils directory with the source files.
-
-* Enter the binutils-build directory and configure binutils from there
- with the following command line:
-
-../binutils-<version>/configure --prefix=/usr/local/mipsel-unknown-elf \
---target=mipsel-unknown-elf --disable-docs --disable-nls --with-float=soft
-
-Replace <version> with the version of binutils you wish to use. You may also
-want to change the prefix argument to a path you prefer to have the toolchain
-installed to (ie. somewhere within your home directory so you wouldn't need
-root privileges to install).
-
-* Run `make -j 4` to compile binutils (-j specifies how many simultaneous
- jobs to spawn at once, set it equal to the number of cores/threads your
- system has available to speed up compiling).
-
-* Run `make install-strip` to install binutils to the path specified by the
- --prefix argument (root privileges are required if the prefix points to
- /usr/local).
-
-
-Building gcc:
-
-With binutils built it should be possible to build the GCC toolchain. Since
-GCC is considerably larger than binutils, compile time is going to be much
-longer so it's going to take a longer while to build this.
-
-* Download gcc source files at ftp://ftp.gnu.org and choose the version you
- wish to use with PSn00bSDK. The reference version that PSn00bSDK is tested
- with most is 7.4.0.
-
-* Extract it to the same toolchain directory you extracted binutils in.
-
-* Enter the extracted "gcc-<version>" folder and run the following command
- from there to download the required dependencies:
-
-./contrib/download_prerequisites
-
-* Go back and create a directory named gcc-build inside the toolchain
- directory.
-
-* Enter the gcc-build directory and configure gcc from there with the
- following command line:
-
-../gcc-<version>/configure --prefix=/usr/local/mipsel-unknown-elf \
---target=mipsel-unknown-elf --disable-docs --disable-nls --disable-libada \
---disable-libssp --disable-libquadmath --disable-libstdc++-v3 \
---with-float=soft --enable-languages=c,c++ --with-gnu-as --with-gnu-ld
-
-Replace <version> with the version of gcc you downloaded. The prefix path
-must match to what you've specified for binutils earlier, if you've decided
-to use a different prefix path for binutils.
-
-When building under Windows you must additionally specify --disable-libgcc,
-as libgcc cannot be built under Windows as it needs symlinks which are not
-supported by the operating system.
-
-* Run make in the same manner you built binutils with.
-
-* Run `make install-strip` to install gcc to the path specified by --prefix
- (root privileges are required if the prefix points to /usr/local).
-
-* Add a path to the bin directory of the toolchain into your PATH environment
- variable by adding the following line in your .bashrc or .bash_profile file:
-
-export PATH=$PATH:/usr/local/mipsel-unknown-elf/bin
-
-Under Windows, you'll have to add the path to the PATH environment variable
-through System Properties.
-
-
-Note regarding C++ support:
-
-C++ support in PSn00bSDK, besides compile-time features like constexpr, only
-goes as far as basic classes, namespaces and the ability to dynamically create
-and delete class objects at any point of the program. The required dependencies
-are supplied by libc of libpsn00b.
-
-Standard C++ libraries are not implemented and likely never going to be
-implemented due to bloat concerns that it may introduce. Besides, the official
-SDK lacks full C++ support as well.
-
-If you're trying to compile with C++ code and you get a linker error about
-undefined vtables, try specifying --fno-rtti to the g++ command line.
-
------------------------------------------------------------------------------
-Updating the ldscript (NO LONGER REQUIRED as PSn00bSDK now ships with its own
-linker scripts, the section below is only kept for reference):
-
-The following changes used to be required in order for basic C++ functionality
-to work in older PSn00bSDK versions. The changes define the constructor and
-deconstructor sections which are required for the relevant support functions
-in PSn00bSDK's libc library to be linked properly for C++.
-
-* Go to mipsel-unknown-elf/lib/ldscripts in the toolchain directory.
-
-* Open elf32elmip.x in any text editor.
-
-* Locate the .text definition (with the {} brackets) and add the following
- inside the bracket block:
-
-__CTOR_LIST__ = .;
-___CTOR_LIST__ = .;
-LONG (((__CTOR_END__ - __CTOR_LIST__) / 4) - 2)
-KEEP (*(SORT (.ctors.*)))
-KEEP (*(.ctors))
-LONG (0x00000000)
-__CTOR_END__ = .;
-. = ALIGN (0x10);
-
-__DTOR_LIST__ = .;
-___DTOR_LIST__ = .;
-LONG (((__DTOR_END__ - __DTOR_LIST__) / 4) - 2)
-KEEP (*(SORT (.dtors.*)))
-KEEP (*(.dtors))
-LONG (0x00000000)
-__DTOR_END__ = .;
-. = ALIGN (0x10);
-
-* Save script changes.
-
-Since there's no known way (at least to me -Lameguy64) to configure GCC such
-that it uses the modified ldscript as the default, you must specify the
-modified script during the linking stage of your projects with the -T
-argument, when invoking mipsel-unknown-elf-ld.
-
-Alternatively, you can make a copy of the ldscript file and modify it within
-your project directory. This is especially useful if your project uses code
-overlays.
-