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

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 1.3 構建和鏈接靜態庫和動態庫 **NOTE**: *這個示例代碼可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-01/recipe-03 找到,其中有C++和Fortran示例。該配置在CMake 3.5版(或更高版本)測試有效的,并且已經在GNU/Linux、macOS和Windows上進行了測試。* 項目中會有單個源文件構建的多個可執行文件的可能。項目中有多個源文件,通常分布在不同子目錄中。這種實踐有助于項目的源代碼結構,而且支持模塊化、代碼重用和關注點分離。同時,這種分離可以簡化并加速項目的重新編譯。本示例中,我們將展示如何將源代碼編譯到庫中,以及如何鏈接這些庫。 ## 準備工作 回看第一個例子,這里并不再為可執行文件提供單個源文件,我們現在將引入一個類,用來包裝要打印到屏幕上的消息。更新一下的`hello-world.cpp`: ```c++ #include "Message.hpp" #include <cstdlib> #include <iostream> int main() { Message say_hello("Hello, CMake World!"); std::cout << say_hello << std::endl; Message say_goodbye("Goodbye, CMake World"); std::cout << say_goodbye << std::endl; return EXIT_SUCCESS; } ``` `Message`類包裝了一個字符串,并提供重載過的`<<`操作,并且包括兩個源碼文件:`Message.hpp`頭文件與`Message.cpp`源文件。`Message.hpp`中的接口包含以下內容: ```c++ #pragma once #include <iosfwd> #include <string> class Message { public: Message(const std::string &m) : message_(m) {} friend std::ostream &operator<<(std::ostream &os, Message &obj) { return obj.printObject(os); } private: std::string message_; std::ostream &printObject(std::ostream &os); }; ``` `Message.cpp`實現如下: ```c++ #include "Message.hpp" #include <iostream> #include <string> std::ostream &Message::printObject(std::ostream &os) { os << "This is my very nice message: " << std::endl; os << message_; return os; } ``` ## 具體實施 這里有兩個文件需要編譯,所以`CMakeLists.txt`必須進行修改。本例中,先把它們編譯成一個庫,而不是直接編譯成可執行文件: 1. 創建目標——靜態庫。庫的名稱和源碼文件名相同,具體代碼如下: ```cmake add_library(message STATIC Message.hpp Message.cpp ) ``` 2. 創建`hello-world`可執行文件的目標部分不需要修改: ```cmake add_executable(hello-world hello-world.cpp) ``` 3. 最后,將目標庫鏈接到可執行目標: ```cmake target_link_libraries(hello-world message) ``` 4. 對項目進行配置和構建。庫編譯完成后,將連接到`hello-world`可執行文件中: ```shell $ mkdir -p build $ cd build $ cmake .. $ cmake --build . Scanning dependencies of target message [ 25%] Building CXX object CMakeFiles/message.dir/Message.cpp.o [ 50%] Linking CXX static library libmessage.a [ 50%] Built target message Scanning dependencies of target hello-world [ 75%] Building CXX object CMakeFiles/hello-world.dir/hello-world.cpp.o [100%] Linking CXX executable hello-world [100%] Built target hello-world ``` ```shell $ ./hello-world This is my very nice message: Hello, CMake World! This is my very nice message: Goodbye, CMake World ``` ## 工作原理 本節引入了兩個新命令: * `add_library(message STATIC Message.hpp Message.cpp)`:生成必要的構建指令,將指定的源碼編譯到庫中。`add_library`的第一個參數是目標名。整個`CMakeLists.txt`中,可使用相同的名稱來引用庫。生成的庫的實際名稱將由CMake通過在前面添加前綴`lib`和適當的擴展名作為后綴來形成。生成庫是根據第二個參數(`STATIC`或`SHARED`)和操作系統確定的。 * `target_link_libraries(hello-world message)`: 將庫鏈接到可執行文件。此命令還確保`hello-world`可執行文件可以正確地依賴于消息庫。因此,在消息庫鏈接到`hello-world`可執行文件之前,需要完成消息庫的構建。 編譯成功后,構建目錄包含`libmessage.a`一個靜態庫(在GNU/Linux上)和`hello-world`可執行文件。 CMake接受其他值作為`add_library`的第二個參數的有效值,我們來看下本書會用到的值: * **STATIC**:用于創建靜態庫,即編譯文件的打包存檔,以便在鏈接其他目標時使用,例如:可執行文件。 * **SHARED**:用于創建動態庫,即可以動態鏈接,并在運行時加載的庫。可以在`CMakeLists.txt`中使用`add_library(message SHARED Message.hpp Message.cpp) `從靜態庫切換到動態共享對象(DSO)。 * **OBJECT**:可將給定`add_library`的列表中的源碼編譯到目標文件,不將它們歸檔到靜態庫中,也不能將它們鏈接到共享對象中。如果需要一次性創建靜態庫和動態庫,那么使用對象庫尤其有用。我們將在本示例中演示。 * **MODULE**:又為DSO組。與`SHARED`庫不同,它們不鏈接到項目中的任何目標,不過可以進行動態加載。該參數可以用于構建運行時插件。 CMake還能夠生成特殊類型的庫,這不會在構建系統中產生輸出,但是對于組織目標之間的依賴關系,和構建需求非常有用: * **IMPORTED**:此類庫目標表示位于項目外部的庫。此類庫的主要用途是,對現有依賴項進行構建。因此,`IMPORTED`庫將被視為不可變的。我們將在本書的其他章節演示使用`IMPORTED`庫的示例。參見: https://cmake.org/cmake/help/latest/manual/cmakebuildsystem.7.html#imported-targets * **INTERFACE**:與`IMPORTED`庫類似。不過,該類型庫可變,沒有位置信息。它主要用于項目之外的目標構建使用。我們將在本章第5節中演示`INTERFACE`庫的示例。參見: https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#interface-libraries * **ALIAS**:顧名思義,這種庫為項目中已存在的庫目標定義別名。不過,不能為`IMPORTED`庫選擇別名。參見: https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#alias-libraries 本例中,我們使用`add_library`直接集合了源代碼。后面的章節中,我們將使用`target_sources`匯集源碼,特別是在第7章。請參見Craig Scott的這篇精彩博文: https://crascit.com/2016/01/31/enhanced-source-file-handling-with-target_sources/ ,其中有對`target_sources`命令的具體使用。 ## 更多信息 現在展示`OBJECT`庫的使用,修改`CMakeLists.txt`,如下: ```cmake cmake_minimum_required(VERSION 3.5 FATAL_ERROR) project(recipe-03 LANGUAGES CXX) add_library(message-objs OBJECT Message.hpp Message.cpp ) # this is only needed for older compilers # but doesn't hurt either to have it set_target_properties(message-objs PROPERTIES POSITION_INDEPENDENT_CODE 1 ) add_library(message-shared SHARED $<TARGET_OBJECTS:message-objs> ) add_library(message-static STATIC $<TARGET_OBJECTS:message-objs> ) add_executable(hello-world hello-world.cpp) target_link_libraries(hello-world message-static) ``` 首先,`add_library`改為`add_library(Message-objs OBJECT Message.hpp Message.cpp)`。此外,需要保證編譯的目標文件與生成位置無關。可以通過使用`set_target_properties`命令,設置`message-objs`目標的相應屬性來實現。 **NOTE**: *可能在某些平臺和/或使用較老的編譯器上,需要顯式地為目標設置`POSITION_INDEPENDENT_CODE`屬性。* 現在,可以使用這個對象庫來獲取靜態庫(`message-static`)和動態庫(` message-shared `)。要注意引用對象庫的生成器表達式語法:`$<TARGET_OBJECTS:message-objs> `。生成器表達式是CMake在生成時(即配置之后)構造,用于生成特定于配置的構建輸出。參見: https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html 。我們將在第5章中深入研究生成器表達式。最后,將`hello-world`可執行文件鏈接到消息庫的靜態版本。 是否可以讓CMake生成同名的兩個庫?換句話說,它們都可以被稱為`message`,而不是`message-static`和`message-share`d嗎?我們需要修改這兩個目標的屬性: ```cmake add_library(message-shared SHARED $<TARGET_OBJECTS:message-objs> ) set_target_properties(message-shared PROPERTIES OUTPUT_NAME "message" ) add_library(message-static STATIC $<TARGET_OBJECTS:message-objs> ) set_target_properties(message-static PROPERTIES OUTPUT_NAME "message" ) ``` 我們可以鏈接到DSO嗎?這取決于操作系統和編譯器: 1. GNU/Linux和macOS上,不管選擇什么編譯器,它都可以工作。 2. Windows上,不能與Visual Studio兼容,但可以與MinGW和MSYS2兼容。 這是為什么呢?生成好的DSO組需要程序員限制符號的可見性。需要在編譯器的幫助下實現,但不同的操作系統和編譯器上,約定不同。CMake有一個機制來處理這個問題,我們將在第10章中解釋它如何工作。
                  <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>

                              哎呀哎呀视频在线观看