<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 5.9 使用生成器表達式微調配置和編譯 **NOTE**:*此示例代碼可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-5/recipe-09 中找到,其中包含一個C++例子。該示例在CMake 3.9版(或更高版本)中是有效的,并且已經在GNU/Linux、macOS和Windows上進行過測試。* CMake提供了一種特定于領域的語言,來描述如何配置和構建項目。自然會引入描述特定條件的變量,并在`CMakeLists.txt`中包含基于此的條件語句。 本示例中,我們將重新討論生成器表達式。第4章中,以簡潔地引用顯式的測試可執行路徑,使用了這些表達式。生成器表達式為邏輯和信息表達式,提供了一個強大而緊湊的模式,這些表達式在生成構建系統時進行評估,并生成特定于每個構建配置的信息。換句話說,生成器表達式用于引用僅在生成時已知,但在配置時未知或難于知曉的信息;對于文件名、文件位置和庫文件后綴尤其如此。 本例中,我們將使用生成器表達式,有條件地設置預處理器定義,并有條件地鏈接到消息傳遞接口庫(Message Passing Interface, MPI),并允許我們串行或使用MPI構建相同的源代碼。 **NOTE**:*本例中,我們將使用一個導入的目標來鏈接到MPI,該目標僅從CMake 3.9開始可用。但是,生成器表達式可以移植到CMake 3.0或更高版本。* ## 準備工作 我們將編譯以下示例源代碼(`example.cpp`): ```c++ #include <iostream> #ifdef HAVE_MPI #include <mpi.h> #endif int main() { #ifdef HAVE_MPI // initialize MPI MPI_Init(NULL, NULL); // query and print the rank int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); std::cout << "hello from rank " << rank << std::endl; // initialize MPI MPI_Finalize(); #else std::cout << "hello from a sequential binary" << std::endl; #endif /* HAVE_MPI */ } ``` 代碼包含預處理語句(`#ifdef HAVE_MPI ... #else ... #endif`),這樣我們就可以用相同的源代碼編譯一個順序的或并行的可執行文件了。 ## 具體實施 編寫`CMakeLists.txt`文件時,我們將重用第3章第6節的一些構建塊: 1. 聲明一個C++11項目: ```cmake cmake_minimum_required(VERSION 3.9 FATAL_ERROR) project(recipe-09 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_STANDARD_REQUIRED ON) ``` 2. 然后,我們引入一個選項`USE_MPI`來選擇MPI并行化,并將其設置為默認值`ON`。如果為`ON`,我們使用`find_package`來定位MPI環境: ```cmake option(USE_MPI "Use MPI parallelization" ON) if(USE_MPI) find_package(MPI REQUIRED) endif() ``` 3. 然后定義可執行目標,并有條件地設置相應的庫依賴項(`MPI::MPI_CXX`)和預處理器定義(`HAVE_MPI`),稍后將對此進行解釋: ```cmake add_executable(example example.cpp) target_link_libraries(example PUBLIC $<$<BOOL:${MPI_FOUND}>:MPI::MPI_CXX> ) target_compile_definitions(example PRIVATE $<$<BOOL:${MPI_FOUND}>:HAVE_MPI> ) ``` 4. 如果找到MPI,還將打印由`FindMPI.cmake`導出的`INTERFACE_LINK_LIBRARIES`,為了方便演示,使用了`cmake_print_properties()`函數: ```cmake if(MPI_FOUND) include(CMakePrintHelpers) cmake_print_properties( TARGETS MPI::MPI_CXX PROPERTIES INTERFACE_LINK_LIBRARIES ) endif() ``` 5. 首先使用默認MPI配置。觀察`cmake_print_properties()`的輸出: ```shell $ mkdir -p build_mpi $ cd build_mpi $ cmake .. -- ... -- Properties for TARGET MPI::MPI_CXX: MPI::MPI_CXX.INTERFACE_LINK_LIBRARIES = "-Wl,-rpath -Wl,/usr/lib/openmpi -Wl,--enable-new-dtags -pthread;/usr/lib/openmpi/libmpi_cxx.so;/usr/lib/openmpi/libmpi.so" ``` 6. 編譯并運行并行例子: ```cmake $ cmake --build . $ mpirun -np 2 ./example hello from rank 0 hello from rank 1 ``` 7. 現在,創建一個新的構建目錄,這次構建串行版本: ```shell $ mkdir -p build_seq $ cd build_seq $ cmake -D USE_MPI=OFF .. $ cmake --build . $ ./example hello from a sequential binary ``` ## 工作原理 CMake分兩個階段生成項目的構建系統:配置階段(解析`CMakeLists.txt`)和生成階段(實際生成構建環境)。生成器表達式在第二階段進行計算,可以使用僅在生成時才能知道的信息來調整構建系統。生成器表達式在交叉編譯時特別有用,一些可用的信息只有解析`CMakeLists.txt`之后,或在多配置項目后獲取,構建系統生成的所有項目可以有不同的配置,比如Debug和Release。 本例中,將使用生成器表達式有條件地設置鏈接依賴項并編譯定義。為此,可以關注這兩個表達式: ```cmake target_link_libraries(example PUBLIC $<$<BOOL:${MPI_FOUND}>:MPI::MPI_CXX> ) target_compile_definitions(example PRIVATE $<$<BOOL:${MPI_FOUND}>:HAVE_MPI> ) ``` 如果`MPI_FOUND`為真,那么` $<BOOL:${MPI_FOUND}>`的值將為1。本例中,`$<$<BOOL:${MPI_FOUND}>:MPI::MPI_CXX>`將計算`MPI::MPI_CXX`,第二個生成器表達式將計算結果存在`HAVE_MPI`。如果將`USE_MPI`設置為`OFF`,則`MPI_FOUND`為假,兩個生成器表達式的值都為空字符串,因此不會引入鏈接依賴關系,也不會設置預處理定義。 我們可以通過`if`來達到同樣的效果: ```cmake if(MPI_FOUND) target_link_libraries(example PUBLIC MPI::MPI_CXX ) target_compile_definitions(example PRIVATE HAVE_MPI ) endif() ``` 這個解決方案不太優雅,但可讀性更好。我們可以使用生成器表達式來重新表達`if`語句,而這個選擇取決于個人喜好。但當我們需要訪問或操作文件路徑時,生成器表達式尤其出色,因為使用變量和`if`構造這些路徑可能比較困難。本例中,我們更注重生成器表達式的可讀性。第4章中,我們使用生成器表達式來解析特定目標的文件路徑。第11章中,我們會再次來討論生成器。 ## 更多信息 CMake提供了三種類型的生成器表達式: * **邏輯表達式**,基本模式為` $<condition:outcome> `。基本條件為0表示false, 1表示true,但是只要使用了正確的關鍵字,任何布爾值都可以作為條件變量。 * **信息表達式**,基本模式為`$<information>`或`$<information:input>`。這些表達式對一些構建系統信息求值,例如:包含目錄、目標屬性等等。這些表達式的輸入參數可能是目標的名稱,比如表達式` $<TARGET_PROPERTY:tgt,prop> `,將獲得的信息是tgt目標上的prop屬性。 * **輸出表達式**,基本模式為`$<operation>`或`$<operation:input>`。這些表達式可能基于一些輸入參數,生成一個輸出。它們的輸出可以直接在CMake命令中使用,也可以與其他生成器表達式組合使用。例如, ` - I$<JOIN:$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>, -I> `將生成一個字符串,其中包含正在處理的目標的包含目錄,每個目錄的前綴由`-I`表示。 有關生成器表達式的完整列表,請參考https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看