build(msys2): add local Windows build support

This commit is contained in:
Aethersailor
2026-05-19 18:47:06 +08:00
parent f4181dc9d2
commit 6c21fd5a44
10 changed files with 163 additions and 4 deletions

6
.gitignore vendored
View File

@@ -8,4 +8,8 @@ scripts/yaml-cpp
.DS_Store
src/.DS_Store
build
build
bridge/libmihomo.a
bridge/libmihomo.so
bridge/libmihomo.dll
bridge/libmihomo.dll.a

View File

@@ -1460,7 +1460,11 @@ public:
if(!rt)
throw std::runtime_error{"qjs: Cannot create runtime"};
#ifdef _WIN32
JS_SetHostPromiseRejectionTracker(rt, promise_unhandled_rejection_tracker, NULL);
#else
JS_SetHostUnhandledPromiseRejectionTracker(rt, promise_unhandled_rejection_tracker, NULL);
#endif // _WIN32
JS_SetModuleLoaderFunc(rt, nullptr, module_loader, nullptr);
}

View File

@@ -0,0 +1,94 @@
param(
[ValidateRange(1, 32)]
[int]$Jobs = 8,
[ValidateSet("Debug", "Release", "RelWithDebInfo")]
[string]$BuildType = "RelWithDebInfo",
[switch]$RebuildBridge,
[switch]$RebuildLibCron
)
$ErrorActionPreference = "Stop"
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
$bash = "C:\msys64\usr\bin\bash.exe"
if (-not (Test-Path $bash)) {
throw "MSYS2 was not found at C:\msys64. Install MSYS2 first."
}
$env:SCX_ROOT_WIN = $repoRoot
$env:SCX_JOBS = [string]$Jobs
$env:SCX_BUILD_TYPE = $BuildType
$env:SCX_REBUILD_BRIDGE = if ($RebuildBridge) { "1" } else { "0" }
$env:SCX_REBUILD_LIBCRON = if ($RebuildLibCron) { "1" } else { "0" }
$script = @'
set -euo pipefail
export MSYSTEM=UCRT64
export PATH="/c/Program Files/Go/bin:/ucrt64/bin:/usr/bin:$PATH"
root="$(cygpath -u "$SCX_ROOT_WIN")"
cd "$root"
for tool in gcc g++ cmake ninja pkg-config git go; do
command -v "$tool" >/dev/null || {
echo "Missing required tool: $tool" >&2
exit 1
}
done
pkg-config --exists libcurl yaml-cpp libpcre2-8 || {
echo "Missing one or more pkg-config dependencies: libcurl yaml-cpp libpcre2-8" >&2
exit 1
}
if [ ! -f /ucrt64/include/quickjs/quickjs.h ] || [ ! -f /ucrt64/lib/quickjs/libquickjs.a ]; then
echo "Missing QuickJS. Install mingw-w64-ucrt-x86_64-quickjs in MSYS2." >&2
exit 1
fi
if [ "$SCX_REBUILD_LIBCRON" = "1" ] || [ ! -f /ucrt64/lib/liblibcron.a ]; then
work=/tmp/subconverter-build-deps
mkdir -p "$work"
cd "$work"
if [ ! -d libcron/.git ]; then
git clone --depth=1 https://github.com/PerMalmberg/libcron
fi
cd libcron
git submodule update --init
cmake -S . -B build-ucrt -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build-ucrt --target libcron -j "$SCX_JOBS"
mkdir -p /ucrt64/lib /ucrt64/include/libcron /ucrt64/include/date
cp -f libcron/out/Release/liblibcron.a /ucrt64/lib/
cp -f libcron/include/libcron/* /ucrt64/include/libcron/
cp -f libcron/externals/date/include/date/* /ucrt64/include/date/
cd "$root"
fi
if [ "$SCX_REBUILD_BRIDGE" = "1" ] || [ ! -f bridge/libmihomo.a ]; then
cd "$root/bridge"
go mod download
CC=gcc CXX=g++ CGO_ENABLED=1 go build -buildmode=c-archive -o libmihomo.a .
unix2dos libmihomo.h >/dev/null 2>&1 || true
cd "$root"
fi
cmake -S . -B build/ucrt64 -G Ninja \
-DCMAKE_BUILD_TYPE="$SCX_BUILD_TYPE" \
-DCMAKE_PREFIX_PATH=/ucrt64 \
-DCMAKE_C_COMPILER=gcc \
-DCMAKE_CXX_COMPILER=g++ \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
cmake --build build/ucrt64 -j "$SCX_JOBS"
echo
echo "Built: $root/build/ucrt64/subconverter.exe"
echo "Run: ./scripts/run-local-msys2.ps1"
'@
& $bash -lc $script
exit $LASTEXITCODE

View File

@@ -0,0 +1,37 @@
param(
[string]$Config = "base/pref.example.toml"
)
$ErrorActionPreference = "Stop"
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
$bash = "C:\msys64\usr\bin\bash.exe"
$exe = Join-Path $repoRoot "build\ucrt64\subconverter.exe"
$configPath = Resolve-Path (Join-Path $repoRoot $Config)
if (-not (Test-Path $bash)) {
throw "MSYS2 was not found at C:\msys64."
}
if (-not (Test-Path $exe)) {
throw "subconverter.exe was not found. Run scripts\build-local-msys2.ps1 first."
}
$env:SCX_ROOT_WIN = $repoRoot
$env:SCX_CONFIG_WIN = $configPath.Path
$script = @'
set -euo pipefail
export MSYSTEM=UCRT64
export PATH="/ucrt64/bin:/usr/bin:$PATH"
root="$(cygpath -u "$SCX_ROOT_WIN")"
config="$(cygpath -w "$SCX_CONFIG_WIN")"
cd "$root"
exec ./build/ucrt64/subconverter.exe -f "$config"
'@
& $bash -lc $script
exit $LASTEXITCODE

View File

@@ -22,6 +22,7 @@
#include "utils/rapidjson_extra.h"
#include "utils/regexp.h"
#include "utils/stl_extra.h"
#include "utils/time_compat.h"
#include "utils/urlencode.h"
#include "utils/yamlcpp_extra.h"

View File

@@ -12,6 +12,7 @@
#include "utils/logger.h"
#include "utils/network.h"
#include "utils/regexp.h"
#include "utils/time_compat.h"
#include "utils/urlencode.h"
#include "utils/yamlcpp_extra.h"
#include "templates.h"
@@ -312,12 +313,13 @@ int render_template(const std::string &content, const template_args &vars,
#endif // NO_WEBGET
//env.add_callback("parseHostname", 1, parseHostname);
env.set_include_callback([&](const std::string &name, const std::string &template_name)
env.set_include_callback([&](const std::filesystem::path &path, const std::string &template_name)
{
const std::string include_path = path.string();
std::string absolute_path;
try
{
absolute_path = std::filesystem::canonical(template_name).string();
absolute_path = std::filesystem::canonical(path).string();
}
catch(std::exception &e)
{
@@ -326,7 +328,7 @@ int render_template(const std::string &content, const template_args &vars,
if(!absolute_scope.empty() &&
!path_is_inside_scope(absolute_path, absolute_scope))
throw inja::FileError("access denied when trying to include '" + template_name + "': out of scope");
return env.parse(fileGet(template_name, true));
return env.parse(fileGet(include_path, true));
});
env.set_search_included_templates_in_files(false);

View File

@@ -21,6 +21,7 @@
#include "server/webserver.h"
#include "settings.h"
#include "upload.h"
#include "utils/time_compat.h"
// Multiple CDN fallback URLs for default external config
// Will be tried in order if user-provided config fails to load

View File

@@ -9,6 +9,7 @@
#include "utils/rapidjson_extra.h"
#include "utils/regexp.h"
#include "utils/string.h"
#include "utils/time_compat.h"
unsigned long long streamToInt(const std::string &stream)
{

View File

@@ -12,6 +12,7 @@
#include "defer.h"
#include "lock.h"
#include "logger.h"
#include "time_compat.h"
std::string getTime(int type)
{

14
src/utils/time_compat.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef TIME_COMPAT_H_INCLUDED
#define TIME_COMPAT_H_INCLUDED
#include <ctime>
#ifdef _WIN32
inline tm *localtime_r(const time_t *timep, tm *result) {
if (timep == nullptr || result == nullptr)
return nullptr;
return localtime_s(result, timep) == 0 ? result : nullptr;
}
#endif // _WIN32
#endif // TIME_COMPAT_H_INCLUDED