CMAKE中的特定于操作系统的指令:如何使用?

175
我是CMAKE的初学者。下面是一个简单的CMake文件,它在mingw环境的Windows中运行良好。问题显然出现在CMAKE的`target_link_libraries()`函数中,我正在链接libwsock32.a。在Windows中可以工作并获得结果。
但是,如预期所示,在Linux上,`/usr/bin/ld`将查找`-lwsock32`,但该库在Linux操作系统中不存在。
我的问题是:如何指示CMAKE在Linux OS上避免链接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 )
10个回答

223

使用

if (WIN32)
    # do something
endif (WIN32)

或者

if (UNIX)
    # do something
endif (UNIX)

或者

if (MSVC)
    # do something
endif (MSVC)

或类似内容

请参阅CMake 有用的变量CMake 平台检查


用于Solaris,应该使用什么? - jww
嗯,链接页面很有帮助,但没有提到WIN32或UNIX。还有其他/类似的资源吗? - rchilton1980
2
啊,找到了这个。它提到了UNIX、WIN32和它们的“同行”:https://cmake.org/Wiki/CMake_Checking_Platform - rchilton1980
3
@rchilton1980:页面已移动,新链接:https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/Checking-Platform - schnaader
3
对于其他人的疑问:根据惯例,else() 和 endif() 命令允许使用可选的 <condition> 参数。如果使用,它必须与 if 命令的参数完全相同。来源:https://cmake.org/cmake/help/latest/command/if.html - Zyl
4
等一下,这是检查主机平台还是构建目标平台?似乎是后者(而我需要前者)。 - Violet Giraffe

120

考虑到这是一个普遍的问题,老年人发布:

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布尔逻辑文档

CMake平台名称等


14
谢谢提到“APPLE”。 - Victor Sergienko
1
@VictorSergienko 很高兴能帮忙 :) - mlvljr
5
不要假设Unix是Linux。链接到cmake有用的变量网站,找到cmake_system_name。使用Linux混合大小写操作系统检测器。 - don bright
tibur的答案更好。 - don bright
2
是的,FreeBSD也会通过(UNIX AND NOT APPLE) ... 而且@mlvljr的链接已经更改为:https://gitlab.kitware.com/cmake/community/-/wikis/doc/tutorials/How-To-Write-Platform-Checks。 - SlySven
显示剩余2条评论

74

一般情况下

您可以通过以下方式检测和指定多个操作系统的变量:

检测微软Windows操作系统

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

或者:

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

检测苹果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特定的库的问题,只需从其他系统中删除它,就像这样:

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

3
在Solaris上使用什么? - jww
1
笔误:MSVS 应该是 MSVC。我尝试为您编辑,但出于某种原因,stackoverflow 不允许少于 6 个字符的编辑... - mchiasson
2
根据文档,“APPLE”仅意味着我们正在构建苹果目标;即OSX,但也包括iOS、watchOS等。有没有可靠的方法来检测OS X? - user1596212
@Julien 如果你正在为iOS、tvOS或watchOS构建应用程序,那么你很可能会使用cmake工具链文件,其中“应该”设置了某种变量,可以用来实现你想要的功能。 - mchiasson
@Julien FWIW:cmake文档仅确认自3.10.3以来也包括iOS、watchOS和tvOS。 - itMaxence
如果(UNIX 且 非 APPLE),在使用 Cygwin 的情况下也可能是 Windows。 - Cris Luengo

31

你有一些来自CMAKE的特殊单词,请看一下:

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

4
标准的CMake方式:内部不一致 :) - mlvljr
3
对于那些正在寻找的人,这里是名称列表 https://github.com/Kitware/CMake/blob/master/Modules/CMakeDetermineSystem.cmake - A T
3
STREQUAL 可以接受变量作为第一个操作数(除了字符串),因此可以使用更简洁的方式 if(CMAKE_SYSTEM_NAME STREQUAL "Linux")... - Ad N
@AdN 你确定它只在第一个操作数上吗?例如,if(CMAKE_CXX_COMPILER_ID STREQUAL MSVC)将不起作用,因为MSVC恰好是一个变量。 - Johan Boulé
1
@JohanBoulé,实际上它确实接受第二个操作数的变量(https://cmake.org/cmake/help/latest/command/if.html#comparisons)。尽管有些误导,但我的评论并没有真正声称它仅适用于第一个操作数,但对于这个特定的答案,仅对第一个操作数有意义;) - Ad N

27

现代CMake方式

避免使用WIN32APPLE等变量。以下是论坛管理员在官方论坛上的回复摘录:

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

CMAKE_SYSTEM_NAMEPLAFORM_ID可能具有哪些值?请参考源代码

如何检测平台

使用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才明白为什么。


3
我对负评没有任何问题。默默地给负评有助于宣泄情绪,但更有用的是告诉别人为什么要这样做。这将有助于其他人(包括我自己)从这篇文章中学习到哪些方面存在问题。谢谢! - legends2k
1
“现代 CMake 方式” 在我的 Mac Os 上可以使用 CMake 3.21.0,而下面的解决方案则不行。只是让你知道一下。 - Kabu

26

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

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生成器表达式


1
谢谢,你只需添加额外的">"。即"$<$<PLATFORM_ID:Windows>:wsock32>" - wow2006

9

我想留下这个问题,因为在Windows上使用Android SDK编译时,我遇到了困难。

CMake区分TARGET和HOST平台。

我的TARGET是Android,所以像CMAKE_SYSTEM_NAME这样的变量的值为“Android”,而来自其他答案的WIN32变量未定义。 但我想知道我的HOST系统是否是Windows,因为在Windows或Linux或IOS上编译时需要有不同的做法。 为了实现这一点,我使用了CMAKE_HOST_SYSTEM_NAME,发现这个变量几乎没有人知道或提及,因为对于大多数人来说,TARGET和HOST是相同的,或者他们不关心。

希望这可以帮助某个地方的某个人...


7
请尝试以下操作:
if(WIN32)
    set(ADDITIONAL_LIBRARIES wsock32)
else()
    set(ADDITIONAL_LIBRARIES "")
endif()

target_link_libraries(${PROJECT_NAME} bioutils ${ADDITIONAL_LIBRARIES})

您可以在此处找到其他有用的变量。

注:该链接为英文内容。

这个可行,而且我个人很喜欢,因为它非常直观。非常感谢。 - Prasad

1

简单易懂

target_link_libraries(${PROJECT_NAME}
  aaa
  bbb
  ccc
  $<$<BOOL:$<PLATFORM_ID:Linux>>:rt>
  $<$<BOOL:$<PLATFORM_ID:Linux>>:dl>
  )

-6
使用一些预处理宏来检查程序运行在Windows还是Linux系统中。例如:
#ifdef WIN32
LIB= 
#elif __GNUC__
LIB=wsock32
#endif

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

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


7
用户正在请求 CMake 的 Makefile 文件。 - tibur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接