vere: basic MingW compatibility changes

This commit adds code changes, compatibility functions, stubs and a build script
to build urbit binaries on MingW64. Some functionality is limited or missing:
terminal input and daemon mode is not available, graceful exit does not work,
and the binaries are not completely static and use (portable) MingW dlls.

To build the binaries, install the MSYS2 environment, check out or copy the urbit
repo and pill binaries, open a MingW64 shell and `cd pkg/urbit && ./build-mingw`.
This commit is contained in:
~locpyl-tidnyd 2021-03-28 19:27:26 +00:00
parent ef0b87a1cb
commit 4d14b410d5
25 changed files with 2904 additions and 20 deletions

47
nix/sources-mingw.json Normal file
View File

@ -0,0 +1,47 @@
{
"lmdb": {
"branch": "mdb.master",
"description": "LMDB library",
"homepage": "http://www.lmdb.tech/",
"mingw": {
"strip": 2,
"make": "liblmdb.a"
},
"owner": "LMDB",
"repo": "lmdb",
"rev": "48a7fed59a8aae623deff415dda27097198ca0c1",
"type": "tarball",
"url": "https://github.com/LMDB/lmdb/archive/48a7fed59a8aae623deff415dda27097198ca0c1.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"secp256k1": {
"branch": "master",
"description": "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1.",
"homepage": null,
"mingw": {
"include": "include",
"lib": ".libs",
"prepare": "./autogen.sh && ./configure --enable-module-recovery"
},
"owner": "bitcoin-core",
"repo": "secp256k1",
"rev": "26de4dfeb1f1436dae1fcf17f57bdaa43540f940",
"type": "tarball",
"url": "https://github.com/bitcoin-core/secp256k1/archive/26de4dfeb1f1436dae1fcf17f57bdaa43540f940.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"ent": {
"mingw": {
"prepare": "./configure"
}
},
"ge-additions": {
"mingw": {
"make": "CFLAGS=-I../ed25519"
}
},
"libaes_siv": {
"mingw": {
}
}
}

View File

@ -3,6 +3,10 @@
"branch": "master",
"description": "With argon2u. Based off https://github.com/P-H-C/phc-winner-argon2",
"homepage": "",
"mingw": {
"include": ["include", "src/blake2"],
"make": "libargon2.a"
},
"owner": "urbit",
"repo": "argon2",
"rev": "4da94a611ee62bad87ab2b131ffda3bcc0723d9c",
@ -15,6 +19,10 @@
"branch": "master",
"description": "Submodule included by Urbit",
"homepage": null,
"mingw": {
"strip": 1,
"make": "all"
},
"owner": "urbit",
"repo": "ed25519",
"rev": "76385f2ebbbc9580a9c236952d68d11d73a6135c",
@ -27,12 +35,17 @@
"branch": "master",
"description": "H2O - the optimized HTTP/1, HTTP/2, HTTP/3 server",
"homepage": "https://h2o.examp1e.net",
"mingw": {
"include": "include",
"prepare": "cmake -G\"MSYS Makefiles\" .",
"make": "libh2o"
},
"owner": "h2o",
"repo": "h2o",
"rev": "v2.2.4",
"sha256": "0176x0bzjry19zs074a9i5vhncc842xikmx43wj61jky318nq4w4",
"rev": "v2.2.6",
"sha256": "0qni676wqvxx0sl0pw9j0ph7zf2krrzqc1zwj73mgpdnsr8rsib7",
"type": "tarball",
"url": "https://github.com/h2o/h2o/archive/v2.2.4.tar.gz",
"url": "https://github.com/h2o/h2o/archive/v2.2.6.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"hackage.nix": {
@ -63,6 +76,9 @@
"branch": "master",
"description": null,
"homepage": null,
"mingw": {
"make": "libscrypt.a CFLAGS_EXTRA=-ffast-math"
},
"owner": "urbit",
"repo": "libscrypt",
"rev": "029693ff1cbe4f69d3a2da87d0f4f034f92cc0c2",
@ -75,6 +91,9 @@
"branch": "master",
"description": null,
"homepage": null,
"mingw": {
"make": "static"
},
"owner": "urbit",
"repo": "murmur3",
"rev": "71a75d57ca4e7ca0f7fc2fd84abd93595b0624ca",
@ -111,6 +130,11 @@
"branch": "master",
"description": null,
"homepage": null,
"mingw": {
"include": "source/include",
"lib": "build/Win64-MinGW-w64",
"make": "-C build/Win64-MinGW-w64 libsoftfloat3.a"
},
"owner": "urbit",
"repo": "berkeley-softfloat-3",
"rev": "ec4c7e31b32e07aad80e52f65ff46ac6d6aad986",

View File

@ -9,7 +9,17 @@ worker = $(wildcard worker/*.c)
tests = $(wildcard tests/*.c)
bench = $(wildcard bench/*.c)
common = $(jets) $(noun) $(ur) $(vere)
ifdef use_dumb_terminal
vere := $(filter-out vere/io/term.c,$(vere))
else
vere := $(filter-out vere/io/dumb.c,$(vere))
endif
ifdef compat
compat := $(wildcard compat/$(compat)/*.c)
endif
common = $(jets) $(noun) $(ur) $(vere) $(compat)
headers = $(shell find include -type f)
common_objs = $(shell echo $(common) | sed 's/\.c/.o/g')

61
pkg/urbit/build-mingw Executable file
View File

@ -0,0 +1,61 @@
#!/usr/bin/env bash
set -euo pipefail
function xxd()
{
cch=0
echo "unsigned char $2[] = {"
while IFS='' read line
do
for i in $line
do
echo -n " 0x$i,"
cch=$((cch+1))
done
echo
done < <(od -An -v -tx1 $1)
echo "};"
echo "unsigned int $2_len = $cch;"
}
case $(uname -s|tr A-Z a-z) in
*mingw64*)
;;
*)
echo This script works only on MingW64.
exit 1
;;
esac
if [ ! -e config.mk ]
then
# ensure required mingw packages are installed
mpkgs=(cmake curl gcc jq libsigsegv libuv make wslay)
pacman -S --needed autoconf automake-wrapper libtool patch ${mpkgs[@]/#/mingw-w64-x86_64-}
unset cdirs
unset ldirs
declare -a cdirs
declare -a ldirs
. <(jq -sr '
add|to_entries|.[]|select(.value.mingw)|.key as $key|(if .value.url then "
mkdir -p ../\($key)
pushd ../\($key)
curl -L \(.value.url)|(tar --strip \(.value.mingw.strip+1) -xzf - || true)" +
("../urbit/compat/mingw/\($key).patch"|"
[ -e \(.) ] && patch -p 1 <\(.)") else "
pushd ../\($key)" end) + "
\(.value.mingw.prepare//"")
make \(.value.mingw.make//"")
popd
\(.value.mingw.include//"."|if type == "array" then .[] else . end|"cdirs+=(-I../\($key)/\(.))
")\(.value.mingw.lib//"."|if type == "array" then .[] else . end|"ldirs+=(-L../\($key)/\(.))
")"' ../../nix/sources.json ../../nix/sources-mingw.json)
xxd /etc/pki/ca-trust/extracted/openssl/ca-bundle.trust.crt include_ca_bundle_crt >include/ca-bundle.h
xxd ../../bin/ivory.pill u3_Ivory_pill >include/ivory.h
CFLAGS="${CFLAGS-} ${cdirs[@]}" LDFLAGS="${LDFLAGS-} ${ldirs[@]}" PKG_CONFIG=echo ./configure
fi
make build/urbit build/urbit-worker

View File

@ -0,0 +1,22 @@
diff --git a/src/encoding.c b/src/encoding.c
index 73c36f5..753a1e1 100644
--- a/src/encoding.c
+++ b/src/encoding.c
@@ -370,7 +370,7 @@ int decode_string(argon2_context *ctx, const char *str, argon2_type type) {
#undef BIN
}
-void itoa(int i, char b[]){
+static void encode_decimal(int i, char b[]){
#ifdef ARGON2_JS
// because this generates WASM error:
@@ -416,7 +416,7 @@ int encode_string(char *dst, size_t dst_len, argon2_context *ctx,
#define SX(x) \
do { \
char tmp[30]; \
- itoa(x, tmp); \
+ encode_decimal(x, tmp); \
SS(tmp); \
} while ((void)0, 0)

View File

@ -0,0 +1,436 @@
#include "c/portable.h"
#include <sys/utime.h>
#include <windows.h>
// from https://github.com/git/git/blob/master/compat/mingw.c
// -----------------------------------------------------------------------
int err_win_to_posix(DWORD winerr)
{
int error = ENOSYS;
switch(winerr) {
case ERROR_ACCESS_DENIED: error = EACCES; break;
case ERROR_ACCOUNT_DISABLED: error = EACCES; break;
case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break;
case ERROR_ALREADY_ASSIGNED: error = EBUSY; break;
case ERROR_ALREADY_EXISTS: error = EEXIST; break;
case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break;
case ERROR_BAD_COMMAND: error = EIO; break;
case ERROR_BAD_DEVICE: error = ENODEV; break;
case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break;
case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break;
case ERROR_BAD_FORMAT: error = ENOEXEC; break;
case ERROR_BAD_LENGTH: error = EINVAL; break;
case ERROR_BAD_PATHNAME: error = ENOENT; break;
case ERROR_BAD_PIPE: error = EPIPE; break;
case ERROR_BAD_UNIT: error = ENODEV; break;
case ERROR_BAD_USERNAME: error = EINVAL; break;
case ERROR_BROKEN_PIPE: error = EPIPE; break;
case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break;
case ERROR_BUSY: error = EBUSY; break;
case ERROR_BUSY_DRIVE: error = EBUSY; break;
case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break;
case ERROR_CANNOT_MAKE: error = EACCES; break;
case ERROR_CANTOPEN: error = EIO; break;
case ERROR_CANTREAD: error = EIO; break;
case ERROR_CANTWRITE: error = EIO; break;
case ERROR_CRC: error = EIO; break;
case ERROR_CURRENT_DIRECTORY: error = EACCES; break;
case ERROR_DEVICE_IN_USE: error = EBUSY; break;
case ERROR_DEV_NOT_EXIST: error = ENODEV; break;
case ERROR_DIRECTORY: error = EINVAL; break;
case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break;
case ERROR_DISK_CHANGE: error = EIO; break;
case ERROR_DISK_FULL: error = ENOSPC; break;
case ERROR_DRIVE_LOCKED: error = EBUSY; break;
case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break;
case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break;
case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break;
case ERROR_FILE_EXISTS: error = EEXIST; break;
case ERROR_FILE_INVALID: error = ENODEV; break;
case ERROR_FILE_NOT_FOUND: error = ENOENT; break;
case ERROR_GEN_FAILURE: error = EIO; break;
case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break;
case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break;
case ERROR_INVALID_ACCESS: error = EACCES; break;
case ERROR_INVALID_ADDRESS: error = EFAULT; break;
case ERROR_INVALID_BLOCK: error = EFAULT; break;
case ERROR_INVALID_DATA: error = EINVAL; break;
case ERROR_INVALID_DRIVE: error = ENODEV; break;
case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break;
case ERROR_INVALID_FLAGS: error = EINVAL; break;
case ERROR_INVALID_FUNCTION: error = ENOSYS; break;
case ERROR_INVALID_HANDLE: error = EBADF; break;
case ERROR_INVALID_LOGON_HOURS: error = EACCES; break;
case ERROR_INVALID_NAME: error = EINVAL; break;
case ERROR_INVALID_OWNER: error = EINVAL; break;
case ERROR_INVALID_PARAMETER: error = EINVAL; break;
case ERROR_INVALID_PASSWORD: error = EPERM; break;
case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break;
case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break;
case ERROR_INVALID_TARGET_HANDLE: error = EIO; break;
case ERROR_INVALID_WORKSTATION: error = EACCES; break;
case ERROR_IO_DEVICE: error = EIO; break;
case ERROR_IO_INCOMPLETE: error = EINTR; break;
case ERROR_LOCKED: error = EBUSY; break;
case ERROR_LOCK_VIOLATION: error = EACCES; break;
case ERROR_LOGON_FAILURE: error = EACCES; break;
case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break;
case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break;
case ERROR_MORE_DATA: error = EPIPE; break;
case ERROR_NEGATIVE_SEEK: error = ESPIPE; break;
case ERROR_NOACCESS: error = EFAULT; break;
case ERROR_NONE_MAPPED: error = EINVAL; break;
case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break;
case ERROR_NOT_READY: error = EAGAIN; break;
case ERROR_NOT_SAME_DEVICE: error = EXDEV; break;
case ERROR_NO_DATA: error = EPIPE; break;
case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break;
case ERROR_NO_PROC_SLOTS: error = EAGAIN; break;
case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break;
case ERROR_OPEN_FAILED: error = EIO; break;
case ERROR_OPEN_FILES: error = EBUSY; break;
case ERROR_OPERATION_ABORTED: error = EINTR; break;
case ERROR_OUTOFMEMORY: error = ENOMEM; break;
case ERROR_PASSWORD_EXPIRED: error = EACCES; break;
case ERROR_PATH_BUSY: error = EBUSY; break;
case ERROR_PATH_NOT_FOUND: error = ENOENT; break;
case ERROR_PIPE_BUSY: error = EBUSY; break;
case ERROR_PIPE_CONNECTED: error = EPIPE; break;
case ERROR_PIPE_LISTENING: error = EPIPE; break;
case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break;
case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break;
case ERROR_READ_FAULT: error = EIO; break;
case ERROR_SEEK: error = EIO; break;
case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break;
case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break;
case ERROR_SHARING_VIOLATION: error = EACCES; break;
case ERROR_STACK_OVERFLOW: error = ENOMEM; break;
case ERROR_SUCCESS: error = 0; break;
case ERROR_SWAPERROR: error = ENOENT; break;
case ERROR_TOO_MANY_MODULES: error = EMFILE; break;
case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break;
case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break;
case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break;
case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break;
case ERROR_WRITE_FAULT: error = EIO; break;
case ERROR_WRITE_PROTECT: error = EROFS; break;
}
return error;
}
int kill(pid_t pid, int sig)
{
if (pid > 0 && sig == SIGKILL) {
HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
if (TerminateProcess(h, -1)) {
CloseHandle(h);
return 0;
}
errno = err_win_to_posix(GetLastError());
CloseHandle(h);
return -1;
}
// TODO: handle signals for self
// TODO: send SIGTERM as ctrl-c: https://stackoverflow.com/questions/813086/can-i-send-a-ctrl-c-sigint-to-an-application-on-windows
errno = EINVAL;
return -1;
}
static HANDLE timer_event;
static HANDLE timer_thread;
static int timer_signal;
static int timer_interval;
static int one_shot;
static __p_sig_fn_t timer_fn = SIG_DFL, sigint_fn = SIG_DFL;
/* The timer works like this:
* The thread, ticktack(), is a trivial routine that most of the time
* only waits to receive the signal to terminate. The main thread tells
* the thread to terminate by setting the timer_event to the signalled
* state.
* But ticktack() interrupts the wait state after the timer's interval
* length to call the signal handler.
*/
static unsigned __stdcall ticktack(void *dummy)
{
while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
raise(timer_signal);
if (one_shot)
break;
}
return 0;
}
static int error(const char* s, ...)
{
// TODO
va_list ap;
va_start(ap, s);
vfprintf(stderr, s, ap);
va_end(ap);
return -1;
}
static int start_timer_thread(void)
{
timer_event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (timer_event) {
timer_thread = (HANDLE) _beginthreadex(NULL, 0, ticktack, NULL, 0, NULL);
if (!timer_thread )
return errno = ENOMEM,
error("cannot start timer thread");
} else
return errno = ENOMEM,
error("cannot allocate resources for timer");
return 0;
}
static void stop_timer_thread(void)
{
if (timer_event)
SetEvent(timer_event); /* tell thread to terminate */
if (timer_thread) {
int rc = WaitForSingleObject(timer_thread, 10000);
if (rc == WAIT_TIMEOUT)
error("timer thread did not terminate timely");
else if (rc != WAIT_OBJECT_0)
error("waiting for timer thread failed: %lu",
GetLastError());
CloseHandle(timer_thread);
}
if (timer_event)
CloseHandle(timer_event);
timer_event = NULL;
timer_thread = NULL;
}
static inline int is_timeval_eq(const struct timeval *i1, const struct timeval *i2)
{
return i1->tv_sec == i2->tv_sec && i1->tv_usec == i2->tv_usec;
}
int setitimer(int type, struct itimerval *in, struct itimerval *out)
{
static const struct timeval zero;
static int atexit_done;
if (out != NULL)
return errno = EINVAL,
error("setitimer param 3 != NULL not implemented");
if (!is_timeval_eq(&in->it_interval, &zero) &&
!is_timeval_eq(&in->it_interval, &in->it_value))
return errno = EINVAL,
error("setitimer: it_interval must be zero or eq it_value");
if (timer_thread)
stop_timer_thread();
if (is_timeval_eq(&in->it_value, &zero) &&
is_timeval_eq(&in->it_interval, &zero))
return 0;
timer_signal = type == ITIMER_VIRTUAL ? SIGVTALRM : SIGALRM;
timer_interval = in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000;
one_shot = is_timeval_eq(&in->it_interval, &zero);
if (!atexit_done) {
atexit(stop_timer_thread);
atexit_done = 1;
}
return start_timer_thread();
}
// from msys2 mingw-packages-dev patches
// -----------------------------------------------------------------------
static DWORD __map_mmap_prot_page(const int prot)
{
DWORD protect = 0;
if (prot == PROT_NONE)
return protect;
if ((prot & PROT_EXEC) != 0)
{
protect = ((prot & PROT_WRITE) != 0) ?
PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
}
else
{
protect = ((prot & PROT_WRITE) != 0) ?
PAGE_READWRITE : PAGE_READONLY;
}
return protect;
}
static DWORD __map_mmap_prot_file(const int prot)
{
DWORD desiredAccess = 0;
if (prot == PROT_NONE)
return desiredAccess;
if ((prot & PROT_READ) != 0)
desiredAccess |= FILE_MAP_READ;
if ((prot & PROT_WRITE) != 0)
desiredAccess |= FILE_MAP_WRITE;
if ((prot & PROT_EXEC) != 0)
desiredAccess |= FILE_MAP_EXECUTE;
return desiredAccess;
}
void* mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
{
HANDLE fm, h;
void * map = MAP_FAILED;
const DWORD dwFileOffsetLow = (sizeof(off_t) <= sizeof(DWORD)) ?
(DWORD)off : (DWORD)(off & 0xFFFFFFFFL);
const DWORD dwFileOffsetHigh = (sizeof(off_t) <= sizeof(DWORD)) ?
(DWORD)0 : (DWORD)((off >> 32) & 0xFFFFFFFFL);
const DWORD protect = __map_mmap_prot_page(prot);
const DWORD desiredAccess = __map_mmap_prot_file(prot);
errno = 0;
if (len == 0
/* Usupported protection combinations */
|| prot == PROT_EXEC)
{
errno = EINVAL;
return MAP_FAILED;
}
if ((flags & MAP_ANON) == 0)
{
h = (HANDLE)_get_osfhandle(fildes);
if (h == INVALID_HANDLE_VALUE)
{
errno = EBADF;
return MAP_FAILED;
}
}
else h = INVALID_HANDLE_VALUE;
fm = CreateFileMapping(h, NULL, protect, 0, len, NULL);
if (fm == NULL)
{
errno = err_win_to_posix(GetLastError());
return MAP_FAILED;
}
map = MapViewOfFileEx(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len, addr);
errno = err_win_to_posix(GetLastError());
CloseHandle(fm);
if (map == NULL)
return MAP_FAILED;
if ((flags & MAP_FIXED) != 0 && map != addr)
{
UnmapViewOfFile(map);
errno = EEXIST;
return MAP_FAILED;
}
return map;
}
int munmap(void *addr, size_t len)
{
if (UnmapViewOfFile(addr))
return 0;
errno = err_win_to_posix(GetLastError());
return -1;
}
int msync(void *addr, size_t len, int flags)
{
if (FlushViewOfFile(addr, len))
return 0;
errno = err_win_to_posix(GetLastError());
return -1;
}
// -----------------------------------------------------------------------
// libgcc built for mingw has included an implementation of mprotect
// via VirtualProtect since olden days, but it takes int rather than size_t
// and therefore fails or does unexpected things for >2GB blocks on 64-bit
// https://github.com/gcc-mirror/gcc/blob/master/libgcc/libgcc2.c
int mprotect (void *addr, size_t len, int prot)
{
DWORD np, op;
if (prot == (PROT_READ | PROT_WRITE | PROT_EXEC))
np = PAGE_EXECUTE_READWRITE;
else if (prot == (PROT_READ | PROT_EXEC))
np = PAGE_EXECUTE_READ;
else if (prot == (PROT_EXEC))
np = PAGE_EXECUTE;
else if (prot == (PROT_READ | PROT_WRITE))
np = PAGE_READWRITE;
else if (prot == (PROT_READ))
np = PAGE_READONLY;
else if (prot == 0)
np = PAGE_NOACCESS;
else
{
errno = EINVAL;
return -1;
}
if (VirtualProtect (addr, len, np, &op))
return 0;
// NB: return code of ntdll!RtlGetLastNtStatus() is useful
// for diagnosing obscure VirtualProtect failures
errno = err_win_to_posix(GetLastError());
return -1;
}
int utimes(const char *path, const struct timeval times[2])
{
// TODO: implement in terms of utime
return -1;
}
int fdatasync(int fildes)
{
HANDLE h = (HANDLE)_get_osfhandle(fildes);
if (h == INVALID_HANDLE_VALUE)
{
errno = EBADF;
return -1;
}
if (FlushFileBuffers(h))
{
errno = 0;
return 0;
}
else
{
errno = err_win_to_posix(GetLastError());
return -1;
}
}
char *realpath(const char *path, char *resolved_path)
{
// TODO
return strdup(path);
}

View File

@ -0,0 +1,41 @@
#ifndef _MINGW_IO_H
#define _MINGW_IO_H
// msvcrt setjmp/longjmp are broken on 64-bit systems, use gcc builtins
typedef struct jmp_buf {
intptr_t buffer[5];
int retval;
} jmp_buf;
#define _setjmp setjmp
#define _longjmp longjmp
#define longjmp(buf, val) {buf.retval = (val); __builtin_longjmp(buf.buffer, 1);}
#define setjmp(buf) (__builtin_setjmp(buf.buffer) ? (buf.retval) : 0)
// no profiling on MingW means signal masks are not used
#define sigjmp_buf jmp_buf
#define siglongjmp longjmp
#define sigsetjmp(A, B) setjmp(A)
#define mkdir(A, B) mkdir(A)
char *realpath(const char *path, char *resolved_path);
int fdatasync(int fd);
int utimes(const char *path, const struct timeval times[2]);
int kill(pid_t pid, int signum);
#define SIGALRM 1233
#define SIGVTALRM 1234
#define SIGINFO 1235
#define SIGUSR1 1236
#define SIGTSTP 1238
#define ITIMER_REAL 0
#define ITIMER_VIRTUAL 1
struct itimerval {
struct timeval it_value, it_interval;
};
int setitimer(int type, struct itimerval *in, struct itimerval *out);
#endif//_MINGW_IO_H

View File

@ -0,0 +1,13 @@
diff --git a/Makefile b/Makefile
new file mode 100644
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,8 @@
+.PHONY: all clean
+
+all: *.c *.h
+ $(CC) -c -O3 -Wall -Werror *.c
+ $(AR) rcs libed25519.a *.o
+
+clean:
+ rm -f *.o *.a

1834
pkg/urbit/compat/mingw/h2o.patch Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
diff --git a/Makefile b/Makefile
index 783c537..3156ee2 100644
--- a/Makefile
+++ b/Makefile
@@ -12,10 +12,9 @@ LDFLAGS_EXTRA?=-Wl,-z,relro
all: reference
-OBJS= crypto_scrypt-nosse.o sha256.o crypto-mcf.o b64.o crypto-scrypt-saltgen.o crypto_scrypt-check.o crypto_scrypt-hash.o slowequals.o
+OBJS= crypto_scrypt-nosse.o sha256.o crypto-mcf.o b64.o slowequals.o
-libscrypt.so.0: $(OBJS)
- $(CC) $(LDFLAGS) -shared -o libscrypt.so.0 $(OBJS) -lm -lc
+libscrypt.a: $(OBJS)
ar rcs libscrypt.a $(OBJS)
reference: libscrypt.so.0 main.o crypto_scrypt-hexconvert.o

View File

@ -0,0 +1,74 @@
diff --git a/mdb.c b/mdb.c
--- a/mdb.c
+++ b/mdb.c
@@ -1707,28 +1707,27 @@ static char *const mdb_errstr[] = {
"MDB_PROBLEM: Unexpected problem - txn should abort",
};
-char *
-mdb_strerror(int err)
+void
+mdb_logerror(FILE* f, int err, const char* fmt, ...)
{
-#ifdef _WIN32
- /** HACK: pad 4KB on stack over the buf. Return system msgs in buf.
- * This works as long as no function between the call to mdb_strerror
- * and the actual use of the message uses more than 4K of stack.
- */
-#define MSGSIZE 1024
-#define PADSIZE 4096
- char buf[MSGSIZE+PADSIZE], *ptr = buf;
-#endif
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(f, fmt, ap);
+ va_end(ap);
+
int i;
if (!err)
- return ("Successful return: 0");
+ {
+ fprintf(stderr, ": %s\r\n", "Successful return: 0");
+ return;
+ }
if (err >= MDB_KEYEXIST && err <= MDB_LAST_ERRCODE) {
i = err - MDB_KEYEXIST;
- return mdb_errstr[i];
+ fprintf(stderr, ": %s\r\n", mdb_errstr[i]);
+ return;
}
-#ifdef _WIN32
/* These are the C-runtime error codes we use. The comment indicates
* their numeric value, and the Win32 error they would correspond to
* if the error actually came from a Win32 API. A major mess, we should
@@ -1742,18 +1741,20 @@ mdb_strerror(int err)
case EBUSY: /* 16, CURRENT_DIRECTORY */
case EINVAL: /* 22, BAD_COMMAND */
case ENOSPC: /* 28, OUT_OF_PAPER */
- return strerror(err);
+ fprintf(stderr, ": %s\r\n", strerror(err));
default:
;
}
- buf[0] = 0;
- FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
+ LPSTR ptr;
+ if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, err, 0, ptr, MSGSIZE, (va_list *)buf+MSGSIZE);
- return ptr;
-#else
- return strerror(err);
-#endif
+ NULL, err, 0, (LPSTR)&ptr, sizeof (LPSTR), NULL))
+ {
+ fprintf(stderr, ": %s\r\n", ptr);
+ LocalFree(ptr);
+ } else
+ fprintf(stderr, ": <%d>\r\n", err);
}
/** assert(3) variant in cursor context */

View File

@ -0,0 +1,26 @@
#ifndef _SYS_MMAN_H
#define _SYS_MMAN_H
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);
int msync(void *addr, size_t length, int flags);
int mprotect(void *addr, size_t len, int prot);
#define PROT_NONE 0x00 /* No access. */
#define PROT_READ 0x01 /* Pages can be read. */
#define PROT_WRITE 0x02 /* Pages can be written. */
#define PROT_EXEC 0x04 /* Pages can be executed. */
#define MAP_FILE 0x0001 /* Mapped from a file or device. */
#define MAP_ANON 0x0002 /* Allocated from anonymous virtual memory. */
#define MAP_TYPE 0x000f /* Mask for type field. */
#define MAP_SHARED 0x0010 /* Share changes. */
#define MAP_PRIVATE 0x0000 /* Changes private; copy pages on write. */
#define MAP_FIXED 0x0100 /* Map address must be exactly as requested. */
#define MAP_FAILED ((void *) -1)
#define MS_ASYNC 1 /* Sync memory asynchronously. */
#define MS_SYNC 0 /* Synchronous memory sync. */
#define MS_INVALIDATE 2 /* Invalidate the caches. */
#endif//_SYS_MMAN_H

View File

@ -0,0 +1,13 @@
diff --git a/makefile b/makefile
--- a/makefile
+++ b/makefile
@@ -12,5 +12,9 @@ shared: murmur3.c murmur3.h
$(CC) -fPIC -O3 -c murmur3.c
$(CC) -shared -Wl,--export-dynamic murmur3.o -o libmurmur3.so
+static: murmur3.c murmur3.h
+ $(CC) -fPIC -O3 -c murmur3.c
+ $(AR) rcs libmurmur3.a murmur3.o
+
clean:
rm -rf example *.o *.so

View File

@ -0,0 +1,36 @@
diff --git a/build/Win64-MinGW-w64/Makefile b/build/Win64-MinGW-w64/Makefile
--- a/build/Win64-MinGW-w64/Makefile
+++ b/build/Win64-MinGW-w64/Makefile
@@ -46,7 +46,8 @@ C_INCLUDES = -I. -I$(SOURCE_DIR)/$(SPECIALIZE_TYPE) -I$(SOURCE_DIR)/include
COMPILE_C = \
x86_64-w64-mingw32-gcc -c -Werror-implicit-function-declaration \
-DSOFTFLOAT_FAST_INT64 $(SOFTFLOAT_OPTS) $(C_INCLUDES) -O2 -o $@
-MAKELIB = x86_64-w64-mingw32-ar crs $@
+MAKELIB = x86_64-w64-mingw32-gcc-ar crs $@
+LIBNAME = libsoftfloat3
OBJ = .o
LIB = .a
@@ -54,7 +55,7 @@ LIB = .a
OTHER_HEADERS = $(SOURCE_DIR)/include/opts-GCC.h
.PHONY: all
-all: softfloat$(LIB)
+all: $(LIBNAME)$(LIB)
OBJS_PRIMITIVES = \
s_eq128$(OBJ) \
@@ -380,11 +381,11 @@ $(OBJS_PRIMITIVES) $(OBJS_OTHERS): %$(OBJ): $(SOURCE_DIR)/%.c
$(OBJS_SPECIALIZE): %$(OBJ): $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/%.c
$(COMPILE_C) $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/$*.c
-softfloat$(LIB): $(OBJS_ALL)
+$(LIBNAME)$(LIB): $(OBJS_ALL)
$(DELETE) $@
$(MAKELIB) $^
.PHONY: clean
clean:
- $(DELETE) $(OBJS_ALL) softfloat$(LIB)
+ $(DELETE) $(OBJS_ALL) $(LIBNAME)$(LIB)

View File

@ -0,0 +1,8 @@
#ifndef _TERMIOS_H
#define _TERMIOS_H
struct termios {
char _dummy;
};
#endif

15
pkg/urbit/configure vendored
View File

@ -6,7 +6,7 @@ URBIT_VERSION="$(cat ./version)"
deps=" \
curl gmp sigsegv argon2 ed25519 ent h2o scrypt uv murmur3 secp256k1 \
softfloat3 ssl crypto z lmdb ge-additions aes_siv pthread \
softfloat3 aes_siv ssl crypto z lmdb ge-additions pthread \
"
headers=" \
@ -58,6 +58,15 @@ esac
# TODO Determine if the target cpu is little or big endian.
case $(tr A-Z a-z <<< $os) in
*mingw*)
defmacro U3_OS_mingw 1
# increase default thread stack size and link Windows implibs
ldextra="-Wl,--stack,67108864 -lbcrypt -lws2_32"
mkextra="use_dumb_terminal = 1"
vcompat="compat = mingw"
CFLAGS="${CFLAGS-} -DH2O_NO_UNIX_SOCKETS -Icompat/mingw"
;;
*linux*)
defmacro U3_OS_linux 1
defmacro U3_OS_PROF 1
@ -94,8 +103,10 @@ done
cat >config.mk <<EOF
CFLAGS := ${CFLAGS-} -funsigned-char -ffast-math -fcommon -std=gnu99
LDFLAGS := $LDFLAGS
LDFLAGS := $LDFLAGS ${ldextra-}
CC := ${CC-cc}
${vcompat-}
${mkextra-}
EOF
echo == config.mk == >&2

View File

@ -590,6 +590,10 @@ static void _on_boot_completed_cb() {
static void
_fork_into_background_process()
{
#if defined(U3_OS_mingw)
fprintf(stderr, "Daemon mode is not yet supported on MingW\r\n");
exit(1);
#else
c3_i pipefd[2];
if ( 0 != pipe(pipefd) ) {
@ -618,6 +622,7 @@ _fork_into_background_process()
c3_i status;
wait(&status);
exit(WEXITSTATUS(status));
#endif
}
/* _stop_on_boot_completed_cb(): exit gracefully after boot is complete
@ -642,7 +647,12 @@ main(c3_i argc,
// Set `u3_Host.wrk_c` to the worker executable path.
c3_i worker_exe_len = 1 + strlen(argv[0]) + strlen("-worker");
u3_Host.wrk_c = c3_malloc(worker_exe_len);
#if defined(U3_OS_mingw)
strcpy(u3_Host.wrk_c, argv[0]);
strcpy(u3_Host.wrk_c + strlen(argv[0]) - 4, "-worker.exe");
#else
snprintf(u3_Host.wrk_c, worker_exe_len, "%s-worker", argv[0]);
#endif
if ( c3y == u3_Host.ops_u.dem ) {
_fork_into_background_process();

View File

@ -72,6 +72,23 @@
# include <sys/resource.h>
# include <sys/mman.h>
# elif defined(U3_OS_mingw)
# define _POSIX
# include <openssl/opensslv.h>
# include <inttypes.h>
# include <stdlib.h>
# include <string.h>
# include <stdarg.h>
# include <unistd.h>
# include <stdint.h>
# include <assert.h>
# include <stdio.h>
# include <dirent.h>
# include <signal.h>
# include <sys/time.h>
# include "mman.h"
# include "compat.h"
# else
#error "port: headers"
# endif
@ -101,19 +118,15 @@
# define U3_OS_LoomBase 0x36000000
# endif
# define U3_OS_LoomBits 29 // ie, 2^29 words == 2GB
# elif defined(U3_OS_osx)
# elif defined(U3_OS_osx) || defined(U3_OS_bsd)
# ifdef __LP64__
# define U3_OS_LoomBase 0x200000000
# else
# define U3_OS_LoomBase 0x4000000
# endif
# define U3_OS_LoomBits 29 // ie, 2^29 words == 2GB
# elif defined(U3_OS_bsd)
# ifdef __LP64__
# define U3_OS_LoomBase 0x200000000
# else
# define U3_OS_LoomBase 0x4000000
# endif
# elif defined(U3_OS_mingw)
# define U3_OS_LoomBase 0x28000000000
# define U3_OS_LoomBits 29 // ie, 2^29 words == 2GB
# else
# error "port: LoomBase"
@ -157,7 +170,7 @@
/* Byte swapping.
*/
# if defined(U3_OS_linux) || defined(U3_OS_bsd)
# if defined(U3_OS_linux) || defined(U3_OS_bsd) || defined(U3_OS_mingw)
# define c3_bswap_16(x) bswap_16(x)
# define c3_bswap_32(x) bswap_32(x)
# define c3_bswap_64(x) bswap_64(x)
@ -171,7 +184,7 @@
/* Sync.
*/
# if defined(U3_OS_linux)
# if defined(U3_OS_linux) || defined(U3_OS_mingw)
# define c3_sync(fd) (fdatasync(fd))
# elif defined(U3_OS_osx)
# define c3_sync(fd) (fcntl(fd, F_FULLFSYNC, 0))
@ -186,7 +199,7 @@
# if defined(U3_OS_linux)
# include <stdio_ext.h>
# define c3_fpurge __fpurge
# elif defined(U3_OS_bsd) || defined(U3_OS_osx)
# elif defined(U3_OS_bsd) || defined(U3_OS_osx) || defined(U3_OS_mingw)
# define c3_fpurge fpurge
# else
# error "port: fpurge"
@ -194,7 +207,7 @@
/* Stat.
*/
# if defined(U3_OS_linux)
# if defined(U3_OS_linux) || defined(U3_OS_mingw)
# define c3_stat_mtime(dp) (u3_time_t_in_ts((dp)->st_mtime))
# elif defined(U3_OS_osx)
# define c3_stat_mtime(dp) (u3_time_in_ts(&((dp)->st_mtimespec)))

View File

@ -717,7 +717,7 @@
*/
u3_atom
u3_time_in_ts(struct timespec* tim_ts);
#if defined(U3_OS_linux)
#if defined(U3_OS_linux) || defined(U3_OS_mingw)
/* u3_time_t_in_ts(): urbit time from time_t.
*/
u3_atom

View File

@ -1557,6 +1557,10 @@ u3m_wall(u3_noun wol)
static void
_cm_limits(void)
{
# ifdef U3_OS_mingw
// Windows doesn't have rlimits. Default maximum thread
// stack size is set in the executable file header.
# else
struct rlimit rlm;
// Moar stack.
@ -1604,6 +1608,7 @@ _cm_limits(void)
}
}
# endif
# endif
}
/* _cm_signals(): set up interrupts, etc.

View File

@ -451,6 +451,7 @@ u3_lmdb_save_meta(MDB_env* env_u,
return c3y;
}
#if !defined(U3_OS_mingw)
/* mdb_logerror(): writes an error message and lmdb error code to f.
*/
void mdb_logerror(FILE* f, int err, const char* fmt, ...)
@ -461,3 +462,4 @@ void mdb_logerror(FILE* f, int err, const char* fmt, ...)
va_end(ap);
fprintf(f, ": %s\r\n", mdb_strerror(err));
}
#endif

171
pkg/urbit/vere/io/dumb.c Normal file
View File

@ -0,0 +1,171 @@
/* vere/dumb.c
**
*/
#include "all.h"
#include "vere/vere.h"
/* u3_term_log_init(): initialize terminal for logging
*/
void
u3_term_log_init(void)
{
}
/* u3_term_log_exit(): clean up terminal.
*/
void
u3_term_log_exit(void)
{
}
/* u3_term_start_spinner(): prepare spinner state. RETAIN.
*/
void
u3_term_start_spinner(u3_atom say, c3_o del_o)
{
}
/* u3_term_stop_spinner(): reset spinner state and restore input line.
*/
void
u3_term_stop_spinner(void)
{
}
/* u3_term_get_blew(): return window size [columns rows].
*/
u3_noun
u3_term_get_blew(c3_l tid_l)
{
return u3nc(80, 24);
}
/* u3_term_ef_winc(): window change. Just console right now.
*/
void
u3_term_ef_winc(void)
{
}
/* u3_term_ef_ctlc(): send ^C on console.
*/
void
u3_term_ef_ctlc(void)
{
}
/* u3_term_io_hija(): hijack console for fprintf, returning FILE*.
*/
FILE*
u3_term_io_hija(void)
{
return stdout;
}
/* u3_term_io_loja(): release console from fprintf.
*/
void
u3_term_io_loja(int x)
{
fflush(stdout);
}
/* u3_term_it_log(): writes a log message
*/
void
u3_term_io_log(c3_c* line)
{
FILE* stream = u3_term_io_hija();
u3_term_io_loja(fprintf(stream, "%s", line));
}
/* _term_ovum_plan(): plan term ovums, configuring spinner.
*/
static u3_ovum*
_term_ovum_plan(u3_auto* car_u, u3_noun wir, u3_noun cad)
{
u3_ovum* egg_u = u3_auto_plan(car_u, u3_ovum_init(0, c3__d, wir, cad));
// term events have no spinner label
//
u3z(egg_u->pin_u.lab);
egg_u->pin_u.lab = u3_blip;
return egg_u;
}
/* _term_io_talk():
*/
static void
_term_io_talk(u3_auto* car_u)
{
// XX groace hardcoded terminal number
//
u3_noun wir = u3nt(c3__term, '1', u3_nul);
u3_noun cad;
// send terminal dimensions
//
{
cad = u3nc(c3__blew, u3_term_get_blew(1));
_term_ovum_plan(car_u, u3k(wir), cad);
}
// NB, term.c used to also start :dojo
//
// u3nq(c3__flow, c3__seat, c3__dojo, u3_nul)
// refresh terminal state
//
{
cad = u3nc(c3__hail, u3_nul);
_term_ovum_plan(car_u, wir, cad);
}
}
/* _term_io_kick(): apply effects.
*/
static c3_o
_term_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad)
{
u3_noun tag, dat, i_wir, t_wir;
c3_o ret_o;
if ( (c3n == u3r_cell(wir, &i_wir, &t_wir))
|| (c3n == u3r_cell(cad, &tag, &dat))
|| (c3__term != i_wir) )
{
ret_o = c3n;
}
else {
// eat everything
ret_o = c3y;
}
u3z(wir); u3z(cad);
return ret_o;
}
/* _term_io_exit(): clean up terminal.
*/
static void
_term_io_exit(u3_auto* car_u)
{
c3_free(car_u);
}
/* u3_term_io_init(): initialize terminal
*/
u3_auto*
u3_term_io_init(u3_pier* pir_u)
{
u3_auto* car_u = c3_calloc(sizeof(*car_u));
car_u->nam_m = c3__term;
car_u->liv_o = c3y;
car_u->io.talk_f = _term_io_talk;
car_u->io.kick_f = _term_io_kick;
car_u->io.exit_f = _term_io_exit;
return car_u;
}

View File

@ -749,12 +749,16 @@ u3_king_commence()
u3C.sign_move_f = _king_sign_move;
// Ignore SIGPIPE signals.
#ifndef U3_OS_mingw
{
struct sigaction sig_s = {{0}};
sigemptyset(&(sig_s.sa_mask));
sig_s.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sig_s, 0);
}
#else
signal(SIGPIPE, SIG_IGN);
#endif
// boot the ivory pill
//
@ -762,6 +766,7 @@ u3_king_commence()
// disable core dumps (due to lmdb size)
//
#ifndef U3_OS_mingw
{
struct rlimit rlm;
@ -773,6 +778,7 @@ u3_king_commence()
exit(1);
}
}
#endif
// run the loop
//

View File

@ -98,7 +98,7 @@ u3_time_in_ts(struct timespec* tim_ts)
return u3_time_in_tv(&tim_tv);
}
#if defined(U3_OS_linux)
#if defined(U3_OS_linux) || defined(U3_OS_mingw)
/* u3_time_t_in_ts(): urbit time from time_t.
*/
u3_atom
@ -111,7 +111,7 @@ u3_time_t_in_ts(time_t tim)
return u3_time_in_tv(&tim_tv);
}
#endif // defined(U3_OS_linux)
#endif // defined(U3_OS_linux) || defined(U3_OS_mingw)
/* u3_time_out_ts(): struct timespec from urbit time.
*/

View File

@ -195,12 +195,16 @@ _cw_serf_commence(c3_i argc, c3_c* argv[])
// Ignore SIGPIPE signals.
//
#ifndef U3_OS_mingw
{
struct sigaction sig_s = {{0}};
sigemptyset(&(sig_s.sa_mask));
sig_s.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sig_s, 0);
}
#else
signal(SIGPIPE, SIG_IGN);
#endif
// configure pipe to daemon process
//