169

I am a beginner to CMAKE. Below is a simple cmake file which works well in mingw environment windows. The problem is clearly with target_link_libraries() function of CMAKE where I am linking libwsock32.a. In windows this works and I get the results.

However, as expected, in Linux, the /usr/bin/ld will look for -lwsock32 which is NOT there on the Linux OS.

My Problem is: How do I instruct CMAKE to avoid linking wsock32 library in Linux OS???

Any help will be greatly appreciated.

My Simple CMake file:

 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 )
Guy Avraham
  • 3,482
  • 3
  • 38
  • 50
Prasad
  • 1,837
  • 2
  • 12
  • 7

10 Answers10

219

Use

if (WIN32)
    # do something
endif (WIN32)

or

if (UNIX)
    # do something
endif (UNIX)

or

if (MSVC)
    # do something
endif (MSVC)

or similar

see CMake Useful Variables and CMake Checking Platform

starball
  • 20,030
  • 7
  • 43
  • 238
relaxxx
  • 7,566
  • 8
  • 37
  • 64
  • What does one use for Solaris? – jww Aug 29 '17 at 11:16
  • Hmm, the linked-to page is helpful but doesn't mention either WIN32 or UNIX. Any other/similar resources that might? – rchilton1980 Nov 29 '17 at 17:20
  • 2
    Ah, found this. It mentions UNIX, WIN32, and presumably all their "peers": https://cmake.org/Wiki/CMake_Checking_Platform – rchilton1980 Nov 29 '17 at 17:35
  • 3
    @rchilton1980: Page moved, new link: https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/Checking-Platform – schnaader Sep 10 '18 at 13:09
  • 3
    For anyone else wondering: `Per legacy, the else() and endif() commands admit an optional argument. If used, it must be a verbatim repeat of the argument of the opening if command.` Source: https://cmake.org/cmake/help/latest/command/if.html – Zyl Jun 25 '20 at 13:33
  • 4
    Wait, is this checking the host platform or the build target platform? Seems to be latter (and I need the former). – Violet Giraffe Jan 19 '21 at 10:07
116

Given this is such a common issue, 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.

starball
  • 20,030
  • 7
  • 43
  • 238
mlvljr
  • 4,066
  • 8
  • 44
  • 61
  • 13
    Thanks for mentioning `APPLE`. – Victor Sergienko Jan 28 '16 at 15:50
  • 1
    @VictorSergienko Всегда рад помочь :) – mlvljr Jan 28 '16 at 20:14
  • 5
    dont assume unix is linux. link to the cmake useful variables website for cmake_system_name. use Linux mixed case OS detector – don bright Oct 22 '16 at 17:24
  • tibur's answer is better – don bright Oct 25 '16 at 01:28
  • Cygwin is identified as `UNIX` as well, as are all flavors of Unix. It's not only Linux and MacOS. – Cris Luengo Apr 26 '19 at 21:16
  • @CrisLuengo , sure -- my idea back then was you know what platforms you are building on, if not, you can follow https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/Checking-Platform for a more complete list (beware, these things might be changing as newer versions of CMake come out and god knows if older versions supported the same set -- you should always google ( :) ) for the specific CMake version's docs and nuse that, when doing just about anything with CMake, in my limited experience) – mlvljr Apr 27 '19 at 08:47
  • 2
    Yeah, FreeBSD will also pass `(UNIX AND NOT APPLE)` ... and @mlvljr 's link has changed to: https://gitlab.kitware.com/cmake/community/-/wikis/doc/tutorials/How-To-Write-Platform-Checks now. – SlySven Mar 24 '20 at 23:12
70

In General

You can detect and specify variables for several operating systems like that:

Detect Microsoft Windows

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

Or:

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

Detect Apple MacOS

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

Detect Unix and Linux

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

Your specific linker issue

To solve your issue with the Windows-specific wsock32 library, just remove it from other systems, like that:

if(WIN32)
    target_link_libraries(${PROJECT_NAME} bioutils wsock32)
else
    target_link_libraries(${PROJECT_NAME} bioutils)
endif()
itMaxence
  • 1,230
  • 16
  • 28
q9f
  • 11,293
  • 8
  • 57
  • 96
  • 3
    What does one use for Solaris? – jww Aug 29 '17 at 11:16
  • 1
    Typo: MSVS should be MSVC. I tried to edit it for you but stackoverflow doesn't allow edits that are less than 6 characters for some reason... – mchiasson Mar 11 '18 at 15:25
  • 2
    According to the documentation, "APPLE" only implies, that we're building for an apple target; i.e. OSX, but also iOS, watchOS etc. Are there any ways to detect os X in a reliable manner? –  Mar 28 '18 at 22:19
  • @Julien if you are building for iOS, tvOS or watchOS, you're most likely going to be using a cmake toolchain file, which _should_ have some kind of variable set in there that could be used to achieve what you're looking for. – mchiasson Apr 07 '18 at 21:43
  • @Julien FWIW: the [cmake documentation](https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html) only confirms that it also includes iOS, watchOS, tvOS since [3.10.3](https://cmake.org/cmake/help/v3.10/variable/APPLE.html) – itMaxence Jul 25 '18 at 11:11
  • `if(UNIX AND NOT APPLE)` could be Windows too (if using Cygwin). – Cris Luengo Apr 26 '19 at 21:17
31

You have some special words from CMAKE, take a look:

if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
    // do something for Linux
else
    // do something for other OS
Bruno Soares
  • 756
  • 5
  • 6
  • 4
    The standard CMake way: *internally-inconsistent* :) [this is one right / to-the-point answer, though] – mlvljr Aug 27 '15 at 20:44
  • 3
    For those searching, here is the list of names https://github.com/Kitware/CMake/blob/master/Modules/CMakeDetermineSystem.cmake – A T Apr 15 '20 at 02:45
  • 3
    `STREQUAL` accepts variables (in addition to string) as first operand, so it could be the more concise `if(CMAKE_SYSTEM_NAME STREQUAL "Linux")...` – Ad N Jul 06 '20 at 14:37
  • @AdN Are you sure it's only on the first operand ? For example, `if(CMAKE_CXX_COMPILER_ID STREQUAL MSVC)` will not work because `MSVC` happens to be a variable. – Johan Boulé Nov 10 '21 at 02:17
  • 1
    @JohanBoulé It also accepts a variable for the second operand indeed (https://cmake.org/cmake/help/latest/command/if.html#comparisons). Although misleading, my comment did not really claim it worked **only** for first operand though, but for this specific answer it only made sense for the first operand ; ) – Ad N Nov 10 '21 at 08:37
26

Generator expressions are also possible:

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

This will link libA, wsock32 & libC on Windows and link libA, libB & libC on Linux

CMake Generator Expressions

Cascades
  • 627
  • 7
  • 18
23

Modern CMake Way

Avoid using WIN32, APPLE, etc. Excerpt of a moderator's reply on official forum:

The WIN32, APPLE, UNIX, etc. variables are “soft” deprecated [...] CMAKE_SYSTEM_NAME is what I’d use in CMake code, PLATFORM_ID is needed in generator expressions.

What possible values can CMAKE_SYSTEM_NAME or PLAFORM_ID take? Refer the source.

How to detect a platform

Use STREQUAL:

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

How to detect multiple platforms

Create a list variable and use 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 ()

Generator Expression

Use PLATFORM_ID:

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

Aside: Generator expressions can only be used if the manual calls it out. For example target_link_libraries's documentation calls it out while set_target_properties doesn't. I'd to read CMake: set_target_properties fails with target defined by generator expression to realize why.

legends2k
  • 31,634
  • 25
  • 118
  • 222
  • 3
    I've no issues with downvoting. Silently downvoting is useful to vent out your emotion, what's more useful is to tell why. It'd help others (and myself) learn from what's wrong with this post. Thanks! – legends2k Mar 03 '22 at 07:17
  • 1
    "Modern CMake Way" works as CMake 3.21.0 on my Mac Os, while below solution doesn't. Just to let you know. – Kabu May 27 '22 at 07:13
8

I want to leave this here because I struggled with this when compiling for Android in Windows with the Android SDK.

CMake distinguishes between TARGET and HOST platform.

My TARGET was Android so the variables like CMAKE_SYSTEM_NAME had the value "Android" and the variable WIN32 from the other answer here was not defined. But I wanted to know if my HOST system was Windows because I needed to do a few things differently when compiling on either Windows or Linux or IOs. To do that I used CMAKE_HOST_SYSTEM_NAME which I found is barely known or mentioned anywhere because for most people TARGEt and HOST are the same or they don't care.

Hope this helps someone somewhere...

Nico Heidtke
  • 525
  • 4
  • 7
7

Try that:

if(WIN32)
    set(ADDITIONAL_LIBRARIES wsock32)
else()
    set(ADDITIONAL_LIBRARIES "")
endif()

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

You can find other useful variables here.

tibur
  • 11,531
  • 2
  • 37
  • 39
1

simple like

target_link_libraries(${PROJECT_NAME}
  aaa
  bbb
  ccc
  $<$<BOOL:$<PLATFORM_ID:Linux>>:rt>
  $<$<BOOL:$<PLATFORM_ID:Linux>>:dl>
  )
Mouse
  • 111
  • 1
  • 7
-6

Use some preprocessor macro to check if it's in windows or linux. For example

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

include -l$(LIB) in you build command.

You can also specify some command line argument to differentiate both.

ForceMagic
  • 6,230
  • 12
  • 66
  • 88