From 90c58250ed8f10996000bc6cea10385f97969847 Mon Sep 17 00:00:00 2001 From: cbdev Date: Sat, 23 Mar 2019 14:30:11 +0100 Subject: Fix link visibilities --- plugin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'plugin.c') diff --git a/plugin.c b/plugin.c index 48db410..fc642ac 100644 --- a/plugin.c +++ b/plugin.c @@ -8,8 +8,8 @@ #include #include "plugin.h" -size_t plugins = 0; -void** plugin_handle = NULL; +static size_t plugins = 0; +static void** plugin_handle = NULL; static int plugin_attach(char* path, char* file){ plugin_init init = NULL; -- cgit v1.2.3 From 20a6882a063404858588596bd3f12bdd9e53460a Mon Sep 17 00:00:00 2001 From: cbdev Date: Sat, 3 Aug 2019 18:42:39 +0200 Subject: Windows build compatiblity --- .gitignore | 3 +++ Makefile | 23 +++++++++++++++++-- backend.c | 31 ++++++++++++++----------- backend.h | 9 +++++++- backends/Makefile | 26 +++++++++++++++++++-- backends/artnet.c | 16 ++++++++----- backends/artnet.h | 2 ++ backends/libmmbackend.c | 12 ++++++++-- backends/libmmbackend.h | 6 +++++ backends/lua.c | 4 ---- backends/osc.c | 18 +++++++++------ backends/osc.h | 2 ++ backends/sacn.c | 28 ++++++++++++++--------- backends/sacn.h | 1 - config.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ midimonster.c | 39 ++++++++++++++++++++++++++------ midimonster.h | 38 ++++++++++++++++++++++++------- monster.cfg | 12 +++------- plugin.c | 60 +++++++++++++++++++++++++++++++++++++++++++++---- portability.h | 17 ++++++++++++++ 20 files changed, 326 insertions(+), 77 deletions(-) (limited to 'plugin.c') diff --git a/.gitignore b/.gitignore index 3afd872..4396a38 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ midimonster +midimonster.exe +libmmapi.a *.swp *.o *.so +*.dll diff --git a/Makefile b/Makefile index 5ee9cd9..b82d6d8 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,14 @@ -.PHONY: all clean run sanitize backends full backends-full +.PHONY: all clean run sanitize backends windows full backends-full OBJS = config.o backend.o plugin.o PLUGINDIR = "\"./backends/\"" +PLUGINDIR_W32 = "\"backends\\\\\"" SYSTEM := $(shell uname -s) -CFLAGS ?= -g -Wall +CFLAGS ?= -g -Wall -Wpedantic +# Hide all non-API symbols for export +CFLAGS += -fvisibility=hidden + #CFLAGS += -DDEBUG midimonster: LDLIBS = -ldl midimonster: CFLAGS += -DPLUGINS=$(PLUGINDIR) @@ -21,6 +25,8 @@ all: midimonster backends full: midimonster backends-full +windows: midimonster.exe + backends: $(MAKE) -C backends @@ -31,8 +37,21 @@ backends-full: midimonster: midimonster.c portability.h $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $< $(OBJS) $(LDLIBS) -o $@ +midimonster.exe: export CC = x86_64-w64-mingw32-gcc +#midimonster.exe: CFLAGS += -Wno-format +midimonster.exe: CFLAGS += -DPLUGINS=$(PLUGINDIR_W32) -Wno-format +midimonster.exe: LDLIBS = -lws2_32 +midimonster.exe: LDFLAGS += -Wl,--out-implib,libmmapi.a +midimonster.exe: midimonster.c portability.h $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $< $(OBJS) $(LDLIBS) -o $@ + # The windows build for backends requires the import library generated with the build, + # so the backends can't be a prerequisite for the executable... + $(MAKE) -C backends windows + clean: $(RM) midimonster + $(RM) midimonster.exe + $(RM) libmmapi.a $(RM) $(OBJS) $(MAKE) -C backends clean diff --git a/backend.c b/backend.c index 5df5d73..4fa7704 100644 --- a/backend.c +++ b/backend.c @@ -1,4 +1,9 @@ #include +#ifndef _WIN32 +#define MM_API __attribute__((visibility ("default"))) +#else +#define MM_API __attribute__((dllexport)) +#endif #include "midimonster.h" #include "backend.h" @@ -26,7 +31,7 @@ int backends_handle(size_t nfds, managed_fd* fds){ } } - DBGPF("Notifying backend %s of %zu waiting FDs\n", backends[u].name, n); + DBGPF("Notifying backend %s of %lu waiting FDs\n", backends[u].name, n); rv |= backends[u].process(n, fds); if(rv){ fprintf(stderr, "Backend %s failed to handle input\n", backends[u].name); @@ -59,28 +64,28 @@ int backends_notify(size_t nev, channel** c, channel_value* v){ } } - DBGPF("Calling handler for instance %s with %zu events\n", instances[u]->name, n); + DBGPF("Calling handler for instance %s with %lu events\n", instances[u]->name, n); rv |= instances[u]->backend->handle(instances[u], n, c, v); } return 0; } -channel* mm_channel(instance* i, uint64_t ident, uint8_t create){ +channel* MM_API mm_channel(instance* inst, uint64_t ident, uint8_t create){ size_t u; for(u = 0; u < nchannels; u++){ - if(channels[u]->instance == i && channels[u]->ident == ident){ - DBGPF("Requested channel %zu on instance %s already exists, reusing\n", ident, i->name); + if(channels[u]->instance == inst && channels[u]->ident == ident){ + DBGPF("Requested channel %lu on instance %s already exists, reusing\n", ident, inst->name); return channels[u]; } } if(!create){ - DBGPF("Requested unknown channel %zu on instance %s\n", ident, i->name); + DBGPF("Requested unknown channel %lu on instance %s\n", ident, inst->name); return NULL; } - DBGPF("Creating previously unknown channel %zu on instance %s\n", ident, i->name); + DBGPF("Creating previously unknown channel %lu on instance %s\n", ident, inst->name); channel** new_chan = realloc(channels, (nchannels + 1) * sizeof(channel*)); if(!new_chan){ fprintf(stderr, "Failed to allocate memory\n"); @@ -95,12 +100,12 @@ channel* mm_channel(instance* i, uint64_t ident, uint8_t create){ return NULL; } - channels[nchannels]->instance = i; + channels[nchannels]->instance = inst; channels[nchannels]->ident = ident; return channels[nchannels++]; } -instance* mm_instance(){ +instance* MM_API mm_instance(){ instance** new_inst = realloc(instances, (ninstances + 1) * sizeof(instance*)); if(!new_inst){ //TODO free @@ -118,7 +123,7 @@ instance* mm_instance(){ return instances[ninstances++]; } -instance* mm_instance_find(char* name, uint64_t ident){ +instance* MM_API mm_instance_find(char* name, uint64_t ident){ size_t u; backend* b = backend_match(name); if(!b){ @@ -134,7 +139,7 @@ instance* mm_instance_find(char* name, uint64_t ident){ return NULL; } -int mm_backend_instances(char* name, size_t* ninst, instance*** inst){ +int MM_API mm_backend_instances(char* name, size_t* ninst, instance*** inst){ backend* b = backend_match(name); size_t n = 0, u; //count number of affected instances @@ -177,7 +182,7 @@ void instances_free(){ void channels_free(){ size_t u; for(u = 0; u < nchannels; u++){ - DBGPF("Destroying channel %zu on instance %s\n", channels[u]->ident, channels[u]->instance->name); + DBGPF("Destroying channel %lu on instance %s\n", channels[u]->ident, channels[u]->instance->name); if(channels[u]->impl){ channels[u]->instance->backend->channel_free(channels[u]); } @@ -232,7 +237,7 @@ struct timeval backend_timeout(){ return tv; } -int mm_backend_register(backend b){ +int MM_API mm_backend_register(backend b){ if(!backend_match(b.name)){ backends = realloc(backends, (nbackends + 1) * sizeof(backend)); if(!backends){ diff --git a/backend.h b/backend.h index daf96bc..7529154 100644 --- a/backend.h +++ b/backend.h @@ -1,8 +1,8 @@ #include +/* Internal API */ int backends_handle(size_t nfds, managed_fd* fds); int backends_notify(size_t nev, channel** c, channel_value* v); - backend* backend_match(char* name); instance* instance_match(char* name); struct timeval backend_timeout(); @@ -10,3 +10,10 @@ int backends_start(); int backends_stop(); void instances_free(); void channels_free(); + +/* Backend API */ +channel* MM_API mm_channel(instance* inst, uint64_t ident, uint8_t create); +instance* MM_API mm_instance(); +instance* MM_API mm_instance_find(char* name, uint64_t ident); +int MM_API mm_backend_instances(char* name, size_t* ninst, instance*** inst); +int MM_API mm_backend_register(backend b); diff --git a/backends/Makefile b/backends/Makefile index 22cb95b..2374df0 100644 --- a/backends/Makefile +++ b/backends/Makefile @@ -1,12 +1,13 @@ .PHONY: all clean full OPTIONAL_BACKENDS = ola.so +WINDOWS_BACKENDS = loopback.dll artnet.dll osc.dll sacn.dll LINUX_BACKENDS = midi.so evdev.so BACKENDS = artnet.so osc.so loopback.so sacn.so lua.so BACKEND_LIB = libmmbackend.o SYSTEM := $(shell uname -s) -CFLAGS += -g -fPIC -I../ +CFLAGS += -g -fPIC -I../ -Wall -Wpedantic CPPFLAGS += -g -fPIC -I../ LDFLAGS += -shared @@ -20,8 +21,17 @@ LDFLAGS += -undefined dynamic_lookup endif artnet.so: ADDITIONAL_OBJS += $(BACKEND_LIB) +artnet.dll: ADDITIONAL_OBJS += $(BACKEND_LIB) +artnet.dll: LDLIBS += -lws2_32 + osc.so: ADDITIONAL_OBJS += $(BACKEND_LIB) +osc.dll: ADDITIONAL_OBJS += $(BACKEND_LIB) +osc.dll: LDLIBS += -lws2_32 + sacn.so: ADDITIONAL_OBJS += $(BACKEND_LIB) +sacn.dll: ADDITIONAL_OBJS += $(BACKEND_LIB) +sacn.dll: LDLIBS += -lws2_32 + midi.so: LDLIBS = -lasound evdev.so: CFLAGS += $(shell pkg-config --cflags libevdev) evdev.so: LDLIBS = $(shell pkg-config --libs libevdev) @@ -33,12 +43,24 @@ lua.so: LDLIBS += $(shell pkg-config --libs lua5.3) %.so :: %.c %.h $(BACKEND_LIB) $(CC) $(CFLAGS) $(LDLIBS) $< $(ADDITIONAL_OBJS) -o $@ $(LDFLAGS) +%.dll :: %.c %.h $(BACKEND_LIB) + $(CC) $(CFLAGS) $< $(ADDITIONAL_OBJS) -o $@ $(LDFLAGS) $(LDLIBS) + %.so :: %.cpp %.h $(CXX) $(CPPFLAGS) $(LDLIBS) $< $(ADDITIONAL_OBJS) -o $@ $(LDFLAGS) all: $(BACKEND_LIB) $(BACKENDS) +../libmmapi.a: + $(MAKE) -C ../ midimonster.exe + +windows: export CC = x86_64-w64-mingw32-gcc +windows: LDLIBS += -lmmapi +windows: LDFLAGS += -L../ +windows: CFLAGS += -Wno-format -Wno-pointer-sign +windows: ../libmmapi.a $(BACKEND_LIB) $(WINDOWS_BACKENDS) + full: $(BACKEND_LIB) $(BACKENDS) $(OPTIONAL_BACKENDS) clean: - $(RM) $(BACKEND_LIB) $(BACKENDS) $(OPTIONAL_BACKENDS) + $(RM) $(BACKEND_LIB) $(BACKENDS) $(OPTIONAL_BACKENDS) $(WINDOWS_BACKENDS) diff --git a/backends/artnet.c b/backends/artnet.c index 8b404a6..a6df4ab 100644 --- a/backends/artnet.c +++ b/backends/artnet.c @@ -3,8 +3,8 @@ #include #include "libmmbackend.h" - #include "artnet.h" + #define MAX_FDS 255 #define BACKEND_NAME "artnet" @@ -32,7 +32,7 @@ static int artnet_listener(char* host, char* port){ return -1; } - fprintf(stderr, "ArtNet backend interface %zu bound to %s port %s\n", artnet_fds, host, port); + fprintf(stderr, "ArtNet backend interface %lu bound to %s port %s\n", artnet_fds, host, port); artnet_fd[artnet_fds].fd = fd; artnet_fd[artnet_fds].output_instances = 0; artnet_fd[artnet_fds].output_instance = NULL; @@ -212,7 +212,7 @@ static int artnet_transmit(instance* inst){ }; memcpy(frame.data, data->data.out, 512); - if(sendto(artnet_fd[data->fd_index].fd, &frame, sizeof(frame), 0, (struct sockaddr*) &data->dest_addr, data->dest_len) < 0){ + if(sendto(artnet_fd[data->fd_index].fd, (uint8_t*) &frame, sizeof(frame), 0, (struct sockaddr*) &data->dest_addr, data->dest_len) < 0){ fprintf(stderr, "Failed to output ArtNet frame for instance %s: %s\n", inst->name, strerror(errno)); } @@ -230,7 +230,7 @@ static int artnet_set(instance* inst, size_t num, channel** c, channel_value* v) artnet_instance_data* data = (artnet_instance_data*) inst->impl; if(!data->dest_len){ - fprintf(stderr, "ArtNet instance %s not enabled for output (%zu channel events)\n", inst->name, num); + fprintf(stderr, "ArtNet instance %s not enabled for output (%lu channel events)\n", inst->name, num); return 0; } @@ -295,7 +295,7 @@ static inline int artnet_process_frame(instance* inst, artnet_pkt* frame){ } if(!chan){ - fprintf(stderr, "Active channel %zu on %s not known to core\n", p, inst->name); + fprintf(stderr, "Active channel %lu on %s not known to core\n", p, inst->name); return 1; } @@ -367,7 +367,11 @@ static int artnet_handle(size_t num, managed_fd* fds){ } } while(bytes_read > 0); + #ifdef _WIN32 + if(bytes_read < 0 && WSAGetLastError() != WSAEWOULDBLOCK){ + #else if(bytes_read < 0 && errno != EAGAIN){ + #endif fprintf(stderr, "ArtNet failed to receive data: %s\n", strerror(errno)); } @@ -438,7 +442,7 @@ static int artnet_start(){ } } - fprintf(stderr, "ArtNet backend registering %zu descriptors to core\n", artnet_fds); + fprintf(stderr, "ArtNet backend registering %lu descriptors to core\n", artnet_fds); for(u = 0; u < artnet_fds; u++){ if(mm_manage_fd(artnet_fd[u].fd, BACKEND_NAME, 1, (void*) u)){ goto bail; diff --git a/backends/artnet.h b/backends/artnet.h index 90aedd5..f5aa745 100644 --- a/backends/artnet.h +++ b/backends/artnet.h @@ -1,4 +1,6 @@ +#ifndef _WIN32 #include +#endif #include "midimonster.h" int init(); diff --git a/backends/libmmbackend.c b/backends/libmmbackend.c index 6320611..b27ebc5 100644 --- a/backends/libmmbackend.c +++ b/backends/libmmbackend.c @@ -53,7 +53,7 @@ int mmbackend_parse_sockaddr(char* host, char* port, struct sockaddr_storage* ad } int mmbackend_socket(char* host, char* port, int socktype, uint8_t listener){ - int fd = -1, status, yes = 1, flags; + int fd = -1, status, yes = 1; struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = socktype, @@ -106,12 +106,20 @@ int mmbackend_socket(char* host, char* port, int socktype, uint8_t listener){ } //set nonblocking - flags = fcntl(fd, F_GETFL, 0); + #ifdef _WIN32 + u_long mode = 1; + if(ioctlsocket(fd, FIONBIO, &mode) != NO_ERROR){ + closesocket(fd); + return 1; + } + #else + int flags = fcntl(fd, F_GETFL, 0); if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0){ fprintf(stderr, "Failed to set socket nonblocking\n"); close(fd); return -1; } + #endif return fd; } diff --git a/backends/libmmbackend.h b/backends/libmmbackend.h index 38bfca0..77cad6a 100644 --- a/backends/libmmbackend.h +++ b/backends/libmmbackend.h @@ -1,14 +1,20 @@ #include #include #include +#ifdef _WIN32 +#include +//#define close closesocket +#else #include #include +#endif #include #include #include #include #include #include +#include "../portability.h" /* Parse spec as host specification in the form * host port diff --git a/backends/lua.c b/backends/lua.c index 4a910a2..ec02575 100644 --- a/backends/lua.c +++ b/backends/lua.c @@ -161,8 +161,6 @@ static int lua_callback_output(lua_State* interpreter){ static int lua_callback_interval(lua_State* interpreter){ size_t n = 0; - instance* inst = NULL; - lua_instance_data* data = NULL; uint64_t interval = 0; int reference = LUA_NOREF; @@ -174,8 +172,6 @@ static int lua_callback_interval(lua_State* interpreter){ //get instance pointer from registry lua_pushstring(interpreter, LUA_REGISTRY_KEY); lua_gettable(interpreter, LUA_REGISTRYINDEX); - inst = (instance*) lua_touserdata(interpreter, -1); - data = (lua_instance_data*) inst->impl; //fetch and round the interval interval = luaL_checkinteger(interpreter, 2); diff --git a/backends/osc.c b/backends/osc.c index 18c8bad..03e431f 100644 --- a/backends/osc.c +++ b/backends/osc.c @@ -1,8 +1,8 @@ #include #include #include -#include "libmmbackend.h" +#include "libmmbackend.h" #include "osc.h" /* @@ -480,14 +480,14 @@ static int osc_register_pattern(osc_instance_data* data, char* pattern_path, cha //parse min/max values token = strtok(NULL, " "); if(!token){ - fprintf(stderr, "Missing minimum specification for parameter %zu of OSC pattern %s\n", u, pattern_path); + fprintf(stderr, "Missing minimum specification for parameter %lu of OSC pattern %s\n", u, pattern_path); return 1; } data->pattern[pattern].min[u] = osc_parse_value_spec(format[u], token); token = strtok(NULL, " "); if(!token){ - fprintf(stderr, "Missing maximum specification for parameter %zu of OSC pattern %s\n", u, pattern_path); + fprintf(stderr, "Missing maximum specification for parameter %lu of OSC pattern %s\n", u, pattern_path); return 1; } data->pattern[pattern].max[u] = osc_parse_value_spec(format[u], token); @@ -689,7 +689,7 @@ static int osc_output_channel(instance* inst, size_t channel){ //write data if(offset + osc_data_length(data->channel[channel].type[p]) >= sizeof(xmit_buf)){ - fprintf(stderr, "Insufficient buffer size for OSC transmitting channel %s.%s at parameter %zu\n", inst->name, data->channel[channel].path, p); + fprintf(stderr, "Insufficient buffer size for OSC transmitting channel %s.%s at parameter %lu\n", inst->name, data->channel[channel].path, p); return 1; } @@ -720,7 +720,7 @@ static int osc_set(instance* inst, size_t num, channel** c, channel_value* v){ osc_instance_data* data = (osc_instance_data*) inst->impl; if(!data->dest_len){ - fprintf(stderr, "OSC instance %s does not have a destination, output is disabled (%zu channels)\n", inst->name, num); + fprintf(stderr, "OSC instance %s does not have a destination, output is disabled (%lu channels)\n", inst->name, num); return 0; } @@ -778,7 +778,7 @@ static int osc_process_packet(instance* inst, char* local_path, char* format, ui channel* chan = NULL; if(payload_len % 4){ - fprintf(stderr, "Invalid OSC packet, data length %zu\n", payload_len); + fprintf(stderr, "Invalid OSC packet, data length %lu\n", payload_len); return 0; } @@ -877,7 +877,11 @@ static int osc_handle(size_t num, managed_fd* fds){ } } while(bytes_read > 0); + #ifdef _WIN32 + if(bytes_read < 0 && WSAGetLastError() != WSAEWOULDBLOCK){ + #else if(bytes_read < 0 && errno != EAGAIN){ + #endif fprintf(stderr, "OSC failed to receive data for instance %s: %s\n", inst->name, strerror(errno)); } @@ -924,7 +928,7 @@ static int osc_start(){ } } - fprintf(stderr, "OSC backend registered %zu descriptors to core\n", fds); + fprintf(stderr, "OSC backend registered %lu descriptors to core\n", fds); free(inst); return 0; diff --git a/backends/osc.h b/backends/osc.h index 4e9dec5..b2aaea7 100644 --- a/backends/osc.h +++ b/backends/osc.h @@ -1,6 +1,8 @@ #include "midimonster.h" #include +#ifndef _WIN32 #include +#endif #define OSC_RECV_BUF 8192 #define OSC_XMIT_BUF 8192 diff --git a/backends/sacn.c b/backends/sacn.c index 75bb76f..6f7d1a5 100644 --- a/backends/sacn.c +++ b/backends/sacn.c @@ -1,16 +1,18 @@ #include #include -#include -#include #include #include #include #include +#ifndef _WIN32 +#include #include +#include +#endif #include "libmmbackend.h" - #include "sacn.h" + //upper limit imposed by using the fd index as 16-bit part of the instance id #define MAX_FDS 4096 #define BACKEND_NAME "sacn" @@ -71,7 +73,7 @@ static int sacn_listener(char* host, char* port, uint8_t fd_flags){ return -1; } - fprintf(stderr, "sACN backend interface %zu bound to %s port %s\n", global_cfg.fds, host, port); + fprintf(stderr, "sACN backend interface %lu bound to %s port %s\n", global_cfg.fds, host, port); global_cfg.fd[global_cfg.fds].fd = fd; global_cfg.fd[global_cfg.fds].flags = fd_flags; global_cfg.fd[global_cfg.fds].universes = 0; @@ -271,7 +273,7 @@ static int sacn_transmit(instance* inst){ memcpy(pdu.data.source_name, global_cfg.source_name, sizeof(pdu.data.source_name)); memcpy((((uint8_t*)pdu.data.data) + 1), data->data.out, 512); - if(sendto(global_cfg.fd[data->fd_index].fd, &pdu, sizeof(pdu), 0, (struct sockaddr*) &data->dest_addr, data->dest_len) < 0){ + if(sendto(global_cfg.fd[data->fd_index].fd, (uint8_t*) &pdu, sizeof(pdu), 0, (struct sockaddr*) &data->dest_addr, data->dest_len) < 0){ fprintf(stderr, "Failed to output sACN frame for instance %s: %s\n", inst->name, strerror(errno)); } @@ -293,7 +295,7 @@ static int sacn_set(instance* inst, size_t num, channel** c, channel_value* v){ } if(!data->xmit_prio){ - fprintf(stderr, "sACN instance %s not enabled for output (%zu channel events)\n", inst->name, num); + fprintf(stderr, "sACN instance %s not enabled for output (%lu channel events)\n", inst->name, num); return 0; } @@ -378,7 +380,7 @@ static int sacn_process_frame(instance* inst, sacn_frame_root* frame, sacn_frame } if(!chan){ - fprintf(stderr, "Active channel %zu on %s not known to core", u, inst->name); + fprintf(stderr, "Active channel %lu on %s not known to core", u, inst->name); return 1; } @@ -445,8 +447,8 @@ static void sacn_discovery(size_t fd){ pdu.data.page = page; memcpy(pdu.data.data, global_cfg.fd[fd].universe + page * 512, universes * sizeof(uint16_t)); - if(sendto(global_cfg.fd[fd].fd, &pdu, sizeof(pdu) - (512 - universes) * sizeof(uint16_t), 0, (struct sockaddr*) &discovery_dest, sizeof(discovery_dest)) < 0){ - fprintf(stderr, "Failed to output sACN universe discovery frame for interface %zu: %s\n", fd, strerror(errno)); + if(sendto(global_cfg.fd[fd].fd, (uint8_t*) &pdu, sizeof(pdu) - (512 - universes) * sizeof(uint16_t), 0, (struct sockaddr*) &discovery_dest, sizeof(discovery_dest)) < 0){ + fprintf(stderr, "Failed to output sACN universe discovery frame for interface %lu: %s\n", fd, strerror(errno)); } } } @@ -512,7 +514,11 @@ static int sacn_handle(size_t num, managed_fd* fds){ } } while(bytes_read > 0); + #ifdef _WIN32 + if(bytes_read < 0 && WSAGetLastError() != WSAEWOULDBLOCK){ + #else if(bytes_read < 0 && errno != EAGAIN){ + #endif fprintf(stderr, "sACN failed to receive data: %s\n", strerror(errno)); } @@ -577,7 +583,7 @@ static int sacn_start(){ if(!data->unicast_input){ mcast_req.imr_multiaddr.s_addr = htobe32(((uint32_t) 0xefff0000) | ((uint32_t) data->uni)); - if(setsockopt(global_cfg.fd[data->fd_index].fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcast_req, sizeof(mcast_req))){ + if(setsockopt(global_cfg.fd[data->fd_index].fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (uint8_t*) &mcast_req, sizeof(mcast_req))){ fprintf(stderr, "Failed to join Multicast group for sACN universe %u on instance %s: %s\n", data->uni, inst[u]->name, strerror(errno)); } } @@ -604,7 +610,7 @@ static int sacn_start(){ } } - fprintf(stderr, "sACN backend registering %zu descriptors to core\n", global_cfg.fds); + fprintf(stderr, "sACN backend registering %lu descriptors to core\n", global_cfg.fds); for(u = 0; u < global_cfg.fds; u++){ //allocate memory for storing last frame transmission timestamp global_cfg.fd[u].last_frame = calloc(global_cfg.fd[u].universes, sizeof(uint64_t)); diff --git a/backends/sacn.h b/backends/sacn.h index e7106f7..7af2a36 100644 --- a/backends/sacn.h +++ b/backends/sacn.h @@ -1,4 +1,3 @@ -#include #include "midimonster.h" int init(); diff --git a/config.c b/config.c index 6d5fd16..93fb56d 100644 --- a/config.c +++ b/config.c @@ -20,6 +20,62 @@ typedef enum { static backend* current_backend = NULL; static instance* current_instance = NULL; +#ifdef _WIN32 +#define GETLINE_BUFFER 4096 + +static ssize_t getline(char** line, size_t* alloc, FILE* stream){ + size_t bytes_read = 0; + char c; + //sanity checks + if(!line || !alloc || !stream){ + return -1; + } + + //allocate buffer if none provided + if(!*line || !*alloc){ + *alloc = GETLINE_BUFFER; + *line = calloc(GETLINE_BUFFER, sizeof(char)); + if(!*line){ + fprintf(stderr, "Failed to allocate memory\n"); + return -1; + } + } + + if(feof(stream)){ + return -1; + } + + for(c = fgetc(stream); 1; c = fgetc(stream)){ + //end of buffer, resize + if(bytes_read == (*alloc) - 1){ + *alloc += GETLINE_BUFFER; + *line = realloc(*line, (*alloc) * sizeof(char)); + if(!*line){ + fprintf(stderr, "Failed to allocate memory\n"); + return -1; + } + } + + //store character + (*line)[bytes_read] = c; + + //end of line + if(feof(stream) || c == '\n'){ + //terminate string + (*line)[bytes_read + 1] = 0; + return bytes_read; + } + + //input broken + if(ferror(stream) || c < 0){ + return -1; + } + + bytes_read++; + } +} +#endif + static char* config_trim_line(char* in){ ssize_t n; //trim front diff --git a/midimonster.c b/midimonster.c index fb664a4..df27ca3 100644 --- a/midimonster.c +++ b/midimonster.c @@ -1,9 +1,14 @@ #include #include -#include #include #include #include +#ifndef _WIN32 +#include +#define MM_API __attribute__((visibility("default"))) +#else +#define MM_API __attribute__((dllexport)) +#endif #include "midimonster.h" #include "config.h" #include "backend.h" @@ -35,11 +40,14 @@ static void signal_handler(int signum){ shutdown_requested = 1; } -uint64_t mm_timestamp(){ +uint64_t MM_API mm_timestamp(){ return global_timestamp; } static void update_timestamp(){ + #ifdef _WIN32 + global_timestamp = GetTickCount(); + #else struct timespec current; if(clock_gettime(CLOCK_MONOTONIC_COARSE, ¤t)){ fprintf(stderr, "Failed to update global timestamp, time-based processing for some backends may be impaired: %s\n", strerror(errno)); @@ -47,6 +55,7 @@ static void update_timestamp(){ } global_timestamp = current.tv_sec * 1000 + current.tv_nsec / 1000000; + #endif } int mm_map_channel(channel* from, channel* to){ @@ -99,7 +108,7 @@ void map_free(){ map = NULL; } -int mm_manage_fd(int new_fd, char* back, int manage, void* impl){ +int MM_API mm_manage_fd(int new_fd, char* back, int manage, void* impl){ backend* b = backend_match(back); size_t u; @@ -163,7 +172,7 @@ void fds_free(){ fd = NULL; } -int mm_channel_event(channel* c, channel_value v){ +int MM_API mm_channel_event(channel* c, channel_value v){ size_t u, p; //find mapped channels @@ -229,7 +238,7 @@ static fd_set fds_collect(int* max_fd){ *max_fd = -1; } - DBGPF("Building selector set from %zu FDs registered to core\n", fds); + DBGPF("Building selector set from %lu FDs registered to core\n", fds); FD_ZERO(&rv_fds); for(u = 0; u < fds; u++){ if(fd[u].fd >= 0){ @@ -243,6 +252,17 @@ static fd_set fds_collect(int* max_fd){ return rv_fds; } +int platform_initialize(){ +#ifdef _WIN32 + WSADATA wsa; + WORD version = MAKEWORD(2, 2); + if(WSAStartup(version, &wsa)){ + return 1; + } +#endif + return 0; +} + int main(int argc, char** argv){ fd_set all_fds, read_fds; event_collection* secondary = NULL; @@ -255,6 +275,11 @@ int main(int argc, char** argv){ cfg_file = argv[1]; } + if(platform_initialize()){ + fprintf(stderr, "Failed to perform platform-specific initialization\n"); + return EXIT_FAILURE; + } + FD_ZERO(&all_fds); //initialize backends if(plugins_load(PLUGINS)){ @@ -316,14 +341,14 @@ int main(int argc, char** argv){ update_timestamp(); //run backend processing, collect events - DBGPF("%zu backend FDs signaled\n", n); + DBGPF("%lu backend FDs signaled\n", n); if(backends_handle(n, signaled_fds)){ goto bail; } while(primary->n){ //swap primary and secondary event collectors - DBGPF("Swapping event collectors, %zu events in primary\n", primary->n); + DBGPF("Swapping event collectors, %lu events in primary\n", primary->n); for(u = 0; u < sizeof(event_pool) / sizeof(event_collection); u++){ if(primary != event_pool + u){ secondary = primary; diff --git a/midimonster.h b/midimonster.h index 7f70f5b..eb118c6 100644 --- a/midimonster.h +++ b/midimonster.h @@ -4,6 +4,21 @@ #include #include +#ifndef MM_API + #ifdef _WIN32 + #define MM_API __attribute__((dllimport)) + #else + #define MM_API + #endif +#endif + +/* GCC ignores the visibility attributes on some API functions, so override visibility */ +#if !defined(_WIN32) && defined(__GNUC__) && !defined(__clang__) + #undef MM_API + #define MM_API + #pragma GCC visibility push(default) +#endif + /* Straight-forward min / max macros */ #define max(a,b) (((a) > (b)) ? (a) : (b)) #define min(a,b) (((a) < (b)) ? (a) : (b)) @@ -187,7 +202,7 @@ typedef struct /*_mm_channel_mapping*/ { /* * Register a new backend. */ -int mm_backend_register(backend b); +int MM_API mm_backend_register(backend b); /* * Provides a pointer to a newly (zero-)allocated instance. @@ -201,7 +216,8 @@ int mm_backend_register(backend b); * mmbackend_shutdown procedure of the backend, eg. by querying * all instances for the backend. */ -instance* mm_instance(); +instance* MM_API mm_instance(); + /* * Finds an instance matching the specified backend and identifier. * Since setting an identifier for an instance is optional, @@ -209,7 +225,8 @@ instance* mm_instance(); * Instance identifiers may for example be set in the backends * mmbackend_start call. */ -instance* mm_instance_find(char* backend, uint64_t ident); +instance* MM_API mm_instance_find(char* backend, uint64_t ident); + /* * Provides a pointer to a channel structure, pre-filled with * the provided instance reference and identifier. @@ -224,30 +241,35 @@ instance* mm_instance_find(char* backend, uint64_t ident); * this function, the backend will receive a call to its channel_free * function. */ -channel* mm_channel(instance* i, uint64_t ident, uint8_t create); +channel* MM_API mm_channel(instance* i, uint64_t ident, uint8_t create); //TODO channel* mm_channel_find() + /* * Register (manage = 1) or unregister (manage = 0) a file descriptor * to be selected on. The backend will be notified when the descriptor * becomes ready to read via its registered mmbackend_process_fd call. */ -int mm_manage_fd(int fd, char* backend, int manage, void* impl); +int MM_API mm_manage_fd(int fd, char* backend, int manage, void* impl); + /* * Notifies the core of a channel event. Called by backends to * inject events gathered from their backing implementation. */ -int mm_channel_event(channel* c, channel_value v); +int MM_API mm_channel_event(channel* c, channel_value v); + /* * Query all active instances for a given backend. * *i will need to be freed by the caller. */ -int mm_backend_instances(char* backend, size_t* n, instance*** i); +int MM_API mm_backend_instances(char* backend, size_t* n, instance*** i); + /* * Query an internal timestamp, which is updated every core iteration. * This timestamp should not be used as a performance counter, but can be * used for timeouting. Resolution is milliseconds. */ -uint64_t mm_timestamp(); +uint64_t MM_API mm_timestamp(); + /* * Create a channel-to-channel mapping. This API should not * be used by backends. It is only exported for core modules. diff --git a/monster.cfg b/monster.cfg index 2e6f76f..2413f6d 100644 --- a/monster.cfg +++ b/monster.cfg @@ -1,18 +1,12 @@ [backend artnet] bind = 0.0.0.0 -[backend evdev] +[loopback loop] [artnet art] universe = 0 dest = 255.255.255.255 -[evdev mouse] -input = TPPS - -[loopback loop] - [map] -mouse.EV_REL.REL_X > loop.chan0 -art.{3..4}{4..3} > loop.chan{4..3}{3..4} -art.{1..10} > loop.data{1..10} + +art.1+2 > loop.b diff --git a/plugin.c b/plugin.c index fc642ac..a452559 100644 --- a/plugin.c +++ b/plugin.c @@ -1,11 +1,20 @@ #include #include -#include #include #include #include #include #include +#include "portability.h" +#ifdef _WIN32 +#define dlclose FreeLibrary +#define dlsym GetProcAddress +#define dlerror() "Failed" +#define dlopen(lib,ig) LoadLibrary(lib) +#else +#include +#endif + #include "plugin.h" static size_t plugins = 0; @@ -14,19 +23,29 @@ static void** plugin_handle = NULL; static int plugin_attach(char* path, char* file){ plugin_init init = NULL; void* handle = NULL; + char* lib = NULL; + char* error = NULL; - char* lib = calloc(strlen(path) + strlen(file) + 1, sizeof(char)); + lib = calloc(strlen(path) + strlen(file) + 1, sizeof(char)); if(!lib){ fprintf(stderr, "Failed to allocate memory\n"); return 1; } - snprintf(lib, strlen(path) + strlen(file) + 1, "%s%s", path, file); handle = dlopen(lib, RTLD_NOW); if(!handle){ - fprintf(stderr, "Failed to load plugin %s: %s\n", lib, dlerror()); + #ifdef _WIN32 + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &error, 0, NULL); + #else + error = dlerror(); + #endif + fprintf(stderr, "Failed to load plugin %s: %s\n", lib, error); free(lib); + #ifdef _WIN32 + LocalFree(error); + #endif return 0; } @@ -62,6 +81,38 @@ static int plugin_attach(char* path, char* file){ int plugins_load(char* path){ int rv = -1; +#ifdef _WIN32 + char* search_expression = calloc(strlen(path) + strlen("*.dll") + 1, sizeof(char)); + if(!search_expression){ + fprintf(stderr, "Failed to allocate memory\n"); + return -1; + } + snprintf(search_expression, strlen(path) + strlen("*.dll"), "%s*.dll", path); + + WIN32_FIND_DATA result; + HANDLE hSearch = FindFirstFile(search_expression, &result); + + if(hSearch == INVALID_HANDLE_VALUE){ + LPVOID lpMsgBuf = NULL; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); + fprintf(stderr, "Failed to search for backend plugin files in %s: %s\n", path, lpMsgBuf); + LocalFree(lpMsgBuf); + return -1; + } + + do { + if(plugin_attach(path, result.cFileName)){ + goto load_done; + } + } while(FindNextFile(hSearch, &result)); + + rv = 0; +load_done: + free(search_expression); + FindClose(hSearch); + return rv; +#else struct dirent* entry; struct stat file_stat; DIR* directory = opendir(path); @@ -100,6 +151,7 @@ load_done: return -1; } return rv; +#endif } int plugins_close(){ diff --git a/portability.h b/portability.h index 25aee01..903ecd8 100644 --- a/portability.h +++ b/portability.h @@ -19,3 +19,20 @@ #define be64toh(x) OSSwapBigToHostInt64(x) #define le64toh(x) OSSwapLittleToHostInt64(x) #endif + +#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #include + #include + + #define htobe16(x) htons(x) + #define be16toh(x) ntohs(x) + + #define htobe32(x) htonl(x) + #define be32toh(x) ntohl(x) + + #define htobe64(x) _byteswap_uint64(x) + #define htole64(x) (x) + #define be64toh(x) _byteswap_uint64(x) + #define le64toh(x) (x) +#endif -- cgit v1.2.3 From 1c8d7c570678c2f4f3bf61529489336f9d085f8d Mon Sep 17 00:00:00 2001 From: cbdev Date: Sun, 15 Sep 2019 23:09:44 +0200 Subject: Fix minor MIDI issues --- backends/midi.c | 27 +++++++++++++++------------ plugin.c | 22 ++++++++++++++++------ 2 files changed, 31 insertions(+), 18 deletions(-) (limited to 'plugin.c') diff --git a/backends/midi.c b/backends/midi.c index 571a61d..65ce48a 100644 --- a/backends/midi.c +++ b/backends/midi.c @@ -84,14 +84,14 @@ static instance* midi_instance(){ return inst; } -static int midi_configure_instance(instance* instance, char* option, char* value){ - midi_instance_data* data = (midi_instance_data*) instance->impl; +static int midi_configure_instance(instance* inst, char* option, char* value){ + midi_instance_data* data = (midi_instance_data*) inst->impl; //FIXME maybe allow connecting more than one device if(!strcmp(option, "read")){ //connect input device if(data->read){ - fprintf(stderr, "MIDI port already connected to an input device\n"); + fprintf(stderr, "MIDI instance %s was already connected to an input device\n", inst->name); return 1; } data->read = strdup(value); @@ -100,7 +100,7 @@ static int midi_configure_instance(instance* instance, char* option, char* value else if(!strcmp(option, "write")){ //connect output device if(data->write){ - fprintf(stderr, "MIDI port already connected to an output device\n"); + fprintf(stderr, "MIDI instance %s was already connected to an output device\n", inst->name); return 1; } data->write = strdup(value); @@ -111,7 +111,7 @@ static int midi_configure_instance(instance* instance, char* option, char* value return 1; } -static channel* midi_channel(instance* instance, char* spec){ +static channel* midi_channel(instance* inst, char* spec){ midi_channel_ident ident = { .label = 0 }; @@ -142,13 +142,13 @@ static channel* midi_channel(instance* instance, char* spec){ old_syntax = 1; } else{ - fprintf(stderr, "Unknown MIDI channel specification %s\n", spec); + fprintf(stderr, "Unknown MIDI channel control type in %s\n", spec); return NULL; } ident.fields.channel = strtoul(channel, &channel, 10); if(ident.fields.channel > 15){ - fprintf(stderr, "MIDI channel out of range in channel spec %s\n", spec); + fprintf(stderr, "MIDI channel out of range in midi channel spec %s\n", spec); return NULL; } @@ -176,18 +176,22 @@ static channel* midi_channel(instance* instance, char* spec){ ident.fields.type = pressure; channel += 8; } - else if(!strncmp(channel, "pitch", 8)){ + else if(!strncmp(channel, "pitch", 5)){ ident.fields.type = pitchbend; } else if(!strncmp(channel, "aftertouch", 10)){ ident.fields.type = aftertouch; } + else{ + fprintf(stderr, "Unknown MIDI channel control type in %s\n", spec); + return NULL; + } } ident.fields.control = strtoul(channel, NULL, 10); if(ident.label){ - return mm_channel(instance, ident.label, 1); + return mm_channel(inst, ident.label, 1); } return NULL; @@ -196,13 +200,12 @@ static channel* midi_channel(instance* instance, char* spec){ static int midi_set(instance* inst, size_t num, channel** c, channel_value* v){ size_t u; snd_seq_event_t ev; - midi_instance_data* data; + midi_instance_data* data = (midi_instance_data*) inst->impl; midi_channel_ident ident = { .label = 0 }; for(u = 0; u < num; u++){ - data = (midi_instance_data*) c[u]->instance->impl; ident.label = c[u]->ident; snd_seq_ev_clear(&ev); @@ -334,7 +337,7 @@ static int midi_handle(size_t num, managed_fd* fds){ } static int midi_start(){ - size_t n, p; + size_t n = 0, p; int nfds, rv = 1; struct pollfd* pfds = NULL; instance** inst = NULL; diff --git a/plugin.c b/plugin.c index a452559..dd99041 100644 --- a/plugin.c +++ b/plugin.c @@ -24,7 +24,6 @@ static int plugin_attach(char* path, char* file){ plugin_init init = NULL; void* handle = NULL; char* lib = NULL; - char* error = NULL; lib = calloc(strlen(path) + strlen(file) + 1, sizeof(char)); if(!lib){ @@ -36,16 +35,15 @@ static int plugin_attach(char* path, char* file){ handle = dlopen(lib, RTLD_NOW); if(!handle){ #ifdef _WIN32 + char* error = NULL; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &error, 0, NULL); - #else - error = dlerror(); - #endif fprintf(stderr, "Failed to load plugin %s: %s\n", lib, error); - free(lib); - #ifdef _WIN32 LocalFree(error); + #else + fprintf(stderr, "Failed to load plugin %s: %s\n", lib, dlerror()); #endif + free(lib); return 0; } @@ -156,10 +154,22 @@ load_done: int plugins_close(){ size_t u; + for(u = 0; u < plugins; u++){ +#ifdef _WIN32 + char* error = NULL; + //FreeLibrary returns the inverse of dlclose + if(!FreeLibrary(plugin_handle[u])){ + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &error, 0, NULL); + fprintf(stderr, "Failed to unload plugin: %s\n", error); + LocalFree(error); + } +#else if(dlclose(plugin_handle[u])){ fprintf(stderr, "Failed to unload plugin: %s\n", dlerror()); } +#endif } free(plugin_handle); -- cgit v1.2.3 From 350f0d2d2eaff5f0d57b09857102e2df1e96d733 Mon Sep 17 00:00:00 2001 From: cbdev Date: Thu, 7 Nov 2019 18:44:19 +0100 Subject: Makefile install target and packaging instructions (Fixes #28) --- Makefile | 22 +++++++++++++++++----- README.md | 23 +++++++++++++++++++++++ backends/lua.md | 5 +---- backends/maweb.c | 2 +- backends/winmidi.c | 2 +- config.c | 38 +++++++++++++++++++++++++++++++++++--- configs/flying-faders.cfg | 2 +- configs/lua.cfg | 2 +- midimonster.h | 13 ++++++++++++- plugin.c | 12 ++++++++++-- 10 files changed, 102 insertions(+), 19 deletions(-) (limited to 'plugin.c') diff --git a/Makefile b/Makefile index 2d88c49..5a83a2d 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,7 @@ -.PHONY: all clean run sanitize backends windows full backends-full +.PHONY: all clean run sanitize backends windows full backends-full install OBJS = config.o backend.o plugin.o -PLUGINDIR = "\"./backends/\"" -PLUGINDIR_W32 = "\"backends\\\\\"" +PREFIX ?= /usr SYSTEM := $(shell uname -s) CFLAGS ?= -g -Wall -Wpedantic @@ -11,7 +10,6 @@ CFLAGS += -fvisibility=hidden #CFLAGS += -DDEBUG midimonster: LDLIBS = -ldl -midimonster: CFLAGS += -DPLUGINS=$(PLUGINDIR) # Work around strange linker passing convention differences in Linux and OSX ifeq ($(SYSTEM),Linux) @@ -21,6 +19,14 @@ ifeq ($(SYSTEM),Darwin) midimonster: LDFLAGS += -Wl,-export_dynamic endif +# Allow overriding the locations for backend plugins and default configuration +ifdef DEFAULT_CFG +midimonster: CFLAGS += -DDEFAULT_CFG=\"$(DEFAULT_CFG)\" +endif +ifdef PLUGINS +midimonster: CFLAGS += -DPLUGINS=\"$(PLUGINS)\" +endif + all: midimonster backends full: midimonster backends-full @@ -39,7 +45,7 @@ midimonster: midimonster.c portability.h $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $< $(OBJS) $(LDLIBS) -o $@ midimonster.exe: export CC = x86_64-w64-mingw32-gcc -midimonster.exe: CFLAGS += -DPLUGINS=$(PLUGINDIR_W32) -Wno-format +midimonster.exe: CFLAGS += -Wno-format midimonster.exe: LDLIBS = -lws2_32 midimonster.exe: LDFLAGS += -Wl,--out-implib,libmmapi.a midimonster.exe: midimonster.c portability.h $(OBJS) @@ -55,6 +61,12 @@ clean: run: valgrind --leak-check=full --show-leak-kinds=all ./midimonster +install: + install -d "$(DESTDIR)$(PREFIX)/bin" + install -d "$(DESTDIR)$(PREFIX)/lib/midimonster" + install -m 0755 midimonster "$(DESTDIR)$(PREFIX)/bin" + install -m 0755 backends/*.so "$(DESTDIR)$(PREFIX)/lib/midimonster" + sanitize: export CC = clang sanitize: export CFLAGS += -g -Wall -Wpedantic -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer sanitize: midimonster backends diff --git a/README.md b/README.md index 130945a..c31f16c 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,16 @@ be used to build a subset of the backends as well as the core. For Linux and OSX, just running `make` in the source directory should do the trick. +The build process accepts the following parameters, either from the environment or +as arguments to the `make` invocation: + +| Target | Parameter | Default value | Description | +|---------------|-----------------------|-------------------------------|-------------------------------| +| build targets | `DEFAULT_CFG` | `monster.cfg` | Default configuration file | +| build targets | `PLUGINS` | Linux/OSX: `./backends/`, Windows: `backends\` | Backend plugin library path | +| `install` | `DESTDIR` | empty | Destination directory for packaging builds | +| `install` | `PREFIX` | `/usr` | Install prefix for binaries | + Some backends have been marked as optional as they require rather large additional software to be installed, for example the `ola` backend. To create a build including these, run `make full`. @@ -163,6 +173,19 @@ To build for Windows, you still need to compile on a Linux machine. Install the crosscompiler package listed above and run `make windows`. This will build `midimonster.exe` as well as a set of backends as DLL files. +For system-wide install or packaging builds, the following steps are recommended: + +``` +export PREFIX=/usr +export PLUGINS=$PREFIX/lib/midimonster +export DEFAULT_CFG=/etc/midimonster.cfg +make +make install +``` + +Depending on your configuration of `DESTDIR`, the `make install` step may require root privileges to +install the binaries to the appropriate destinations. + ## Development The architecture is split into the `midimonster` core, handling mapping diff --git a/backends/lua.md b/backends/lua.md index 6ad5c2a..f38e189 100644 --- a/backends/lua.md +++ b/backends/lua.md @@ -43,7 +43,7 @@ The `lua` backend does not take any global configuration. | Option | Example value | Default value | Description | |---------------|-----------------------|-----------------------|-----------------------| -| `script` | `script.lua` | none | Lua source file | +| `script` | `script.lua` | none | Lua source file (relative to configuration file)| A single instance may have multiple `source` options specified, which will all be read cumulatively. @@ -64,6 +64,3 @@ Using these names as arguments to the output and value interface functions works Output values will not trigger corresponding input event handlers unless the channel is mapped back in the MIDIMonster configuration. - -The path to the Lua source files is relative to the current working directory. This may lead -to problems when copying configuration between installations. diff --git a/backends/maweb.c b/backends/maweb.c index c98d04b..57d04ae 100644 --- a/backends/maweb.c +++ b/backends/maweb.c @@ -470,7 +470,7 @@ static int maweb_request_playbacks(instance* inst){ offsets[0] = offsets[1] = offsets[2] = 1; page_index = data->channel[channel].page; //poll logic differs between the consoles because reasons - //dont quote me on this section + //don't quote me on this section if(data->peer_type == peer_dot2){ //blocks 0, 100 & 200 have 21 execs and need to be queried from fader view view = (data->channel[channel].index >= 300) ? 3 : 2; diff --git a/backends/winmidi.c b/backends/winmidi.c index de7d867..d6bc0bc 100644 --- a/backends/winmidi.c +++ b/backends/winmidi.c @@ -84,7 +84,7 @@ static int winmidi_configure_instance(instance* inst, char* option, char* value) } if(!strcmp(option, "write")){ if(data->write){ - fprintf(stderr, "winmidi instance %s already connected to an otput device\n", inst->name); + fprintf(stderr, "winmidi instance %s already connected to an output device\n", inst->name); return 1; } data->write = strdup(value); diff --git a/config.c b/config.c index f4d928e..ddee720 100644 --- a/config.c +++ b/config.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include "midimonster.h" #include "config.h" #include "backend.h" @@ -310,16 +312,45 @@ done: return rv; } -int config_read(char* cfg_file){ +int config_read(char* cfg_filepath){ int rv = 1; size_t line_alloc = 0; ssize_t status; map_type mapping_type = map_rtl; char* line_raw = NULL, *line, *separator; - FILE* source = fopen(cfg_file, "r"); + + //create heap copy of file name because original might be in readonly memory + char* source_dir = strdup(cfg_filepath), *source_file = NULL; + #ifdef _WIN32 + char path_separator = '\\'; + #else + char path_separator = '/'; + #endif + + if(!source_dir){ + fprintf(stderr, "Failed to allocate memory\n"); + return 1; + } + + //change working directory to the one containing the configuration file so relative paths work as expected + source_file = strrchr(source_dir, path_separator); + if(source_file){ + *source_file = 0; + source_file++; + if(chdir(source_dir)){ + fprintf(stderr, "Failed to change to configuration file directory %s: %s\n", source_dir, strerror(errno)); + goto bail; + } + } + else{ + source_file = source_dir; + } + + FILE* source = fopen(source_file, "r"); + if(!source){ fprintf(stderr, "Failed to open configuration file for reading\n"); - return 1; + goto bail; } for(status = getline(&line_raw, &line_alloc, source); status >= 0; status = getline(&line_raw, &line_alloc, source)){ @@ -459,6 +490,7 @@ int config_read(char* cfg_file){ rv = 0; bail: + free(source_dir); fclose(source); free(line_raw); return rv; diff --git a/configs/flying-faders.cfg b/configs/flying-faders.cfg index 4197581..d331f38 100644 --- a/configs/flying-faders.cfg +++ b/configs/flying-faders.cfg @@ -13,7 +13,7 @@ dest = learn@9000 /1/xy = ff 0.0 1.0 0.0 1.0 [lua generator] -script = configs/flying-faders.lua +script = flying-faders.lua [map] diff --git a/configs/lua.cfg b/configs/lua.cfg index af17496..098c0f1 100644 --- a/configs/lua.cfg +++ b/configs/lua.cfg @@ -13,7 +13,7 @@ axis.ABS_X = 34300 0 65535 255 4095 axis.ABS_Y = 34300 0 65535 255 4095 [lua lua] -script = configs/demo.lua +script = demo.lua [artnet art] universe = 0 diff --git a/midimonster.h b/midimonster.h index 491cc11..b05326c 100644 --- a/midimonster.h +++ b/midimonster.h @@ -33,7 +33,18 @@ #include "portability.h" /* Default configuration file name to read when no other is specified */ -#define DEFAULT_CFG "monster.cfg" +#ifndef DEFAULT_CFG + #define DEFAULT_CFG "monster.cfg" +#endif + +/* Default backend plugin location */ +#ifndef PLUGINS + #ifndef _WIN32 + #define PLUGINS "./backends/" + #else + #define PLUGINS "backends\\" + #endif +#endif /* Forward declare some of the structs so we can use them in each other */ struct _channel_value; diff --git a/plugin.c b/plugin.c index dd99041..a14baff 100644 --- a/plugin.c +++ b/plugin.c @@ -24,13 +24,21 @@ static int plugin_attach(char* path, char* file){ plugin_init init = NULL; void* handle = NULL; char* lib = NULL; + #ifdef _WIN32 + char* path_separator = "\\"; + #else + char* path_separator = "/"; + #endif - lib = calloc(strlen(path) + strlen(file) + 1, sizeof(char)); + lib = calloc(strlen(path) + strlen(file) + 2, sizeof(char)); if(!lib){ fprintf(stderr, "Failed to allocate memory\n"); return 1; } - snprintf(lib, strlen(path) + strlen(file) + 1, "%s%s", path, file); + snprintf(lib, strlen(path) + strlen(file) + 2, "%s%s%s", + path, + (path[strlen(path)] == path_separator[0]) ? "" : path_separator, + file); handle = dlopen(lib, RTLD_NOW); if(!handle){ -- cgit v1.2.3 From 8979c52e767791f97f462835a9e4c5e66d1112cc Mon Sep 17 00:00:00 2001 From: cbdev Date: Wed, 4 Dec 2019 22:53:27 +0100 Subject: Remove check for executable bit on shared libraries --- plugin.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'plugin.c') diff --git a/plugin.c b/plugin.c index a14baff..c7c9812 100644 --- a/plugin.c +++ b/plugin.c @@ -141,10 +141,6 @@ load_done: continue; } - if(!(file_stat.st_mode & S_IXUSR)){ - continue; - } - if(plugin_attach(path, entry->d_name)){ goto load_done; } -- cgit v1.2.3