From 53f8ec625b0197e695ae96bf3a97a1daf531bab0 Mon Sep 17 00:00:00 2001 From: Hoon Ma Date: Sun, 22 Feb 2026 18:38:11 +0900 Subject: [PATCH] Fix Windows building issue --- contrib/sys/time.h | 38 ++++++++++++++++++++++++++++++++++++++ setup.py | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 contrib/sys/time.h diff --git a/contrib/sys/time.h b/contrib/sys/time.h new file mode 100644 index 0000000..4696ffa --- /dev/null +++ b/contrib/sys/time.h @@ -0,0 +1,38 @@ +/* + * MSVC compatibility shim for + * + * Provides gettimeofday() and struct timeval for Windows builds. + * On POSIX systems this header is never reached because the real + * is found first. + */ + +#ifndef COMPAT_SYS_TIME_H +#define COMPAT_SYS_TIME_H + +#ifdef _MSC_VER + +#ifndef NOMINMAX +#define NOMINMAX /* Prevent windows.h from defining min/max macros */ +#endif +#include /* struct timeval */ +#include + +static __inline int gettimeofday(struct timeval *tp, void *tzp) { + (void)tzp; + FILETIME ft; + unsigned __int64 tmp; + GetSystemTimeAsFileTime(&ft); + tmp = ((unsigned __int64)ft.dwHighDateTime << 32) | ft.dwLowDateTime; + /* FILETIME epoch is 1601-01-01; convert to Unix epoch 1970-01-01 */ + tmp -= 116444736000000000ULL; + tp->tv_sec = (long)(tmp / 10000000ULL); + tp->tv_usec = (long)((tmp % 10000000ULL) / 10); + return 0; +} + +#else +/* Non-MSVC: just include the real header */ +#include_next +#endif + +#endif /* COMPAT_SYS_TIME_H */ diff --git a/setup.py b/setup.py index a22e8a8..68120ac 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the -# “Software”), to deal in the Software without restriction, including +# "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to @@ -12,7 +12,7 @@ # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # -# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN # NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, @@ -24,13 +24,27 @@ from setuptools import setup, Extension import numpy import os +import sys numpy_includes = [numpy.get_include()] +extra_compile_args = [] +extra_link_args = [] +define_macros = [] + +if sys.platform == 'win32': + # /permissive- enables C++ alternative tokens (or, and, not, etc.) + # /DNOMINMAX prevents windows.h from defining min/max macros + extra_compile_args = ['/permissive-'] + define_macros = [('NOMINMAX', None)] + lpartitionext = Extension( 'linearpartition', ['linearpartitionmodule.cc'], - include_dirs=['LinearPartition/src', 'contrib'] + numpy_includes) + include_dirs=['LinearPartition/src', 'contrib'] + numpy_includes, + extra_compile_args=extra_compile_args, + extra_link_args=extra_link_args, + define_macros=define_macros) if not os.path.exists('LinearPartition/src/LinearPartition.cpp'): print(''' @@ -47,6 +61,23 @@ def patch_linearpartition_files(srcdir): with open(bppcpp_file, 'w') as fout: fout.write(content.replace('(!bpseq)', '__mea_hook__')) + # Patch LinearFoldEval.h to replace VLAs with vectors (MSVC compat) + evalh_file = os.path.join(srcdir, 'LinearFoldEval.h') + if os.path.exists(evalh_file): + content = open(evalh_file).read() + if 'long M1_energy[seq_length]' in content: + content = content.replace( + 'long M1_energy[seq_length];\n long multi_number_unpaired[seq_length];', + 'std::vector M1_energy(seq_length, 0);\n std::vector multi_number_unpaired(seq_length, 0);' + ) + # Remove redundant initialization since vector constructor already zeros + content = content.replace( + 'M1_energy[j] = 0; // init multi of position j\n multi_number_unpaired[j] = 0;', + '// (vectors already zero-initialized)' + ) + with open(evalh_file, 'w') as fout: + fout.write(content) + patch_linearpartition_files('LinearPartition/src') setup(