This also defines SOEXT as the extension of shared objects (ie. "so"
or "dll"), and uses it everywhere. I assumed this must already be
defined by either autoconf or mingw (like OBJEXT) but I cannot find
anything except in glib (G_MODULE_SUFFIX).
Thanks: Zebediah Figura for helping out with exec vs spawn on Windows.
---
configure.ac | 8 +++-
common/utils/windows-compat.h | 3 ++
server/fuzzer.c | 2 +-
server/main.c | 6 +--
wrapper.c | 72 ++++++++++++++++++++++++++++++++---
README | 18 ++++-----
6 files changed, 87 insertions(+), 22 deletions(-)
diff --git a/configure.ac b/configure.ac
index 0b17ef95..61ee3a02 100644
--- a/configure.ac
+++ b/configure.ac
@@ -489,12 +489,18 @@ AS_CASE([$host_os],
LIBS="$LIBS -lmsvcrt -lkernel32 -luser32"
NO_UNDEFINED_ON_WINDOWS="-no-undefined"
IMPORT_LIBRARY_ON_WINDOWS='-Wl,-L$(top_builddir)/server -Wl,-lnbdkit'
+ SOEXT="dll"
],
- [is_windows=no]
+ [is_windows=no], [
+ SOEXT="so"
+ ]
)
AC_MSG_RESULT([$is_windows])
AC_SUBST([NO_UNDEFINED_ON_WINDOWS])
AC_SUBST([IMPORT_LIBRARY_ON_WINDOWS])
+AC_SUBST([SOEXT])
+AC_DEFINE_UNQUOTED([SOEXT],["$SOEXT"],[Extension used for shared
objects/DLLs.])
+AC_DEFINE_UNQUOTED([EXEEXT],["$EXEEXT"],[Extension used for executables.])
AM_CONDITIONAL([IS_WINDOWS],[test "x$is_windows" = "xyes"])
AS_IF([test "x$is_windows" = "xyes"],[
diff --git a/common/utils/windows-compat.h b/common/utils/windows-compat.h
index 74241a19..0fcb20d2 100644
--- a/common/utils/windows-compat.h
+++ b/common/utils/windows-compat.h
@@ -103,6 +103,9 @@ extern int win_send (int fd, const void *buf, size_t len, int flags);
#define dup _dup
#define dup2 _dup2
+/* setenv replacement. */
+#define setenv(k, v, replace) _putenv_s ((k), (v));
+
/* Unfortunately quite commonly used at the moment. Make it a common
* macro so we can easily find places which need porting.
*
diff --git a/server/fuzzer.c b/server/fuzzer.c
index c28a1798..4bbb0061 100644
--- a/server/fuzzer.c
+++ b/server/fuzzer.c
@@ -119,7 +119,7 @@ server (int sock)
"nbdkit",
"-s", /* take input from stdin/stdout */
"--log=null", /* discard error messages */
- "plugins/memory/.libs/nbdkit-memory-plugin.so", "1M",
+ "plugins/memory/.libs/nbdkit-memory-plugin." SOEXT, "1M",
NULL
};
const int argc = sizeof argv / sizeof argv[0] - 1;
diff --git a/server/main.c b/server/main.c
index fa5073d6..4b6f72e1 100644
--- a/server/main.c
+++ b/server/main.c
@@ -497,7 +497,7 @@ main (int argc, char *argv[])
/* Incorrect use of --dump-plugin. */
fprintf (stderr,
"%s: use 'nbdkit plugin --dump-plugin' or\n"
- "'nbdkit /path/to/plugin.so --dump-plugin'\n",
+ "'nbdkit /path/to/plugin." SOEXT "
--dump-plugin'\n",
program_name);
exit (EXIT_FAILURE);
}
@@ -819,7 +819,7 @@ open_plugin_so (size_t i, const char *name, int short_name)
if (short_name) {
/* Short names are rewritten relative to the plugindir. */
if (asprintf (&filename,
- "%s/nbdkit-%s-plugin.so", plugindir, name) == -1) {
+ "%s/nbdkit-%s-plugin." SOEXT, plugindir, name) == -1) {
perror ("asprintf");
exit (EXIT_FAILURE);
}
@@ -872,7 +872,7 @@ open_filter_so (struct backend *next, size_t i,
if (short_name) {
/* Short names are rewritten relative to the filterdir. */
if (asprintf (&filename,
- "%s/nbdkit-%s-filter.so", filterdir, name) == -1) {
+ "%s/nbdkit-%s-filter." SOEXT, filterdir, name) == -1) {
perror ("asprintf");
exit (EXIT_FAILURE);
}
diff --git a/wrapper.c b/wrapper.c
index c27afae0..fe750936 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -72,6 +72,7 @@
#include <time.h>
#include "options.h"
+#include "windows-compat.h"
#include "utils.h"
/* Construct an array of parameters passed through to real nbdkit. */
@@ -131,6 +132,45 @@ print_command (void)
fputc ('\n', stderr);
}
+#ifdef WIN32
+/* Windows behaviour of _spawnvp is completely retarded:
+ *
https://stackoverflow.com/questions/4146980/how-to-avoid-space-splitting-...
+ */
+static const char *
+quote_string_for_spawn (const char *str)
+{
+ size_t i, len;
+ char *p, *ret = (char *) str;
+
+ if (strchr (str, ' ') || strchr (str, '"')) {
+ len = strlen (str);
+
+ p = ret = malloc (2 + len*2 + 1);
+ if (ret == NULL) {
+ perror ("malloc");
+ exit (EXIT_FAILURE);
+ }
+
+ *p++ = '"';
+ for (i = 0; i < len; ++i) {
+ switch (str[i]) {
+ case '"':
+ *p++ = '\\';
+ *p++ = '"';
+ break;
+ default:
+ *p++ = str[i];
+ }
+ }
+ *p++ = '"';
+ *p++ = '\0';
+ }
+
+ /* We never free these strings. */
+ return ret;
+}
+#endif /* WIN32 */
+
int
main (int argc, char *argv[])
{
@@ -141,6 +181,7 @@ main (int argc, char *argv[])
char ts[32];
int r;
+#ifndef WIN32
/* If NBDKIT_VALGRIND=1 is set in the environment, then we run the
* program under valgrind. This is used by the tests. Similarly if
* NBDKIT_GDB=1 is set, we run the program under GDB, useful during
@@ -167,9 +208,15 @@ main (int argc, char *argv[])
passthru ("--args");
}
}
+#endif
/* Needed for plugins written in OCaml. */
- s = getenv ("LD_LIBRARY_PATH");
+#ifndef WIN32
+#define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
+#else
+#define LD_LIBRARY_PATH "PATH"
+#endif
+ s = getenv (LD_LIBRARY_PATH);
if (s)
r = asprintf (&s, "%s/plugins/ocaml/.libs:%s", builddir, s);
else
@@ -178,7 +225,7 @@ main (int argc, char *argv[])
perror ("asprintf");
exit (EXIT_FAILURE);
}
- setenv ("LD_LIBRARY_PATH", s, 1);
+ setenv (LD_LIBRARY_PATH, s, 1);
free (s);
s = getenv ("LIBRARY_PATH");
if (s)
@@ -193,7 +240,7 @@ main (int argc, char *argv[])
free (s);
/* Absolute path of the real nbdkit command. */
- passthru_format ("%s/server/nbdkit", builddir);
+ passthru_format ("%s/server/nbdkit" EXEEXT, builddir);
/* Option parsing. We don't really parse options here. We are only
* interested in which options have arguments and which need
@@ -225,7 +272,8 @@ main (int argc, char *argv[])
/* Filters can be rewritten if they are a short name. */
else if (c == FILTER_OPTION) {
if (is_short_name (optarg))
- passthru_format ("--filter=%s/filters/%s/.libs/nbdkit-%s-filter.so",
+ passthru_format ("--filter="
+ "%s/filters/%s/.libs/nbdkit-%s-filter." SOEXT,
builddir, optarg, optarg);
else
passthru_format ("--filter=%s", optarg);
@@ -258,13 +306,13 @@ main (int argc, char *argv[])
if (is_short_name (argv[optind])) {
/* Special plugins written in Perl. */
if (is_perl_plugin (argv[optind])) {
- passthru_format ("%s/plugins/perl/.libs/nbdkit-perl-plugin.so",
+ passthru_format ("%s/plugins/perl/.libs/nbdkit-perl-plugin." SOEXT,
builddir);
passthru_format ("%s/plugins/%s/nbdkit-%s-plugin",
builddir, argv[optind], argv[optind]);
}
else {
- passthru_format ("%s/plugins/%s/.libs/nbdkit-%s-plugin.so",
+ passthru_format ("%s/plugins/%s/.libs/nbdkit-%s-plugin." SOEXT,
builddir, argv[optind], argv[optind]);
}
++optind;
@@ -295,7 +343,19 @@ main (int argc, char *argv[])
setenv ("MALLOC_PERTURB_", ts, 0);
/* Run the final command. */
+#ifndef WIN32
execvp (cmd[0], (char **) cmd);
perror (cmd[0]);
exit (EXIT_FAILURE);
+#else /* WIN32 */
+ size_t i;
+ for (i = 1; cmd[i] != NULL; ++i)
+ cmd[i] = quote_string_for_spawn (cmd[i]);
+ r = _spawnvp (_P_WAIT, cmd[0], cmd);
+ if (r == -1) {
+ perror (cmd[0]);
+ exit (EXIT_FAILURE);
+ }
+ exit (r == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+#endif /* WIN32 */
}
diff --git a/README b/README
index 2bf8ce5f..56b0c984 100644
--- a/README
+++ b/README
@@ -331,21 +331,17 @@ To cross compile do:
mingw64-configure --disable-ocaml --disable-perl --disable-vddk
mingw64-make
-It is expected to fail, but check that it gets as far as building
-server/nbdkit.exe. You can test if the server is working by doing:
+You can test if the server is working by doing:
- wine server/nbdkit.exe --dump-config
+ ./nbdkit.exe --dump-config
-Now try to build plugins and filters (many will not compile):
+(This usually runs wine automatically. If not, you may need to prefix
+the command "wine ./nbdkit.exe ...")
- mingw64-make -k
+To see which plugins and filters were compiled:
-To see which ones were compiled:
-
- find -name '*.dll'
+ find plugins filters -name '*.dll'
You can run them under Wine without installing using eg:
- wine server/nbdkit.exe -f -v \
- plugins/memory/.libs/nbdkit-memory-plugin.dll \
- size=1G
+ ./nbdkit.exe -f -v memory 1G
--
2.27.0