Instruções específicas do sistema operacional no CMAKE: Como fazer?

108

Eu sou um iniciante no CMAKE. Abaixo está um arquivo cmake simples que funciona bem nas janelas do ambiente mingw. O problema é claramente com a target_link_libraries()função do CMAKE ao qual estou vinculando libwsock32.a. No windows isso funciona e recebo os resultados.

No entanto, como esperado, no Linux, o /usr/bin/ldprocurará o -lwsock32que NÃO está lá no sistema operacional Linux.

Meu problema é: Como faço para instruir o CMAKE para evitar vincular a biblioteca wsock32 no sistema operacional Linux ??

Qualquer ajuda será muito apreciada.

Meu arquivo CMake simples:

 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 )
Prasad
fonte

Respostas:

144

Usar

if (WIN32)
    #do something
endif (WIN32)

ou

if (UNIX)
    #do something
endif (UNIX)

ou

if (MSVC)
    #do something
endif (MSVC)

ou similar

consulte Variáveis ​​úteis CMake e Plataforma de verificação CMake

relaxxx
fonte
O que se usa para Solaris?
jww
Hmm, a página com link é útil, mas não menciona WIN32 ou UNIX. Quaisquer outros recursos / semelhantes que podem?
rchilton1980
1
Ah, encontrei isso. Menciona UNIX, WIN32 e, presumivelmente, todos os seus "pares": cmake.org/Wiki/CMake_Checking_Platform
rchilton1980
2
@ rchilton1980: Página movida, novo link: gitlab.kitware.com/cmake/community/wikis/doc/cmake/…
schnaader
Para quem está se perguntando: Per legacy, the else() and endif() commands admit an optional <condition> argument. If used, it must be a verbatim repeat of the argument of the opening if command.Fonte: cmake.org/cmake/help/latest/command/if.html
Zyl
73

Dado que este é um problema tão comum, postagem geronto:

    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()

Documentos de lógica booleana CMake

Nomes de plataforma CMake, etc.

mlvljr
fonte
9
Obrigado por mencionar APPLE.
Victor Sergienko
@VictorSergienko Всегда рад помочь :)
mlvljr
3
não assuma que o unix é Linux. link para o site de variáveis ​​úteis cmake para cmake_system_name. usar detector de sistema operacional de caixa mista Linux
don brilhante
A resposta de tibur é melhor
don brilhante
1
Sim, o FreeBSD também passará (UNIX AND NOT APPLE)... e o link de @mlvljr mudou para: gitlab.kitware.com/cmake/community/-/wikis/doc/tutorials/… agora.
SlySven
45

Em geral

Você pode detectar e especificar variáveis ​​para vários sistemas operacionais como este:

Detectar Microsoft Windows

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

Ou:

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

Detectar Apple MacOS

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

Detectar Unix e Linux

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

Seu problema específico de vinculador

Para resolver seu problema com a wsock32biblioteca específica do Windows , basta removê-la de outros sistemas, assim:

if(WIN32)
    target_link_libraries(${PROJECT_NAME} bioutils wsock32)
else
    target_link_libraries(${PROJECT_NAME} bioutils)
endif()
Afr
fonte
2
O que se usa para Solaris?
jww
1
Typo: MSVS deve ser MSVC. Tentei editá-lo para você, mas stackoverflow não permite edições com menos de 6 caracteres por algum motivo ...
mchiasson
1
De acordo com a documentação, "APPLE" apenas implica que estamos construindo para um alvo apple; ou seja, OSX, mas também iOS, watchOS etc. Há alguma maneira de detectar o OS X de maneira confiável?
@Julien se você estiver construindo para iOS, tvOS ou watchOS, provavelmente usará um arquivo de conjunto de ferramentas cmake, que deve ter algum tipo de variável definida que possa ser usada para alcançar o que você está procurando.
mchiasson,
@Julien FWIW: a documentação do cmake apenas confirma que também inclui iOS, watchOS, tvOS desde 3.10.3
itMaxence
19

Você tem algumas palavras especiais do CMAKE, dê uma olhada:

if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
    // do something for Linux
else
    // do something for other OS
Bruno Soares
fonte
3
A maneira padrão do CMake: internamente inconsistente :) [esta é uma resposta certa / direta, no entanto]
mlvljr
Para quem busca, aqui está a lista de nomes github.com/Kitware/CMake/blob/master/Modules/…
EM
STREQUALaceita variáveis ​​(além de string) como primeiro operando, por isso poderia ser mais concisoif(CMAKE_SYSTEM_NAME STREQUAL "Linux")...
Anúncio N
11

Expressões geradoras também são possíveis:

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

Isso irá vincular libA, wsock32 & libC no Windows e vincular libA, libB & libC no Linux

Expressões do gerador CMake

Cascades
fonte
Obrigado por isso, basta adicionar ">" extra. que é "$ <$ <PLATFORM_ID: Windows>: wsock32>"
wow2006
6

Tente isso:

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

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

Você pode encontrar outras variáveis ​​úteis aqui .

Tibur
fonte
Isso funcionou e eu pessoalmente gosto disso, pois é muito intuitivo. Muito obrigado.
Prasad
2

Quero deixar isso aqui porque tive dificuldade com isso ao compilar para Android no Windows com o Android SDK.

O CMake distingue entre plataforma TARGET e HOST.

Meu TARGET era Android, então as variáveis ​​como CMAKE_SYSTEM_NAME tinham o valor "Android" e a variável WIN32 da outra resposta aqui não foi definida. Mas eu queria saber se meu sistema HOST era Windows porque eu precisava fazer algumas coisas diferentes ao compilar no Windows ou Linux ou IOs. Para fazer isso, usei CMAKE_HOST_SYSTEM_NAME, que descobri ser pouco conhecido ou mencionado em qualquer lugar porque para a maioria das pessoas TARGEt e HOST são iguais ou não se importam.

Espero que isso ajude alguém em algum lugar ...

Nico Heidtke
fonte
-5

Use alguma macro de pré-processador para verificar se está no Windows ou Linux. Por exemplo

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

inclua -l $ (LIB) em seu comando de construção.

Você também pode especificar algum argumento de linha de comando para diferenciar ambos.

Barun Parichha
fonte
6
O usuário está pedindo makefiles CMake.
tibur