From 54b09fe44c89e825296487cdd4d65feba46fcf84 Mon Sep 17 00:00:00 2001 From: Maschell Date: Sat, 25 Feb 2023 20:51:48 +0100 Subject: [PATCH] Improve the example documentation and code --- plugins/example_plugin/.clang-format | 67 ++++++++++++++++++++ plugins/example_plugin/Dockerfile | 5 ++ plugins/example_plugin/Makefile | 2 +- plugins/example_plugin/README.md | 54 +++++++++++++++-- plugins/example_plugin/src/main.cpp | 69 ++++++++++----------- plugins/example_plugin/src/utils/logger.c | 36 +++++++++++ plugins/example_plugin/src/utils/logger.h | 74 ++++++++++++++++++----- 7 files changed, 251 insertions(+), 56 deletions(-) create mode 100644 plugins/example_plugin/.clang-format create mode 100644 plugins/example_plugin/Dockerfile create mode 100644 plugins/example_plugin/src/utils/logger.c diff --git a/plugins/example_plugin/.clang-format b/plugins/example_plugin/.clang-format new file mode 100644 index 0000000..56cc685 --- /dev/null +++ b/plugins/example_plugin/.clang-format @@ -0,0 +1,67 @@ +# Generated from CLion C/C++ Code Style settings +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: Consecutive +AlignConsecutiveMacros: AcrossEmptyLinesAndComments +AlignOperands: Align +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Always +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: Yes +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: true +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +ColumnLimit: 0 +CompactNamespaces: false +ContinuationIndentWidth: 8 +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: true +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: All +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PointerAlignment: Right +ReflowComments: false +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 4 +UseTab: Never diff --git a/plugins/example_plugin/Dockerfile b/plugins/example_plugin/Dockerfile new file mode 100644 index 0000000..95b95c3 --- /dev/null +++ b/plugins/example_plugin/Dockerfile @@ -0,0 +1,5 @@ +FROM wiiuenv/devkitppc:20230218 + +COPY --from=wiiuenv/wiiupluginsystem:20230215 /artifacts $DEVKITPRO + +WORKDIR project \ No newline at end of file diff --git a/plugins/example_plugin/Makefile b/plugins/example_plugin/Makefile index 79d3a3e..565db8d 100644 --- a/plugins/example_plugin/Makefile +++ b/plugins/example_plugin/Makefile @@ -18,7 +18,7 @@ WUT_ROOT := $(DEVKITPRO)/wut # DATA is a list of directories containing data files # INCLUDES is a list of directories containing header files #------------------------------------------------------------------------------- -TARGET := $(notdir $(CURDIR)) +TARGET := ExamplePlugin BUILD := build SOURCES := src src/utils DATA := data diff --git a/plugins/example_plugin/README.md b/plugins/example_plugin/README.md index df01f44..cf5c0c2 100644 --- a/plugins/example_plugin/README.md +++ b/plugins/example_plugin/README.md @@ -1,11 +1,57 @@ # Example plugin This is just a simple example plugin which can be used as a template. +The plugin logs the FSOpenFile calls via UDP (**Only when build via `make DEBUG=1`**). + +The logging can be enabled/disabled via the WUPS Config menu (press L, DPAD Down and Minus on the GamePad, Pro Controller or Classic Controller). + +## Installation + +(`[ENVIRONMENT]` is a placeholder for the actual environment name.) + +1. Copy the file `ExamplePlugin.wps` into `sd:/wiiu/environments/[ENVIRONMENT]/plugins`. +2. Requires the [WiiUPluginLoaderBackend](https://github.com/wiiu-env/WiiUPluginLoaderBackend) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`. + +Start the environment (e.g Aroma) and the backend should load the plugin. ## Building -For building you need: -- [wups](https://github.com/Maschell/WiiUPluginSystem) -- [wut](https://github.com/decaf-emu/wut) +For building you need: -Install them (in this order) according to their README's. Don't forget the dependencies of the libs itself. \ No newline at end of file +- [wups](https://github.com/Maschell/WiiUPluginSystem) +- [wut](https://github.com/devkitpro/wut) + +Install them (in this order) according to their README's. Don't forget the dependencies of the libs itself. + +Then you should be able to compile via `make` (with no logging) or `make DEBUG=1` (with logging). + +## Buildflags + +### Logging + +Building via `make` only logs errors (via OSReport). To enable logging via the [LoggingModule](https://github.com/wiiu-env/LoggingModule) set `DEBUG` to `1` or `VERBOSE`. + +`make` Logs errors only (via OSReport). +`make DEBUG=1` Enables information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule). +`make DEBUG=VERBOSE` Enables verbose information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule). + +If the [LoggingModule](https://github.com/wiiu-env/LoggingModule) is not present, it'll fallback to UDP (Port 4405) and [CafeOS](https://github.com/wiiu-env/USBSerialLoggingModule) logging. + +## Building using the Dockerfile + +It's possible to use a docker image for building. This way you don't need anything installed on your host system. + +``` +# Build docker image (only needed once) +docker build . -t example-plugin-builder + +# make +docker run -it --rm -v ${PWD}:/project example-plugin-builder make DEBUG=1 + +# make clean +docker run -it --rm -v ${PWD}:/project example-plugin-builder make clean +``` + +## Format the code via docker + +`docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./src -i` \ No newline at end of file diff --git a/plugins/example_plugin/src/main.cpp b/plugins/example_plugin/src/main.cpp index 4bf6607..62c7c12 100644 --- a/plugins/example_plugin/src/main.cpp +++ b/plugins/example_plugin/src/main.cpp @@ -1,13 +1,7 @@ +#include "utils/logger.h" #include -#include -#include #include #include -#include -#include -#include -#include -#include #include #include @@ -21,6 +15,8 @@ WUPS_PLUGIN_VERSION("v1.0"); WUPS_PLUGIN_AUTHOR("Maschell"); WUPS_PLUGIN_LICENSE("BSD"); +#define LOG_FS_OPEN_CONFIG_ID "logFSOpen" + /** All of this defines can be used in ANY file. It's possible to split it up into multiple files. @@ -28,18 +24,16 @@ WUPS_PLUGIN_LICENSE("BSD"); **/ WUPS_USE_WUT_DEVOPTAB(); // Use the wut devoptabs -WUPS_USE_STORAGE("example_plugin"); // Unqiue id for the storage api +WUPS_USE_STORAGE("example_plugin"); // Unique id for the storage api bool logFSOpen = true; /** - Get's called ONCE when the loader exits, but BEFORE the ON_APPLICATION_START gets called or functions are overridden. + Gets called ONCE when the plugin was loaded. **/ INITIALIZE_PLUGIN() { - if (!WHBLogModuleInit()) { - WHBLogCafeInit(); - WHBLogUdpInit(); - } + // Logging only works when compiled with `make DEBUG=1`. See the README for more information. + initLogging(); DEBUG_FUNCTION_LINE("INITIALIZE_PLUGIN of example_plugin!"); // Open storage to read values @@ -48,9 +42,9 @@ INITIALIZE_PLUGIN() { DEBUG_FUNCTION_LINE("Failed to open storage %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes); } else { // Try to get value from storage - if ((storageRes = WUPS_GetBool(nullptr, "logFSOpen", &logFSOpen)) == WUPS_STORAGE_ERROR_NOT_FOUND) { + if ((storageRes = WUPS_GetBool(nullptr, LOG_FS_OPEN_CONFIG_ID, &logFSOpen)) == WUPS_STORAGE_ERROR_NOT_FOUND) { // Add the value to the storage if it's missing. - if (WUPS_StoreBool(nullptr, "logFSOpen", logFSOpen) != WUPS_STORAGE_ERROR_SUCCESS) { + if (WUPS_StoreBool(nullptr, LOG_FS_OPEN_CONFIG_ID, logFSOpen) != WUPS_STORAGE_ERROR_SUCCESS) { DEBUG_FUNCTION_LINE("Failed to store bool"); } } else if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) { @@ -62,11 +56,11 @@ INITIALIZE_PLUGIN() { DEBUG_FUNCTION_LINE("Failed to close storage"); } } + deinitLogging(); } /** - Gets called when the plugin loader is re-entered => when the plugin is unloaded. - The overridden functions are restored before this is getting called. + Gets called when the plugin will be unloaded. **/ DEINITIALIZE_PLUGIN() { DEBUG_FUNCTION_LINE("DEINITIALIZE_PLUGIN of example_plugin!"); @@ -74,34 +68,39 @@ DEINITIALIZE_PLUGIN() { /** Gets called when an application starts. - This is called BEFORE the functions are overridden. - Make sure to initialize all functions you're using in the overridden functions! **/ ON_APPLICATION_START() { - if (!WHBLogModuleInit()) { - WHBLogCafeInit(); - WHBLogUdpInit(); - } + initLogging(); DEBUG_FUNCTION_LINE("ON_APPLICATION_START of example_plugin!"); } +/** + * Gets called when an application actually ends + */ +ON_APPLICATION_ENDS() { + deinitLogging(); +} + /** Gets called when an application request to exit. **/ ON_APPLICATION_REQUESTS_EXIT() { - DEBUG_FUNCTION_LINE("ON_APPLICATION_REQUESTS_EXIT of example_plugin!"); + DEBUG_FUNCTION_LINE_INFO("ON_APPLICATION_REQUESTS_EXIT of example_plugin!"); } +/** + * Callback that will be called if the config has been changed + */ void logFSOpenChanged(ConfigItemBoolean *item, bool newValue) { - DEBUG_FUNCTION_LINE("New value in logFSOpenChanged: %d", newValue); + DEBUG_FUNCTION_LINE_INFO("New value in logFSOpenChanged: %d", newValue); logFSOpen = newValue; // If the value has changed, we store it in the storage. - WUPS_StoreInt(nullptr, "logFSOpen", logFSOpen); + WUPS_StoreInt(nullptr, LOG_FS_OPEN_CONFIG_ID, logFSOpen); } WUPS_GET_CONFIG() { - // We open the storage so we can persist the configuration the user did. + // We open the storage, so we can persist the configuration the user did. if (WUPS_OpenStorage() != WUPS_STORAGE_ERROR_SUCCESS) { DEBUG_FUNCTION_LINE("Failed to open storage"); return 0; @@ -113,7 +112,7 @@ WUPS_GET_CONFIG() { WUPSConfigCategoryHandle cat; WUPSConfig_AddCategoryByNameHandled(config, "Logging", &cat); - WUPSConfigItemBoolean_AddToCategoryHandled(config, cat, "logFSOpen", "Log FSOpen calls", logFSOpen, &logFSOpenChanged); + WUPSConfigItemBoolean_AddToCategoryHandled(config, cat, LOG_FS_OPEN_CONFIG_ID, "Log FSOpen calls", logFSOpen, &logFSOpenChanged); return config; } @@ -121,14 +120,14 @@ WUPS_GET_CONFIG() { WUPS_CONFIG_CLOSED() { // Save all changes if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) { - DEBUG_FUNCTION_LINE("Failed to close storage"); + DEBUG_FUNCTION_LINE_ERR("Failed to close storage"); } } /** This defines a function replacement. It allows to replace the system function with an own function. - So whenever a game / application calles an overridden function, your function gets called instead. + So whenever a game / application calls an overridden function, your function gets called instead. Currently it's only possible to override functions that are loaded from .rpl files of OSv10 (00050010-1000400A). @@ -138,7 +137,7 @@ WUPS_CONFIG_CLOSED() { } Within this macro, two more function get declare you can use. - my_ARBITRARY_NAME_OF_FUNCTION and real_FSOpenFile + my_ARBITRARY_NAME_OF_FUNCTION and real_ARBITRARY_NAME_OF_FUNCTION RETURN_TYPE my_ARBITRARY_NAME_OF_FUNCTION(ARGS_SEPERATED_BY_COMMA): is just name of the function that gets declared in this macro. @@ -147,16 +146,14 @@ WUPS_CONFIG_CLOSED() { RETURN_TYPE real_ARBITRARY_NAME_OF_FUNCTION(ARGS_SEPERATED_BY_COMMA): is the name of the function, that leads to function that was overridden. Use this to call the original function that will be overridden. - CAUTION: Other plugins may already have manipulated the the return value or arguments. - - - Use this macro for each function you want to override + CAUTION: Other plugins may already have manipulated the return value or arguments. + Use this macro for each function you want to override **/ DECL_FUNCTION(int, FSOpenFile, FSClient *pClient, FSCmdBlock *pCmd, const char *path, const char *mode, int *handle, int error) { int result = real_FSOpenFile(pClient, pCmd, path, mode, handle, error); if (logFSOpen) { - DEBUG_FUNCTION_LINE("FSOpenFile called for folder %s! Result %d", path, result); + DEBUG_FUNCTION_LINE_INFO("FSOpenFile called for folder %s! Result %d", path, result); } return result; } diff --git a/plugins/example_plugin/src/utils/logger.c b/plugins/example_plugin/src/utils/logger.c new file mode 100644 index 0000000..f700806 --- /dev/null +++ b/plugins/example_plugin/src/utils/logger.c @@ -0,0 +1,36 @@ +#ifdef DEBUG +#include +#include +#include +#include + +uint32_t moduleLogInit = false; +uint32_t cafeLogInit = false; +uint32_t udpLogInit = false; +#endif // DEBUG + +void initLogging() { +#ifdef DEBUG + if (!(moduleLogInit = WHBLogModuleInit())) { + cafeLogInit = WHBLogCafeInit(); + udpLogInit = WHBLogUdpInit(); + } +#endif // DEBUG +} + +void deinitLogging() { +#ifdef DEBUG + if (moduleLogInit) { + WHBLogModuleDeinit(); + moduleLogInit = false; + } + if (cafeLogInit) { + WHBLogCafeDeinit(); + cafeLogInit = false; + } + if (udpLogInit) { + WHBLogUdpDeinit(); + udpLogInit = false; + } +#endif // DEBUG +} \ No newline at end of file diff --git a/plugins/example_plugin/src/utils/logger.h b/plugins/example_plugin/src/utils/logger.h index b0fdbc6..5f195ba 100644 --- a/plugins/example_plugin/src/utils/logger.h +++ b/plugins/example_plugin/src/utils/logger.h @@ -1,29 +1,73 @@ #pragma once +#include +#include +#include + #ifdef __cplusplus extern "C" { #endif -#include -#include +#define LOG_APP_TYPE "P" +#define LOG_APP_NAME "ExamplePlugin" -#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) -#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) +#define __FILENAME__ ({ \ + const char *__filename = __FILE__; \ + const char *__pos = strrchr(__filename, '/'); \ + if (!__pos) __pos = strrchr(__filename, '\\'); \ + __pos ? __pos + 1 : __filename; \ +}) -#define OSFATAL_FUNCTION_LINE(FMT, ARGS...) \ - do { \ - OSFatal_printf("[%s]%s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \ +#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX_DEFAULT(LOG_FUNC, "", "", FMT, ##ARGS) + +#define LOG_EX_DEFAULT(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) LOG_EX(__FILENAME__, __FUNCTION__, __LINE__, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ##ARGS) + +#define LOG_EX(FILENAME, FUNCTION, LINE, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \ + do { \ + LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, FILENAME, FUNCTION, LINE, ##ARGS); \ } while (0) -#define DEBUG_FUNCTION_LINE(FMT, ARGS...) \ - do { \ - WHBLogPrintf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \ - } while (0); +#ifdef DEBUG -#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) \ - do { \ - WHBLogWritef("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \ - } while (0); +#ifdef VERBOSE_DEBUG +#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS) +#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "", "", FMT, ##ARGS); +#else +#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0) +#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FMT, ARGS...) while (0) +#endif + +#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS) + +#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS) + +#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS) +#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##WARN ## ", "", FMT, ##ARGS) +#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##INFO ## ", "", FMT, ##ARGS) + +#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS); + +#else + +#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FMT, ARGS...) while (0) + +#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0) + +#define DEBUG_FUNCTION_LINE(FMT, ARGS...) while (0) + +#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0) + +#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##ERROR## ", "\n", FMT, ##ARGS) +#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##WARN ## ", "\n", FMT, ##ARGS) +#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##INFO ## ", "\n", FMT, ##ARGS) + +#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, "##ERROR## ", "\n", FMT, ##ARGS); + +#endif + +void initLogging(); + +void deinitLogging(); #ifdef __cplusplus }