Skip to content

Commit 334679f

Browse files
committed
Windows compatibility
1 parent 9a69bbc commit 334679f

File tree

4 files changed

+127
-33
lines changed

4 files changed

+127
-33
lines changed

.github/workflows/build_wheels.yml

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,37 +37,34 @@ jobs:
3737
with:
3838
submodules: true
3939

40-
- name: Cache pip
41-
uses: actions/cache@v2
42-
with:
43-
key: cache--${{ github.event.inputs.os }}--${{ github.event.inputs.python }}--${{ hashFiles('./requirements.txt') }}
44-
path: ~/.cache/pip
45-
4640
- name: Setup python
4741
uses: actions/setup-python@v2
4842
with:
4943
python-version: ${{ github.event.inputs.python }}
5044

5145
- name: Update pip
52-
run: python -m pip install -U pip wheel setuptools
46+
run: python3 -m pip install -U pip wheel setuptools
5347

5448
- name: Install requirements
55-
run: python -m pip install -Ur requirements.txt
49+
run: python3 -m pip install -Ur requirements.txt
5650

5751
- name: Cythonize
5852
run: make _pytidyhtml5.cpp
5953

6054
- name: Build wheels
61-
run: python -m cibuildwheel --output-dir wheelhouse
55+
run: python3 -m cibuildwheel --output-dir wheelhouse-${{ github.event.inputs.manylinux }}-${{ github.event.inputs.os }}
6256
env:
6357
CIBW_SKIP: "cp27-* cp34-* cp35-* pp27-*"
6458
CIBW_MANYLINUX_X86_64_IMAGE: ${{ github.event.inputs.manylinux }}
6559
CIBW_MANYLINUX_I686_IMAGE: ${{ github.event.inputs.manylinux }}
6660
CIBW_ARCHS: ${{ github.event.inputs.archs }}
61+
CIBW_ARCHS_WINDOWS: auto64
6762
CIBW_BEFORE_BUILD: make clean-artifacts && make tidy-html5/build/cmake/libtidy.a
63+
CIBW_BUILD_FRONTEND: pip
64+
CIBW_TEST_COMMAND: "{project}/basic-sanity-test.py"
6865

6966
- name: Store artifacts
7067
uses: actions/upload-artifact@v2
7168
with:
72-
name: Wheelhouse
73-
path: ./wheelhouse/*.whl
69+
name: Wheelhouse-${{ github.event.inputs.manylinux }}-${{ github.event.inputs.os }}
70+
path: ./wheelhouse-${{ github.event.inputs.manylinux }}-${{ github.event.inputs.os }}/*.whl

Makefile

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ all: sdist bdist_wheel docs
44

55
NAME := pytidyhtml5
66

7-
.PHONY: all sdist bdist_wheel clean docs prepare clean-generated clean-artifacts
7+
.PHONY: all sdist bdist_wheel clean docs prepare clean-generated clean-artifacts export-environ
88

99
FILES := Makefile MANIFEST.in _${NAME}.pyx README.rst setup.py \
1010
lib/native.hpp lib/VERSION.txt lib/DESCRIPTION.txt \
@@ -17,25 +17,43 @@ TIDY_CFLAGS += -fstack-protector-strong --param=ssp-buffer-size=8
1717
TIDY_CFLAGS += -fvisibility=internal -fmerge-all-constants
1818
TIDY_CFLAGS += -std=c11 -D_ISOC11_SOURCE -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE
1919

20-
export CC = $(shell which gcc clang g++ clang++ | head -n1)
21-
export CXX = $(shell which g++ clang++ gcc clang | head -n1)
22-
export AR = $(shell which gcc-ar llvm-ar ar | head -n1)
23-
export RANLIB = $(shell which gcc-ranlib llvm-ranlib ranlib | head -n1)
2420

25-
$(info CC=${CC})
26-
$(info CXX=${CXX})
27-
$(info AR=${AR})
28-
$(info RANLIB=${RANLIB})
21+
CC:=$(shell which gcc clang g++ clang++ | head -n1 2> /dev/null)
22+
CXX:=$(shell which g++ clang++ gcc clang | head -n1 2> /dev/null)
23+
AR:=$(shell which gcc-ar llvm-ar ar | head -n1 2> /dev/null)
24+
RANLIB:=$(shell which gcc-ranlib llvm-ranlib ranlib | head -n1 2> /dev/null)
25+
26+
ifeq ($(findstring */c/,*${CC}),*/c/)
27+
CC:=$(patsubst /c/%,c:/%,${CC}).exe
28+
endif
29+
30+
ifeq ($(findstring */c/,*${CXX}),*/c/)
31+
CXX:=$(patsubst /c/%,c:/%,${CXX}).exe
32+
endif
33+
34+
ifeq ($(findstring */c/,*${AR}),*/c/)
35+
AR:=$(patsubst /c/%,c:/%,${AR}).exe
36+
endif
37+
38+
ifeq ($(findstring */c/,*${RANLIB}),*/c/)
39+
RANLIB:=$(patsubst /c/%,c:/%,${RANLIB}).exe
40+
endif
41+
42+
export CC
43+
export CXX
44+
export AR
45+
export ARFLAGS
46+
export RANLIB
47+
2948

3049
tidy-html5/.git:
3150
git submodule init
3251
git submodule update
3352

3453
tidy-html5/build/cmake/libtidy.a: | tidy-html5/.git
35-
mkdir -p tidy-html5/build/
36-
3754
cd tidy-html5/build/cmake && \
3855
cmake ../.. \
56+
"-GUnix Makefiles" \
3957
-DCMAKE_BUILD_TYPE=Release \
4058
-DBUILD_SHARED_LIBS=OFF \
4159
-DCMAKE_C_FLAGS="${TIDY_CFLAGS}" \
@@ -45,35 +63,44 @@ tidy-html5/build/cmake/libtidy.a: | tidy-html5/.git
4563
-DCMAKE_RANLIB="${RANLIB}"
4664

4765
cd tidy-html5/build/cmake/ && \
48-
$(MAKE) VERBOSE=1 -B
66+
$(MAKE) VERBOSE=1 -B tidy-static
4967

68+
-mv tidy-html5/build/cmake/libtidy_static.a tidy-html5/build/cmake/libtidy.a
5069
$(RANLIB) $@
5170

52-
-rm tidy-html5/build/cmake/libtidy.so
71+
-rm tidy-html5/build/cmake/libtidy.so*
5372

5473
lib/_import_tidy_enum.pyx:
5574
./generate_imports.py
5675

5776
_${NAME}.cpp: _${NAME}.pyx $(wildcard lib/*.pyx) | lib/_import_tidy_enum.pyx
5877
-rm -- dist/*.so
5978
-rm ./_${NAME}.cpp
60-
python -m Cython.Build.Cythonize -f $<
79+
80+
python3 -m Cython.Build.Cythonize -f $<
81+
82+
sed -i -e '1s;^;#ifdef _WIN64\
83+
static void hypot() {}\
84+
namespace std { static void _hypot() {} }\
85+
#include <cmath>\
86+
#endif\
87+
;' -e 's/%z/%" PY_FORMAT_SIZE_T "/g' $@
6188

6289
prepare: _${NAME}.cpp ${FILES}
6390

6491
sdist: _${NAME}.cpp ${FILES}
6592
-rm -- dist/${NAME}-*.tar.gz
66-
python setup.py sdist --format=gztar
67-
python setup.py sdist --format=xztar
93+
python3 setup.py sdist --format=gztar
94+
python3 setup.py sdist --format=xztar
6895

6996
bdist_wheel: _${NAME}.cpp ${FILES} | sdist
7097
-rm -- dist/${NAME}-*.whl
71-
python setup.py bdist_wheel
98+
python3 setup.py bdist_wheel
7299

73100
docs: bdist_wheel $(wildcard docs/* docs/*/*)
74101
-rm -r -- dist/html/
75102
pip install --force dist/${NAME}-*.whl
76-
python -m sphinx -M html docs/ dist/
103+
python3 -m sphinx -M html docs/ dist/
77104

78105
clean: clean-generated clean-artifacts
79106

@@ -88,3 +115,10 @@ clean-artifacts:
88115
-rm -r -- ./dist/
89116
-rm -r -- ./"${NAME}.egg-info/"
90117
-pip uninstall pytidyhtml5 -y
118+
119+
export-environ:
120+
@echo CC=${CC}
121+
@echo CXX=${CXX}
122+
@echo AR=${AR}
123+
@echo ARFLAGS=${ARFLAGS}
124+
@echo RANLIB=${RANLIB}

basic-sanity-test.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/env python3
2+
3+
import pytidyhtml5
4+
5+
pytidyhtml5.set_language('de')
6+
expected = (
7+
'<!DOCTYPE html>\n<html>\n<head>\n<meta name="generator" content="HTML Tidy for HTML5 for Linux version 5.8.0">\n<title></title>\n</head>\n<body>\nHall&ouml;chen\n</body>\n</html>\n',
8+
"Zeile 1 Spalte 1 - Warnung: fehlende <!DOCTYPE> Deklaration\nZeile 1 Spalte 1 - Warnung: Klartext ist im Element <head> nicht erlaubt\nZeile 1 Spalte 1 - Info: <head> bereits vermerkt\nZeile 1 Spalte 1 - Warnung: füge implizites <body> ein\nZeile 1 Spalte 1 - Warnung: füge fehlendes 'title' Element ein\n"
9+
)
10+
actual = pytidyhtml5.tidy_document('Hallöchen')
11+
if expected != actual:
12+
print('actual=' + repr(actual))
13+
raise SystemExit(1)
14+
15+
print('OK')

setup.py

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
#!/usr/bin/env python
1+
#!/usr/bin/env python3
22

33
from os.path import dirname, join, abspath
4+
from os import environ
45
from platform import system
56
from setuptools import setup, Extension
7+
from subprocess import check_output
8+
from sys import argv
9+
from traceback import print_last
610

711

812
def get_text(name):
@@ -25,6 +29,7 @@ def get_text(name):
2529
'-Wl,-zrelro,-znow,-zcombreloc,-znocommon,-znoexecstack',
2630
]
2731
else:
32+
# OSX or Windows
2833
extra_compile_args = [
2934
'-std=c++11', '-flto',
3035
'-O2', '-fomit-frame-pointer', '-fPIC', '-ggdb1', '-pipe',
@@ -37,8 +42,49 @@ def get_text(name):
3742
'-fPIC',
3843
]
3944

40-
name = 'pytidyhtml5'
45+
if system() == 'Windows':
46+
# I cannot get cibuildwheel to accept my CC + CXX overrides. :(
47+
# So monkey patching it is ...
48+
49+
for line in check_output(['make', 'export-environ']).decode('UTF-8').splitlines():
50+
(key, value) = line.split('=', 1)
51+
environ[key] = value
52+
53+
import distutils.command.build_ext
54+
55+
def customize_compiler(compiler):
56+
compiler_settings = [
57+
environ['CXX'], '-m64',
58+
'-Wall', '-Wno-unused-result', '-Wformat', '-Werror=format-security', '-Wdate-time',
59+
'-O2', '-g', '-fwrapv', '-fstack-protector-strong',
60+
'-DNDEBUG', '-D_FORTIFY_SOURCE=2',
61+
62+
'-DMS_WIN64', # https://github.com/cython/cython/issues/3405#issuecomment-596975159
63+
]
64+
65+
compiler.preprocessor = [environ['CXX'], '-m64', '-E', '-Wdate-time', '-D_FORTIFY_SOURCE=2']
66+
compiler.compiler = [*compiler_settings]
67+
compiler.compiler_cxx = [*compiler_settings]
68+
compiler.compiler_so = [*compiler_settings, '-fPIC']
69+
compiler.linker_so = [*compiler_settings, '-shared']
70+
compiler.linker_exe = [*compiler_settings, '-fPIC']
71+
compiler.archiver = [environ['AR'], environ['ARFLAGS']]
72+
compiler.ranlib = [environ['RANLIB']]
4173

74+
class build_ext(distutils.command.build_ext.build_ext):
75+
def run(self):
76+
self.compiler = 'unix'
77+
return super().run()
78+
79+
def build_extensions(self):
80+
print('self.compiler', repr(vars(self.compiler)))
81+
return super().build_extensions()
82+
83+
distutils.command.build_ext.customize_compiler = customize_compiler
84+
distutils.command.build_ext.build_ext = build_ext
85+
86+
87+
name = 'pytidyhtml5'
4288
setup(
4389
name=name,
4490
version=get_text('VERSION.txt'),
@@ -63,11 +109,13 @@ def get_text(name):
63109
platforms=['any'],
64110
license='ISC',
65111
classifiers=[
66-
'Development Status :: 4 - Beta',
112+
'Development Status :: 5 - Production/Stable',
67113
'Intended Audience :: Developers',
68114
'Intended Audience :: System Administrators',
69115
'License :: OSI Approved :: ISC License (ISCL)',
70-
'Operating System :: OS Independent',
116+
'Operating System :: POSIX :: Linux',
117+
'Operating System :: MacOS :: MacOS X',
118+
'Operating System :: Microsoft :: Windows',
71119
'Programming Language :: Cython',
72120
'Programming Language :: Python :: 3',
73121
'Programming Language :: Python :: 3.6',

0 commit comments

Comments
 (0)