• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-90  評論-947  文章-0  trackbacks-0

            背景

            事情的起因是,想找個跨 Windows 和 Mac 的構建方案。第一考慮自然是 CMake,畢竟基本上是事實標準了。

            但是研究了一下 Modern CMake,也就是以 target 為核心的理念。但發現看了好幾天文檔,也折騰出了可用的東西,但仍然是沒梳理清楚什么理念、原理。然后 CMake 本身語法就很復雜,再加上搞 target 一套概念,要給 target 設置各種屬性之類的,有點強行 OOP 的感覺……但其實我們只是需要一個 include_dir 和 lib_dir 而已,其他都是浮云~

            但如果退回到傳統模式,不用 Modern 概念呢,好像可以將就,但第一不去用一個工具的最新模式,好像有點不上進的感覺(python 2 除外);第二,CMake 的兩大痛點——語法特立獨行、文檔晦澀難懂——還是讓人有點不爽。

            那跳出來看別的選擇呢?目前相對成熟的也只有 Google 的 gn+ninja 方案了。gn 這套東西在 Chromium 里是完全配置好的,用起來還算順手,但要是獨立拿出來呢,就沒那么便宜了。關鍵是它的 toolchain 是要自己定義的。

            之前還在公司搞客戶端的時候,大家就從 Chromium 里面把 build、build_overrides 等等東西全部拷出來,好家伙,幾百 MB 甚至上 G。但是公司里嘛,沒人管干不干凈,怎么快怎么來。后來又看到 Google 自家的 Crashpad 里面也用了這套構建,但工具鏈被簡化了一下,叫 mini_chromium。這個比 Chromium 里的小多了,是可以拿過來直接用的,缺少一些配置可以自己加。但是呢,像我們這種潔癖,仍然是受不鳥的。所以呢,我們要干干凈凈的建立一套工具鏈。

            構建系統安裝

            首先,我們明確定位。gn 和 ninja 都是開發機上需要預裝的,不是軟件提供的。Chromium 的搞法是自己提供,gn 的文檔也說讓開發者提供工具。但這套思路跟傳統的理念是沖突的。同時,自己安裝工具成本是比較低的:

            • linux
              • ninja 在主流包管理系統里已經有了,包名可能是 ninja 或 ninja-build,直接安裝就可以
              • gn 在部分包管理系統有,嘗試包名 gn 或 gn-build 等,沒有的話可以下載二進制版本,或者從源代碼自行編譯
            • mac
              • ninja 在 brew 里包名叫 ninja,在 MacPorts 里包名叫 ninja-build
              • gn 在 brew 里沒有,可以下載二進制版本;在 MacPorts 里叫 gn-devel
            • win

            自己下載的設置到 PATH,測試 gn --version 以及 ninja --version,能運行即可

            目標

            希望做到提供一個 git repo,使用者 clone 到自己項目的 build 目錄,然后使用者只要在 .gn 文件里配置

            buildconfig = "//build/BUILDCONFIG.gn"
            

            就可以使用我們提供的工具鏈,在 PC 三端進行構建。

            使用者的唯一負擔就是編寫自己的 BUILD.gn

            工具鏈搭建

            首先我們看 gn 的文檔,以及它的例程 simple_build 里的工具鏈配置:

            https://gn.googlesource.com/gn/+/HEAD/examples/simple_build/build/toolchain/BUILD.gn

            這個是可以直接用的,只不過只有 linux 端(當然 mac 也能用)。我們再結合 chrome 里的工具鏈配置,進行一些完善。

            基礎概念

            首先我們了解 gn 體系需要的最小配置是什么。

            第一,它需要在根目錄寫一個 .gn 文件,在里面定義 buildconfig,指到另一個文件,一般是

            buildconfig = "//build/BUILDCONFIG.gn"
            

            第二、BUILDCONFIG.gn 里面需要設置默認工具鏈,也就是寫一行

            set_default_toolchain("//build/toolchain:gcc")
            

            第三、定義工具鏈,如上例的 //build/toolchain:gcc。

            需要在 build/toolchain 下建立 BUILD.gn 文件,內容是

            toolchain("gcc") {
            	# ...
            }
            

            最后在 toolchain 里定義各種 tool。

            工具鏈中的工具

            這部分文檔在這里:https://gn.googlesource.com/gn/+/main/docs/reference.md#func_tool

            簡單復述一下,可被定義的工具有:

            • 編譯工具:
              "cc": C 編譯器
              "cxx": C++ 編譯器
              "cxx_module": 支持 module 的 C++ 編譯器
              "objc": Objective C 編譯器
              "objcxx": Objective C++ 編譯器
              "rc": Windows 資源腳本編譯器
              "asm": 匯編器
              "swift": Swift 編譯器
            • 鏈接工具:
              "alink": 靜態庫鏈接器
              "solink": 動態庫鏈接器
              "link": 可執行文件鏈接器

            (其他的就先不看了)

            我們來看一下 https://gn.googlesource.com/gn/+/HEAD/examples/simple_build/build/toolchain/BUILD.gn 的一些關鍵配置:

            toolchain("gcc") {
              tool("cc") {
                command = "gcc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
                outputs = [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
                # ...
              }
              tool("cxx") {
                command = "g++ -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
                outputs = [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
                # ...
              }
              tool("alink") {
                command = "rm -f {{output}} && ar rcs {{output}} {{inputs}}"
                outputs = [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
                # ...
              }
              tool("solink") {
                command = "g++ -shared {{ldflags}} -o $sofile $os_specific_option @$rspfile"
                outputs = [ sofile ]
                # ...
              }
              tool("link") {
                command = "g++ {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}}"
                outputs = [ outfile ]
                # ...
              }
              tool("stamp") {
                command = "touch {{output}}"
              }
              tool("copy") {
                command = "cp -af {{source}} {{output}}"
              }
            }
            

            可以看到,cc 和 cxx 執行 command 后,生成 .o 文件,然后這些 .o 文件可以作為 alink、solink、link 的 inputs,被它們 command 繼續使用,最后輸出靜態庫、動態庫以及可執行文件。

            其余屬性可以查文檔了解含義。

            對比 Chromium 中的配置

            Linux

            主要配置在這里:https://source.chromium.org/chromium/chromium/src/+/main:build/toolchain/gcc_toolchain.gni

            也是 gcc 的,與 simple_build 里的大同小異,沒有特別的。

            Mac

            主要配置在這里:https://source.chromium.org/chromium/chromium/src/+/main:build/toolchain/apple/toolchain.gni

            區別有:

            • 用 clang 系列編譯工具,而不是 gcc
            • alink 不是用 ar,而使用 libtool
            • solink 的默認擴展名改成了 dylib
            • 用了一個 linker_driver.py 來支持生成 dSYM,在里面調用了 dsymutil 和 strip

            Win

            • 編譯用 cl,靜態庫鏈接用 lib,動態庫和可執行文件的鏈接用 link
            • lib_switch = "",lib_dir_switch = "/LIBPATH:";前兩者 lib_switch = "-l",lib_dir_switch = "-L"

            建立我們的工具鏈

            基本上是根據上面分析的要點配置,最終結果在此:https://github.com/Streamlet/gn_toolchain

            新增的一些差異有:

            • 增加全局參數 is_debug,可以在 gn gen out --args="is_debug=true"傳入。默認 is_debug 為 false,開啟所有優化。

            • mac 下生成 dSYM 不使用 python 腳本,直接是 $ld ... && dsymutil ... && strip

            • mac 下加了一個 template:app_bundle,用來生成 xxx.app,主要配置來自于 create_bundle 文檔里的例子

            • win 下增加了一些配置集

              • 動態/靜態鏈接 CRT://build/config/win:console_subsystem、//build/config/win:static_runtime

              • 控制臺程序、Win32 程序://build/config/win:console_subsystem、//build/config/win:windows_subsystem

                這個其實一般情況下用不著,只要入口函數是 main/WinMain,link 默認就是控制臺程序/Win32 程序

              • XP 支持://build/config/win:console_subsystem_xp、//build/config/win:windows_subsystem_xp

                具體實現是鏈接參數加 /SUBSYSTEM:CONSOLE,5.01 或 /SUBSYSTEM:WINDOWS,5.01。關鍵是后面的版本號 5.01,為了加版本號則必須指定子系統名稱,所以分了 console_subsystem_xp 和 windows_subsystem_xp。又,xp 這里提供了兩個 subsystem 的配置集,非 xp 也提供兩個。

                但是我們沒有加 _WIN32_WINNT=0x0501、WINVER=0x0501、_USING_V110_SDK71_,也沒有指定必須使用 7.0 版本的 SDK,這些都是非必須的,只要不用到 XP 以后添加的 API 即可。使用者可以在自己的 target 里面定義這些宏。

            使用案例

            提供一個使用案例:https://github.com/Streamlet/gn_toolchain_sample

            因為它以 git submodule 形式引用了 https://github.com/Streamlet/gn_toolchain,所以 git clone 以后,需要 git submodule update --init一下。

            然后在根目錄執行:(確保 gn 和 ninja 已經在 PATH 中)

            gn gen out
            ninja -C out
            

            即可。

            Mac 下會額外生成一個 objc 項目 objc_console_application 以及一個 app_bundle:ns_application.app。

            Win 會額外生成一個 Win32 項目 win32_application。

            Win 下需要先執行一下 Visual Studio 帶的命令行環境,如 VS 2022 Community 的 “x64 Native Tools Command Prompt for VS 2022”,cl 等工具才會可用。

            如果要測試 XP(32位),用“x86 Native Tools Command Prompt for VS 2022”進入,CD 到項目目錄,執行:

            gn gen out --args="target_cpu=\"x86\""
            ninja -C out
            

            總結

            我們只用幾十 KB 的大小完成了跨端支持,是很輕量的一個配置。如果您覺得實用并認可這種方式,歡迎一起來維護、完善。

            posted on 2022-11-06 02:05 溪流 閱讀(13405) 評論(0)  編輯 收藏 引用 所屬分類: C++WindowsLinuxMac
            久久精品视频一| 午夜不卡888久久| 色播久久人人爽人人爽人人片AV| 久久精品夜色噜噜亚洲A∨| 爱做久久久久久| 欧美性大战久久久久久| 国产成人精品三上悠亚久久| 狠狠色丁香婷婷综合久久来| 久久亚洲精品无码播放| 综合人妻久久一区二区精品| 久久久青草久久久青草| 国内精品久久久久影院老司| www.久久热.com| 久久精品亚洲AV久久久无码| 国产精品伦理久久久久久| 亚洲日韩中文无码久久| 久久久久亚洲AV综合波多野结衣| 欧美牲交A欧牲交aⅴ久久| 久久久一本精品99久久精品88| 国内精品久久久久久99蜜桃| 亚洲国产成人久久综合一区77| 久久香蕉国产线看观看乱码| 狠狠色噜噜色狠狠狠综合久久| 亚洲国产小视频精品久久久三级| 国产精品久久久久久| 人妻无码αv中文字幕久久| 久久久这里只有精品加勒比| 久久99精品国产99久久| 久久久亚洲欧洲日产国码aⅴ| 久久久无码精品亚洲日韩蜜臀浪潮| 办公室久久精品| 狠狠精品干练久久久无码中文字幕 | 久久久精品国产Sm最大网站| 97久久久精品综合88久久| 亚洲精品无码久久久久AV麻豆| 久久99免费视频| 久久久久久免费一区二区三区| 精品综合久久久久久888蜜芽| 日本强好片久久久久久AAA| 久久久久国产精品嫩草影院| 久久亚洲日韩看片无码|