OS specific instructions in CMAKE: How to?
C++LinuxCmakeMingwPortabilityC++ Problem Overview
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 )
C++ Solutions
Solution 1 - C++
Use
if (WIN32)
#do something
endif (WIN32)
or
if (UNIX)
#do something
endif (UNIX)
or
if (MSVC)
#do something
endif (MSVC)
or similar
Solution 2 - C++
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()
Solution 3 - C++
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()
Solution 4 - C++
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
Solution 5 - C++
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
Solution 6 - C++
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.
Solution 7 - C++
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 https://stackoverflow.com/questions/67180311/cmake-set-target-properties-fails-with-target-defined-by-generator-expression to realize why.
Solution 8 - C++
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...
Solution 9 - C++
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.