Skip to content

Add support for Windows #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions .github/julia/build_tarballs.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Note that this script can accept some limited command-line arguments, run
# `julia build_tarballs.jl --help` to see a usage message.
using BinaryBuilder, Pkg

name = "MiniZinc"

version = v"2.8.5"

sources = [
GitSource(
"https://github.com/MiniZinc/libminizinc.git",
"2fdef7b40921981f3f9ea82017e9d84937ddab77",
),
DirectorySource(joinpath(@__DIR__, "bundled")),
]

script = raw"""
cd $WORKSPACE/srcdir/libminizinc

atomic_patch -p1 ${WORKSPACE}/srcdir/patches/fixes.patch

# Patch for MinGW toolchain
find .. -type f -exec sed -i 's/Windows.h/windows.h/g' {} +

# FAST_BUILD is needed when linking HiGHS, because that's what
# we used when compiling HiGHS_jll.
cmake -B build \
-DCMAKE_INSTALL_PREFIX=${prefix} \
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TARGET_TOOLCHAIN} \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_FLAGS="-std=c++17 -I${includedir}/highs" \
-DFAST_BUILD=ON
cmake --build build --parallel ${nproc}
cmake --install build
"""

products = [
ExecutableProduct("minizinc", :minizinc),
]

# These are the platforms we will build for by default, unless further
# platforms are passed in on the command line
platforms = expand_cxxstring_abis(
supported_platforms(; exclude = p -> arch(p) == "i686" && Sys.iswindows(p)),
)

dependencies = [
Dependency("CompilerSupportLibraries_jll"),
# Use an exact version for HiGHS. @odow has observed segfaults with
# HiGHS_jll v1.5.3 when libminizinc compiled with v1.5.1.
Dependency("HiGHS_jll"; compat="=1.7.1"),
]

build_tarballs(
ARGS,
name,
version,
sources,
script,
platforms,
products,
dependencies;
preferred_gcc_version = v"12",
julia_compat = "1.6",
)
82 changes: 82 additions & 0 deletions .github/julia/bundled/patches/fixes.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
--- a/lib/file_utils.cpp
+++ b/lib/file_utils.cpp
@@ -130,7 +130,7 @@ std::string file_path(const std::string& filename, const std::string& basePath)
auto f = !basePath.empty() && !is_absolute(filename) ? basePath + "/" + filename : filename;

// Get real path of absolute path or resolve relative to current directory
-#ifdef _MSC_VER
+#ifdef _WIN32
LPWSTR lpFilePart;
DWORD nBufferLength = GetFullPathNameW(utf8_to_wide(f).c_str(), 0, nullptr, &lpFilePart);
auto* lpBuffer = static_cast<LPWSTR>(LocalAlloc(LMEM_FIXED, sizeof(WCHAR) * nBufferLength));
--- a/minizinc.cpp
+++ b/minizinc.cpp
@@ -89,7 +89,7 @@ int run(const std::string& exe, const std::vector<std::string>& args, bool jsonS

} // namespace

-#ifdef _WIN32
+#if defined(_WIN32) && !defined(__MINGW32__)
#include <minizinc/interrupt.hh>

int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) {
@@ -121,7 +121,9 @@ int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) {
}
#else
int main(int argc, const char** argv) {
+ #if !defined(__MINGW32__)
OverflowHandler::install(argv);
+ #endif
std::vector<std::string> args(argc - 1);
bool jsonStream = false;
for (int i = 1; i < argc; i++) {
--- a/include/minizinc/file_utils.hh
+++ b/include/minizinc/file_utils.hh
@@ -16,7 +16,7 @@

// Macro so that we can use overloaded wide versions of fstream::open for Windows
#ifdef _WIN32
-#define FILE_PATH(path) MiniZinc::FileUtils::utf8_to_wide(path)
+#define FILE_PATH(path) (path)
#else
#define FILE_PATH(path) (path)
#endif
--- a/include/minizinc/process.hh
+++ b/include/minizinc/process.hh
@@ -225,11 +225,11 @@ public:
std::condition_variable cv;

std::deque<std::string> outputQueue;
- thread thrStdout(&ReadPipePrint<S2O>, g_hChildStd_OUT_Rd, &doneStdout, nullptr, &outputQueue,
+ std::thread thrStdout(&ReadPipePrint<S2O>, g_hChildStd_OUT_Rd, &doneStdout, nullptr, &outputQueue,
&pipeMutex, &cv_mutex, &cv);
- thread thrStderr(&ReadPipePrint<S2O>, g_hChildStd_ERR_Rd, &doneStderr, &_pS2Out->getLog(),
+ std::thread thrStderr(&ReadPipePrint<S2O>, g_hChildStd_ERR_Rd, &doneStderr, &_pS2Out->getLog(),
nullptr, &pipeMutex, nullptr, nullptr);
- thread thrTimeout([&] {
+ std::thread thrTimeout([&] {
auto shouldStop = [&] { return hadInterrupt || (doneStderr && doneStdout); };
std::unique_lock<std::mutex> lck(_interruptMutex);
if (_timelimit != 0) {
--- a/solvers/MIP/MIP_cplex_wrap.cpp
+++ b/solvers/MIP/MIP_cplex_wrap.cpp
@@ -61,7 +61,7 @@ void* dll_open(const std::string& file) {
}
void* dll_sym(void* dll, const char* sym) {
#ifdef _WIN32
- void* ret = GetProcAddress((HMODULE)dll, sym);
+ void* ret = (void*)GetProcAddress((HMODULE)dll, sym);
#else
void* ret = dlsym(dll, sym);
#endif
--- a/solvers/MIP/MIP_gurobi_wrap.cpp
+++ b/solvers/MIP/MIP_gurobi_wrap.cpp
@@ -263,7 +263,7 @@ void* dll_open(const char* file) {
}
void* dll_sym(void* dll, const char* sym) {
#ifdef _WIN32
- void* ret = GetProcAddress((HMODULE)dll, sym);
+ void* ret = (void*)GetProcAddress((HMODULE)dll, sym);
#else
void* ret = dlsym(dll, sym);
#endif
80 changes: 80 additions & 0 deletions .github/julia/bundled/patches/fixes.patch.bak
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
--- a/include/minizinc/file_utils.hh
+++ b/include/minizinc/file_utils.hh
@@ -15,12 +15,16 @@
#include <vector>

// Macro so that we can use overloaded wide versions of fstream::open for Windows
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(__MINGW32__)
#define FILE_PATH(path) MiniZinc::FileUtils::utf8_to_wide(path)
#else
#define FILE_PATH(path) (path)
#endif

+#ifdef __MINGW32__
+ #define realpath(N,R) _fullpath((R),(N),PATH_MAX)
+#endif
+
namespace MiniZinc {
namespace FileUtils {

--- a/minizinc.cpp
+++ b/minizinc.cpp
@@ -89,7 +89,7 @@ int run(const std::string& exe, const std::vector<std::string>& args, bool jsonS

} // namespace

-#ifdef _WIN32
+#if defined(_WIN32) && !defined(__MINGW32__)
#include <minizinc/interrupt.hh>

int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) {
@@ -121,7 +121,9 @@ int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) {
}
#else
int main(int argc, const char** argv) {
+ #if !defined(__MINGW32__)
OverflowHandler::install(argv);
+ #endif
std::vector<std::string> args(argc - 1);
bool jsonStream = false;
for (int i = 1; i < argc; i++) {
--- a/include/minizinc/process.hh
+++ b/include/minizinc/process.hh
@@ -225,11 +225,11 @@ public:
std::condition_variable cv;

std::deque<std::string> outputQueue;
- thread thrStdout(&ReadPipePrint<S2O>, g_hChildStd_OUT_Rd, &doneStdout, nullptr, &outputQueue,
+ std::thread thrStdout(&ReadPipePrint<S2O>, g_hChildStd_OUT_Rd, &doneStdout, nullptr, &outputQueue,
&pipeMutex, &cv_mutex, &cv);
- thread thrStderr(&ReadPipePrint<S2O>, g_hChildStd_ERR_Rd, &doneStderr, &_pS2Out->getLog(),
+ std::thread thrStderr(&ReadPipePrint<S2O>, g_hChildStd_ERR_Rd, &doneStderr, &_pS2Out->getLog(),
nullptr, &pipeMutex, nullptr, nullptr);
- thread thrTimeout([&] {
+ std::thread thrTimeout([&] {
auto shouldStop = [&] { return hadInterrupt || (doneStderr && doneStdout); };
std::unique_lock<std::mutex> lck(_interruptMutex);
if (_timelimit != 0) {
--- a/solvers/MIP/MIP_cplex_wrap.cpp
+++ b/solvers/MIP/MIP_cplex_wrap.cpp
@@ -61,7 +61,7 @@ void* dll_open(const std::string& file) {
}
void* dll_sym(void* dll, const char* sym) {
#ifdef _WIN32
- void* ret = GetProcAddress((HMODULE)dll, sym);
+ void* ret = (void*)GetProcAddress((HMODULE)dll, sym);
#else
void* ret = dlsym(dll, sym);
#endif
--- a/solvers/MIP/MIP_gurobi_wrap.cpp
+++ b/solvers/MIP/MIP_gurobi_wrap.cpp
@@ -263,7 +263,7 @@ void* dll_open(const char* file) {
}
void* dll_sym(void* dll, const char* sym) {
#ifdef _WIN32
- void* ret = GetProcAddress((HMODULE)dll, sym);
+ void* ret = (void*)GetProcAddress((HMODULE)dll, sym);
#else
void* ret = dlsym(dll, sym);
#endif
File renamed without changes.
File renamed without changes.
55 changes: 55 additions & 0 deletions .github/workflows/test-windows.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Build on Linux, Run on Windows
on:
push:
branches: [master]
pull_request:
types: [opened, synchronize, reopened]
permissions:
actions: write
contents: read
jobs:
build-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: julia-actions/setup-julia@v2
with:
version: "1.7"
arch: x64
- uses: julia-actions/cache@v2
- run: |
PACKAGE=MiniZinc_jll
PLATFORM=x86_64-w64-mingw32-cxx11
julia --color=yes -e 'using Pkg; Pkg.add("BinaryBuilder")'
julia --color=yes .github/julia/build_tarballs.jl ${PLATFORM} --verbose --deploy=local
file=/home/runner/.julia/dev/${PACKAGE}/Artifacts.toml
sha1=$(grep '^git-tree-sha1' "$file" | cut -d '"' -f2)
echo "ARTIFACT_SHA=${sha1}" >> $GITHUB_ENV
- uses: actions/upload-artifact@v4
with:
name: artifacts
path: '/home/runner/.julia/artifacts/${{ env.ARTIFACT_SHA }}'
run-windows:
runs-on: windows-latest
needs: build-linux
steps:
- uses: actions/checkout@v4
- uses: julia-actions/setup-julia@v2
with:
version: "1"
arch: x64
- uses: julia-actions/cache@v2
- uses: julia-actions/julia-buildpkg@v1
- uses: actions/download-artifact@v4
with:
name: artifacts
path: override
- shell: julia --color=yes --project=. {0}
run: |
import MiniZinc_jll
artifact_dir = MiniZinc_jll.artifact_dir
sha = last(splitpath(artifact_dir))
dir = escape_string(joinpath(ENV["GITHUB_WORKSPACE"], "override"))
content = "$sha = \"$(dir)\"\n"
write(replace(artifact_dir, sha => "Overrides.toml"), content)
- uses: julia-actions/julia-runtest@v1
3 changes: 2 additions & 1 deletion src/optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function _minizinc_exe(f::F) where {F}
else
return f(joinpath(user_dir, "minizinc"))
end
elseif Sys.islinux() || Sys.isapple()
else MiniZinc_jll.is_available()
return f(MiniZinc_jll.minizinc())
end
return error(
Expand Down Expand Up @@ -103,6 +103,7 @@ function _run_minizinc(dest::Optimizer)
if isfile(_stderr)
status *= read(_stderr, String)
end
@show status
return status
end
if isfile(output)
Expand Down
Loading