Skip to content

Commit 55d39d4

Browse files
committed
Windows support
Pygolang stopped to work on Windows in 2019 starting from 8fa3c15 (Start using Cython and providing Cython/nogil API). Restore it now.
2 parents 3a83e8f + d1e92fa commit 55d39d4

35 files changed

+686
-247
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ build/
1010
*.so.*
1111
*.dylib
1212
*.dll
13+
*.lib
14+
*.exp
1315
*.pyd
1416
*_dsoinfo.py
1517

MANIFEST.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ include golang/libgolang.h
33
include golang/runtime/libgolang.cpp
44
include golang/runtime/libpyxruntime.cpp
55
include golang/pyx/runtime.h
6+
include golang/pyx/testprog/golang_dso_user/dsouser/dso.h
67
include golang/pyx/testprog/golang_dso_user/dsouser/dso.cpp
78
include golang/runtime/internal.h
89
include golang/runtime/internal/atomic.h
@@ -33,6 +34,8 @@ include golang/sync_test.cpp
3334
include golang/time.h
3435
include golang/time.cpp
3536
include golang/_testing.h
37+
include golang/_compat/windows/strings.h
38+
include golang/_compat/windows/unistd.h
3639
recursive-include golang *.py *.pxd *.pyx *.toml *.txt*
3740
recursive-include gpython *.py
3841
recursive-include 3rdparty *.h

golang/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- coding: utf-8 -*-
2-
# Copyright (C) 2018-2022 Nexedi SA and Contributors.
2+
# Copyright (C) 2018-2023 Nexedi SA and Contributors.
33
# Kirill Smelkov <[email protected]>
44
#
55
# This program is free software: you can Use, Study, Modify and Redistribute
@@ -42,6 +42,9 @@
4242
import inspect, sys
4343
import decorator, six
4444

45+
import setuptools_dso
46+
setuptools_dso.dylink_prepare_dso('golang.runtime.libgolang')
47+
4548
from golang._golang import _pysys_exc_clear as _sys_exc_clear
4649

4750
# @func is a necessary decorator for functions for selected golang features to work.

golang/_compat/windows/strings.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#ifndef _NXD_LIBGOLANG_COMPAT_WIN_STRINGS_H
2+
#define _NXD_LIBGOLANG_COMPAT_WIN_STRINGS_H
3+
//
4+
// Copyright (C) 2023 Nexedi SA and Contributors.
5+
// Kirill Smelkov <[email protected]>
6+
//
7+
// This program is free software: you can Use, Study, Modify and Redistribute
8+
// it under the terms of the GNU General Public License version 3, or (at your
9+
// option) any later version, as published by the Free Software Foundation.
10+
//
11+
// You can also Link and Combine this program with other software covered by
12+
// the terms of any of the Free Software licenses or any of the Open Source
13+
// Initiative approved licenses and Convey the resulting work. Corresponding
14+
// source of such a combination shall include the source code for all other
15+
// software used.
16+
//
17+
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
18+
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19+
//
20+
// See COPYING file for full licensing terms.
21+
// See https://www.nexedi.com/licensing for rationale and options.
22+
23+
#include <string.h>
24+
25+
static inline void bzero(void *p, size_t n) {
26+
memset(p, '\0', n);
27+
}
28+
29+
#endif // _NXD_LIBGOLANG_COMPAT_WIN_STRINGS_H
30+

golang/_compat/windows/unistd.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#ifndef _NXD_LIBGOLANG_COMPAT_WIN_UNISTD_H
2+
#define _NXD_LIBGOLANG_COMPAT_WIN_UNISTD_H
3+
//
4+
// Copyright (C) 2023 Nexedi SA and Contributors.
5+
// Kirill Smelkov <[email protected]>
6+
//
7+
// This program is free software: you can Use, Study, Modify and Redistribute
8+
// it under the terms of the GNU General Public License version 3, or (at your
9+
// option) any later version, as published by the Free Software Foundation.
10+
//
11+
// You can also Link and Combine this program with other software covered by
12+
// the terms of any of the Free Software licenses or any of the Open Source
13+
// Initiative approved licenses and Convey the resulting work. Corresponding
14+
// source of such a combination shall include the source code for all other
15+
// software used.
16+
//
17+
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
18+
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19+
//
20+
// See COPYING file for full licensing terms.
21+
// See https://www.nexedi.com/licensing for rationale and options.
22+
23+
// stub unistd.h to be used on Windows where it is absent.
24+
// we need this because e.g. `cimport posix.stat` forces inclusion of unistd.h
25+
// even if we use part of posix.stat that is available everywhere.
26+
27+
#include <io.h>
28+
29+
#define O_CLOEXEC _O_NOINHERIT
30+
31+
#endif // _NXD_LIBGOLANG_COMPAT_WIN_UNISTD_H

golang/fmt.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2019-2020 Nexedi SA and Contributors.
1+
// Copyright (C) 2019-2023 Nexedi SA and Contributors.
22
// Kirill Smelkov <[email protected]>
33
//
44
// This program is free software: you can Use, Study, Modify and Redistribute
@@ -48,7 +48,7 @@ string _vsprintf(const char *format, va_list argp) {
4848
return string(buf.get(), buf.get() + nchar); // without trailing '\0'
4949
}
5050

51-
string sprintf(const string &format, ...) {
51+
string sprintf(const string format, ...) {
5252
va_list argp;
5353
va_start(argp, format);
5454
string str = fmt::_vsprintf(format.c_str(), argp);
@@ -64,7 +64,7 @@ string sprintf(const char *format, ...) {
6464
return str;
6565
}
6666

67-
error ___errorf(const string &format, ...) {
67+
error ___errorf(const string format, ...) {
6868
va_list argp;
6969
va_start(argp, format);
7070
error err = errors::New(fmt::_vsprintf(format.c_str(), argp));

golang/fmt.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef _NXD_LIBGOLANG_FMT_H
22
#define _NXD_LIBGOLANG_FMT_H
33

4-
// Copyright (C) 2019-2020 Nexedi SA and Contributors.
4+
// Copyright (C) 2019-2023 Nexedi SA and Contributors.
55
// Kirill Smelkov <[email protected]>
66
//
77
// This program is free software: you can Use, Study, Modify and Redistribute
@@ -40,7 +40,7 @@ namespace golang {
4040
namespace fmt {
4141

4242
// sprintf formats text into string.
43-
LIBGOLANG_API string sprintf(const string &format, ...);
43+
LIBGOLANG_API string sprintf(const string format, ...);
4444

4545

4646
// intseq<i1, i2, ...> and intrange<n> are used by errorf to handle %w.
@@ -75,7 +75,7 @@ namespace {
7575
//
7676
// format suffix ": %w" is additionally handled as in Go with
7777
// `errorf("... : %w", ..., err)` creating error that can be unwrapped back to err.
78-
LIBGOLANG_API error ___errorf(const string& format, ...);
78+
LIBGOLANG_API error ___errorf(const string format, ...);
7979
LIBGOLANG_API error ___errorfTryWrap(const string& format, error last_err, ...);
8080
LIBGOLANG_API string ___error_str(error err);
8181

@@ -111,7 +111,10 @@ inline error errorf(const string& format, Argv... argv) {
111111
// `const char *` overloads just to catch format mistakes as
112112
// __attribute__(format) does not work with std::string.
113113
LIBGOLANG_API string sprintf(const char *format, ...)
114-
__attribute__ ((format (printf, 1, 2)));
114+
#ifndef _MSC_VER
115+
__attribute__ ((format (printf, 1, 2)))
116+
#endif
117+
;
115118

116119
// cannot use __attribute__(format) for errorf as we add %w handling.
117120
// still `const char *` overload is useful for performance.

golang/golang_test.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1739,8 +1739,28 @@ def _pyrun(argv, stdin=None, stdout=None, stderr=None, **kw): # -> retcode, st
17391739
pathv.extend(envpath.split(os.pathsep))
17401740
env['PYTHONPATH'] = os.pathsep.join(pathv)
17411741

1742+
# set $PYTHONIOENCODING to encoding of stdin/stdout/stderr
1743+
# we need to do it because on Windows `python x.py | ...` runs with stdio
1744+
# encoding set to cp125X even if just `python x.py` runs with stdio
1745+
# encoding=UTF-8.
1746+
if 'PYTHONIOENCODING' not in env:
1747+
enc = set([_.encoding for _ in (sys.stdin, sys.stdout, sys.stderr)])
1748+
if None in enc: # without -s pytest uses _pytest.capture.DontReadFromInput
1749+
enc.remove(None) # with None .encoding
1750+
assert len(enc) == 1
1751+
env['PYTHONIOENCODING'] = enc.pop()
1752+
17421753
p = Popen(argv, stdin=(PIPE if stdin else None), stdout=stdout, stderr=stderr, env=env, **kw)
17431754
stdout, stderr = p.communicate(stdin)
1755+
1756+
# on windows print emits \r\n instead of just \n
1757+
# normalize that to \n in *out
1758+
if os.name == 'nt':
1759+
if stdout is not None:
1760+
stdout = stdout.replace(b'\r\n', b'\n')
1761+
if stderr is not None:
1762+
stderr = stderr.replace(b'\r\n', b'\n')
1763+
17441764
return p.returncode, stdout, stderr
17451765

17461766
# pyrun runs `sys.executable argv... <stdin`.
@@ -1807,6 +1827,13 @@ def assertDoc(want, got):
18071827
got = got.replace(dir_pygolang, "PYGOLANG") # /home/x/.../pygolang -> PYGOLANG
18081828
got = got.replace(udir_pygolang, "PYGOLANG") # ~/.../pygolang -> PYGOLANG
18091829

1830+
# got: normalize PYGOLANG\a\b\c -> PYGOLANG/a/b/c
1831+
# a\b\c\d.py -> a/b/c/d.py
1832+
def _(m):
1833+
return m.group(0).replace(os.path.sep, '/')
1834+
got = re.sub(r"(?<=PYGOLANG)[^\s]+(?=\s)", _, got)
1835+
got = re.sub(r"([\w\\\.]+)(?=\.py)", _, got)
1836+
18101837
# want: process conditionals
18111838
# PY39(...) -> ... if py ≥ 3.9 else ø (inline)
18121839
# `... +PY39` -> ... if py ≥ 3.9 else ø (whole line)
@@ -1862,8 +1889,10 @@ def f(x, y=3, z=4, *argv, **kw): pass
18621889

18631890

18641891
# readfile returns content of file @path.
1865-
def readfile(path):
1866-
with open(path, "r") as f:
1892+
def readfile(path): # -> bytes
1893+
# on windows in text mode files are opened with encoding=locale.getdefaultlocale()
1894+
# which is CP125X instead of UTF-8. -> manually decode as 'UTF-8'
1895+
with open(path, "rb") as f:
18671896
return f.read()
18681897

18691898
# abbrev_home returns path with user home prefix abbreviated with ~.

golang/libgolang.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,12 @@
176176
#include <sys/types.h>
177177
#include <sys/stat.h>
178178

179+
#include <fcntl.h>
180+
#ifdef _MSC_VER // no mode_t on msvc
181+
typedef int mode_t;
182+
#endif
183+
184+
179185
// DSO symbols visibility (based on https://gcc.gnu.org/wiki/Visibility)
180186
#if defined _WIN32 || defined __CYGWIN__
181187
#define LIBGOLANG_DSO_EXPORT __declspec(dllexport)
@@ -829,7 +835,7 @@ struct _interface {
829835

830836
protected:
831837
// don't use destructor -> use decref
832-
~_interface();
838+
LIBGOLANG_API ~_interface();
833839
};
834840
typedef refptr<_interface> interface;
835841

golang/os.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
// GLIBC < 2.32 provides sys_siglist but not sigdescr_np in its headers
3838
// cut this short
3939
// (on darwing sys_siglist declaration is normally provided)
40-
#ifndef __APPLE__
40+
// (on windows sys_siglist is not available at all)
41+
#if !(defined(__APPLE__) || defined(_WIN32))
4142
extern "C" {
4243
extern const char * const sys_siglist[];
4344
}
@@ -248,7 +249,7 @@ tuple<string, error> ReadFile(const string& path) {
248249

249250
tuple<File, File, error> Pipe() {
250251
int vfd[2], syserr;
251-
syserr = sys::Pipe(vfd);
252+
syserr = sys::Pipe(vfd, 0);
252253
if (syserr != 0)
253254
return make_tuple(nil, nil, fmt::errorf("pipe: %w", sys::NewErrno(syserr)));
254255

@@ -286,8 +287,20 @@ string Signal::String() const {
286287
const Signal& sig = *this;
287288
const char *sigstr = nil;
288289

290+
#ifdef _WIN32
291+
switch (sig.signo) {
292+
case SIGABRT: return "Aborted";
293+
case SIGBREAK: return "Break";
294+
case SIGFPE: return "Floating point exception";
295+
case SIGILL: return "Illegal instruction";
296+
case SIGINT: return "Interrupt";
297+
case SIGSEGV: return "Segmentation fault";
298+
case SIGTERM: return "Terminated";
299+
}
300+
#else
289301
if (0 <= sig.signo && sig.signo < NSIG)
290302
sigstr = ::sys_siglist[sig.signo]; // might be nil as well
303+
#endif
291304

292305
if (sigstr != nil)
293306
return string(sigstr);

golang/os.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef _NXD_LIBGOLANG_OS_H
22
#define _NXD_LIBGOLANG_OS_H
33
//
4-
// Copyright (C) 2019-2022 Nexedi SA and Contributors.
4+
// Copyright (C) 2019-2023 Nexedi SA and Contributors.
55
// Kirill Smelkov <[email protected]>
66
//
77
// This program is free software: you can Use, Study, Modify and Redistribute
@@ -61,7 +61,7 @@ class _File : public object {
6161
~_File();
6262
friend File _newFile(_libgolang_ioh* ioh, const string& name);
6363
public:
64-
void decref();
64+
LIBGOLANG_API void decref();
6565

6666
public:
6767
LIBGOLANG_API string Name() const;
@@ -95,9 +95,15 @@ class _File : public object {
9595

9696
// Open opens file @path.
9797
LIBGOLANG_API std::tuple<File, error> Open(const string &path, int flags = O_RDONLY,
98-
mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR |
98+
mode_t mode =
99+
#if !defined(_MSC_VER)
100+
S_IRUSR | S_IWUSR | S_IXUSR |
99101
S_IRGRP | S_IWGRP | S_IXGRP |
100-
S_IROTH | S_IWOTH | S_IXOTH);
102+
S_IROTH | S_IWOTH | S_IXOTH
103+
#else
104+
_S_IREAD | _S_IWRITE
105+
#endif
106+
);
101107

102108
// NewFile wraps OS-level file-descriptor into File.
103109
// The ownership of sysfd is transferred to File.

0 commit comments

Comments
 (0)