Skip to content

Commit 4d67638

Browse files
committed
Add base for python.exe support in python loader and port.
1 parent 5a4adc5 commit 4d67638

File tree

14 files changed

+220
-776
lines changed

14 files changed

+220
-776
lines changed

source/configuration/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ function(configurations_write config_dir config_path)
191191
set(CONFIGURATION_GLOBAL "${CONFIGURATION_GLOBAL}\n\t\"node_loader\":\"${config_dir}/node_loader.json\",")
192192
endif()
193193

194+
if(OPTION_BUILD_LOADERS_PY)
195+
set(CONFIGURATION_GLOBAL "${CONFIGURATION_GLOBAL}\n\t\"py_loader\":\"${config_dir}/py_loader.json\",")
196+
endif()
197+
194198
#if(OPTION_BUILD_LOADERS_JS)
195199
# set(CONFIGURATION_GLOBAL "${CONFIGURATION_GLOBAL}\n\t\"js_loader\":\"${config_dir}/js_loader.json\",")
196200
#endif()

source/loaders/py_loader/CMakeLists.txt

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,22 @@ if(PROJECT_OS_FAMILY STREQUAL win32 AND Python3_LIBRARIES AND Python3_ROOT_DIR A
3333
# Get the library name
3434
get_filename_component(LIB_NAME "${LIB_PATH}" NAME)
3535
# Find the library in the Python3 root path
36-
find_file(Python3_LIBRARY_NAME ${LIB_NAME}
36+
find_file(Python3_LIBRARY_NAME_PATH ${LIB_NAME}
3737
PATHS ${Python3_ROOT_DIR}
3838
NO_DEFAULT_PATH
3939
)
40-
if(Python3_LIBRARY_NAME)
40+
if(Python3_LIBRARY_NAME_PATH)
4141
break()
4242
endif()
4343
endif()
4444
endforeach()
4545
endif()
4646

47-
if(Python3_LIBRARY_NAME)
47+
if(Python3_LIBRARY_NAME_PATH)
4848
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_OUTPUT_DIR})
49-
file(COPY "${Python3_LIBRARY_NAME}" DESTINATION ${PROJECT_OUTPUT_DIR})
49+
file(COPY "${Python3_LIBRARY_NAME_PATH}" DESTINATION ${PROJECT_OUTPUT_DIR})
50+
else()
51+
set(Python3_LIBRARY_NAME_PATH "${Python3_LIBRARIES}")
5052
endif()
5153

5254
#
@@ -169,7 +171,10 @@ target_include_directories(${target}
169171
target_link_libraries(${target}
170172
PRIVATE
171173
${META_PROJECT_NAME}::metacall # MetaCall library
172-
${Python3_LIBRARIES} # Python libraries
174+
175+
# Delay load for MSVC
176+
$<$<CXX_COMPILER_ID:MSVC>:${Python3_LIBRARIES}> # Python library
177+
$<$<CXX_COMPILER_ID:MSVC>:delayimp>
173178

174179
PUBLIC
175180
${DEFAULT_LIBRARIES}
@@ -183,7 +188,6 @@ target_link_libraries(${target}
183188

184189
target_compile_definitions(${target}
185190
PRIVATE
186-
PY_LOADER_PORT_NAME=$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:lib>py_loader$<$<CONFIG:DEBUG>:d>
187191

188192
PUBLIC
189193
$<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:${target_upper}_STATIC_DEFINE>
@@ -209,8 +213,12 @@ target_compile_options(${target}
209213
# Linker options
210214
#
211215

216+
get_filename_component(Python3_LIBRARY_NAME "${Python3_LIBRARY_NAME_PATH}" NAME)
217+
212218
target_link_options(${target}
213219
PRIVATE
220+
$<$<AND:$<BOOL:${APPLE}>,$<CXX_COMPILER_ID:AppleClang,Clang>>:-Wl,-undefined,dynamic_lookup>
221+
$<$<CXX_COMPILER_ID:MSVC>:/DELAYLOAD:${Python3_LIBRARY_NAME}>
214222

215223
PUBLIC
216224
${DEFAULT_LINKER_OPTIONS}
@@ -233,10 +241,30 @@ install(TARGETS ${target}
233241
# Runtime (pack Python DLL in windows)
234242
# TODO: https://cmake.org/cmake/help/latest/command/file.html#get-runtime-dependencies
235243
# TODO: https://gist.github.com/micahsnyder/5d98ac8548b429309ec5a35bca9366da
236-
if(Python3_LIBRARY_NAME)
244+
set(Python3_LIBRARY_DEVELOPMENT "${Python3_LIBRARY_NAME_PATH}")
245+
246+
if(Python3_LIBRARY_NAME_PATH AND PROJECT_OS_FAMILY STREQUAL win32)
237247
install(FILES
238-
"${Python3_LIBRARY_NAME}"
248+
"${Python3_LIBRARY_NAME_PATH}"
239249
DESTINATION ${INSTALL_LIB}
240250
COMPONENT runtime
241251
)
252+
253+
set(Python3_LIBRARY_INSTALL "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB}/${Python3_LIBRARY_NAME}")
254+
else()
255+
set(Python3_LIBRARY_INSTALL "${Python3_LIBRARY_NAME_PATH}")
242256
endif()
257+
258+
#
259+
# Configuration
260+
#
261+
262+
# Development
263+
loader_configuration_begin(py_loader)
264+
loader_configuration_deps(python "${Python3_LIBRARY_DEVELOPMENT}")
265+
loader_configuartion_end_development()
266+
267+
# Install
268+
loader_configuration_begin(py_loader)
269+
loader_configuration_deps(python "${Python3_LIBRARY_INSTALL}")
270+
loader_configuartion_end_install()

source/loaders/py_loader/include/py_loader/py_loader_port.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,7 @@
2727
extern "C" {
2828
#endif
2929

30-
#define PY_LOADER_PORT_NAME_FUNC_IMPL_EXPAND(x) PyInit_##x
31-
#define PY_LOADER_PORT_NAME_FUNC_IMPL(x) PY_LOADER_PORT_NAME_FUNC_IMPL_EXPAND(x)
32-
#define PY_LOADER_PORT_NAME_FUNC PY_LOADER_PORT_NAME_FUNC_IMPL(PY_LOADER_PORT_NAME)
33-
34-
PyMODINIT_FUNC PY_LOADER_PORT_NAME_FUNC(void);
30+
int py_port_initialize(void);
3531

3632
#ifdef __cplusplus
3733
}

source/loaders/py_loader/source/py_loader_impl.c

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ static void py_loader_impl_value_invoke_state_finalize(value v, void *data);
192192

193193
static void py_loader_impl_value_ptr_finalize(value v, void *data);
194194

195-
static int py_loader_impl_finalize(loader_impl_py py_impl);
195+
static int py_loader_impl_finalize(loader_impl impl, loader_impl_py py_impl);
196196

197197
static PyObject *py_loader_impl_load_from_memory_compile(loader_impl_py py_impl, const loader_name name, const char *buffer);
198198

@@ -2620,19 +2620,22 @@ loader_impl_data py_loader_impl_initialize(loader_impl impl, configuration confi
26202620
goto error_alloc_py_impl;
26212621
}
26222622

2623-
Py_InitializeEx(0);
2624-
2625-
if (Py_IsInitialized() == 0)
2623+
if (loader_impl_get_option_host(impl) == 0)
26262624
{
2627-
goto error_init_py;
2628-
}
2625+
Py_InitializeEx(0);
2626+
2627+
if (Py_IsInitialized() == 0)
2628+
{
2629+
goto error_init_py;
2630+
}
26292631

26302632
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION <= 6
2631-
if (PyEval_ThreadsInitialized() == 0)
2632-
{
2633-
PyEval_InitThreads();
2634-
}
2633+
if (PyEval_ThreadsInitialized() == 0)
2634+
{
2635+
PyEval_InitThreads();
2636+
}
26352637
#endif
2638+
}
26362639

26372640
/* Hook the deallocation of PyCFunction */
26382641
py_loader_impl_pycfunction_dealloc = PyCFunction_Type.tp_dealloc;
@@ -2695,7 +2698,7 @@ loader_impl_data py_loader_impl_initialize(loader_impl impl, configuration confi
26952698
goto error_after_inspect;
26962699
}
26972700

2698-
if (PY_LOADER_PORT_NAME_FUNC() == NULL)
2701+
if (py_port_initialize() != 0)
26992702
{
27002703
goto error_after_import;
27012704
}
@@ -2759,7 +2762,7 @@ loader_impl_data py_loader_impl_initialize(loader_impl impl, configuration confi
27592762
#endif
27602763
error_after_argv:
27612764
error_after_sys_executable:
2762-
(void)py_loader_impl_finalize(py_impl);
2765+
(void)py_loader_impl_finalize(impl, py_impl);
27632766
error_init_py:
27642767
free(py_impl);
27652768
error_alloc_py_impl:
@@ -4140,7 +4143,7 @@ void py_loader_impl_sys_path_print(PyObject *sys_path_list)
41404143
}
41414144
#endif
41424145

4143-
int py_loader_impl_finalize(loader_impl_py py_impl)
4146+
int py_loader_impl_finalize(loader_impl impl, loader_impl_py py_impl)
41444147
{
41454148
if (Py_IsInitialized() != 0)
41464149
{
@@ -4149,19 +4152,18 @@ int py_loader_impl_finalize(loader_impl_py py_impl)
41494152
py_loader_impl_error_print(py_impl);
41504153
}
41514154

4152-
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 6
4155+
if (loader_impl_get_option_host(impl) == 0)
41534156
{
4157+
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 6
41544158
if (Py_FinalizeEx() != 0)
41554159
{
41564160
log_write("metacall", LOG_LEVEL_DEBUG, "Error when executing Py_FinalizeEx");
41574161
return 1;
41584162
}
4159-
}
41604163
#else
4161-
{
41624164
Py_Finalize();
4163-
}
41644165
#endif
4166+
}
41654167
}
41664168

41674169
return 0;
@@ -4225,7 +4227,7 @@ int py_loader_impl_destroy(loader_impl impl)
42254227
}
42264228
#endif
42274229

4228-
int result = py_loader_impl_finalize(py_impl);
4230+
int result = py_loader_impl_finalize(impl, py_impl);
42294231

42304232
/* Unhook the deallocation of PyCFunction */
42314233
PyCFunction_Type.tp_dealloc = py_loader_impl_pycfunction_dealloc;

source/loaders/py_loader/source/py_loader_port.c

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@
2727

2828
#include <loader/loader.h>
2929

30-
#ifndef PY_LOADER_PORT_NAME
31-
#error "The Python Loader Port must be defined"
32-
#endif
33-
3430
static const loader_tag py_loader_tag = "py";
3531

3632
static PyObject *py_loader_port_none(void)
@@ -955,26 +951,33 @@ static PyMethodDef metacall_methods[] = {
955951
{ NULL, NULL, 0, NULL }
956952
};
957953

958-
static struct PyModuleDef metacall_definition = {
959-
PyModuleDef_HEAD_INIT,
960-
"metacall",
961-
"A library for providing inter-language foreign function interface calls.",
962-
-1,
963-
metacall_methods,
964-
NULL,
965-
NULL,
966-
NULL,
967-
NULL
968-
};
969-
970-
PyMODINIT_FUNC PY_LOADER_PORT_NAME_FUNC(void)
954+
int py_port_initialize(void)
971955
{
972-
static PyObject *module = NULL;
956+
static struct PyModuleDef metacall_definition = {
957+
PyModuleDef_HEAD_INIT,
958+
"py_port_impl_module",
959+
"A library for providing inter-language foreign function interface calls.",
960+
-1,
961+
metacall_methods,
962+
NULL,
963+
NULL,
964+
NULL,
965+
NULL
966+
};
967+
968+
PyObject *module = PyModule_Create(&metacall_definition);
973969

974970
if (module == NULL)
975971
{
976-
module = PyModule_Create(&metacall_definition);
972+
return 1;
973+
}
974+
975+
PyObject *sys_modules = PyImport_GetModuleDict();
976+
977+
if (PyDict_SetItemString(sys_modules, metacall_definition.m_name, module) < 0)
978+
{
979+
return 1;
977980
}
978981

979-
return module;
982+
return 0;
980983
}

0 commit comments

Comments
 (0)