CMake 3.8.0 在 makefile 中生成错误的 link 命令
CMake 3.8.0 generates wrong link command in makefiles
问题:
在我 运行 cmake 生成一个带有 STATIC 库的项目并成功完成后,ninja 和 mingw32-make 都无法在链接时建立它们的目标。对于 SHARED 库或可执行文件,同样的设置工作正常。我已经为 "Ninja" 和 "MinGW Makefiles" 生成器尝试了这个:
忍者输出:
[2/2] Linking CXX static library hello_wsl.lib
FAILED: hello_wsl.lib
cmd.exe /C "cd . && "C:\Program Files\CMake\bin\cmake.exe" -E remove hello_wsl.lib && "" qc hello_wsl.lib CMakeFiles/hello_wsl.dir/lib_hello_world.cpp.obj && cd ."
"""" no se reconoce como un comando interno o externo,
programa o archivo por lotes ejecutable.
ninja: build stopped: subcommand failed.
mingw32-make 输出:
Scanning dependencies of target hello_wsl
[ 50%] Building CXX object CMakeFiles/hello_wsl.dir/lib_hello_world.cpp.obj
[100%] Linking CXX static library hello_wsl.lib
Error running link command: El parámetro no es correcto
CMakeFiles\hello_wsl.dir\build.make:93: recipe for target 'hello_wsl.lib' failed
mingw32-make.exe[2]: *** [hello_wsl.lib] Error 2
CMakeFiles\Makefile2:66: recipe for target 'CMakeFiles/hello_wsl.dir/all' failed
mingw32-make.exe[1]: *** [CMakeFiles/hello_wsl.dir/all] Error 2
Makefile:82: recipe for target 'all' failed
mingw32-make.exe: *** [all] Error 2
也看看 "project_root\build\CMakeFiles\hello_wsl.dir\link.txt" 生成的 "MinGW Makefiles":
"" qc hello_wsl.lib CMakeFiles/hello_wsl.dir/lib_hello_world.cpp.obj
示例项目,按步骤重现 "MinGW Makefiles" 的问题:
- 安装CMake 3.8.0
- 安装 MinGWx64 6.3 windows 二进制文件 (I've downloaded them from here)
- 为此项目创建一个根文件夹,我将在本示例中将其命名为 project_root。
- 在里面创建这些子文件夹:
- project_root\build
- project_root\include
- project_root\include\lib_hello_world
创建这些文件:
project_root\include\lib_hello_world\lib_hello_world.cpp:
#include <iostream>
class HelloWorldClass{
HelloWorldClass(){
std::cout << "Hello, world!" << std::endl;
}
};
project_root\include\lib_hello_world\CMakeLists.txt:
cmake_minimum_required(VERSION 3.8.0)
project(lib_hello_world)
add_library(lib_hello_world STATIC lib_hello_world.cpp)
project_root\toolchain.cmake:
# Target system (cross compile)
set(CMAKE_SYSTEM_NAME WindowsStore)
set(CMAKE_SYSTEM_VERSION 10.0)
# BIN utils
SET(CMAKE_AR "$ENV{MINGW_W64_BIN_DIR}/ar.exe")
SET(CMAKE_OBJCOPY "$ENV{MINGW_W64_BIN_DIR}/objcopy.exe")
SET(CMAKE_OBJDUMP "$ENV{MINGW_W64_BIN_DIR}/objdump.exe")
SET(CMAKE_RANLIB "$ENV{MINGW_W64_BIN_DIR}/ranlib.exe")
SET(CMAKE_NM "$ENV{MINGW_W64_BIN_DIR}/nm.exe")
SET(CMAKE_STRIP "$ENV{MINGW_W64_BIN_DIR}/strip.exe")
# C compiler
SET(CMAKE_C_COMPILER "$ENV{MINGW_W64_BIN_DIR}/gcc.exe")
# CXX compiler
SET(CMAKE_CXX_COMPILER "$ENV{MINGW_W64_BIN_DIR}/g++.exe")
# LINKER
SET(CMAKE_LINKER "$ENV{MINGW_W64_BIN_DIR}/ld.bfd.exe")
project_root\configure.bat:
@ECHO OFF
SETLOCAL
@ECHO OFF
REM Change these variables to the corresponding paths on your own system
SET "CMAKE_EXECUTABLE=C:\Program Files\CMake\bin\cmake.exe"
SET "MINGW_W64_BIN_DIR=C:/Program Files/MinGWx64/bin"
CD "%~dp0\build"
CALL "%CMAKE_EXECUTABLE%" "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON" "-DCMAKE_BUILD_TYPE=Debug" -G "MinGW Makefiles" "-DCMAKE_MAKE_PROGRAM='%MINGW_W64_BIN_DIR%/mingw32-make.exe'" "-DCMAKE_TOOLCHAIN_FILE='%~dp0/toolchain.cmake'" "%~dp0/include/lib_hello_world"
ENDLOCAL
project_root\build.bat:
@ECHO OFF
SETLOCAL
@ECHO OFF
REM Change this variable to the corresponding path on your own system
SET "MINGW_W64_BIN_DIR=C:/Program Files/MinGWx64/bin"
CD "%~dp0\build"
CALL "%MINGW_W64_BIN_DIR%/mingw32-make.exe"
ENDLOCAL
最后,打开CMD并运行命令:
project_root\configure.bat
project_root\build.bat
这是我发现的粗略 fix/workaround:
创建这个文件:
project_root\fix.bat:
@ECHO OFF
SETLOCAL
@ECHO OFF
MOVE "%~dp0\build\CMakeCache.txt" ".\"
RMDIR "%~dp0\build" /S /Q
MKDIR "%~dp0\build"
MOVE "%~dp0\CMakeCache.txt" ".\build\"
ENDLOCAL
重现错误后,打开CMD和运行:
project_root\fix.bat
project_root\configure.bat
project_root\build.bat
修复后的ninja输出(链接成功):
[2/2] Linking CXX static library hello_wsl.lib
mingw32-make after fix(链接成功):
Scanning dependencies of target hello_wsl
[ 50%] Building CXX object CMakeFiles/hello_wsl.dir/lib_hello_world.cpp.obj
[100%] Linking CXX static library hello_wsl.lib
[100%] Built target hello_wsl
为了解决这个问题,我做了一些事情:
我备份了 CMakeCache.txt (CMakeCache.txt.before_fix),然后再应用修复并重新运行 配置和构建。重新配置并成功构建项目后,CMakeCache.txt.before_fix 和 CMakeCache.txt 文件之间没有区别。
我也备份了"rules.ninja"然后和FC对比。这是 FC "project_root\rules.ninja.before_fix" "project_root\build\rules.ninja":
的输出
Comparando archivos .\rules.ninja.before_fix y .\BUILD\RULES.NINJA
***** .\rules.ninja.before_fix
rule CXX_STATIC_LIBRARY_LINKER__lib_hello_world
command = cmd.exe /C "$PRE_LINK && "C:\Program Files\CMake\bin\cmake.exe" -E remove $TARGET_FILE && "" qc $TARGET_FILE $LINK_
FLAGS $in && $POST_BUILD"
description = Linking CXX static library $TARGET_FILE
***** .\BUILD\RULES.NINJA
rule CXX_STATIC_LIBRARY_LINKER__lib_hello_world
command = cmd.exe /C "$PRE_LINK && "C:\Program Files\CMake\bin\cmake.exe" -E remove $TARGET_FILE && C:\PROGRA~1\MinGWx64\bin\
ar.exe qc $TARGET_FILE $LINK_FLAGS $in && C:\PROGRA~1\MinGWx64\bin\ranlib.exe $TARGET_FILE && $POST_BUILD"
description = Linking CXX static library $TARGET_FILE
*****
并对 "MinGW Makefiles" 做了同样的事情。这是 FC "project_root\link.txt.before_fix" "project_root\build\CMakeFiles\lib_hello_world.dir\link.txt":
的输出
Comparando archivos .\link.txt.before_fix y .\BUILD\CMAKEFILES\LIB_HELLO_WORLD.DIR\LINK.TXT
***** .\link.txt.before_fix
"" qc hello_wsl.lib CMakeFiles/hello_wsl.dir/lib_hello_world.cpp.obj
***** .\BUILD\CMAKEFILES\LIB_HELLO_WORLD.DIR\LINK.TXT
C:\PROGRA~1\MinGWx64\bin\ar.exe qc lib_hello_world.lib CMakeFiles/lib_hello_world.dir/lib_hello_world.cpp.obj
C:\PROGRA~1\MinGWx64\bin\ranlib.exe lib_hello_world.lib
*****
关于 CMAKE_AR 和 CMAKE_RUNLIB 变量有一些具体说明:根据 bugreport 它们应该声明为 CACHED:
SET(CMAKE_AR "$ENV{MINGW_W64_BIN_DIR}/ar.exe" CACHE FILEPATH "Arhiver")
SET(CMAKE_RANLIB "$ENV{MINGW_W64_BIN_DIR}/ranlib.exe" CACHE FILEPATH "Runlib")
问题:
在我 运行 cmake 生成一个带有 STATIC 库的项目并成功完成后,ninja 和 mingw32-make 都无法在链接时建立它们的目标。对于 SHARED 库或可执行文件,同样的设置工作正常。我已经为 "Ninja" 和 "MinGW Makefiles" 生成器尝试了这个:
忍者输出:
[2/2] Linking CXX static library hello_wsl.lib
FAILED: hello_wsl.lib
cmd.exe /C "cd . && "C:\Program Files\CMake\bin\cmake.exe" -E remove hello_wsl.lib && "" qc hello_wsl.lib CMakeFiles/hello_wsl.dir/lib_hello_world.cpp.obj && cd ."
"""" no se reconoce como un comando interno o externo,
programa o archivo por lotes ejecutable.
ninja: build stopped: subcommand failed.
mingw32-make 输出:
Scanning dependencies of target hello_wsl
[ 50%] Building CXX object CMakeFiles/hello_wsl.dir/lib_hello_world.cpp.obj
[100%] Linking CXX static library hello_wsl.lib
Error running link command: El parámetro no es correcto
CMakeFiles\hello_wsl.dir\build.make:93: recipe for target 'hello_wsl.lib' failed
mingw32-make.exe[2]: *** [hello_wsl.lib] Error 2
CMakeFiles\Makefile2:66: recipe for target 'CMakeFiles/hello_wsl.dir/all' failed
mingw32-make.exe[1]: *** [CMakeFiles/hello_wsl.dir/all] Error 2
Makefile:82: recipe for target 'all' failed
mingw32-make.exe: *** [all] Error 2
也看看 "project_root\build\CMakeFiles\hello_wsl.dir\link.txt" 生成的 "MinGW Makefiles":
"" qc hello_wsl.lib CMakeFiles/hello_wsl.dir/lib_hello_world.cpp.obj
示例项目,按步骤重现 "MinGW Makefiles" 的问题:
- 安装CMake 3.8.0
- 安装 MinGWx64 6.3 windows 二进制文件 (I've downloaded them from here)
- 为此项目创建一个根文件夹,我将在本示例中将其命名为 project_root。
- 在里面创建这些子文件夹:
- project_root\build
- project_root\include
- project_root\include\lib_hello_world
创建这些文件:
project_root\include\lib_hello_world\lib_hello_world.cpp:
#include <iostream> class HelloWorldClass{ HelloWorldClass(){ std::cout << "Hello, world!" << std::endl; } };
project_root\include\lib_hello_world\CMakeLists.txt:
cmake_minimum_required(VERSION 3.8.0) project(lib_hello_world) add_library(lib_hello_world STATIC lib_hello_world.cpp)
project_root\toolchain.cmake:
# Target system (cross compile) set(CMAKE_SYSTEM_NAME WindowsStore) set(CMAKE_SYSTEM_VERSION 10.0) # BIN utils SET(CMAKE_AR "$ENV{MINGW_W64_BIN_DIR}/ar.exe") SET(CMAKE_OBJCOPY "$ENV{MINGW_W64_BIN_DIR}/objcopy.exe") SET(CMAKE_OBJDUMP "$ENV{MINGW_W64_BIN_DIR}/objdump.exe") SET(CMAKE_RANLIB "$ENV{MINGW_W64_BIN_DIR}/ranlib.exe") SET(CMAKE_NM "$ENV{MINGW_W64_BIN_DIR}/nm.exe") SET(CMAKE_STRIP "$ENV{MINGW_W64_BIN_DIR}/strip.exe") # C compiler SET(CMAKE_C_COMPILER "$ENV{MINGW_W64_BIN_DIR}/gcc.exe") # CXX compiler SET(CMAKE_CXX_COMPILER "$ENV{MINGW_W64_BIN_DIR}/g++.exe") # LINKER SET(CMAKE_LINKER "$ENV{MINGW_W64_BIN_DIR}/ld.bfd.exe")
project_root\configure.bat:
@ECHO OFF SETLOCAL @ECHO OFF REM Change these variables to the corresponding paths on your own system SET "CMAKE_EXECUTABLE=C:\Program Files\CMake\bin\cmake.exe" SET "MINGW_W64_BIN_DIR=C:/Program Files/MinGWx64/bin" CD "%~dp0\build" CALL "%CMAKE_EXECUTABLE%" "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON" "-DCMAKE_BUILD_TYPE=Debug" -G "MinGW Makefiles" "-DCMAKE_MAKE_PROGRAM='%MINGW_W64_BIN_DIR%/mingw32-make.exe'" "-DCMAKE_TOOLCHAIN_FILE='%~dp0/toolchain.cmake'" "%~dp0/include/lib_hello_world" ENDLOCAL
project_root\build.bat:
@ECHO OFF SETLOCAL @ECHO OFF REM Change this variable to the corresponding path on your own system SET "MINGW_W64_BIN_DIR=C:/Program Files/MinGWx64/bin" CD "%~dp0\build" CALL "%MINGW_W64_BIN_DIR%/mingw32-make.exe" ENDLOCAL
最后,打开CMD并运行命令:
project_root\configure.bat project_root\build.bat
这是我发现的粗略 fix/workaround:
创建这个文件: project_root\fix.bat:
@ECHO OFF SETLOCAL @ECHO OFF MOVE "%~dp0\build\CMakeCache.txt" ".\" RMDIR "%~dp0\build" /S /Q MKDIR "%~dp0\build" MOVE "%~dp0\CMakeCache.txt" ".\build\" ENDLOCAL
重现错误后,打开CMD和运行:
project_root\fix.bat project_root\configure.bat project_root\build.bat
修复后的ninja输出(链接成功):
[2/2] Linking CXX static library hello_wsl.lib
mingw32-make after fix(链接成功):
Scanning dependencies of target hello_wsl [ 50%] Building CXX object CMakeFiles/hello_wsl.dir/lib_hello_world.cpp.obj [100%] Linking CXX static library hello_wsl.lib [100%] Built target hello_wsl
为了解决这个问题,我做了一些事情:
我备份了 CMakeCache.txt (CMakeCache.txt.before_fix),然后再应用修复并重新运行 配置和构建。重新配置并成功构建项目后,CMakeCache.txt.before_fix 和 CMakeCache.txt 文件之间没有区别。
我也备份了"rules.ninja"然后和FC对比。这是 FC "project_root\rules.ninja.before_fix" "project_root\build\rules.ninja":
的输出Comparando archivos .\rules.ninja.before_fix y .\BUILD\RULES.NINJA ***** .\rules.ninja.before_fix rule CXX_STATIC_LIBRARY_LINKER__lib_hello_world command = cmd.exe /C "$PRE_LINK && "C:\Program Files\CMake\bin\cmake.exe" -E remove $TARGET_FILE && "" qc $TARGET_FILE $LINK_ FLAGS $in && $POST_BUILD" description = Linking CXX static library $TARGET_FILE ***** .\BUILD\RULES.NINJA rule CXX_STATIC_LIBRARY_LINKER__lib_hello_world command = cmd.exe /C "$PRE_LINK && "C:\Program Files\CMake\bin\cmake.exe" -E remove $TARGET_FILE && C:\PROGRA~1\MinGWx64\bin\ ar.exe qc $TARGET_FILE $LINK_FLAGS $in && C:\PROGRA~1\MinGWx64\bin\ranlib.exe $TARGET_FILE && $POST_BUILD" description = Linking CXX static library $TARGET_FILE *****
并对 "MinGW Makefiles" 做了同样的事情。这是 FC "project_root\link.txt.before_fix" "project_root\build\CMakeFiles\lib_hello_world.dir\link.txt":
的输出Comparando archivos .\link.txt.before_fix y .\BUILD\CMAKEFILES\LIB_HELLO_WORLD.DIR\LINK.TXT ***** .\link.txt.before_fix "" qc hello_wsl.lib CMakeFiles/hello_wsl.dir/lib_hello_world.cpp.obj ***** .\BUILD\CMAKEFILES\LIB_HELLO_WORLD.DIR\LINK.TXT C:\PROGRA~1\MinGWx64\bin\ar.exe qc lib_hello_world.lib CMakeFiles/lib_hello_world.dir/lib_hello_world.cpp.obj C:\PROGRA~1\MinGWx64\bin\ranlib.exe lib_hello_world.lib *****
关于 CMAKE_AR 和 CMAKE_RUNLIB 变量有一些具体说明:根据 bugreport 它们应该声明为 CACHED:
SET(CMAKE_AR "$ENV{MINGW_W64_BIN_DIR}/ar.exe" CACHE FILEPATH "Arhiver")
SET(CMAKE_RANLIB "$ENV{MINGW_W64_BIN_DIR}/ranlib.exe" CACHE FILEPATH "Runlib")