forked from WHC/Hermit
Compare commits
1
Commits
main
..
3db33eddac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3db33eddac |
+17
-6
@@ -18,12 +18,17 @@ endif()
|
|||||||
# Separate archive for MinGW so Linux host builds keep libsashidown.a
|
# Separate archive for MinGW so Linux host builds keep libsashidown.a
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||||
set(SASHIDOWN_A "${SD_DIR}/libsashidown-mingw.a")
|
set(SASHIDOWN_A "${SD_DIR}/libsashidown-mingw.a")
|
||||||
set(_MINGW_AR x86_64-w64-mingw32-ar)
|
# Use whatever archiver CMake found for the active toolchain. Hardcoding
|
||||||
|
# "x86_64-w64-mingw32-ar" only works on cross-build hosts, where binutils
|
||||||
|
# installs prefixed names; MSYS2's mingw-w64 toolchain ships plain ar.exe
|
||||||
|
# and ranlib.exe, so the hardcoded names are not found.
|
||||||
|
set(_MINGW_AR "${CMAKE_AR}")
|
||||||
|
set(_MINGW_RANLIB "${CMAKE_RANLIB}")
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT "${SASHIDOWN_A}"
|
OUTPUT "${SASHIDOWN_A}"
|
||||||
COMMAND ${CMAKE_MAKE_PROGRAM} -C "${SD_DIR}" clean
|
COMMAND ${CMAKE_MAKE_PROGRAM} -C "${SD_DIR}" clean
|
||||||
COMMAND ${CMAKE_MAKE_PROGRAM} -C "${SD_DIR}" libsashidown.a
|
COMMAND ${CMAKE_MAKE_PROGRAM} -C "${SD_DIR}" libsashidown.a
|
||||||
CC=${CMAKE_C_COMPILER} AR=${_MINGW_AR} RANLIB=x86_64-w64-mingw32-ranlib
|
CC=${CMAKE_C_COMPILER} AR=${_MINGW_AR} RANLIB=${_MINGW_RANLIB}
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
"${SD_DIR}/libsashidown.a" "${SASHIDOWN_A}"
|
"${SD_DIR}/libsashidown.a" "${SASHIDOWN_A}"
|
||||||
COMMAND ${CMAKE_MAKE_PROGRAM} -C "${SD_DIR}" clean
|
COMMAND ${CMAKE_MAKE_PROGRAM} -C "${SD_DIR}" clean
|
||||||
@@ -111,9 +116,11 @@ endif()
|
|||||||
if(CST_BUILD_TUI)
|
if(CST_BUILD_TUI)
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
# Prefer PDCurses (pdcurses / curses). Users may set PDCurses_ROOT.
|
# Prefer PDCurses (pdcurses / curses). Users may set PDCurses_ROOT.
|
||||||
|
# PATH_SUFFIXES also covers the layout MSYS2's mingw-w64-pdcurses uses,
|
||||||
|
# which puts the headers under include/pdcurses/ rather than include/.
|
||||||
find_path(PDCURSES_INCLUDE_DIR curses.h
|
find_path(PDCURSES_INCLUDE_DIR curses.h
|
||||||
HINTS ENV PDCurses_ROOT "${PDCurses_ROOT}"
|
HINTS ENV PDCurses_ROOT "${PDCurses_ROOT}"
|
||||||
PATH_SUFFIXES include)
|
PATH_SUFFIXES include pdcurses include/pdcurses)
|
||||||
find_library(PDCURSES_LIBRARY
|
find_library(PDCURSES_LIBRARY
|
||||||
NAMES pdcurses pdcurses.dll curses
|
NAMES pdcurses pdcurses.dll curses
|
||||||
HINTS ENV PDCurses_ROOT "${PDCurses_ROOT}"
|
HINTS ENV PDCurses_ROOT "${PDCurses_ROOT}"
|
||||||
@@ -121,7 +128,11 @@ if(CST_BUILD_TUI)
|
|||||||
if(PDCURSES_INCLUDE_DIR AND PDCURSES_LIBRARY)
|
if(PDCURSES_INCLUDE_DIR AND PDCURSES_LIBRARY)
|
||||||
target_include_directories(cst-agent PRIVATE ${PDCURSES_INCLUDE_DIR})
|
target_include_directories(cst-agent PRIVATE ${PDCURSES_INCLUDE_DIR})
|
||||||
target_link_libraries(cst-agent PRIVATE ${PDCURSES_LIBRARY})
|
target_link_libraries(cst-agent PRIVATE ${PDCURSES_LIBRARY})
|
||||||
target_compile_definitions(cst-agent PRIVATE CST_USE_PDCURSES=1)
|
# PDCurses suffixes its exported symbols with an ABI tag (endwin_u64_4400
|
||||||
|
# etc.). MSYS2 builds the UTF-8 wide variant, so PDC_FORCE_UTF8 has to be
|
||||||
|
# defined or curses.h maps to the w64 names and the link fails.
|
||||||
|
target_compile_definitions(cst-agent PRIVATE
|
||||||
|
CST_USE_PDCURSES=1 PDC_FORCE_UTF8=1)
|
||||||
message(STATUS "TUI: PDCurses (${PDCURSES_LIBRARY})")
|
message(STATUS "TUI: PDCurses (${PDCURSES_LIBRARY})")
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "CST_BUILD_TUI=ON on Windows requires PDCurses (set PDCurses_ROOT)")
|
message(FATAL_ERROR "CST_BUILD_TUI=ON on Windows requires PDCurses (set PDCurses_ROOT)")
|
||||||
@@ -143,9 +154,9 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "Windows" OR WIN32)
|
if(CMAKE_SYSTEM_NAME STREQUAL "Windows" OR WIN32)
|
||||||
# curl Schannel + networking
|
# curl Schannel + networking; winmm is needed by PDCurses (PlaySoundW)
|
||||||
target_link_libraries(cst-agent PRIVATE
|
target_link_libraries(cst-agent PRIVATE
|
||||||
ws2_32 crypt32 secur32 bcrypt advapi32)
|
ws2_32 crypt32 secur32 bcrypt advapi32 winmm)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# --- tests ---
|
# --- tests ---
|
||||||
|
|||||||
@@ -41,6 +41,35 @@ cmake --build build-win-tui
|
|||||||
Copy `build-win-tui/cst-agent.exe`, `third_party/busybox/busybox.exe`, and
|
Copy `build-win-tui/cst-agent.exe`, `third_party/busybox/busybox.exe`, and
|
||||||
`libwinpthread-1.dll` into one folder.
|
`libwinpthread-1.dll` into one folder.
|
||||||
|
|
||||||
|
## Build natively on Windows (MSYS2)
|
||||||
|
|
||||||
|
The CMake build also works directly on Windows with MSYS2's mingw-w64
|
||||||
|
toolchain -- no separate Linux host needed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# in an MSYS2 MINGW64 shell
|
||||||
|
pacman -S --needed --noconfirm \
|
||||||
|
mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-make \
|
||||||
|
mingw-w64-x86_64-curl mingw-w64-x86_64-pdcurses
|
||||||
|
|
||||||
|
cd agent
|
||||||
|
cmake -B build-win -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release
|
||||||
|
cmake --build build-win --target cst-agent -j"$(nproc)"
|
||||||
|
```
|
||||||
|
|
||||||
|
`CST_BUILD_TUI=ON` (the default) picks up MSYS2's PDCurses automatically,
|
||||||
|
including its `include/pdcurses/` layout; set `-DPDCurses_ROOT=...` only for
|
||||||
|
a custom PDCurses.
|
||||||
|
|
||||||
|
Two differences from the cross-build release layout above:
|
||||||
|
|
||||||
|
- **Extra DLLs.** MSYS2's curl package is the shared OpenSSL build, so the
|
||||||
|
executable needs its whole dependency chain beside it. Collect it with
|
||||||
|
`ldd build-win/cst-agent.exe | grep mingw64`.
|
||||||
|
- **Only build the `cst-agent` target.** Some sources under `tests/` are
|
||||||
|
POSIX-only (two-argument `mkdir`, `setenv`, `arpa/inet.h`, `symlink`) and
|
||||||
|
do not compile with MinGW. The main program is unaffected.
|
||||||
|
|
||||||
## Run
|
## Run
|
||||||
|
|
||||||
```bat
|
```bat
|
||||||
|
|||||||
@@ -111,6 +111,17 @@ void os_localtime(const time_t *t, struct tm *out);
|
|||||||
int os_getpid(void);
|
int os_getpid(void);
|
||||||
int os_chmod_private(const char *path); /* best-effort 0600; no-op/ok on Win */
|
int os_chmod_private(const char *path); /* best-effort 0600; no-op/ok on Win */
|
||||||
|
|
||||||
|
/* --- libc gaps on Windows ------------------------------------------------
|
||||||
|
* MinGW-w64 provides neither strcasestr() (a GNU extension) nor
|
||||||
|
* setenv()/unsetenv() (POSIX): they are simply absent from its headers.
|
||||||
|
* src/tui.c uses all three. Implemented in os_compat.c for _WIN32 only,
|
||||||
|
* so the Unix builds keep using the libc versions. */
|
||||||
|
#if defined(_WIN32)
|
||||||
|
char *strcasestr(const char *haystack, const char *needle);
|
||||||
|
int setenv(const char *name, const char *value, int overwrite);
|
||||||
|
int unsetenv(const char *name);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1168,3 +1168,52 @@ void os_proc_kill(os_proc_t *p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* --- libc gaps on Windows -----------------------------------------------
|
||||||
|
* strcasestr() is a GNU extension and setenv()/unsetenv() are POSIX; glibc
|
||||||
|
* has all three, MinGW-w64 has none of them. src/tui.c needs them (command
|
||||||
|
* filtering and ESCDELAY), so the Windows build supplies its own.
|
||||||
|
*
|
||||||
|
* The case folding here is ASCII-only, unlike glibc's locale-aware version.
|
||||||
|
* That is deliberate: these are used to match command and setting names,
|
||||||
|
* which are ASCII.
|
||||||
|
*/
|
||||||
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
static int ascii_lower(int c) {
|
||||||
|
return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strcasestr(const char *haystack, const char *needle) {
|
||||||
|
if (!haystack || !needle)
|
||||||
|
return NULL;
|
||||||
|
if (!*needle)
|
||||||
|
return (char *)haystack;
|
||||||
|
for (; *haystack; haystack++) {
|
||||||
|
const char *h = haystack;
|
||||||
|
const char *n = needle;
|
||||||
|
while (*h && *n && ascii_lower((unsigned char)*h) == ascii_lower((unsigned char)*n)) {
|
||||||
|
h++;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
if (!*n)
|
||||||
|
return (char *)haystack;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int setenv(const char *name, const char *value, int overwrite) {
|
||||||
|
if (!name || !*name || strchr(name, '='))
|
||||||
|
return -1;
|
||||||
|
if (!overwrite && getenv(name))
|
||||||
|
return 0;
|
||||||
|
return _putenv_s(name, value ? value : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
int unsetenv(const char *name) {
|
||||||
|
if (!name || !*name || strchr(name, '='))
|
||||||
|
return -1;
|
||||||
|
return _putenv_s(name, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|||||||
Reference in New Issue
Block a user