From 878449ca0bd20d3b8bf5348e0279c5c8e3020695 Mon Sep 17 00:00:00 2001 From: Dan Green Date: Mon, 23 Dec 2024 13:06:20 -0800 Subject: [PATCH] Allow building external plugins as built-in, for simulator Simulator builds assets image using firmware assets plus ext plugin assets Modify internal plugin manager to build Venom Ext plugin brand and path can be different Firmware ignores ext builtin plugins --- .../vcv_plugin/export/src/plugin/Plugin.cpp | 2 +- firmware/vcv_ports/CMakeLists.txt | 6 +- .../glue/ext_plugin/ext_plugin_builtin.hh | 3 + firmware/vcv_ports/internal_plugin_manager.hh | 2 + simulator/CMakeLists.txt | 5 +- simulator/ext-plugins.cmake | 65 +++++++++++++++++++ simulator/plugin.cmake | 41 ++++++++++++ simulator/src/ext_plugin_builtin.hh.in | 3 + simulator/src/settings.hh | 2 +- 9 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 firmware/vcv_ports/glue/ext_plugin/ext_plugin_builtin.hh create mode 100644 simulator/ext-plugins.cmake create mode 100644 simulator/plugin.cmake create mode 100644 simulator/src/ext_plugin_builtin.hh.in diff --git a/firmware/vcv_plugin/export/src/plugin/Plugin.cpp b/firmware/vcv_plugin/export/src/plugin/Plugin.cpp index 4460af126..2c1174d00 100644 --- a/firmware/vcv_plugin/export/src/plugin/Plugin.cpp +++ b/firmware/vcv_plugin/export/src/plugin/Plugin.cpp @@ -83,7 +83,7 @@ Plugin::~Plugin() { // In VCV Rack: don't delete model because it's allocated once and referenced by a global. // In MetaModule: we need to delete the models when the Plugin is removed - pr_dbg("Deleting Model %s\n", model->slug.c_str()); + pr_trace("Deleting Model %s\n", model->slug.c_str()); delete model; MetaModule::ModuleFactory::unregisterBrand(slug); diff --git a/firmware/vcv_ports/CMakeLists.txt b/firmware/vcv_ports/CMakeLists.txt index 2db48f98e..62a99537c 100644 --- a/firmware/vcv_ports/CMakeLists.txt +++ b/firmware/vcv_ports/CMakeLists.txt @@ -38,6 +38,10 @@ target_include_directories(vcv_ports INTERFACE ${CMAKE_CURRENT_LIST_DIR}/glue ) +if (NOT TARGET simulator) + target_include_directories(vcv_ports INTERFACE ${CMAKE_CURRENT_LIST_DIR}/glue/ext_plugin) +endif() + # Get list of brands include(${CMAKE_CURRENT_LIST_DIR}/brands.cmake) @@ -72,7 +76,7 @@ foreach(brand ${brands}) target_link_libraries(_vcv_ports_internal PUBLIC ${brand}Library) - endif() +endif() endforeach() diff --git a/firmware/vcv_ports/glue/ext_plugin/ext_plugin_builtin.hh b/firmware/vcv_ports/glue/ext_plugin/ext_plugin_builtin.hh new file mode 100644 index 000000000..f8eea5604 --- /dev/null +++ b/firmware/vcv_ports/glue/ext_plugin/ext_plugin_builtin.hh @@ -0,0 +1,3 @@ +// do nothing in firmware: +inline void load_ext_builtin_plugins(auto &internal_plugins) { +} diff --git a/firmware/vcv_ports/internal_plugin_manager.hh b/firmware/vcv_ports/internal_plugin_manager.hh index 2eb05068a..947477865 100644 --- a/firmware/vcv_ports/internal_plugin_manager.hh +++ b/firmware/vcv_ports/internal_plugin_manager.hh @@ -1,5 +1,6 @@ #pragma once #include "convert_plugins.hh" +#include "ext_plugin_builtin.hh" #include "fat_file_io.hh" #include "fs/asset_drive/asset_fs.hh" #include "fs/asset_drive/untar.hh" @@ -27,6 +28,7 @@ struct InternalPluginManager { prepare_ramdisk(); load_internal_assets(); load_internal_plugins(); + load_ext_builtin_plugins(internal_plugins); } void prepare_ramdisk() { diff --git a/simulator/CMakeLists.txt b/simulator/CMakeLists.txt index 47b22adee..45f7f89e2 100644 --- a/simulator/CMakeLists.txt +++ b/simulator/CMakeLists.txt @@ -165,7 +165,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "Ap set(DEBUG_COMMAND ${CMAKE_DEBUGGER_BINARY} $ -- --sdcarddir ${CMAKE_CURRENT_LIST_DIR}/patches --flashdir ${CMAKE_CURRENT_LIST_DIR}/../patches/default - --assets ${CMAKE_CURRENT_LIST_DIR}/../firmware/build/assets.uimg + --assets ${CMAKE_CURRENT_LIST_DIR}/build/assets.uimg ) @@ -178,7 +178,7 @@ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") --args $ --sdcarddir ${CMAKE_CURRENT_LIST_DIR}/patches --flashdir ${CMAKE_CURRENT_LIST_DIR}/../shared/patch/default - --assets ${CMAKE_CURRENT_LIST_DIR}/../firmware/build/assets.uimg + --assets ${CMAKE_CURRENT_LIST_DIR}/build/assets.uimg ) else () set(DEBUG_COMMAND echo "Compiler is ${CMAKE_CXX_COMPILER_ID}, but must be Clang, AppleClang, or GNU to debug") @@ -191,3 +191,4 @@ add_custom_target( USES_TERMINAL ) +include(ext-plugins.cmake) diff --git a/simulator/ext-plugins.cmake b/simulator/ext-plugins.cmake new file mode 100644 index 000000000..601ab7d70 --- /dev/null +++ b/simulator/ext-plugins.cmake @@ -0,0 +1,65 @@ +# Two steps to build an external plugin into the simulator: +# +# 1. Copy/paste the two `list APPEND commands` below, puttting in the path to the +# plugin (where the CMakeLists.txt lives), and the plugin cmake library name +# +# 2. In the plugin, find the file where init(rack::Plugin*) is defined, and rename it to init_Brand +# You can use #if defined(METAMODULE_BUILTIN) so that it's still called init() when building as a plugin for Rack or MM. +# `Brand` in init_Brand must match the plugin cmake library name you used in step 1. + +# Example with Venom: +# list(APPEND ext_builtin_brand_paths "${CMAKE_CURRENT_LIST_DIR}/../../metamodule-plugin-examples/Venom") +# list(APPEND ext_builtin_brand_libname "Venom") + + +# +# Asset dir +# + +cmake_path(SET ASSET_DIR "${CMAKE_CURRENT_BINARY_DIR}/assets") +set(ASSET_IMG_FILENAME assets.uimg) +cmake_path(APPEND ASSET_IMG_PATH "${CMAKE_CURRENT_BINARY_DIR}" "${ASSET_IMG_FILENAME}") + +message("set ASSET_DIR to ${ASSET_DIR}") +message("set ASSET_IMG_PATH to ${ASSET_IMG_PATH}") + +add_custom_command( + OUTPUT ${ASSET_DIR} + COMMAND ${CMAKE_COMMAND} -E echo Copying "${FWDIR}/assets" to "${ASSET_DIR}" + COMMAND ${CMAKE_COMMAND} -E copy_directory "${FWDIR}/assets" "${ASSET_DIR}" + COMMENT "Copying assets/ dir from ${FWDIR}/assets to ${ASSET_DIR}" + VERBATIM USES_TERMINAL +) + +add_custom_command( + OUTPUT ${ASSET_IMG_PATH} + COMMAND cd ${ASSET_DIR} && ${CMAKE_COMMAND} -E tar -cf ${ASSET_IMG_PATH}.tar . + COMMAND cd ${FWDIR} && flashing/uimg_header.py --name Assets ${ASSET_IMG_PATH}.tar ${ASSET_IMG_PATH} + COMMENT "Creating assets uimg file at ${ASSET_IMG_PATH}" + DEPENDS ${ASSET_DIR} + VERBATIM USES_TERMINAL +) + + add_custom_target(asset-image ALL + DEPENDS ${ASSET_IMG_PATH} + ) + + set(EXT_PLUGIN_INIT_CALLS "") + +foreach(branddir brand IN ZIP_LISTS ext_builtin_brand_paths ext_builtin_brand_libname) + set(METAMODULE_SDK_DIR ${CMAKE_CURRENT_LIST_DIR}) + add_subdirectory(${branddir} ${CMAKE_CURRENT_BINARY_DIR}/builtins/${brand}) + + target_link_libraries(${brand} PRIVATE metamodule::vcv-plugin-interface) + target_link_libraries(${brand} PRIVATE cpputil::cpputil) + target_compile_definitions(${brand} PRIVATE METAMODULE METAMODULE_BUILTIN) + + target_link_libraries(_vcv_ports_internal PUBLIC ${brand}) + add_dependencies(asset-image ${brand}-assets) + + string(APPEND EXT_PLUGIN_INIT_CALLS "\textern void init_${brand}(rack::plugin::Plugin *);\n\tinit_${brand}(&internal_plugins.emplace_back(\"${brand}\"));") +endforeach() + +configure_file(src/ext_plugin_builtin.hh.in ${CMAKE_CURRENT_BINARY_DIR}/ext_plugin/ext_plugin_builtin.hh) +target_include_directories(simulator PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/ext_plugin) + diff --git a/simulator/plugin.cmake b/simulator/plugin.cmake new file mode 100644 index 000000000..647250c36 --- /dev/null +++ b/simulator/plugin.cmake @@ -0,0 +1,41 @@ +# TODO: Get cmake to copy the source file that contains init() and rename that function to init_BRAND() +# Also see if Cmake can generate the calls to init (currently manually written into simulator/src/ext_plugin_builtin.hh) + +# file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/replace.cmake" +# [=[ +# file(READ "${SOURCE}" TEXT) +# string(REPLACE "foo" "bar" TEXT "${TEXT}") +# file(WRITE "${TARGET}" "${TEXT}") +# ]=]) + +# add_custom_command( +# OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/plugin.cpp" +# COMMAND "${CMAKE_COMMAND}" +# "-DSOURCE=${CMAKE_CURRENT_SOURCE_DIR}/plugin.cpp" +# "-DTARGET=${CMAKE_CURRENT_BINARY_DIR}/plugin.cpp" +# -P "${CMAKE_CURRENT_BINARY_DIR}/replace.cmake" +# DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/plugin.cpp" "${CMAKE_CURRENT_BINARY_DIR}/replace.cmake" +# ) + + +function(create_plugin) + message("Building ${brand} as built-in plugin (create_plugin)") + + # target_sources(${PLUGIN_OPTIONS_SOURCE_LIB} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/plugin.cpp) + + set(oneValueArgs SOURCE_LIB SOURCE_ASSETS DESTINATION PLUGIN_NAME PLUGIN_JSON) + cmake_parse_arguments(PLUGIN_OPTIONS "" "${oneValueArgs}" "" ${ARGN} ) + + add_custom_command( + OUTPUT "${ASSET_DIR}/${PLUGIN_OPTIONS_PLUGIN_NAME}" + COMMAND ${CMAKE_COMMAND} -E copy_directory "${PLUGIN_OPTIONS_SOURCE_ASSETS}" "${ASSET_DIR}/${PLUGIN_OPTIONS_PLUGIN_NAME}" + COMMENT "Copying ${PLUGIN_OPTIONS_SOURCE_ASSETS} to ${ASSET_DIR}/${PLUGIN_OPTIONS_PLUGIN_NAME}" + VERBATIM + ) + + add_custom_target(${PLUGIN_OPTIONS_SOURCE_LIB}-assets + DEPENDS "${ASSET_DIR}/${PLUGIN_OPTIONS_PLUGIN_NAME}" + ) + + +endfunction() diff --git a/simulator/src/ext_plugin_builtin.hh.in b/simulator/src/ext_plugin_builtin.hh.in new file mode 100644 index 000000000..abb830732 --- /dev/null +++ b/simulator/src/ext_plugin_builtin.hh.in @@ -0,0 +1,3 @@ +inline void load_ext_builtin_plugins(auto &internal_plugins) { +${EXT_PLUGIN_INIT_CALLS} +} diff --git a/simulator/src/settings.hh b/simulator/src/settings.hh index 1b38697ba..bdfee0972 100644 --- a/simulator/src/settings.hh +++ b/simulator/src/settings.hh @@ -10,7 +10,7 @@ struct Settings { unsigned zoom = 100; std::string sdcard_path = "patches/"; std::string flash_path = "../patches/default/"; - std::string asset_file = "../firmware/build/assets.uimg"; + std::string asset_file = "build/assets.uimg"; int audioout_dev = 0; void parse(int argc, char *argv[]) {