|
|
|
10-17-2018, 01:41 AM
|
#1
|
Human being with feelings
Join Date: Jul 2009
Posts: 3,714
|
How to: SWELL_PROVIDED_BY_APP and Linux?
I am struggling to get SWELL_PROVIDED_BY_APP to work in Linux.
Here is a very minimal .cpp for an extension that provides the function "JS_Test":
Code:
// WARNING: Apparently, the file names of user extensions MUST start with "reaper_".
#define REAPERAPI_IMPLEMENT
#define REAPERAPI_MINIMAL // Only load the API functions #define'd by REAPERAPI_WANT_...
#define REAPERAPI_WANT_plugin_register
#define REAPERAPI_WANT_GetMainHwnd
//#define SWELL_PROVIDED_BY_APP
// reaper_plugin_functions.h #include's reaper_plugin.h, which in turn #include's either windows.h or swell.h, depending on platform.
// So probably only necessary to #include reaper_plugins_functions.h
#include "reaper_plugin_functions.h"
#include <cstdio>
#include <cstring>
// Example of a function that will be exported to the ReaScript API
int JS_Test()
{
RECT r{0, 0, 0, 0};
HWND w = GetMainHwnd();
GetWindowRect(w, &r); // Uncomment to test SWELL_PROVIDED_BY_APP
return r.left;
}
// Apparently, under the hood, REAPER converts all ReaScript API functions to this standard format:
// void* func(void** arglist, int numparams)
// The names and types of the parameters and return values that the user see in the IDE are registered by plugin_register(APIdef_...)
// So all functions must either be in this format, or get a wrapper function such as this:
static void* __vararg_JS_Test(void** arglist, int numparms)
{
return (void*)(intptr_t)JS_Test();
}
// (The following struct and macro are derived from SWS.)
// Struct to store info such as function name and help text for each function that the extensions intends to expose as API.
// This info will be used by REAPER's plugin_register functions to register the functions.
struct structAPIdef
{
void* func; // pointer to the function that other extensions use
const char* func_name;
void* func_vararg; // pointer to the wrapper function that ReaScript API calls
const char* regkey_vararg; // "APIvararg_funcName" - for
const char* regkey_func; // "API_funcName"
const char* regkey_def; // "APIdef_funcName"
const char* defstring; // \0-separated string for APIdef... Will be concatenated and assigned while registering function
};
// Macro to construct a comma-separated list of all the variants of a function name that are required for plugin_register(), in the order required by structAPIdef in which these variants are stored.
// APIFUNC(funcName) becomes (void*)funcName, "funcName", (void*)__vararg_funcName, "APIvararg_funcName", "API_funcName", "APIdef_funcName"
#define APIFUNC(x) (void*)x,#x,(void*)__vararg_ ## x,"APIvararg_" #x "","API_" #x "","APIdef_" #x ""
// Array of function info structs
// Each function that will be registered must be listed here.
structAPIdef arrayAPIdefs[] =
{
{ APIFUNC(JS_Test), "int\0\0\0Test\0", }
};
// REAPER calls the "REAPER_PLUGIN_ENTRYPOINT" function to load or unload plugins, so all plugins must include this function.
extern "C" REAPER_PLUGIN_DLL_EXPORT int REAPER_PLUGIN_ENTRYPOINT(REAPER_PLUGIN_HINSTANCE hInstance, reaper_plugin_info_t *rec)
{
// If rec !- nil, the extension is being loaded. If rec == nil, the extension is being UNloaded.
if (rec)
{
if (REAPERAPI_LoadAPI(rec->GetFunc) != 0)
{
fprintf(stderr, "Unable to import API functions.\n");
return 0;
}
else
{
// functions imported, continue initing plugin...
for (structAPIdef& f : arrayAPIdefs)
{
// Each function must be registered in three ways:
// APIdef_... provides for converting parameters to vararg format, and for documentation in the auto-generated REAPER API header and ReaScript documentation.
plugin_register(f.regkey_def, (void*)f.defstring);
// API_... for exposing to other extensions, and for IDE to recognize and color functions while typing .
plugin_register(f.regkey_func, f.func);
// APIvarag_... for exporting to ReaScript API.
plugin_register(f.regkey_vararg, f.func_vararg);
}
return 1; // I'm not sure the relevance is of REAPER_PLUGIN_ENTRYPOINT's return values.
}
}
// Not sure what clean-up needs to be done when REAPER quits.
// Perhaps freeing allocated memory blocks, or mouse cursors created by CreateCursor?
else
{
return 0;
}
}
If I comment out line 9: "#define SWELL_PROVIDED_BY_APP" and link the file to swell myself, the extension loads and the test function works:
Code:
g++ -fPIC -shared -I"./WDL/swell/" Minimal.cpp \
./WDL/swell/swell-appstub-generic.cpp ./WDL/swell/swell-kb-generic.cpp \
./WDL/swell/swell-dlg-generic.cpp ./WDL/swell/swell-menu-generic.cpp \
./WDL/swell/swell-gdi-generic.cpp ./WDL/swell/swell-miscdlg-generic.cpp \
./WDL/swell/swell-gdi-lice.cpp ./WDL/swell/swell-misc-generic.cpp \
./WDL/swell/swell-generic-gdk.cpp \
./WDL/swell/swell-generic-headless.cpp ./WDL/swell/swell.cpp \
./WDL/swell/swell-ini.cpp ./WDL/swell/swell-wnd-generic.cpp \
-std=c++11 -ldl -lXi -lX11 -lfreetype `pkg-config --cflags --libs gtk+-3.0` \
-o reaper_minimal32.so
However, if I uncomment the #define, and only link with swell-modstub-generic.cpp, the extension fails to load, with an error "undefined symbol: GetWindowRect":
Code:
g++ -fPIC -shared -I"./WDL/swell/" Minimal.cpp \
./WDL/swell/swell-modstub-generic.cpp \
-std=c++11 \
-o reaper_minimal32.so
|
|
|
10-17-2018, 02:16 AM
|
#2
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
|
swell-modstub-generic.cpp must be built with SWELL_PROVIDED_BY_APP set. Otherwise it does absolutely nothing (there's a big ifdef in it).
You can define it for every source files being built using the compiler command line: -DSWELL_PROVIDED_BY_APP.
Last edited by cfillion; 10-17-2018 at 02:23 AM.
|
|
|
10-18-2018, 01:11 PM
|
#3
|
Administrator
Join Date: Jan 2005
Location: NYC
Posts: 15,721
|
Quote:
Originally Posted by cfillion
You can define it for every source files being built using the compiler command line: -DSWELL_PROVIDED_BY_APP.
|
This is very much recommended. Also, for best compatibility you should not build with swell directly, and just use that with swell-modstub-generic.cpp in order to use REAPER's (or the end-user's customized) libSwell.so. If you do this, you can also drop the pkg-config and -lX11 stuff, as that'll all be handled for you.
|
|
|
10-18-2018, 01:16 PM
|
#4
|
Human being with feelings
Join Date: Jul 2009
Posts: 3,714
|
Quote:
Originally Posted by cfillion
swell-modstub-generic.cpp must be built with SWELL_PROVIDED_BY_APP set. Otherwise it does absolutely nothing (there's a big ifdef in it).
|
Ah, got it. The new version of js_ReaScriptAPI now loads properly in Linux.
|
|
|
04-21-2019, 08:32 AM
|
#5
|
Human being with feelings
Join Date: Oct 2007
Location: home is where the heart is
Posts: 12,096
|
Sorry for reviving this, as I'm looking into crossplatform development myself currently...
What's the difference between swell-modstub-generic.cpp and swell-modstub.mm, i.e. when to use which? (seeing that OSX uses swell-modstub.mm on OSX).
|
|
|
04-21-2019, 08:51 AM
|
#6
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
|
Files with the -generic suffix are the Linux port of SWELL. Objective-C (.mm) files are for macOS.
|
|
|
04-21-2019, 09:07 AM
|
#7
|
Human being with feelings
Join Date: Oct 2007
Location: home is where the heart is
Posts: 12,096
|
Thanks.
|
|
|
Thread Tools |
|
Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -7. The time now is 08:58 AM.
|