Skip to content

Commit 0b4de27

Browse files
committed
Support building with MSVC
Fixes #7 ### Motivation The Python client cannot be built with MSVC. ### Modifications Add `vcpkg.json` to download the Boost.Python dependency. Then fix some CMake errors: 1. Boost.Python cannot be found on Windows. The component of Boost cannot be `python3`. It should be a specific version like `python310`. 2. Link to `pulsarWithDeps.lib` for MSVC and modify the compilation option from `/MD` to `/MT` when `LINK_STATIC` is `ON`. 3. When `LINK_STATIC` is `OFF` (by default), remove the suffix of the name because CMake will find the correct suffixes on different platforms. 4. Add the Python3 library to the target on Windows, otherwise the symbols cannot be found. Since Python on Windows can only recognize `*.pyd` suffix of a C extension, change the `CMAKE_SHARED_LIBRARY_SUFFIX` and use `_pulsar.pyd` in `setup.py` on Windows. Add README to tell users how to build Python client on Windows. ### TODO Add a GitHub Actions workflow to verify the Windows build.
1 parent 3e37e44 commit 0b4de27

File tree

6 files changed

+107
-14
lines changed

6 files changed

+107
-14
lines changed

.github/workflows/ci-pr-validation.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ jobs:
6767

6868
linux-wheel:
6969
name: Wheel ${{matrix.image.name}} - Py ${{matrix.python.version}} - ${{matrix.cpu.platform}}
70+
needs: unit-tests
7071
runs-on: ubuntu-22.04
7172
timeout-minutes: 300
7273

@@ -118,6 +119,7 @@ jobs:
118119
119120
mac-wheels:
120121
name: Wheel MacOS Universal2 - Py ${{matrix.py.version}}
122+
needs: unit-tests
121123
runs-on: macos-12
122124
timeout-minutes: 300
123125

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,7 @@ __pycache__
1313
.pulsar-mac-wheels-cache
1414
.DS_Store
1515
wheelhouse
16-
.pulsar-mac-build
16+
.pulsar-mac-build
17+
vcpkg_installed/
18+
*.pyd
19+
*.lib

CMakeLists.txt

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ project (pulsar-client-python)
2121
cmake_minimum_required(VERSION 3.18)
2222
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules")
2323

24+
if (VCPKG_TRIPLET)
25+
message(STATUS "Use vcpkg, triplet is ${VCPKG_TRIPLET}")
26+
set(CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/vcpkg_installed/${VCPKG_TRIPLET}" ${CMAKE_PREFIX_PATH})
27+
message(STATUS "Use CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}")
28+
endif ()
2429
option(LINK_STATIC "Link against static libraries" OFF)
2530
MESSAGE(STATUS "LINK_STATIC: " ${LINK_STATIC})
2631

@@ -29,10 +34,22 @@ set(THREADS_PREFER_PTHREAD_FLAG TRUE)
2934
find_package(Threads REQUIRED)
3035
MESSAGE(STATUS "Threads library: " ${CMAKE_THREAD_LIBS_INIT})
3136

37+
if (MSVC)
38+
add_compile_options(/wd4819)
39+
endif ()
40+
3241
if (LINK_STATIC)
33-
find_library(PULSAR_LIBRARY NAMES libpulsar.a)
42+
if (MSVC)
43+
find_library(PULSAR_LIBRARY NAMES pulsarWithDeps.lib)
44+
string(REGEX REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
45+
string(REGEX REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})
46+
string(REGEX REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO})
47+
else ()
48+
find_library(PULSAR_LIBRARY NAMES libpulsar.a)
49+
endif ()
50+
add_definitions("-DPULSAR_STATIC")
3451
else()
35-
find_library(PULSAR_LIBRARY NAMES libpulsar.so libpulsar.dylib)
52+
find_library(PULSAR_LIBRARY NAMES pulsar libpulsar)
3653
endif()
3754
message(STATUS "PULSAR_LIBRARY: ${PULSAR_LIBRARY}")
3855

@@ -44,10 +61,29 @@ SET(CMAKE_CXX_STANDARD 11)
4461
find_package (Python3 REQUIRED COMPONENTS Development.Module)
4562
MESSAGE(STATUS "PYTHON: " ${Python3_VERSION} " - " ${Python3_INCLUDE_DIRS})
4663

64+
find_package(Boost REQUIRED ${Boost_INCLUDE_DIRS})
65+
message(STATUS "Boost_INCLUDE_DIRS: ${Boost_INCLUDE_DIRS}")
66+
4767
SET(Boost_USE_STATIC_LIBS ${LINK_STATIC})
48-
find_package(Boost REQUIRED COMPONENTS python3)
49-
MESSAGE(STATUS "Boost Python3: " ${Boost_PYTHON3_LIBRARY})
50-
MESSAGE(STATUS "Boost_INCLUDE_DIRS: ${Boost_INCLUDE_DIRS}")
68+
69+
set(BOOST_PYTHON_NAME_LIST python3 python310 python39 python38 python37)
70+
foreach (BOOST_PYTHON_NAME IN LISTS BOOST_PYTHON_NAME_LIST)
71+
find_package(Boost QUIET COMPONENTS ${BOOST_PYTHON_NAME})
72+
if (${Boost_FOUND})
73+
set(BOOST_PYTHON_NAME_FOUND ${BOOST_PYTHON_NAME})
74+
message(STATUS "Found Boost COMPONENTS " ${BOOST_PYTHON_NAME_FOUND})
75+
break ()
76+
endif ()
77+
endforeach ()
78+
if (NOT BOOST_PYTHON_NAME_FOUND)
79+
message(FATAL_ERROR "Could not find Boost Python library")
80+
endif ()
81+
find_package(Boost REQUIRED COMPONENTS ${BOOST_PYTHON_NAME_FOUND})
82+
set(Boost_PYTHON3_LIBRARIES
83+
${Boost_PYTHON3_LIBRARY}
84+
${Boost_PYTHON310_LIBRARY}
85+
)
86+
MESSAGE(STATUS "Boost Python3: " ${Boost_PYTHON3_LIBRARIES})
5187

5288
########################################################################################################################
5389

@@ -68,8 +104,11 @@ ADD_LIBRARY(_pulsar SHARED src/pulsar.cc
68104
src/utils.cc
69105
)
70106

71-
SET(CMAKE_SHARED_LIBRARY_PREFIX )
72-
SET(CMAKE_SHARED_LIBRARY_SUFFIX .so)
107+
if (MSVC)
108+
set(CMAKE_SHARED_LIBRARY_SUFFIX .pyd)
109+
else ()
110+
set(CMAKE_SHARED_LIBRARY_SUFFIX .so)
111+
endif ()
73112

74113
if (NOT APPLE AND NOT MSVC)
75114
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_PYTHON}")
@@ -80,12 +119,17 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
80119
endif()
81120

82121
# Try all possible boost-python variable namings
83-
set(PYTHON_WRAPPER_LIBS ${PULSAR_LIBRARY}
84-
${Boost_PYTHON3_LIBRARY})
122+
set(PYTHON_WRAPPER_LIBS
123+
${PULSAR_LIBRARY}
124+
${Boost_PYTHON3_LIBRARIES})
125+
if (MSVC)
126+
message(STATUS "Python3_LIBRARIES: " ${Python3_LIBRARIES})
127+
set(PYTHON_WRAPPER_LIBS ${PYTHON_WRAPPER_LIBS} ${Python3_LIBRARIES})
128+
endif ()
85129

86130
message(STATUS "All libraries: ${PYTHON_WRAPPER_LIBS}")
87131

88-
if (LINK_STATIC)
132+
if (LINK_STATIC AND NOT MSVC)
89133
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
90134

91135
# We need to include all the static libs individually because we cannot easily create a universal2 libpulsar.a
@@ -128,6 +172,7 @@ if (LINK_STATIC)
128172
else()
129173
target_link_libraries(_pulsar ${PYTHON_WRAPPER_LIBS})
130174
endif ()
175+
install(TARGETS _pulsar DESTINATION ${CMAKE_SOURCE_DIR})
131176

132177
find_package(ClangTools)
133178
set(BUILD_SUPPORT_DIR "${CMAKE_SOURCE_DIR}/build-support")

README.md

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,48 @@
3131

3232
## Install the Python wheel
3333

34+
### Windows (with Vcpkg)
35+
36+
First, install the dependencies via [Vcpkg](https://github.com/microsoft/vcpkg).
37+
38+
```PowerShell
39+
vcpkg install --feature-flags=manifests --triplet x64-windows
40+
```
41+
42+
> NOTE: For Windows 32-bit library, change `x64-windows` to `x86-windows`, see [here](https://github.com/microsoft/vcpkg/tree/master/triplets) for all available triplets.
43+
44+
Then, build and install the Python wheel.
45+
46+
```PowerShell
47+
# Assuming the Pulsar C++ client has been installed under the `PULSAR_CPP` directory.
48+
cmake -B build -DVCPKG_TRIPLET=x64-windows -DCMAKE_PREFIX_PATH="$env:PULSAR_CPP" -DLINK_STATIC=ON
49+
cmake --build build --config Release
50+
cmake --install build
51+
py setup.py bdist_wheel
52+
py -m pip install ./dist/pulsar_client-*.whl
53+
```
54+
55+
Since the Python client links to Boost.Python dynamically, you have to copy the dll (e.g. `boost_python310-vc142-mt-x64-1_80.dll`) into the system path (the `PATH` environment variable). If the `-DLINK_STATIC=ON` option is not specified, you have to copy the `pulsar.dll` into the system path as well.
56+
57+
### Linux or macOS
58+
59+
Assuming the Pulsar C++ client and Boost.Python have been installed under the system path.
60+
3461
```bash
3562
cmake -B build
3663
cmake --build build -j8
37-
cp build/_pulsar.so .
64+
cmake --install build
3865
./setup.py bdist_wheel
3966
pip3 install dist/pulsar_client-*.whl --force-reinstall
40-
rm _pulsar.so
4167
```
4268

4369
> **NOTE**
4470
>
4571
> 1. Here a separate `build` directory is created to store all CMake temporary files. However, the `setup.py` requires the `_pulsar.so` is under the project directory.
4672
> 2. Add the `--force-reinstall` option to overwrite the existing Python wheel in case your system has already installed a wheel before.
4773
74+
## Running examples
75+
4876
You can run `python3 -c 'import pulsar'` to see whether the wheel has been installed successfully. If it failed, check whether dependencies (e.g. `libpulsar.so`) are in the system path. If not, make sure the dependencies are in `LD_LIBRARY_PATH` (on Linux) or `DYLD_LIBRARY_PATH` (on macOS).
4977

5078
Then you can run examples as a simple end-to-end test.

setup.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from setuptools import setup
2222
from distutils.core import Extension
2323
from os import environ, path
24+
import platform
2425

2526
from distutils.command import build_ext
2627

@@ -58,7 +59,13 @@ def build_extension(self, ext):
5859
except OSError as e:
5960
if e.errno != 17: # already exists
6061
raise
61-
shutil.copyfile('_pulsar.so', self.get_ext_fullpath(ext.name))
62+
if 'Windows' in platform.platform():
63+
shutil.copyfile('_pulsar.pyd', self.get_ext_fullpath(ext.name))
64+
else:
65+
try:
66+
shutil.copyfile('_pulsar.so', self.get_ext_fullpath(ext.name))
67+
except FileNotFoundError:
68+
shutil.copyfile('lib_pulsar.so', self.get_ext_fullpath(ext.name))
6269

6370

6471
# Core Client dependencies

vcpkg.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "pulsar-python",
3+
"version": "3.0.0",
4+
"description": "Pulsar Python SDK",
5+
"dependencies": [
6+
"boost-python"
7+
]
8+
}

0 commit comments

Comments
 (0)