Don't depend on global constructors for commands

This breaks when using ObjC, as these can run before the ObjC module is
initialized, resulting in non-working message sends as the selectors are
not registered yet.

FossilOrigin-Name: 1ee33c99835abc029ac202afad1f9b3bf26028e55ea1c53c53416c7566ef749d
This commit is contained in:
Jonathan Schleifer 2024-08-03 14:50:31 +00:00
parent 2fc4599331
commit 0bbe1c8bee
5 changed files with 73 additions and 8 deletions

View file

@ -1,5 +1,7 @@
// one big bad include file for the whole engine... nasty!
#import <ObjFW/ObjFW.h>
#include "tools.h"
enum // block types, order matters!
@ -390,21 +392,50 @@ enum // function signatures for script functions, see command.cpp
// nasty macros for registering script functions, abuses globals to avoid
// excessive infrastructure
#define COMMANDN(name, fun, nargs) \
static bool __dummy_##fun = addcommand(#name, (void (*)())fun, nargs)
OF_CONSTRUCTOR() \
{ \
enqueueInit(#name, ^{ \
addcommand(#name, (void (*)())fun, nargs); \
}); \
}
#define COMMAND(name, nargs) COMMANDN(name, name, nargs)
#define VARP(name, min, cur, max) \
int name = variable(#name, min, cur, max, &name, NULL, true)
int name; \
OF_CONSTRUCTOR() \
{ \
enqueueInit(#name, ^{ \
name = variable(#name, min, cur, max, &name, NULL, true); \
}); \
}
#define VAR(name, min, cur, max) \
int name = variable(#name, min, cur, max, &name, NULL, false)
int name; \
OF_CONSTRUCTOR() \
{ \
enqueueInit(#name, ^{ \
name = variable(#name, min, cur, max, &name, NULL, false); \
}); \
}
#define VARF(name, min, cur, max, body) \
void var_##name(); \
static int name = \
variable(#name, min, cur, max, &name, var_##name, false); \
static int name; \
OF_CONSTRUCTOR() \
{ \
enqueueInit(#name, ^{ \
name = variable( \
#name, min, cur, max, &name, var_##name, false); \
}); \
} \
void var_##name() { body; }
#define VARFP(name, min, cur, max, body) \
void var_##name(); \
static int name = \
variable(#name, min, cur, max, &name, var_##name, true); \
static int name; \
OF_CONSTRUCTOR() \
{ \
enqueueInit(#name, ^{ \
name = \
variable(#name, min, cur, max, &name, var_##name, true); \
}); \
} \
void var_##name() { body; }
#define ATOI(s) strtol(s, NULL, 0) // supports hexadecimal numbers

24
src/init.mm Normal file
View file

@ -0,0 +1,24 @@
#include <vector>
#import "cube.h"
#import "protos.h"
static std::vector<void (^)(void)> *queue;
void
enqueueInit(const char *name, void (^init)(void))
{
if (queue == NULL)
queue = new std::vector<void (^)(void)>();
queue->push_back(init);
}
void
processInitQueue(void)
{
for (auto &init : *queue)
init();
queue->clear();
}

View file

@ -104,6 +104,8 @@ main(int argc, char **argv)
char *sdesc = "", *ip = "", *master = NULL, *passwd = "";
islittleendian = *((char *)&islittleendian);
processInitQueue();
#define log(s) conoutf("init: %s", s)
log("sdl");

View file

@ -23,6 +23,10 @@ extern void conoutf(const char *s, ...);
extern char *getcurcommand();
extern void writebinds(FILE *f);
// init
extern void enqueueInit(const char *name, void (^init)(void));
extern void processInitQueue(void);
// menus
extern bool rendermenu();
extern void menuset(int menu);