Skip to content

Commit 2ce4932

Browse files
committed
fix multiple issues around building C extension modules on windows
1 parent 65a561d commit 2ce4932

File tree

9 files changed

+107
-17
lines changed

9 files changed

+107
-17
lines changed

graalpython/com.oracle.graal.python.cext/include/Python.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
#include <stdlib.h>
4343
#ifndef MS_WINDOWS
4444
#include <unistd.h>
45+
#else
46+
#include <winsock.h>
4547
#endif
4648

4749
/* For size_t? */

graalpython/com.oracle.graal.python.cext/include/pyconfig.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@
4343

4444
#define GRAALVM_PYTHON 1
4545

46+
// The graalpy build always sets MS_WINDOWS, so when this is not set, we are
47+
// dealing with an extension build. In that case, if we're on Windows, we need
48+
// to set the appropriate flags to link against our python C API dll.
49+
#if !defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) && !defined(MS_WINDOWS)
50+
# ifdef _MSC_VER
51+
# define MS_WINDOWS
52+
# define Py_ENABLE_SHARED
53+
# define HAVE_DECLSPEC_DLL
54+
# pragma comment(lib, "python-native.lib")
55+
# endif
56+
#endif
57+
4658
/* If Cython is involved, avoid accesses to internal structures. While we are
4759
* supporting this in many cases, it still involves overhead. */
4860
#define CYTHON_USE_TYPE_SLOTS 0

graalpython/com.oracle.graal.python.cext/src/capi.c

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@
4141
#include "capi.h"
4242
#include <stdio.h>
4343
#include <time.h>
44+
#ifdef MS_WINDOWS
45+
#include "libloaderapi.h"
46+
#include "pathcch.h"
47+
#pragma comment(lib, "Pathcch.lib")
48+
#endif
4449

4550
#define ASSERTIONS
4651

@@ -708,15 +713,15 @@ PyAPI_FUNC(Py_ssize_t) PyTruffle_ADDREF(intptr_t ptr, Py_ssize_t value) {
708713
#ifdef ASSERTIONS
709714
if (obj->ob_refcnt & 0xFFFFFFFF00000000L) {
710715
char buf[1024];
711-
sprintf(buf, "suspicious refcnt value during managed adjustment for %p (%li %p + %li)\n", obj, obj->ob_refcnt, (void*) obj->ob_refcnt, value);
716+
sprintf(buf, "suspicious refcnt value during managed adjustment for %p (%lli %p + %lli)\n", obj, obj->ob_refcnt, (void*) obj->ob_refcnt, value);
712717
Py_FatalError(buf);
713718
}
714719
if ((obj->ob_refcnt + value) <= 0) {
715720
char buf[1024];
716-
sprintf(buf, "refcnt reached zero during managed adjustment for %p (%li %p + %li)\n", obj, obj->ob_refcnt, (void*) obj->ob_refcnt, value);
721+
sprintf(buf, "refcnt reached zero during managed adjustment for %p (%lli %p + %lli)\n", obj, obj->ob_refcnt, (void*) obj->ob_refcnt, value);
717722
Py_FatalError(buf);
718723
}
719-
// printf("refcnt value during managed adjustment for %p (%li %p + %li)\n", obj, obj->ob_refcnt, (void*) obj->ob_refcnt, value);
724+
// printf("refcnt value during managed adjustment for %p (%lli %p + %lli)\n", obj, obj->ob_refcnt, (void*) obj->ob_refcnt, value);
720725
#endif // ASSERTIONS
721726

722727
return (obj->ob_refcnt += value);
@@ -728,15 +733,15 @@ PyAPI_FUNC(Py_ssize_t) PyTruffle_SUBREF(intptr_t ptr, Py_ssize_t value) {
728733
#ifdef ASSERTIONS
729734
if (obj->ob_refcnt & 0xFFFFFFFF00000000L) {
730735
char buf[1024];
731-
sprintf(buf, "suspicious refcnt value during managed adjustment for %p (%li %p - %li)\n", obj, obj->ob_refcnt, (void*) obj->ob_refcnt, value);
736+
sprintf(buf, "suspicious refcnt value during managed adjustment for %p (%lli %p - %lli)\n", obj, obj->ob_refcnt, (void*) obj->ob_refcnt, value);
732737
Py_FatalError(buf);
733738
}
734739
if ((obj->ob_refcnt - value) < 0) {
735740
char buf[1024];
736-
sprintf(buf, "refcnt below zero during managed adjustment for %p (%li %p - %li)\n", obj, obj->ob_refcnt, (void*) obj->ob_refcnt, value);
741+
sprintf(buf, "refcnt below zero during managed adjustment for %p (%lli %p - %lli)\n", obj, obj->ob_refcnt, (void*) obj->ob_refcnt, value);
737742
Py_FatalError(buf);
738743
}
739-
// printf("refcnt value during managed adjustment for %p (%li %p - %li)\n", obj, obj->ob_refcnt, (void*) obj->ob_refcnt, value);
744+
// printf("refcnt value during managed adjustment for %p (%lli %p - %lli)\n", obj, obj->ob_refcnt, (void*) obj->ob_refcnt, value);
740745
#endif // ASSERTIONS
741746

742747
Py_ssize_t new_value = ((obj->ob_refcnt) -= value);
@@ -1448,6 +1453,63 @@ PyAPI_FUNC(void) initialize_graal_capi(ptr_cache_t _pythonToNative, void_ptr_cac
14481453
initialize_hashes();
14491454
initialize_bufferprocs();
14501455

1456+
#ifdef MS_WINDOWS
1457+
// when initializing the C API, the appropriate libraries (like
1458+
// python-native.dll or graalvm-llvm.dll) are loaded with their full paths.
1459+
// However, they are not automatically on the search path when any
1460+
// extension modules are loaded later, and Windows wants to resolve them
1461+
// again. So we get their runtime paths here and add those to the dll
1462+
// search path.
1463+
LPSTR lpMsgBuf;
1464+
wchar_t path[MAX_PATH];
1465+
char pathA[MAX_PATH];
1466+
HMODULE hm = NULL;
1467+
if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
1468+
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
1469+
(LPCWSTR) &initialize_graal_capi, &hm) == 0) {
1470+
int ret = GetLastError();
1471+
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
1472+
NULL, ret, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &lpMsgBuf, 0, NULL);
1473+
PyTruffle_Log(PY_TRUFFLE_LOG_FINE, "finding python-native.dll handle failed, error = %s\n", lpMsgBuf);
1474+
LocalFree(lpMsgBuf);
1475+
} else {
1476+
if (GetModuleFileNameW(hm, (LPWSTR)path, sizeof(path)) == 0) {
1477+
int ret = GetLastError();
1478+
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
1479+
NULL, ret, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &lpMsgBuf, 0, NULL);
1480+
PyTruffle_Log(PY_TRUFFLE_LOG_FINE, "finding python-native.dll path failed, error = %s\n", lpMsgBuf);
1481+
LocalFree(lpMsgBuf);
1482+
} else {
1483+
wcstombs(pathA, path, sizeof(pathA));
1484+
PyTruffle_Log(PY_TRUFFLE_LOG_FINE, "Adding python-native.dll path '%s' to search path.\n", pathA);
1485+
PathCchRemoveFileSpec((PWSTR)path, sizeof(path));
1486+
AddDllDirectory((LPWSTR)path);
1487+
}
1488+
}
1489+
if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
1490+
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
1491+
(LPCWSTR) &polyglot_from_string, &hm) == 0) {
1492+
int ret = GetLastError();
1493+
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
1494+
NULL, ret, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &lpMsgBuf, 0, NULL);
1495+
PyTruffle_Log(PY_TRUFFLE_LOG_FINE, "finding graalvm-llvm.dll handle failed, error = %s\n", lpMsgBuf);
1496+
LocalFree(lpMsgBuf);
1497+
} else {
1498+
if (GetModuleFileNameW(hm, (LPWSTR)path, sizeof(path)) == 0) {
1499+
int ret = GetLastError();
1500+
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
1501+
NULL, ret, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &lpMsgBuf, 0, NULL);
1502+
PyTruffle_Log(PY_TRUFFLE_LOG_FINE, "finding graalvm-llvm.dll path failed, error = %s\n", lpMsgBuf);
1503+
LocalFree(lpMsgBuf);
1504+
} else {
1505+
wcstombs(pathA, path, sizeof(pathA));
1506+
PyTruffle_Log(PY_TRUFFLE_LOG_FINE, "Adding graalvm-llvm.dll path '%s' to search path.\n", pathA);
1507+
PathCchRemoveFileSpec((LPWSTR)path, sizeof(path));
1508+
AddDllDirectory((LPWSTR)path);
1509+
}
1510+
}
1511+
#endif
1512+
14511513
// TODO: initialize during cext initialization doesn't work at the moment
14521514
// This is hardcoded the same way in capi_native.c
14531515
Py_FileSystemDefaultEncoding = "utf-8"; // strdup(PyUnicode_AsUTF8(GraalPyTruffle_FileSystemDefaultEncoding()));

graalpython/com.oracle.graal.python.cext/src/capi.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -944,7 +944,7 @@ PyAPI_DATA(ptr_cache_t) ptr_cache;
944944
PyAPI_DATA(cache_query_t) points_to_py_handle_space;
945945
PyAPI_FUNC(void) initialize_type_structure(PyTypeObject* structure, PyTypeObject* ptype, polyglot_typeid tid);
946946

947-
void register_native_slots(PyTypeObject* managed_class, PyGetSetDef* getsets, PyMemberDef* members);
947+
PyAPI_FUNC(void) register_native_slots(PyTypeObject* managed_class, PyGetSetDef* getsets, PyMemberDef* members);
948948

949949
extern ptr_cache_t pythonToNative;
950950
extern void_ptr_cache_t javaStringToTruffleString;

graalpython/com.oracle.graal.python.cext/src/modsupport_shared.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242

4343
#include <stdio.h>
4444

45+
// export the more functions, because we use them dynamically in contrast to cpython on windows
46+
PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...);
4547

4648
#define FLAG_SIZE_T 1
4749
typedef double va_double;

graalpython/lib-graalpython/_sysconfig.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,14 @@ def _get_posix_vars():
6363
toolchain_cxx = get_toolchain('CXX')
6464
have_cxx = toolchain_cxx is not None
6565

66-
python_inc = os.path.join(
67-
os.path.normpath(sys.base_prefix),
68-
'include',
69-
f'python{sys.version_info[0]}.{sys.version_info[1]}{sys.abiflags}'
70-
)
66+
if win32_native:
67+
python_inc = os.path.join(os.path.normpath(sys.base_prefix), 'Include')
68+
else:
69+
python_inc = os.path.join(
70+
os.path.normpath(sys.base_prefix),
71+
'include',
72+
f'python{sys.version_info[0]}.{sys.version_info[1]}{sys.abiflags}'
73+
)
7174

7275
fpic = "" if win32_native else "-fPIC"
7376

@@ -110,7 +113,7 @@ def _get_posix_vars():
110113
g['RANLIB'] = get_toolchain('RANLIB')
111114
g['ARFLAGS'] = "rc"
112115
g['LD'] = get_toolchain('LD')
113-
g['EXE'] = ""
116+
g['EXE'] = ".exe" if win32_native else ""
114117
g['LIBDIR'] = os.path.join(sys.prefix, 'lib')
115118
g['VERSION'] = ".".join(sys.version.split(".")[:2])
116119
g['Py_HASH_ALGORITHM'] = 0 # does not give any specific info about the hashing algorithm
@@ -120,6 +123,7 @@ def _get_posix_vars():
120123
g['Py_DEBUG'] = 0
121124
g['Py_ENABLE_SHARED'] = 0
122125
g['LIBDIR'] = __graalpython__.capi_home
126+
g['LIBDEST'] = __graalpython__.capi_home
123127
g['LDLIBRARY'] = 'libpython.' + so_abi + so_ext
124128
g['WITH_THREAD'] = 1
125129
return g

graalpython/lib-python/3/distutils/ccompiler.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -930,8 +930,7 @@ def mkpath (self, name, mode=0o777):
930930

931931
# OS name mappings
932932
('posix', 'unix'),
933-
# Truffle change ('nt', 'msvc'),
934-
('nt', 'unix'),
933+
('nt', 'msvc'),
935934
)
936935

937936
def get_default_compiler(osname=None, platform=None):

graalpython/lib-python/3/distutils/command/build_ext.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,7 @@ def get_libraries(self, ext):
712712
# pyconfig.h that MSVC groks. The other Windows compilers all seem
713713
# to need it mentioned explicitly, though, so that's what we do.
714714
# Append '_d' to the python import library on debug builds.
715-
if sys.platform == "win32" and False: # Truffle change: never go this path
715+
if sys.platform == "win32":
716716
from distutils._msvccompiler import MSVCCompiler
717717
if not isinstance(self.compiler, MSVCCompiler):
718718
template = "python%d%d"

mx.graalpython/suite.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,7 @@
555555
},
556556
"results" : [
557557
"bin/<lib:python-native>",
558+
"bin/python-native.lib",
558559
"bin/modules/_mmap<graalpy_ext:native>",
559560
"bin/modules/_cpython_sre<graalpy_ext:native>",
560561
"bin/modules/_cpython_unicodedata<graalpy_ext:native>",
@@ -978,9 +979,17 @@
978979
"./Lib/": [
979980
"extracted-dependency:graalpython:GRAALPYTHON_PYTHON_LIB",
980981
],
982+
"./libs/": [
983+
"extracted-dependency:GRAALPYTHON_NATIVE_LIBS/python-native.lib",
984+
],
981985
"./lib-graalpython/": [
982986
"file:graalpython/lib-graalpython/*",
983-
"extracted-dependency:GRAALPYTHON_NATIVE_LIBS/*",
987+
{
988+
"source_type": "extracted-dependency",
989+
"dependency": "GRAALPYTHON_NATIVE_LIBS",
990+
"path": "*",
991+
"exclude": ["python-native.lib"],
992+
},
984993
"file:graalpython/com.oracle.graal.python.cext/CEXT-WINDOWS-README.md",
985994
],
986995
"./lib-graalpython/modules/graalpy_virtualenv": [

0 commit comments

Comments
 (0)