【问题标题】:OS specific instructions in CMAKE: How to?CMAKE 中的操作系统特定说明:如何?
【发布时间】:2022-01-11 08:52:32
【问题描述】:

我是 CMAKE 的初学者。下面是一个简单的 cmake 文件,它在 mingw 环境窗口中运行良好。问题显然出在我正在链接 libwsock32.a 的 CMAKE 的 target_link_libraries() 函数上。在 Windows 中,这是可行的,我得到了结果。

但是,正如预期的那样,在 Linux 中,/usr/bin/ld 将查找在 Linux 操作系统上不存在的-lwsock32

我的问题是:如何指示 CMAKE 避免在 Linux 操作系统中链接 wsock32 库???

任何帮助将不胜感激。

我的简单 CMake 文件:

 PROJECT(biourl)
 set (${PROJECT_NAME}_headers ./BioSocketAddress.h  ./BioSocketBase.h ./BioSocketBuffer.h ./BioSocketCommon.h  ./BioSocketListener.h  ./BioSocketPrivate.h  ./BioSocketStream.h ./BioUrl.h BioDatabase.h )

set (${PROJECT_NAME}_sources BioSocketAddress.C  BioSocketBase.C  BioSocketCommon.C BioSocketStream.C  BioUrl.C BioDatabase.C )

add_library(${PROJECT_NAME} STATIC ${${PROJECT_NAME}_headers} ${${PROJECT_NAME}_sources} )

# linkers
#find_library(ws NAMES wsock32 PATHS ${PROJECT_SOURCE_DIR} NO_SYSTEM_ENVIRONMENT_PATH NO_DEFAULT_PATH)

target_link_libraries(${PROJECT_NAME} bioutils wsock32)

install (TARGETS ${PROJECT_NAME}
       RUNTIME DESTINATION bin
       LIBRARY DESTINATION lib
       ARCHIVE DESTINATION lib/archive )

【问题讨论】:

    标签: c++ linux cmake mingw portability


    【解决方案1】:

    使用

    if (WIN32)
        #do something
    endif (WIN32)
    

    if (UNIX)
        #do something
    endif (UNIX)
    

    if (MSVC)
        #do something
    endif (MSVC)
    

    或类似

    CMake Useful VariablesCMake Checking Platform

    【讨论】:

    【解决方案2】:

    鉴于这是一个常见的问题,geronto-posting:

        if(UNIX AND NOT APPLE)
            set(LINUX TRUE)
        endif()
    
        # if(NOT LINUX) should work, too, if you need that
        if(LINUX) 
            message(STATUS ">>> Linux")
            # linux stuff here
        else()
            message(STATUS ">>> Not Linux")
            # stuff that should happen not on Linux 
        endif()
    

    CMake boolean logic docs

    CMake platform names, etc.

    【讨论】:

    • 感谢您提及APPLE
    • @VictorSergienko Всегда рад помочь :)
    • 不要假设 unix 是 linux。链接到 cmake_system_name 的 cmake 有用变量网站。使用 Linux 混合大小写操作系统检测器
    • tibur 的回答比较好
    • 是的,FreeBSD 也将通过 (UNIX AND NOT APPLE) ... 而 @mlvljr 的链接现在已更改为:gitlab.kitware.com/cmake/community/-/wikis/doc/tutorials/…
    【解决方案3】:

    一般情况

    您可以像这样为多个操作系统检测和指定变量:

    检测 Microsoft Windows

    if(WIN32)
        # for Windows operating system in general
    endif()
    

    或者:

    if(MSVC OR MSYS OR MINGW)
        # for detecting Windows compilers
    endif()
    

    检测 Apple MacOS

    if(APPLE)
        # for MacOS X or iOS, watchOS, tvOS (since 3.10.3)
    endif()
    

    检测 Unix 和 Linux

    if(UNIX AND NOT APPLE)
        # for Linux, BSD, Solaris, Minix
    endif()
    

    您的特定链接器问题

    要解决您使用特定于 Windows 的 wsock32 库的问题,只需将其从其他系统中删除,如下所示:

    if(WIN32)
        target_link_libraries(${PROJECT_NAME} bioutils wsock32)
    else
        target_link_libraries(${PROJECT_NAME} bioutils)
    endif()
    

    【讨论】:

    • Solaris 有什么用途?
    • 错字:MSVS 应该是 MSVC。我尝试为您编辑它,但由于某种原因,stackoverflow 不允许少于 6 个字符的编辑...
    • 根据文档,“APPLE”仅暗示我们正在为苹果目标构建;即 OSX,还有 iOS、watchOS 等。有什么方法可以可靠地检测 os X?
    • @Julien 如果您正在为 iOS、tvOS 或 watchOS 构建,您很可能会使用 cmake 工具链文件,该文件应该设置某种变量在那里可以用来实现你正在寻找的东西。
    • @Julien FWIW:cmake documentation 仅确认它还包括 iOS、watchOS、tvOS,因为3.10.3
    【解决方案4】:

    你有一些来自CMAKE的特殊话,看看:

    if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
        // do something for Linux
    else
        // do something for other OS
    

    【讨论】:

    • 标准 CMake 方式:internally-inconsistent :) [这是一个正确/中肯的答案]
    • 对于那些搜索,这里是名称列表github.com/Kitware/CMake/blob/master/Modules/…
    • STREQUAL 接受变量(除了字符串)作为第一个操作数,所以它可能更简洁 if(CMAKE_SYSTEM_NAME STREQUAL "Linux")...
    • @AdN 你确定它只在第一个操作数上吗?例如,if(CMAKE_CXX_COMPILER_ID STREQUAL MSVC) 将不起作用,因为 MSVC 恰好是一个变量。
    • @JohanBoulé 它还接受第二个操作数的变量(cmake.org/cmake/help/latest/command/if.html#comparisons)。尽管具有误导性,但我的评论并没有真正声称它适用于第一个操作数,但对于这个特定的答案,它只对第一个操作数有意义; )
    【解决方案5】:

    生成器表达式也是可能的:

    target_link_libraries(
        target_name
        PUBLIC
            libA
            $<$<PLATFORM_ID:Windows>:wsock32>
        PRIVATE
            $<$<PLATFORM_ID:Linux>:libB>
            libC
    )
    

    这将在 Windows 上链接 libA、wsock32 和 libC,在 Linux 上链接 libA、libB 和 libC

    CMake Generator Expressions

    【讨论】:

    • 感谢您添加额外的">"。这是 "$:wsock32>"
    【解决方案6】:

    试试看:

    if(WIN32)
        set(ADDITIONAL_LIBRARIES wsock32)
    else()
        set(ADDITIONAL_LIBRARIES "")
    endif()
    
    target_link_libraries(${PROJECT_NAME} bioutils ${ADDITIONAL_LIBRARIES})
    

    您可以找到其他有用的变量here

    【讨论】:

    • 这很有效,我个人喜欢它,因为它非常直观。非常感谢。
    【解决方案7】:

    我想把它留在这里,因为我在使用 Android SDK 在 Windows 中为 Android 编译时遇到了这个问题。

    CMake 区分 TARGET 和 HOST 平台。

    我的目标是 Android,所以像 CMAKE_SYSTEM_NAME 这样的变量的值是“Android”,而这里另一个答案的变量 WIN32 没有定义。 但我想知道我的 HOST 系统是否是 Windows,因为在 Windows、Linux 或 IO 上编译时我需要做一些不同的事情。 为此,我使用了 CMAKE_HOST_SYSTEM_NAME,我发现它在任何地方都鲜为人知或提及,因为对于大多数人来说,TARGEt 和 HOST 是相同的,或者他们不在乎。

    希望这对某个地方的人有所帮助...

    【讨论】:

      【解决方案8】:

      现代 CMake 方式

      避免使用WIN32APPLE等。版主对official forum的回复摘录:

      WIN32APPLEUNIX 等变量被“软”弃用 [...] CMAKE_SYSTEM_NAME 是我在 CMake 代码中使用的,PLATFORM_ID 在生成器表达式中是必需的.

      CMAKE_SYSTEM_NAMEPLAFORM_ID 可以采用哪些可能的值? Refer the source.

      如何检测平台

      使用STREQUAL:

      if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
        # Linux-specific stuff
      endif ()
      

      如何检测多个平台

      创建一个列表变量并使用IN_LIST:

      set(OPENGL_PLATFORMS Linux Windows)
      if (CMAKE_SYSTEM_NAME IN_LIST OPENGL_PLATFORMS)
        # platform-specific stuff e.g.
        find_package(OpenGL REQUIRED)
      endif ()
      

      生成器表达式

      使用PLATFORM_ID:

      target_link_libraries(TARGET_NAME PRIVATE
        $<$<PLATFORM_ID:Linux,Windows>:OpenGL::GL>)
      

      旁白:生成器表达式只能在手册调用时使用。例如,target_link_libraries 的文档将其标注出来,而 set_target_properties 则没有。我想阅读CMake: set_target_properties fails with target defined by generator expression 以了解原因。

      【讨论】:

      • 我没有反对投票的问题。默默地投反对票有助于发泄情绪,更有用的是说出原因。它会帮助其他人(和我自己)从这篇文章的错误中学习。谢谢!
      【解决方案9】:

      使用一些预处理器宏来检查它是在 windows 还是 linux 中。 例如

      #ifdef WIN32
      LIB= 
      #elif __GNUC__
      LIB=wsock32
      #endif
      

      在构建命令中包含 -l$(LIB)。

      您还可以指定一些命令行参数来区分两者。

      【讨论】:

      • 用户要求 CMake 生成文件。
      猜你喜欢
      • 2016-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-27
      • 2013-04-07
      • 1970-01-01
      相关资源
      最近更新 更多