Betriebssystemspezifische Anweisungen in CMAKE: Wie geht das?


107

Ich bin ein Anfänger von CMAKE. Unten finden Sie eine einfache cmake-Datei, die in Fenstern der Mingw-Umgebung gut funktioniert. Das Problem liegt eindeutig in der target_link_libraries()Funktion von CMAKE, wo ich libwsock32.a verknüpfe. In Windows funktioniert das und ich bekomme die Ergebnisse.

Unter Linux /usr/bin/ldwird jedoch erwartungsgemäß nach dem gesucht, -lwsock32was unter Linux NICHT vorhanden ist.

Mein Problem ist: Wie weise ich CMAKE an, das Verknüpfen der wsock32-Bibliothek unter Linux zu vermeiden?

Jede Hilfe wird sehr geschätzt.

Meine einfache CMake-Datei:

 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 )

Antworten:


143

Verwenden

if (WIN32)
    #do something
endif (WIN32)

oder

if (UNIX)
    #do something
endif (UNIX)

oder

if (MSVC)
    #do something
endif (MSVC)

o.ä

Siehe CMake Nützliche Variablen und CMake Checking Platform


Was benutzt man für Solaris?
JWW

Hmm, die verlinkte Seite ist hilfreich, erwähnt aber weder WIN32 noch UNIX. Gibt es noch andere / ähnliche Ressourcen?
rchilton1980

1
Ah, habe das gefunden. Es erwähnt UNIX, WIN32 und vermutlich alle ihre "Kollegen": cmake.org/Wiki/CMake_Checking_Platform
rchilton1980

2
@ rchilton1980: Seite verschoben, neuer Link: gitlab.kitware.com/cmake/community/wikis/doc/cmake/…
Schnaader

Für alle anderen, die sich fragen: 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.Quelle: cmake.org/cmake/help/latest/command/if.html
Zyl

73

Angesichts dessen, dass dies ein so häufiges Problem ist, wird 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 boolesche Logikdokumente

CMake-Plattformnamen usw.


9
Vielen Dank für die Erwähnung APPLE.
Victor Sergienko

@ VictorSergienko Всегда рад помочь :)
mlvljr

3
Gehen Sie nicht davon aus, dass Unix Linux ist. Link zur Website für nützliche Variablen von cmake für cmake_system_name. Verwenden Sie Linux Mixed Case OS Detektor
Don Bright

Tiburs Antwort ist besser
Don Bright

1
Ja, FreeBSD wird auch bestanden (UNIX AND NOT APPLE)... und der Link von @mlvljr wurde geändert in: gitlab.kitware.com/cmake/community/-/wikis/doc/tutorials/… jetzt.
SlySven

45

Allgemein

Sie können Variablen für verschiedene Betriebssysteme wie folgt erkennen und angeben:

Erkennen Sie Microsoft Windows

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

Oder:

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

Apple MacOS erkennen

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

Erkennen Sie Unix und Linux

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

Ihr spezifisches Linker-Problem

Um Ihr Problem mit der Windows-spezifischen wsock32Bibliothek zu lösen , entfernen Sie sie einfach von anderen Systemen:

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

2
Was benutzt man für Solaris?
JWW

1
Tippfehler: MSVS sollte MSVC sein. Ich habe versucht, es für Sie zu bearbeiten, aber Stackoverflow erlaubt aus irgendeinem Grund keine Änderungen, die weniger als 6 Zeichen umfassen ...
mchiasson

1
Laut der Dokumentation impliziert "APPLE" nur, dass wir für ein Apfelziel bauen; dh OSX, aber auch iOS, watchOS usw. Gibt es Möglichkeiten, OS X zuverlässig zu erkennen?

@Julien wenn Sie bauen für iOS, tvOS oder watchOS, sind Sie höchstwahrscheinlich eine Cmake Toolchain - Datei einsetzen möchten, die sollten eine Art von variablen Satz dort haben, dass verwendet werden könnten , zu erreichen , was Sie suchen.
Mchiasson

@ Julien FWIW: Die cmake-Dokumentation bestätigt nur, dass sie seit 3.10.3
itMaxence

19

Sie haben einige spezielle Wörter von CMAKE, werfen Sie einen Blick darauf:

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

3
Der Standard-CMake-Weg: intern inkonsistent :) [dies ist jedoch eine richtige Antwort auf den Punkt]
mlvljr

Für diejenigen, die suchen, ist hier die Liste der Namen github.com/Kitware/CMake/blob/master/Modules/…
AT

STREQUALakzeptiert Variablen (zusätzlich zum String) als ersten Operanden, daher könnte es prägnanter seinif(CMAKE_SYSTEM_NAME STREQUAL "Linux")...
Ad N

10

Generatorausdrücke sind ebenfalls möglich:

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

Dadurch werden libA, wsock32 und libC unter Windows und libA, libB und libC unter Linux verknüpft

CMake Generator-Ausdrücke


Danke dafür, nur fügst du extra ">" hinzu. Das ist "$ <$ <PLATFORM_ID: Windows>: wsock32>"
wow2006

6

Versuch das:

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

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

Weitere nützliche Variablen finden Sie hier .


Das hat funktioniert und ich persönlich mag das, da es sehr intuitiv ist. Vielen Dank.
Prasad

2

Ich möchte dies hier belassen, weil ich beim Kompilieren für Android in Windows mit dem Android SDK damit zu kämpfen hatte.

CMake unterscheidet zwischen TARGET- und HOST-Plattform.

Mein ZIEL war Android, daher hatten Variablen wie CMAKE_SYSTEM_NAME den Wert "Android" und die Variable WIN32 aus der anderen Antwort hier wurde nicht definiert. Aber ich wollte wissen, ob mein HOST-System Windows ist, weil ich beim Kompilieren unter Windows, Linux oder E / A einige Dinge anders machen musste. Zu diesem Zweck habe ich CMAKE_HOST_SYSTEM_NAME verwendet, von dem ich festgestellt habe, dass es kaum bekannt ist oder irgendwo erwähnt wird, da TARGEt und HOST für die meisten Menschen gleich sind oder es ihnen egal ist.

Hoffe das hilft jemandem irgendwo ...


-5

Verwenden Sie ein Präprozessor-Makro, um zu überprüfen, ob es sich um Windows oder Linux handelt. Beispielsweise

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

Fügen Sie -l $ (LIB) in Ihren Build-Befehl ein.

Sie können auch ein Befehlszeilenargument angeben, um beide zu unterscheiden.


6
Der Benutzer fragt nach CMake-Makefiles.
Tibur
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.