added mingw test platform (#829)

* Provide a minimal reimplementation of our autoconf, to try windows builds

* Try building with windows

* Fix thinko in spelling

* Ensure shell script runs inside a shell

* Add a hack to aid include discovery

* Just keep adding tech debt...

* Assume that we will have slashes in some of the replacement strings and avoid that char with sed

* Restore one slash

* Hack around the tools makefile interdependancy bug

* A correct cflags include hack for each compile dir

* Ensure we link against winsock (note, even though this says 32bit, it should link the 64bit library ... I think)

* Bad link ordering if we dont use LDLIBS

* Remove unused make variable

* Remove makefile duplication using inheritance (this does mean you can no longer cd tools; make, but must do make tools)

* Add missing library for win32

* Show OS variable

* Make hack autoconf more robust for tests on non gitlab runners

* Remove no longer used substitutions from hack autoconf

* Add missing include path to tools under win32

* Build the win32 subdir when the compiler is Msys

* The different subdirs have different dependancies

* Ensure we can find the include files

* Fix library link ordering

* Ensure the tools dir can find the special win32 lib

* Deal with the differing basic type sizes on both linux/64bit and windows/64bit

* Document the steps to mimic the github windows/mingw build locally - to allow for simpler debugging

* Ensure branch name in instructions matches my test branch name

* Clarify the shell needed to build with mingw

* Since the makefile depends on knowing the OS, raise a fatal error if we cannot determine this

* Handling different compile environments is hard.

- Linux: sane and reasonable results for both uname -s (=Linux) and
  uname -o (=GNU/Linux)
- Windows/Mingw: insane results for uname -s
  (=MSYS_NT-$MAJOR.$MINOR-$BUILDNR) but sane results for uname -o (Msys)
- Macos: sane results for uname -s (=Darwin) but does not support
  uname -o at all

* Revamp the way that Mingw is detected

* Avoid attempting to generate gcovr report when running under windows

* Whoops, isolate the right step

* Fix spelling mistake

* win32/Makefile: Remove unused setting and add comment

* ensure that all win32 includes use the same expected path

* Allow simpler cross compilation by letting configure pass the CC and AR environment through

* Avoid multiple '_CRT_SECURE_NO_WARNINGS redefined' warnings

* Convert to a consolidated CONFIG_TARGET variable to select any different compile options

* Use the more generic printf defines to avoid warnings on mingw

* Update mingw build docs

* English better for reader happy make

* Address a number of mingw compiler warnings

* Fix Visual C compile

* Be sure to document some of the hacky nature of the mingw build
This commit is contained in:
Hamish Coleman 2021-10-05 20:07:15 +01:00 committed by GitHub
parent db5adc2038
commit 4438f1aa2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 207 additions and 61 deletions

View File

@ -29,6 +29,7 @@ jobs:
- ubuntu-latest
- ubuntu-18.04
- macos-latest
- windows-latest
steps:
- uses: actions/checkout@v2
@ -44,6 +45,14 @@ jobs:
run: |
brew install automake gcovr
- if: runner.os == 'Windows'
# This is a pretty big hammer, but gets the windows compile moving
name: Hack up a fake autoconf
run: |
echo true >autogen.sh
cp scripts/hack_fakeautoconf configure
shell: bash
- name: generate a makefile and use it to install more packages
run: |
./autogen.sh
@ -67,13 +76,19 @@ jobs:
name: tests-out-${{matrix.os}}
path: tests/*.out
- name: Generate coverage reports
- name: Generate coverage data
run: |
make cover
make gcov
shell: bash
- name: Upload gcovr report artifact
- if: runner.os != 'Windows'
name: Generate gcovr report
run: |
make cover
shell: bash
- if: runner.os != 'Windows'
name: Upload gcovr report artifact
uses: actions/upload-artifact@v2
with:
name: coverage-${{matrix.os}}

3
.gitignore vendored
View File

@ -4,7 +4,8 @@
configure
configure.ac
config.*
Makefile
./Makefile
tools/Makefile
autom4te.cache
edge
example_edge_embed_quick_edge_init

View File

@ -6,6 +6,8 @@ GIT_DESCRIBE=$(shell git describe --always --dirty)
########
export CC
export AR
CC=@CC@
AR=@AR@
@ -13,7 +15,9 @@ AR=@AR@
#(thanks to Robert Gibbon)
PLATOPTS_SPARC64=-mcpu=ultrasparc -pipe -fomit-frame-pointer -ffast-math -finline-functions -fweb -frename-registers -mapp-regs
N2N_OBJS_OPT=
export CFLAGS
export LDFLAGS
CFLAGS=@CFLAGS@ -I ./include
LDFLAGS=@LDFLAGS@ -L .
@ -25,17 +29,47 @@ endif
WARN=-Wall
CFLAGS+=$(DEBUG) $(OPTIMIZATION) $(WARN) $(OPTIONS) $(PLATOPTS)
INSTALL=install
MKDIR=mkdir -p
OS := $(shell uname -s)
# Quick sanity check on our build environment
UNAME_S := $(shell uname -s)
ifndef UNAME_S
# This could happen if the Makefile is unable to run "uname", which can
# happen if the shell has a bad path (or is the wrong shell)
$(error Could not run uname command, cannot continue)
endif
# Any compile environment that needs different flags, libraries, includes or
# other settings will get its own CONFIG_TARGET value. For cross compiling,
# this might be set externally to the Makefile, but if not set we try to
# set a reasonable default.
export CONFIG_TARGET
ifndef CONFIG_TARGET
ifeq ($(shell uname -o),Msys)
CONFIG_TARGET=mingw
else ifeq ($(shell uname -s),Darwin)
CONFIG_TARGET=darwin
else ifeq ($(shell uname), SunOS)
CONFIG_TARGET=sunos
else
CONFIG_TARGET=generic
endif
endif
export MKDIR
export INSTALL
export INSTALL_PROG
export INSTALL_DOC
export PREFIX
export SBINDIR
MKDIR=mkdir -p
INSTALL=install
INSTALL_PROG=$(INSTALL) -m755
INSTALL_DOC=$(INSTALL) -m644
# DESTDIR set in debian make system
PREFIX?=$(DESTDIR)/usr
#BINDIR=$(PREFIX)/bin
ifeq ($(OS),Darwin)
ifeq ($(CONFIG_TARGET),darwin)
SBINDIR=$(PREFIX)/local/sbin
else
SBINDIR=$(PREFIX)/sbin
@ -50,14 +84,23 @@ N2N_LIB=libn2n.a
N2N_OBJS=$(patsubst src/%.c, src/%.o, $(wildcard src/*.c))
N2N_DEPS=$(wildcard include/*.h) $(wildcard src/*.c) Makefile
export LDLIBS
LDLIBS+=-ln2n
LDLIBS+=@N2N_LIBS@
#For OpenSolaris (Solaris too?)
ifeq ($(shell uname), SunOS)
ifeq ($(CONFIG_TARGET), sunos)
LDLIBS+=-lsocket -lnsl
endif
ifeq ($(CONFIG_TARGET),mingw)
CFLAGS+=-I. -I./win32 -DWIN32
LDLIBS+=$(abspath win32/n2n_win32.a)
LDLIBS+=-lws2_32 -liphlpapi
N2N_DEPS+=win32/n2n_win32.a
SUBDIRS+=win32
endif
APPS=edge
APPS+=supernode
APPS+=example_edge_embed_quick_edge_init
@ -66,12 +109,18 @@ APPS+=example_sn_embed
DOCS=edge.8.gz supernode.1.gz n2n.7.gz
.PHONY: steps build push all clean install tools test cover gcov build-dep
all: $(APPS) $(DOCS) tools
SUBDIRS+=tools
.PHONY: $(SUBDIRS)
.PHONY: steps build push all clean install test cover gcov build-dep
all: $(APPS) $(DOCS) $(SUBDIRS)
tools: $(N2N_LIB)
$(MAKE) -C $@
win32:
$(MAKE) -C $@
src/edge.o: $(N2N_DEPS)
src/supernode.o: $(N2N_DEPS)
src/example_edge_embed_quick_edge_init.o: $(N2N_DEPS)
@ -94,6 +143,8 @@ $(N2N_LIB): $(N2N_OBJS)
$(AR) rcs $(N2N_LIB) $(N2N_OBJS)
# $(RANLIB) $@
win32/n2n_win32.a: win32
test: tools
tools/test_harness
@ -116,16 +167,18 @@ gcov:
# This is the superset of all packages that might be needed.
# It is a convinent target to use during development or from a CI/CD system
build-dep:
ifeq ($(OS),Linux)
ifeq ($(CONFIG_TARGET),generic)
sudo apt install build-essential autoconf libcap-dev libzstd-dev gcovr
else ifeq ($(CONFIG_TARGET),darwin)
brew install automake gcovr
else
echo Not attempting to handle build dependancies for non dpkg systems
echo Not attempting to install dependancies for system $(CONFIG_TARGET)
endif
clean:
rm -rf $(N2N_OBJS) $(N2N_LIB) $(APPS) $(DOCS) coverage/ *.dSYM *~
rm -f tests/*.out src/*.gcno src/*.gcda
$(MAKE) -C tools clean
for dir in $(SUBDIRS); do $(MAKE) -C $$dir clean; done
install: edge supernode edge.8.gz supernode.1.gz n2n.7.gz
echo "MANDIR=$(MANDIR)"

View File

@ -13,8 +13,13 @@ else
GIT_RELEASE=${N2N_VERSION_SHORT}
fi
if test "${CC+set}" != set; then
CC=gcc
fi
if test "${AR+set}" != set; then
AR=ar
fi
N2N_LIBS=
AC_PROG_CC

View File

@ -12,7 +12,7 @@ If you are on a modern version of macOS (i.e. Catalina), the commands above will
For more information refer to vendor documentation or the [Apple Technical Note](https://developer.apple.com/library/content/technotes/tn2459/_index.html).
# Build on Windows
# Build on Windows (Visual Studio)
## Requirements
@ -46,8 +46,9 @@ In order to run n2n, you will need the following:
- If OpenSSL has been linked dynamically, the corresponding `.dll` file should be available
onto the target computer.
NOTE: Sticking to this tool chain ensures that resulting executables are able to communicate with Linux or other OS builds.
Especialy MinGW builds are reported to not be compatible to other OS builds, please see [#617](https://github.com/ntop/n2n/issues/617) and [#642](https://github.com/ntop/n2n/issues/642).
NOTE: Sticking to this tool chain has historically meant that resulting
executables are more likely to be able to communicate with Linux or other
OS builds, however efforts are being made to address this concern.
## Build (CLI)
@ -97,6 +98,29 @@ Here is an example `supernode.conf` file:
See `edge.exe --help` and `supernode.exe --help` for a full list of supported options.
# Build on Windows (MinGW)
These steps were tested on a fresh install of Windows 10 Pro with all patches
applied as of 2021-09-29.
- Install Chocolatey (Following instructions on https://chocolatey.org/install)
- from an admin cmd prompt
- choco install git mingw make
- All the remaining commands must be run from inside a bash shell ("C:\Program Files\Git\usr\bin\bash.exe")
- git clone $THIS_REPO
- cd n2n
- ./scripts/hack_fakeautoconf
- make
- make test
Due to the hack used to replace autotools on windows, any build created this
way will currently have inaccurate build version numbers.
Note: MinGW builds have a history of incompatibility reports with other OS
builds, please see [#617](https://github.com/ntop/n2n/issues/617) and [#642](https://github.com/ntop/n2n/issues/642).
However, if the tests pass, you should have a high confidence that your build
will be compatible.
# General Building Options
## Compiler Optimizations

View File

@ -41,7 +41,7 @@
#ifndef CMAKE_BUILD
#include "config.h" /* Visual C++ */
#else
#include "win32/winconfig.h"
#include "winconfig.h"
#endif
#define N2N_CAN_NAME_IFACE 1
#undef N2N_HAVE_DAEMON
@ -137,7 +137,7 @@
#ifdef WIN32
#include <winsock2.h> /* for tcp */
#define SHUT_RDWR SD_BOTH /* for tcp */
#include "win32/wintap.h"
#include "wintap.h"
#include <sys/stat.h>
#else
#include <pwd.h>

View File

@ -26,7 +26,7 @@
#endif
#if defined(WIN32)
#include "win32/n2n_win32.h"
#include "n2n_win32.h"
#else /* #if defined(WIN32) */
#include <netinet/in.h>
#include <sys/socket.h> /* AF_INET and AF_INET6 */

24
scripts/hack_fakeautoconf Executable file
View File

@ -0,0 +1,24 @@
#!/bin/sh
#
# Specifically for windows, where installing autoconf looks suspiciously
# like boiling the ocean.
cat Makefile.in | sed \
-e "s%@N2N_VERSION_SHORT@%FIXME%g" \
-e "s%@GIT_COMMITS@%FIXME%g" \
-e "s%@CC@%gcc%g" \
-e "s%@AR@%ar%g" \
-e "s%@CFLAGS@%$CFLAGS%g" \
-e "s%@LDFLAGS@%$LDFLAGS%g" \
-e "s%@N2N_LIBS@%$LDLIBS%g" \
> Makefile
cat tools/Makefile.in | sed \
-e "s%@ADDITIONAL_TOOLS@%%g" \
> tools/Makefile
cat <<EOF >include/config.h
#define PACKAGE_VERSION "FIXME"
#define PACKAGE_OSNAME "FIXME"
#define GIT_RELEASE "FIXME"
EOF

View File

@ -869,8 +869,8 @@ static int loadFromFile (const char *path, n2n_edge_conf_t *conf, n2n_tuntap_pri
/* ************************************** */
static void daemonize () {
#ifndef WIN32
static void daemonize () {
int childpid;
traceEvent(TRACE_NORMAL, "parent process is exiting (this is normal)");
@ -911,8 +911,8 @@ static void daemonize () {
} else /* father */
exit(0);
}
#endif
}
#endif
/* *************************************************** */
@ -1258,9 +1258,6 @@ int main (int argc, char* argv[]) {
setUseSyslog(1); /* traceEvent output now goes to syslog. */
daemonize();
}
#endif /* #ifndef WIN32 */
#ifndef WIN32
#ifdef HAVE_LIBCAP
/* Before dropping the privileges, retain capabilities to regain them in future. */

View File

@ -477,7 +477,7 @@ static ssize_t sendto_fd (n2n_sn_t *sss,
ssize_t sent = 0;
n2n_tcp_connection_t *conn;
sent = sendto(socket_fd, pktbuf, pktsize, 0 /* flags */,
sent = sendto(socket_fd, (void *)pktbuf, pktsize, 0 /* flags */,
socket, sizeof(struct sockaddr_in));
if((sent <= 0) && (errno)) {
@ -1634,7 +1634,7 @@ static int sendto_mgmt (n2n_sn_t *sss,
const uint8_t *mgmt_buf,
size_t mgmt_size) {
ssize_t r = sendto(sss->mgmt_sock, mgmt_buf, mgmt_size, 0 /*flags*/,
ssize_t r = sendto(sss->mgmt_sock, (void *)mgmt_buf, mgmt_size, 0 /*flags*/,
(struct sockaddr *)sender_sock, sizeof (struct sockaddr_in));
if(r <= 0) {
@ -2706,8 +2706,10 @@ int run_sn_loop (n2n_sn_t *sss, int *keep_running) {
fd_set socket_mask;
n2n_tcp_connection_t *conn, *tmp_conn;
#ifdef N2N_HAVE_TCP
SOCKET tmp_sock;
n2n_sock_str_t sockbuf;
#endif
struct timeval wait_time;
time_t before, now = 0;
@ -2748,7 +2750,7 @@ int run_sn_loop (n2n_sn_t *sss, int *keep_running) {
socklen_t i;
i = sizeof(sender_sock);
bread = recvfrom(sss->sock, pktbuf, N2N_SN_PKTBUF_SIZE, 0 /*flags*/,
bread = recvfrom(sss->sock, (void *)pktbuf, N2N_SN_PKTBUF_SIZE, 0 /*flags*/,
(struct sockaddr *)&sender_sock, (socklen_t *)&i);
if((bread < 0)
@ -2873,7 +2875,7 @@ int run_sn_loop (n2n_sn_t *sss, int *keep_running) {
size_t i;
i = sizeof(sender_sock);
bread = recvfrom(sss->mgmt_sock, pktbuf, N2N_SN_PKTBUF_SIZE, 0 /*flags*/,
bread = recvfrom(sss->mgmt_sock, (void *)pktbuf, N2N_SN_PKTBUF_SIZE, 0 /*flags*/,
(struct sockaddr *)&sender_sock, (socklen_t *)&i);
if(bread <= 0) {

View File

@ -1,26 +1,16 @@
CC=@CC@
#
# This is not a standalone makefile, it must be called from the toplevel
# makefile to inherit the correct environment
DEBUG?=-g3
OPTIMIZATION?=-O2 #-march=native
WARN?=-Wall
INSTALL=install
INSTALL_PROG=$(INSTALL) -m755
MKDIR=mkdir -p
PREFIX?=$(DESTDIR)/usr
ifeq ($(OS),Darwin)
SBINDIR=$(PREFIX)/local/sbin
else
SBINDIR=$(PREFIX)/sbin
endif
LDLIBS+=-ln2n
LDLIBS+=@N2N_LIBS@
HEADERS=$(wildcard include/*.h)
CFLAGS+=-I../include @CFLAGS@
CFLAGS+=-I../include
ifeq ($(CONFIG_TARGET),mingw)
CFLAGS+=-I../win32
endif
CFLAGS+=$(DEBUG)
LDFLAGS+=-L..
CFLAGS+=$(DEBUG) $(OPTIMIZATION) $(WARN)
LDFLAGS+=@LDFLAGS@
N2N_LIB=../libn2n.a

View File

@ -16,6 +16,12 @@
*
*/
#ifndef _MSC_VER
/* MinGW has undefined function gettimeofday() warnings without this header
* but Visual C++ doesnt even have the header */
#include <sys/time.h>
#endif
#include "n2n.h"
#define DURATION 2.5 // test duration per algorithm

View File

@ -16,6 +16,8 @@
*
*/
#include <inttypes.h>
#include <assert.h>
#include "n2n.h"
@ -78,7 +80,7 @@ void test_lzo1x() {
assert(compression_len == 47);
printf("%s: output size = 0x%lx\n", test_name, compression_len);
printf("%s: output size = 0x%"PRIx64"\n", test_name, compression_len);
fhexdump(0, compression_buffer, compression_len, stdout);
uint8_t deflation_buffer[N2N_PKT_BUF_SIZE];
@ -111,7 +113,7 @@ void test_zstd() {
assert(compression_len == 33);
printf("%s: output size = 0x%lx\n", test_name, compression_len);
printf("%s: output size = 0x%"PRIx64"\n", test_name, compression_len);
fhexdump(0, compression_buffer, compression_len, stdout);
uint8_t deflation_buffer[N2N_PKT_BUF_SIZE];
@ -148,7 +150,7 @@ int main(int argc, char * argv[]) {
/* Also for compression (init moved here for ciphers get run before in case of lzo init error) */
init_compression_for_benchmark();
printf("%s: input size = 0x%lx\n", "original", sizeof(PKT_CONTENT));
printf("%s: input size = 0x%"PRIx64"\n", "original", sizeof(PKT_CONTENT));
fhexdump(0, PKT_CONTENT, sizeof(PKT_CONTENT), stdout);
printf("\n");

View File

@ -16,6 +16,8 @@
*
*/
#include <inttypes.h>
#include "n2n.h"
#include "hexdump.h"
@ -43,7 +45,7 @@ void test_pearson(void *buf, unsigned int bufsize) {
uint64_t hash = pearson_hash_64(buf, bufsize);
printf("%s: output = 0x%lx\n", test_name, hash);
printf("%s: output = 0x%"PRIx64"\n", test_name, hash);
fprintf(stderr, "%s: tested\n", test_name);
printf("\n");
@ -53,7 +55,7 @@ int main(int argc, char * argv[]) {
pearson_hash_init();
char *test_name = "environment";
printf("%s: input size = 0x%lx\n", test_name, sizeof(PKT_CONTENT));
printf("%s: input size = 0x%"PRIx64"\n", test_name, sizeof(PKT_CONTENT));
fhexdump(0, PKT_CONTENT, sizeof(PKT_CONTENT), stdout);
printf("\n");

View File

@ -16,6 +16,8 @@
*
*/
#include <inttypes.h>
#include "n2n.h"
#include "hexdump.h"
@ -63,7 +65,7 @@ int main(int argc, char * argv[]) {
char *test_name = "environment";
printf("%s: community_name = \"%s\"\n", test_name, conf.community_name);
printf("%s: encrypt_key = \"%s\"\n", test_name, conf.encrypt_key);
printf("%s: input size = 0x%lx\n", test_name, sizeof(PKT_CONTENT));
printf("%s: input size = 0x%"PRIx64"\n", test_name, sizeof(PKT_CONTENT));
fhexdump(0, PKT_CONTENT, sizeof(PKT_CONTENT), stdout);
printf("\n");
@ -111,7 +113,7 @@ static void run_transop_benchmark(const char *op_name, n2n_trans_op_t *op_fn, n2
pktbuf+nw, N2N_PKT_BUF_SIZE-nw,
PKT_CONTENT, sizeof(PKT_CONTENT), mac_buf);
printf("%s: output size = 0x%lx\n", op_name, nw);
printf("%s: output size = 0x%"PRIx64"\n", op_name, nw);
fhexdump(0, pktbuf, nw, stdout);
// decrpytion

View File

@ -16,6 +16,8 @@
*
*/
#include <inttypes.h>
#include "n2n.h"
#include "hexdump.h"
@ -47,8 +49,8 @@ void test_REGISTER(n2n_common_t *common) {
size_t idx = 0;
size_t retval = encode_REGISTER( pktbuf, &idx, common, &reg);
printf("%s: output retval = 0x%lx\n", test_name, retval);
printf("%s: output idx = 0x%lx\n", test_name, idx);
printf("%s: output retval = 0x%"PRIx64"\n", test_name, retval);
printf("%s: output idx = 0x%"PRIx64"\n", test_name, idx);
fhexdump(0, pktbuf, idx, stdout);
// TODO: decode_REGISTER() and print

19
win32/Makefile Normal file
View File

@ -0,0 +1,19 @@
#
# This is not a standalone makefile, it must be called from the toplevel
# makefile to inherit the correct environment
CFLAGS+=-I../include
LDFLAGS+=-L..
.PHONY: all clean install
all: n2n_win32.a
n2n_win32.a: getopt1.o getopt.o wintap.o
$(AR) rcs $@ $+
clean:
rm -rf n2n_win32.a *.o *.gcno *.gcda
install:
true

View File

@ -7,7 +7,9 @@
#undef UNICODE
#undef _UNICODE
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <ws2tcpip.h>
#include <stdio.h>