【c++】UCRT64 原生工具链
使用msys2虚拟环境
pacman -S make
pacman -S --needed mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-make
which gcc # 必须输出 /ucrt64/bin/gcc
which cmake # 必须输出 /ucrt64/bin/cmake
which make # 输出 /ucrt64/bin/make 或 /ucrt64/bin/mingw32-make
which gcc && which cmake && which make
为什么安装了mingw-w64-ucrt-x86_64-make 还是去到了mingw的make
你的 which make 仍然指向 /usr/bin/make(MSYS2 版本),而不是 /ucrt64/bin/make(UCRT64 版本),是因为 PATH 的顺序问题:虽然 UCRT64 终端通常会把 /ucrt64/bin 放在最前面,但有时 /usr/bin 还是会出现在更前面(比如 /etc/profile 或用户 ~/.bashrc 里的干扰),导致 make 找到了 MSYS 版本。
编辑 ~/.bashrc 或 ~/.profile,在最末尾加上:
export PATH="/ucrt64/bin:$PATH"
保存后,重新打开 UCRT64 终端,make 就会指到 UCRT64 版本。
应该指出 UCRT64 的 make 包安装后,可执行文件名为 mingw32-make.exe,位于 /ucrt64/bin/,但可能没有 make 这个链接。所以直接使用 mingw32-make -v。或者创建链接:ln -s /ucrt64/bin/mingw32-make.exe /ucrt64/bin/make.exe,并确保 /ucrt64/bin 在 PATH 最前。
创建一个 make 软链接
bash
ln -s /ucrt64/bin/mingw32-make.exe /ucrt64/bin/make.exe
之后 make -v 就能正常工作了。(确保 /ucrt64/bin 在 PATH 靠前位置)
编译只生成dll 没有a
1. 先分清这两个文件的作用
libhiredis.dll:动态链接库,运行时必须和你的.exe放在一起。libhiredis.dll.a:这是动态库的导入库(import library),用来告诉链接器 “这个符号在 DLL 里”,编译时需要它,运行时不需要。libhiredis.a:这是纯静态库(static library),编译时会直接把所有代码打包进你的.exe,运行时不需要 DLL。
2. 为什么你现在只有 libhiredis.dll 和 libhiredis.dll.a?
因为你用的 CMake 参数是:
bash
运行
-DBUILD_SHARED_LIBS=ON
这个参数的意思是:
- 只构建 动态库(
.dll+.dll.a) - 不构建 静态库(
.a)
所以它不会生成 libhiredis.a,这是正常的,不是编译失败。
3. 如果你需要 .a 静态库
你可以这样重新编译:
bash
运行
# 清空旧的 build 目录
rmdir /s /q build2
mkdir build2 && cd build2
# 构建静态库(关闭动态库)
cmake .. -G "MinGW Makefiles" ^
-DBUILD_SHARED_LIBS=OFF ^
-DENABLE_TESTS=OFF ^
-DCMAKE_C_FLAGS="-lpthread"
mingw32-make
这次你会看到 libhiredis.a 生成出来。
4. 现在你已经有的 .dll 能用吗?
完全可以!你项目里这样链接即可:
cmake
target_link_libraries(你的项目 PRIVATE hiredis ws2_32)
编译时 CMake 会自动找到 libhiredis.dll.a,运行时把 libhiredis.dll 和 .exe 放一起就行。
5. 给你一个快速判断方法
- 要带 DLL 跑:就用现在的
libhiredis.dll+libhiredis.dll.a - 要单文件 exe:就用
libhiredis.a静态库,编译后不用带 DLL
如何同时生成静态库 .a
明确指定目标:
bash
mingw32-make libhiredis.a # 只生成静态库
mingw32-make all # 如果 all 目标同时包含 static 和 dynamic,则生成两者
或者一次性构建所有支持的产物:
bash
mingw32-make dynamic static # 若 Makefile 两者都支持
hiredis win 编译流程
手动增加pthread库,因为mingw 升级不支持旧的方法了
IF(WIN32)
TARGET_LINK_LIBRARIES(hiredis PUBLIC ws2_32 crypt32 pthread)
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
TARGET_LINK_LIBRARIES(hiredis PUBLIC m)
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "SunOS")
TARGET_LINK_LIBRARIES(hiredis PUBLIC socket)
ENDIF()
为什么低版本mingw32能编译hiredis通过,高版本不可以
你在两个环境下都用 CMake 生成的 Makefile 编译 `test.c`,但结果不同,原因在于**编译器默认的语言标准(C 标准版本)不同**,导致对“隐式函数声明”的处理方式不一样。
---
### 🔍 为什么一个报错(error),一个只是警告(warning)?
- **MSYS2 UCRT64 的 GCC 15.2.0**(你之前日志中的版本)默认使用 `-std=gnu17` 或 `-std=c17` 等较新的标准。
在 C99 及以后的 C 标准中,**隐式函数声明(在没有函数原型的情况下调用函数)是违反标准的约束性错误**,GCC 会将其视为错误,并拒绝生成目标文件,因此编译失败。
- **Windows 独立安装的 MinGW-w64** 通常默认使用 `-std=gnu89` 或 `-std=gnu11` 等更老的 GNU 方言,在这些模式下,隐式声明仅被视为警告,仍会生成目标文件并继续链接。
链接阶段恰好能找到 `usleep`(虽然它可能来自某个库,或者被容错的链接器处理了),所以最终生成 `hiredis-test.exe`。
**核心差异**:两个 GCC 的默认语言标准不同,导致对同一行代码的严格程度截然相反。
---
### ✅ 如何在 MSYS2 UCRT64 中也编译通过(保留 CMake 流程)
既然你坚持使用 CMake + make,只需让编译器对 `test.c` 采用宽松的 C 标准,或者修复代码本身。推荐两种方法:
#### 方法一:修补 `test.c`(一劳永逸)
在 `test.c` 开头(所有 `#include` 之前)添加 Windows 兼容宏:
```c
#ifdef _WIN32
#include <windows.h>
#define usleep(us) Sleep((us) / 1000)
#endif
```
然后重新编译。这样显式声明了函数,彻底消除错误。
#### 方法二:强制 CMake 为测试目标设置宽松的 C 标准
在 `CMakeLists.txt` 中找到添加测试目标的地方(通常有 `add_executable(hiredis-test ...)`),在其后加入:
```cmake
set_target_properties(hiredis-test PROPERTIES C_STANDARD 90)
```
或
```cmake
target_compile_options(hiredis-test PRIVATE -std=gnu89)
```
然后**完全删除 build 目录**,重新 `cmake` 并 `make`。这会让 GCC 以宽松模式编译 `test.c`,隐式声明就不再是错误。
---
### 📌 总结
| 环境 | 编译器默认标准 | 隐式声明结果 |
|------|---------------|--------------|
| MSYS2 UCRT64 GCC | 新标准 (C17/gnu17) | **错误,编译停止** |
| 独立 MinGW-w64 GCC | 旧标准 (gnu89/gnu11) | 警告,继续链接 |
所以,你只需要让 MSYS2 的 GCC 也用老标准或修补代码,就能像独立 MinGW 那样顺利生成测试程序。不过如果你只想要 hiredis 库本身,**最简单的仍然是在 CMake 配置时彻底禁用测试**(删除 build 后加 `-DBUILD_TESTS=OFF`),完全避免 `test.c` 的编译。
hiredis的cmakelist中有一段这个,这个类调用了Linux方法
IF(NOT DISABLE_TESTS)
ENABLE_TESTING()
ADD_EXECUTABLE(hiredis-test test.c)
TARGET_LINK_LIBRARIES(hiredis-test hiredis)
IF(ENABLE_SSL_TESTS)
ADD_DEFINITIONS(-DHIREDIS_TEST_SSL=1)
TARGET_LINK_LIBRARIES(hiredis-test hiredis_ssl)
ENDIF()
IF(ENABLE_ASYNC_TESTS)
ADD_DEFINITIONS(-DHIREDIS_TEST_ASYNC=1)
TARGET_LINK_LIBRARIES(hiredis-test event)
ENDIF()
ADD_TEST(NAME hiredis-test
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test.sh)
ENDIF()
编译的时候需要关闭这个文件
cmake .. -G "MinGW Makefiles" -DDISABLE_TESTS=ON
更多推荐



所有评论(0)