2017-08-30 83 views
10

我想編寫一個cmake文件,它在debug和release版本中爲clang ++,g ++和MSVC設置不同的編譯器選項。 我在做什麼目前看起來是這樣的:在跨平臺cmake項目中設置編譯器標誌的現代方法

if(MSVC) 
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++latest /W4") 
    # Default debug flags are OK 
    set(CMAKE_CXX_FLAGS_RELEASE "{CMAKE_CXX_FLAGS_RELEASE} /O2") 
else() 
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1z -Wall -Wextra -Werror") 
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} some other flags") 
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") 

    if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") 
    else() 
     # nothing special for gcc at the moment 
    endif() 
endif() 

但我有這個幾個問題:

  1. 首先簡單:是否有relly沒有命令澳鵬一樣,讓我用append(CMAKE_CXX_FLAGS "Foo")替換set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} Foo")
  2. 我已經多次閱讀,不應該手動設置CMAKE_CXX_FLAGS和類似的變量,但我不知道使用什麼其他機制。
  3. 最重要的是:我在這裏做的方式,我需要爲每個編譯器和配置一個單獨的構建目錄理想情況下,我想要將它轉換爲同一目錄中的多個目標,所以我可以致電make foo_debug_clang

所以我的問題是

  • 一)有沒有更好的方式來寫個,解決了我的「痛點」 cmake的腳本? 解決上述問題?
  • b)有沒有像如何建立這樣的項目的公認的現代最佳實踐?

我可以在互聯網上找到的大多數參考文獻都是過時的或只顯示微不足道的例子。我目前使用cmake3.8,但如果這有什麼不同,我更感興趣的是更新版本的答案。

+0

關於前兩點:https://cmake.org/cmake/help/v3.3/command/add_compile_options.html –

+0

@ AI.G。謝謝。是否還有單獨的調試和釋放集,我必須通過另一級別的if_else解決?我用生成器表達式進行了一些嘗試,但我感覺這變得更不可讀。 – MikeMB

+0

當我看到它,你既可以用髒髮電機表達式或'設置(CMAKE_CXX_FLAGS_DEBUG「$ {} CMAKE_CXX_FLAGS_DEBUG --flags」)'相當詳細的語法。在這種情況下(考慮到這些不滿意),你可以嘗試編寫一些幫助函數,將髒代碼包裝成更令人愉快的東西。 –

回答

6

你的辦法將 - 如@Tsyvarev曾評論 - 絕對很好,只是因爲你已經要求在C進行「新」辦法這裏是你的代碼會翻譯什麼:

cmake_minimum_required(VERSION 3.8) 

project(HelloWorld) 

string(
    APPEND _opts 
    "$<IF:$<CXX_COMPILER_ID:MSVC>," 
     "/W4;$<$<CONFIG:RELEASE>:/O2>," 
     "-Wall;-Wextra;-Werror;" 
      "$<$<CONFIG:RELEASE>:-O3>" 
      "$<$<CXX_COMPILER_ID:Clang>:-stdlib=libc++>" 
    ">" 
) 

add_compile_options("${_opts}") 

add_executable(HelloWorld "main.cpp") 

target_compile_features(HelloWorld PUBLIC cxx_lambda_init_captures) 

你拿add_compile_options()和 - as @ Al.G。已評論 - 「使用髒generator expressions」。

有發電機表達式的一些缺點:

  1. 很有幫助$<IF:...,...,...>表達只是CMake的版本> = 3.8
  2. 你必須把它寫在一行可用。爲了避免它,我使用了string(APPEND ...),您也可以使用它來「優化」您的set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ...調用。
  3. 這很難閱讀和理解。例如。需要分號才能使其成爲編譯選項列表(否則CMake會引用它)。

所以最好使用一個更具可讀性和向後兼容的方式與add_compile_options()

if(MSVC) 
    add_compile_options("/W4" "$<$<CONFIG:RELEASE>:/O2>") 
else() 
    add_compile_options("-Wall" "-Wextra" "-Werror" "$<$<CONFIG:RELEASE>:-O3>") 
    if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 
     add_compile_options("-stdlib=libc++") 
    else() 
     # nothing special for gcc at the moment 
    endif() 
endif() 

是的,你沒有明確指定C++標準了,你剛纔命名C++ feature代碼/目標確實取決於target_compile_features()調用。

在這個例子中,我選擇了cxx_lambda_init_captures,舊的GCC編譯器提供以下錯誤(作爲一個例子會發生什麼,如果編譯器不支持此功能):

The compiler feature "cxx_lambda_init_captures" is not known to CXX compiler 

"GNU" 

version 4.8.4. 

而且你需要寫一個包裝腳本構建與"single configuration" makefile generator或多個配置作爲Visual Studio使用"multi configuration" IDE

下面是引用的例子:

所以,我測試了Open Folder Visual Studio中的下列2017年CMake的支持,在結合此示例爲,編譯器:

Configurations

CMakeSettings.json

{ 
    // See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file. 
    "configurations": [ 
     { 
      "name": "x86-Debug", 
      "generator": "Visual Studio 15 2017", 
      "configurationType": "Debug", 
      "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}", 
      "buildCommandArgs": "-m -v:minimal", 
     }, 
     { 
      "name": "x86-Release", 
      "generator": "Visual Studio 15 2017", 
      "configurationType": "Release", 
      "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}", 
      "buildCommandArgs": "-m -v:minimal", 
     }, 
     { 
      "name": "Clang-Debug", 
      "generator": "Visual Studio 15 2017", 
      "configurationType": "Debug", 
      "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}", 
      "cmakeCommandArgs": "-T\"LLVM-vs2014\"", 
      "buildCommandArgs": "-m -v:minimal", 
     }, 
     { 
      "name": "Clang-Release", 
      "generator": "Visual Studio 15 2017", 
      "configurationType": "Release", 
      "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}", 
      "cmakeCommandArgs": "-T\"LLVM-vs2014\"", 
      "buildCommandArgs": "-m -v:minimal", 
     }, 
     { 
      "name": "GNU-Debug", 
      "generator": "MinGW Makefiles", 
      "configurationType": "Debug", 
      "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}", 
      "variables": [ 
       { 
        "name": "CMAKE_MAKE_PROGRAM", 
        "value": "${projectDir}\\mingw32-make.cmd" 
       } 
      ] 
     }, 
     { 
      "name": "GNU-Release", 
      "generator": "Unix Makefiles", 
      "configurationType": "Release", 
      "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}", 
      "variables": [ 
       { 
        "name": "CMAKE_MAKE_PROGRAM", 
        "value": "${projectDir}\\mingw32-make.cmd" 
       } 
      ] 
     } 
    ] 
} 

的mingw32-make.cmd

@echo off 
mingw32-make.exe %~1 %~2 %~3 %~4 

所以,你可以使用任何CMake的發電機從Visual Studio 2017年中,還有一些不健康的報價正在進行(截至2017年9月,mayb e稍後修復),即需要mingw32-make.cmd中介(刪除引號)。

+0

我嚴重違反規定個人標準語言功能的要求,而不是指定我編碼反對的標準,但在其他方面感謝全面的答案。 – MikeMB

+0

@MikeMB不客氣。你也可以對'target_compile_features(cxx_std_17)'使用一個通用聲明。 – Florian

+0

我不是結果完全滿意,但就是definetively更多的cmake的錯比你的。順便說一句.:指定'cxx_std_XX'比指定每個功能越好,但AFAIK cmake的可解決此到'-std = GNUC++ XX'開關代替'C++ XX'which是跨平臺的發展IMHO問題。通常我儘量把所有的編譯器儘可能接近標準的一致性越好('-std = C++ XX,/ permissive-,-pedantic'等),然後回退,如果某些第三方庫不會在他們編譯,但這超出了問題的範圍。 – MikeMB

1

另一種方法是使用.rsp文件。

set(rsp_file "${CMAKE_CURRENT_BINARY_DIR}/my.rsp") 
configure_file(my.rsp.in ${rsp_file} @ONLY) 
target_compile_options(mytarget PUBLIC "@${rsp_file}") 

這可能會使包含多個和深奧的選項更容易管理。

+0

@Tsyvarev有趣,你是對的。將更新。 –

+0

我不得不承認,我從來沒有聽說過rsp_files - 你能舉個例子嗎?無論如何,我不確定將現在在單個位置的信息拆分爲多個單獨的文件會使過程變得更好。 – MikeMB

+0

@MikeMB rsp文件(響應文件)只是將命令行選項放入文件而非命令行的一種方法。我能想到的所有支持他們的編譯器 –

1

您可以使用target_compile_options()來「追加」編譯選項。

1

尋址所述第一兩分,而不是第三:

  • 我已經多次讀取,即一個不應該手動在所述第一設定CMAKE_CXX_FLAGS和類似的變量地方,但我不知道還有什麼其他機制使用。
  • 你想要的命令是set_property。 CMake支持一系列屬性 - 不是一切,而是大量 - 以某種方式爲您節省了編譯器特定工作的麻煩。例如:

    set_property(TARGET foo PROPERTY CXX_STANDARD 17) 
    

    這對於一些編譯器將導致--std=c++17但對於早期的具有--std=c++1z(前C++ 17定稿)。或:

    set_property(TARGET foo APPEND PROPERTY COMPILE_DEFINITIONS HELLO WORLD) 
    

    將導致它-DHELLO-DWORLD對於GCC,鐺和MSVC但奇怪的編譯器可能會使用其他交換機。

    是否有relly像追加沒有命令,讓我與append(CMAKE_CXX_FLAGS "Foo")?

    set_property不僅可以被用來在設定的模式,或以附加模式替換set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} Foo")(參見上文實施例)。

    我不能說這是否是最好add_compile_optionstarget_compile_features,雖然。