带有 MinGW-w64 的 CMake 不会安装内置的 DLL,但它正在构建中
CMake with MinGW-w64 does not install built DLL, but it's being built fine
注意:这里引用的文件都是在水平标尺下方一点点给出的。
这是从我 运行 参与其中的项目派生的 MWE。使用的 CMake 版本是 Ubuntu 16.04(准确地说是 16.04.6)上的 3.12.2。
目标是创建一个 CMakeLists.txt
,可以使用 MinGW-w64 工具链(apt-get install mingw-w64
on Ubuntu/Debian)重新定位以构建 Windows DLL .
当不使用明确的工具链文件时(即没有 -DCMAKE_TOOLCHAIN_FILE=...
),所有工作都按预期进行,lib${PRJNAME}.so
按需要安装。但是,一旦我使用下面给出的工具链文件,我只会得到生成的导入库 ${PRJNAME}Lib.dll.a
而不是安装相应的 .dll
文件。
如果我按如下方式调用 Bash 脚本:
./build.sh 2>&1 |grep '^-- Install'
输出为:
-- Install configuration: ""
-- Installing: /home/user/cmake-test/build-native/install-target/lib/libtest.so
-- Install configuration: ""
-- Installing: /home/user/cmake-test/build-windows/install-target/lib/test.dll.a
如您所见,本机构建安装 actual 共享库,但目标 Windows 仅安装导入库,不动态链接库。我希望看到的是这样的:
-- Install configuration: ""
-- Installing: /home/user/cmake-test/build-native/install-target/lib/libtest.so
-- Install configuration: ""
-- Installing: /home/user/cmake-test/build-windows/install-target/lib/test.dll
-- Installing: /home/user/cmake-test/build-windows/install-target/lib/test.dll.a
我这里做错了什么? install()
函数似乎被正确调用:
install(
TARGETS ${PRJNAME}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT library
)
很明显,ARCHIVE DESTINATION
生效了,因为那是导入库结束的地方。但是为什么这里构建的.dll
完全被忽略了呢?
旁注:我知道 GNUInstallDirs
,但是一旦我开始为 Windows 进行交叉编译,它就完全崩溃了。所以我在调用 install()
.
之前设置了所需的路径 "manually"
build.sh(应该是可执行的)
脚本将首先擦除文件夹 build-native
和 build-windows
(如果存在),然后重新创建它们。然后它将分别从这些文件夹调用 cmake
,分别使用系统(本机)工具链和 MinGW-w64 工具链作为目标。最后但同样重要的是,它将分别从这些文件夹调用安装。
因此,如果您将它与其他文件一起放入一个空文件夹中,则它不会以任何方式干扰您在其他地方的数据。
#/usr/bin/env bash
for i in native windows; do
D=build-$i
test -d $D && rm -rf $D
mkdir $D
[[ "$i" == "windows" ]] && TCFILE=mingw64-64bit.cmake
( set -x; cd $D && cmake .. -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=. ${TCFILE+-DCMAKE_TOOLCHAIN_FILE=$TCFILE} -DCMAKE_VERBOSE_MAKEFILE=ON )
( set -x; cd $D && cmake --build . --target install )
done
test.cpp
#ifdef _WIN32
# if defined(test_EXPORTS)
# define TEST_API __declspec(dllexport)
# else
# define TEST_API __declspec(dllimport)
# endif
#else
# define TEST_API
#endif
TEST_API void SomeFunction()
{
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.12)
set(PRJNAME test)
set(TARGET_DIR "${CMAKE_CURRENT_BINARY_DIR}/install-target")
project(${PRJNAME})
add_library(${PRJNAME} SHARED test.cpp)
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
set(DLL_PREFIX)
set(DLL_POSTFIX Lib)
else()
set(DLL_PREFIX lib)
set(DLL_POSTFIX)
endif()
set_target_properties(
${PRJNAME}
PROPERTIES
PREFIX "${DLL_PREFIX}"
IMPORT_PREFIX "${DLL_PREFIX}"
DEBUG_POSTFIX "${DLL_POSTFIX}"
RELEASE_POSTFIX "${DLL_POSTFIX}"
CXX_STANDARD 11
CXX_EXTENSIONS OFF
CXX_STANDARD_REQUIRED ON
POSITION_INDEPENDENT_CODE 1
)
set(CMAKE_INSTALL_PREFIX ${TARGET_DIR})
set(CMAKE_INSTALL_LIBDIR lib)
set(CMAKE_INSTALL_INCLUDEDIR include)
install(
TARGETS ${PRJNAME}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT library
)
mingw64-64bit.cmake
set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc-posix)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++-posix)
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
install(
TARGETS ${PRJNAME}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT library
)
根据 install
命令文档,DLL 文件被视为运行时对象。我在 Ubuntu 14.04.
上测试了这个例子
注意:这里引用的文件都是在水平标尺下方一点点给出的。
这是从我 运行 参与其中的项目派生的 MWE。使用的 CMake 版本是 Ubuntu 16.04(准确地说是 16.04.6)上的 3.12.2。
目标是创建一个 CMakeLists.txt
,可以使用 MinGW-w64 工具链(apt-get install mingw-w64
on Ubuntu/Debian)重新定位以构建 Windows DLL .
当不使用明确的工具链文件时(即没有 -DCMAKE_TOOLCHAIN_FILE=...
),所有工作都按预期进行,lib${PRJNAME}.so
按需要安装。但是,一旦我使用下面给出的工具链文件,我只会得到生成的导入库 ${PRJNAME}Lib.dll.a
而不是安装相应的 .dll
文件。
如果我按如下方式调用 Bash 脚本:
./build.sh 2>&1 |grep '^-- Install'
输出为:
-- Install configuration: ""
-- Installing: /home/user/cmake-test/build-native/install-target/lib/libtest.so
-- Install configuration: ""
-- Installing: /home/user/cmake-test/build-windows/install-target/lib/test.dll.a
如您所见,本机构建安装 actual 共享库,但目标 Windows 仅安装导入库,不动态链接库。我希望看到的是这样的:
-- Install configuration: ""
-- Installing: /home/user/cmake-test/build-native/install-target/lib/libtest.so
-- Install configuration: ""
-- Installing: /home/user/cmake-test/build-windows/install-target/lib/test.dll
-- Installing: /home/user/cmake-test/build-windows/install-target/lib/test.dll.a
我这里做错了什么? install()
函数似乎被正确调用:
install(
TARGETS ${PRJNAME}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT library
)
很明显,ARCHIVE DESTINATION
生效了,因为那是导入库结束的地方。但是为什么这里构建的.dll
完全被忽略了呢?
旁注:我知道 GNUInstallDirs
,但是一旦我开始为 Windows 进行交叉编译,它就完全崩溃了。所以我在调用 install()
.
build.sh(应该是可执行的)
脚本将首先擦除文件夹 build-native
和 build-windows
(如果存在),然后重新创建它们。然后它将分别从这些文件夹调用 cmake
,分别使用系统(本机)工具链和 MinGW-w64 工具链作为目标。最后但同样重要的是,它将分别从这些文件夹调用安装。
因此,如果您将它与其他文件一起放入一个空文件夹中,则它不会以任何方式干扰您在其他地方的数据。
#/usr/bin/env bash
for i in native windows; do
D=build-$i
test -d $D && rm -rf $D
mkdir $D
[[ "$i" == "windows" ]] && TCFILE=mingw64-64bit.cmake
( set -x; cd $D && cmake .. -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=. ${TCFILE+-DCMAKE_TOOLCHAIN_FILE=$TCFILE} -DCMAKE_VERBOSE_MAKEFILE=ON )
( set -x; cd $D && cmake --build . --target install )
done
test.cpp
#ifdef _WIN32
# if defined(test_EXPORTS)
# define TEST_API __declspec(dllexport)
# else
# define TEST_API __declspec(dllimport)
# endif
#else
# define TEST_API
#endif
TEST_API void SomeFunction()
{
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.12)
set(PRJNAME test)
set(TARGET_DIR "${CMAKE_CURRENT_BINARY_DIR}/install-target")
project(${PRJNAME})
add_library(${PRJNAME} SHARED test.cpp)
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
set(DLL_PREFIX)
set(DLL_POSTFIX Lib)
else()
set(DLL_PREFIX lib)
set(DLL_POSTFIX)
endif()
set_target_properties(
${PRJNAME}
PROPERTIES
PREFIX "${DLL_PREFIX}"
IMPORT_PREFIX "${DLL_PREFIX}"
DEBUG_POSTFIX "${DLL_POSTFIX}"
RELEASE_POSTFIX "${DLL_POSTFIX}"
CXX_STANDARD 11
CXX_EXTENSIONS OFF
CXX_STANDARD_REQUIRED ON
POSITION_INDEPENDENT_CODE 1
)
set(CMAKE_INSTALL_PREFIX ${TARGET_DIR})
set(CMAKE_INSTALL_LIBDIR lib)
set(CMAKE_INSTALL_INCLUDEDIR include)
install(
TARGETS ${PRJNAME}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT library
)
mingw64-64bit.cmake
set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc-posix)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++-posix)
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
install(
TARGETS ${PRJNAME}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT library
)
根据 install
命令文档,DLL 文件被视为运行时对象。我在 Ubuntu 14.04.