I want to make a Python Package for win_amd64
(Windows x64) of cpp files. I have used Swig to wrap them into python and then used setuptools to build it. I have made CMakeLists.txt files to do all this actions. Note: I am using x86_64-w64-mingw32 cross-compiler to build this in linux machine
Tools Used & its Version:
Note: I can build the python pkg for linux-x86_64 (linux 64) for all of Python3.6 and above, but for windows I can only build for Python3.6 (By using the library libpython36.a) but with later version for win_amd64 I had to use the libpython39.lib (Lib based libraries)
What happens now:
I can build the whl file for win_amd64 successfully. CMake can make the .dll and setuptools wrapped it well
On installing this on windows Python3.9 x64, it installs without any warning
But when I try to import the main module, it throws
import sample # name of the module
# Error below
Traceback:
from . import _sample_swig
ImportError: DLL load failed: The specified module could not be found.ImportError: DLL load failed: The specified module could not be found.`
Project Setup:
Swig File
FIND_PACKAGE(SWIG REQUIRED)
INCLUDE(${SWIG_USE_FILE})
CMAKE_MINIMUM_REQUIRED(VERSION 3.16)
SET(PYTHON_MODULE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/sample)
set(PYTHON_EXECUTABLE python${PYTHON_BUILD_VERSION})
if (${BUILD_PLATFORM} MATCHES "Windows")
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_C_COMPILER /usr/bin/x86_64-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER /usr/bin/x86_64-w64-mingw32-g++)
set(PYTHON_LIBRARY /home/developer/workspace/69/py39/libs/python.lib)
set(PYTHON_INCLUDE_DIR /home/developer/workspace/69/py39/include)
set(TARGET_EXTENSION "pyd")
set(CMAKE_FIND_ROOT_PATH /opt/win_cross_compile_libs)
ELSE()
set(CMAKE_C_COMPILER /usr/bin/gcc)
set(CMAKE_CXX_COMPILER /usr/bin/g++)
set(TARGET_EXTENSION "so")
set(PythonLibs_DIR /usr/lib/x86_64-linux-gnu/)
set(CMAKE_FIND_ROOT_PATH /usr/lib/x86_64-linux-gnu/)
ENDIF()
project(sample LANGUAGES CXX)
set(CMAKE_LANGUAGE_COMPILER ${CMAKE_CXX_COMPILER})
FIND_PACKAGE(Python3 COMPONENTS Interpreter Development)
FIND_PACKAGE(PythonLibs)
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/include)
message(STATUS "Py Libs: ${PYTHON_LIBRARIES}")
message(STATUS "Add. Linking Flags: ${ADD_LINK_FLAGS}")
message(STATUS "Python Incl Dir: ${PYTHON_INCLUDE_DIR}")
message(STATUS "Python Module: ${PYTHON_MODULE_DIR}")
message(STATUS "Machine: ${CMAKE_SYSTEM_NAME}")
set(PythonLibs_DIR "/usr/lib/x86_64-linux-gnu/")
set_property(SOURCE include/sample.i PROPERTY CPLUSPLUS ON)
file(GLOB SRC_FILES ${PROJECT_SOURCE_DIR}/src/*.cpp)
swig_add_library(sample_swig TYPE SHARED
LANGUAGE python
OUTPUT_DIR ${PYTHON_MODULE_DIR}
OUTFILE_DIR src
SOURCES include/sample.i ${SRC_FILES}
)
SWIG_LINK_LIBRARIES(sample_swig ${PYTHON_LIBRARIES})
add_custom_command(
TARGET _sample_swig POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
_sample_swig.${TARGET_EXTENSION}
${PYTHON_MODULE_DIR}/_sample_swig.${TARGET_EXTENSION}
)
INSTALL(TARGETS _sample_swig LIBRARY DESTINATION sample)
Interface file used for swig:
%module arithmetic_operator
%{
#include "addition.h"
%}
%include "addition.h"
%include "stdint.i"`
Header file:
# include <iostream>
using namespace std;
int addition_fn(int a, int b)
{
return (a+b);`
}
CPP File:
# include <iostream>
using namespace std;
const int MAX_ADDABLE = 50;
int main()
{
cout<<"Hello World\n";
}
Setup.py:
from skbuild import setup
setup(
name='sample',
version='0.1.0',
description='Sample',
cmake_with_sdist=True,
packages=['sample'],
python_requires=">=3.6",
include_package_data=True,
zip_safe=False
)
Using os.add_dll_directory(<dll folder location (site-packages/sample)>)
as the Python3.8 and above only loads from trusted sources even though overwritten by PYTHONPATH - Doesn't work
Wasn't able to figure it out for a month.
I finally fixed this by moving my x86_64-w64-mingw32-g++ which was on 9.0.x on Ubuntu 20.04 to compiler x86_64-w64-mingw32-g++-posix with GCC version 10-posix 20220113 (GCC) on Ubuntu-22.04
Seems like the latest GCC will seemingly handle Windows Python 3.8+ DLL based handles when using Shared Libraries