From 7fe76b3c3b05132bae14911a61d8ca9a7f9b7dc0 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 31 Aug 2026 20:48:01 +0300 Subject: [PATCH] =?UTF-8?q?build(protocan):=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D1=8C=20host-=D1=81=D0=B1=D0=BE=D1=80=D0=BA=D1=83=20?= =?UTF-8?q?=D0=B1=D0=B5=D0=B7=20CMake?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c/protocan-transport/README.md | 6 ++ c/protocan-transport/tools/build_host.py | 86 ++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 c/protocan-transport/tools/build_host.py diff --git a/c/protocan-transport/README.md b/c/protocan-transport/README.md index 136969b..4261d0d 100644 --- a/c/protocan-transport/README.md +++ b/c/protocan-transport/README.md @@ -104,6 +104,12 @@ Android-проект подключает `ports/android/Android.mk` и доба `ports/android/kotlin` в `sourceSets`. JNI-код занимается только преобразованием типов и временем жизни parser context, а правила кадра и CAN ID остаются в C. +Если на Windows нет CMake, host-библиотеку тем же MSVC можно собрать так: + +```powershell +python tools/build_host.py --output native/setcore.dll +``` + Либо напрямую: ```bash diff --git a/c/protocan-transport/tools/build_host.py b/c/protocan-transport/tools/build_host.py new file mode 100644 index 0000000..8281bdb --- /dev/null +++ b/c/protocan-transport/tools/build_host.py @@ -0,0 +1,86 @@ +"""Build the SETCore shared library without imposing one host toolchain. + +CMake remains the primary build. On a Windows workstation where CMake is +absent, the script locates Visual Studio and invokes MSVC directly. Unix-like +hosts fall back to the system C compiler. +""" + +from __future__ import annotations + +import argparse +import os +import platform +import shutil +import subprocess +from pathlib import Path + + +ROOT = Path(__file__).resolve().parent.parent +INCLUDE = ROOT / "include" +SOURCES = [ + ROOT / "src" / name for name in ( + "pcan_abi.c", "pcan_crc.c", "pcan_frame.c", "pcan_id.c", + "pcan_link.c", "pcan_ring.c", "pcan_gas.c", + ) +] + + +def _visual_studio_vcvars() -> Path | None: + installer = Path(os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)")) + vswhere = installer / "Microsoft Visual Studio" / "Installer" / "vswhere.exe" + if vswhere.exists(): + result = subprocess.run( + [str(vswhere), "-latest", "-products", "*", + "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "-property", "installationPath"], + text=True, capture_output=True, check=False, + ) + if result.returncode == 0 and result.stdout.strip(): + candidate = (Path(result.stdout.strip()) / "VC" / "Auxiliary" / + "Build" / "vcvars64.bat") + if candidate.exists(): + return candidate + return None + + +def _build_msvc(output: Path, build_dir: Path) -> None: + vcvars = _visual_studio_vcvars() + if vcvars is None: + raise SystemExit("Visual Studio C++ tools were not found") + quoted_sources = " ".join(f'"{source}"' for source in SOURCES) + command = ( + f'call "{vcvars}" && cl /nologo /W4 /std:c11 ' + f'/DPCAN_ABI_BUILD_DLL /I"{INCLUDE}" /LD {quoted_sources} ' + f'/Fe:"{output}"' + ) + subprocess.run(["cmd.exe", "/d", "/c", command], cwd=build_dir, check=True) + + +def _build_cc(output: Path, build_dir: Path) -> None: + compiler = shutil.which("cc") or shutil.which("clang") or shutil.which("gcc") + if compiler is None: + raise SystemExit("C compiler was not found") + command = [compiler, "-std=c99", "-Wall", "-Wextra", "-Wpedantic", + "-fPIC", "-shared", f"-I{INCLUDE}", *map(str, SOURCES), + "-o", str(output)] + subprocess.run(command, cwd=build_dir, check=True) + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--output", type=Path, required=True) + args = parser.parse_args() + output = args.output.resolve() + output.parent.mkdir(parents=True, exist_ok=True) + build_dir = output.parent / ".setcore-build" + build_dir.mkdir(parents=True, exist_ok=True) + if platform.system() == "Windows": + _build_msvc(output, build_dir) + else: + _build_cc(output, build_dir) + print(output) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())