步驟 7:新增系統內省

讓我們考慮在專案中加入一些程式碼,這些程式碼依賴於目標平台可能不具備的功能。在這個範例中,我們將加入一些程式碼,這些程式碼依賴於目標平台是否具有 logexp 函數。當然,幾乎每個平台都有這些函數,但為了本教學,我們假設它們並不常見。

練習 1 - 評估依賴項可用性

目標

根據可用的系統依賴項更改實作。

有用的資源

要編輯的檔案

  • MathFunctions/CMakeLists.txt

  • MathFunctions/mysqrt.cxx

開始

起始程式碼在 Step7 目錄中提供。在本練習中,完成 TODO 1TODO 5

首先編輯 MathFunctions/CMakeLists.txt。包含 CheckCXXSourceCompiles 模組。然後,使用 check_cxx_source_compiles 來判斷 logexp 是否可從 cmath 取得。如果它們可用,請使用 target_compile_definitions() 來指定 HAVE_LOGHAVE_EXP 作為編譯定義。

MathFunctions/mysqrt.cxx 中,包含 cmath。然後,如果系統具有 logexp,則使用它們來計算平方根。

建置和執行

建立一個名為 Step7_build 的新目錄。執行 cmake 可執行檔或 cmake-gui 來組態專案,然後使用您選擇的建置工具建置專案,並執行 Tutorial 可執行檔。

這看起來會像這樣

mkdir Step7_build
cd Step7_build
cmake ../Step7
cmake --build .

現在哪個函數給出更好的結果,sqrt 還是 mysqrt

解決方案

在本練習中,我們將使用 CheckCXXSourceCompiles 模組中的函數,因此首先我們必須將其包含在 MathFunctions/CMakeLists.txt 中。

TODO 1:按一下以顯示/隱藏答案
TODO 1:MathFunctions/CMakeLists.txt
  include(CheckCXXSourceCompiles)

然後使用 check_cxx_compiles_source 測試 logexp 的可用性。此函數可讓我們在真正原始程式碼編譯之前,嘗試使用所需依賴項來編譯簡單的程式碼。產生的變數 HAVE_LOGHAVE_EXP 表示這些依賴項是否可用。

TODO 2:按一下以顯示/隱藏答案
TODO 2:MathFunctions/CMakeLists.txt
  check_cxx_source_compiles("
    #include <cmath>
    int main() {
      std::log(1.0);
      return 0;
    }
  " HAVE_LOG)
  check_cxx_source_compiles("
    #include <cmath>
    int main() {
      std::exp(1.0);
      return 0;
    }
  " HAVE_EXP)

接下來,我們需要將這些 CMake 變數傳遞到我們的原始程式碼。這樣,我們的原始程式碼才能知道哪些資源可用。如果 logexp 都可用,則使用 target_compile_definitions() 來指定 HAVE_LOGHAVE_EXP 作為 PRIVATE 編譯定義。

TODO 3:按一下以顯示/隱藏答案
TODO 3:MathFunctions/CMakeLists.txt
  if(HAVE_LOG AND HAVE_EXP)
    target_compile_definitions(SqrtLibrary
                               PRIVATE "HAVE_LOG" "HAVE_EXP"
                               )
  endif()

  target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()

由於我們可能會使用 logexp,因此我們需要修改 mysqrt.cxx 以包含 cmath

TODO 4:按一下以顯示/隱藏答案
TODO 4:MathFunctions/mysqrt.cxx
#include <cmath>

如果系統上提供 logexp,則在 mysqrt 函數中使用它們來計算平方根。MathFunctions/mysqrt.cxx 中的 mysqrt 函數看起來會像這樣

TODO 5:按一下以顯示/隱藏答案
TODO 5:MathFunctions/mysqrt.cxx
#if defined(HAVE_LOG) && defined(HAVE_EXP)
  double result = std::exp(std::log(x) * 0.5);
  std::cout << "Computing sqrt of " << x << " to be " << result
            << " using log and exp" << std::endl;
#else
  double result = x;

  // do ten iterations
  for (int i = 0; i < 10; ++i) {
    if (result <= 0) {
      result = 0.1;
    }
    double delta = x - (result * result);
    result = result + 0.5 * delta / result;
    std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
  }
#endif