带有MinGW-w64的CMake不会安装内置的DLL,但是可以很好地构建

时间:2019-05-29 14:18:29

标签: cmake mingw-w64

注意:此处引用的文件都在水平标尺下方稍微向下给出了。

这是我遇到的一个项目的MWE。在Ubuntu 16.04上使用的CMake版本是3.12.2(准确地说是16.04.6)。

目标是创建一个CMakeLists.txt,可以使用MinGW-w64工具链(在Ubuntu / Debian中为apt-get install mingw-w64)将其重新定位为构建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的库仅安装了导入库,而不是DLL。我希望看到的是这样的:

-- 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生效,因为导入lib在那里结束。但是为什么在这里完全忽略了内置的.dll

旁注:我知道GNUInstallDirs,但是一旦我开始针对Windows进行交叉编译,那便完全瓦解了。因此,在调用install()之前,我是“手动”设置所需的路径。


build.sh(应为可执行文件)

该脚本将首先擦除文件夹build-nativebuild-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)

1 个答案:

答案 0 :(得分:1)

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上测试了该示例。