??xml version="1.0" encoding="utf-8" standalone="yes"?> 事情的v因是Q想找个?Windows ?Mac 的构建方案。第一考虑自然?CMakeQ毕竟基本上是事实标准了(jin)?/p>
但是研究?jin)一?Modern CMakeQ也是?target 为核?j)的理念。但发现看了(jin)好几天文档,也折腑և?jin)可用的东西Q但仍然是没梳理清楚什么理c(din)原理。然?CMake 本n语法很复杂Q再加上?target 一套概念,要给 target 讄各种属性之cȝQ有点强?OOP 的感觉……但其实我们只是需要一?include_dir ?lib_dir 而已Q其他都是Q云~ 但如果退回到传统模式Q不?Modern 概念呢,好像可以就Q但W一不去用一个工L(fng)最新模式,好像有点不上q的感觉Qpython 2 除外Q;W二QCMake 的两大痛点——语法特立独行、文晦涩难懂——还是让人有点不爽?/p>
那蟩出来看别的选择呢?目前相对成熟的也只有 Google ?gn+ninja Ҏ(gu)?jin)。gn q套东西?Chromium 里是完全配置好的Q用hq算手Q但要是独立拿出来呢Q就没那么便宜了(jin)。关键是它的 toolchain 是要自己定义的?/p>
之前q在公司搞客L(fng)的时候,大家׃ Chromium 里面?build、build_overrides {等东西全部拷出来,好家伙,几百 MB 甚至?G。但是公叔R嘛,没h干不干净Q怎么快怎么来。后来又看到 Google 自家?Crashpad 里面也用?jin)这套构建,但工具链被简化了(jin)一下,?mini_chromium。这个比 Chromium 里的多?jin),是可以拿q来直接用的Q缺一些配|可以自己加。但是呢Q像我们q种z癖Q仍然是受不鸟的。所以呢Q我们要q干净净的徏立一套工具链?/p>
首先Q我们明定位。gn ?ninja 都是开发机上需要预装的Q不是Y件提供的。Chromium 的搞法是自己提供Qgn 的文也说让开发者提供工兗但q套思\跟传l的理念是冲H的。同Ӟ自己安装工具成本是比较低的:(x) 自己下蝲的设|到 PATHQ测? 希望做到提供一?git repoQ用?clone 到自己项目的 build 目录Q然后用者只要在 .gn 文g里配|?/p>
可以用我们提供的工具链,?PC 三端q行构徏?/p>
使用者的唯一负担是~写自己?BUILD.gn 首先我们?gn 的文档,以及(qing)它的例程 simple_build 里的工具N|:(x) https://gn.googlesource.com/gn/+/HEAD/examples/simple_build/build/toolchain/BUILD.gn q个是可以直接用的,只不q只?linux 端(当然 mac 也能用)(j)。我们再l合 chrome 里的工具N|,q行一些完善?/p>
首先我们?jin)?gn 体系需要的最配|是什么?/p>
W一Q它需要在根目录写一?.gn 文gQ在里面定义 buildconfigQ指到另一个文Ӟ一般是 W二、BUILDCONFIG.gn 里面需要设|默认工具链Q也是写一?/p>
W三、定义工具链Q如上例?//build/toolchain:gcc?/p>
需要在 build/toolchain 下徏?BUILD.gn 文gQ内Ҏ(gu) 最后在 toolchain 里定义各U?tool?/p>
q部分文档在q里Qhttps://gn.googlesource.com/gn/+/main/docs/reference.md#func_tool 单复qC下,可被定义的工hQ?/p>
Q其他的先不看?jin)?j) 我们来看一?https://gn.googlesource.com/gn/+/HEAD/examples/simple_build/build/toolchain/BUILD.gn 的一些关键配|:(x) 可以看到Qcc ?cxx 执行 command 后,生成 .o 文gQ然后这?.o 文g可以作ؓ(f) alink、solink、link ?inputsQ被它们 command l箋(hu)使用Q最后输出静(rn)态库、动态库以及(qing)可执行文件?/p>
其余属性可以查文档?jin)解含义?/p>
主要配置在这里:(x)https://source.chromium.org/chromium/chromium/src/+/main:build/toolchain/gcc_toolchain.gni 也是 gcc 的,?simple_build 里的大同异Q没有特别的?/p>
主要配置在这里:(x)https://source.chromium.org/chromium/chromium/src/+/main:build/toolchain/apple/toolchain.gni 区别有:(x) 基本上是Ҏ(gu)上面分析的要炚w|,最l结果在此:(x)https://github.com/Streamlet/gn_toolchain 新增的一些差异有Q?/p>
增加全局参数 is_debugQ可以在 mac 下生?dSYM 不?python 脚本Q直接是 mac 下加?jin)一?templateQapp_bundleQ用来生?xxx.appQ主要配|来自于 create_bundle 文里的例子 win 下增加了(jin)一些配|集 动??rn)态链?CRTQ?/build/config/win:console_subsystem?/build/config/win:static_runtime 控制台程序、Win32 E序Q?/build/config/win:console_subsystem?/build/config/win:windows_subsystem q个其实一般情况下用不着Q只要入口函数是 main/WinMainQlink 默认是控制台程?Win32 E序 XP 支持Q?/build/config/win:console_subsystem_xp?/build/config/win:windows_subsystem_xp 具体实现是链接参数加 /SUBSYSTEM:CONSOLE,5.01 ?/SUBSYSTEM:WINDOWS,5.01。关键是后面的版本号 5.01Qؓ(f)?jin)加版本号则必须指定子系l名Uͼ所以分?console_subsystem_xp ?windows_subsystem_xp。又Qxp q里提供?jin)两?subsystem 的配|集Q非 xp 也提供两个?/p>
但是我们没有?_WIN32_WINNT=0x0501、WINVER=0x0501、_USING_V110_SDK71_Q也没有指定必须使用 7.0 版本?SDKQ这些都是非必须的,只要不用?XP 以后d?API 卛_。用者可以在自己?target 里面定义q些宏?/p>
提供一个用案例:(x)https://github.com/Streamlet/gn_toolchain_sample 因ؓ(f)它以 git submodule 形式引用?https://github.com/Streamlet/gn_toolchainQ所?git clone 以后Q需? 然后在根目录执行Q(保 gn ?ninja 已经?PATH 中)(j) 卛_?/p>
Mac 下会(x)额外生成一?objc 目 objc_console_application 以及(qing)一?app_bundleQns_application.app?/p>
Win ?x)额外生成一?Win32 目 win32_application?/p>
Win 下需要先执行一?Visual Studio 带的命o(h)行环境,?VS 2022 Community ?“x64 Native Tools Command Prompt for VS 2022”,cl {工h?x)可用?/p>
如果要测?XPQ?2位)(j)Q用“x86 Native Tools Command Prompt for VS 2022”进入,CD 到项目目录,执行Q?/p>
我们只用几十 KB 的大完成了(jin)跨端支持Q是很轻量的一个配|。如果?zhn)觉得实用q认可这U方式,Ƣ迎一hl护、完善?/p>
构徏pȝ安装
gn --version
以及(qing) ninja --version
Q能q行卛_目标
buildconfig = "//build/BUILDCONFIG.gn"
工具链搭?/h2>
基础概念
buildconfig = "//build/BUILDCONFIG.gn"
set_default_toolchain("//build/toolchain:gcc")
toolchain("gcc") {
# ...
}
工具链中的工?/h3>
"cc": C ~译?br />
"cxx": C++ ~译?br />
"cxx_module": 支持 module ?C++ ~译?br />
"objc": Objective C ~译?br />
"objcxx": Objective C++ ~译?br />
"rc": Windows 资源脚本~译?br />
"asm": 汇编?br />
"swift": Swift ~译?/li>
"alink": ?rn)态库链接?br />
"solink": 动态库链接?br />
"link": 可执行文仉接器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}}"
}
}
Ҏ(gu) Chromium 中的配置
Linux
Mac
Win
建立我们的工具链
gn gen out --args="is_debug=true"
传入。默?is_debug ?falseQ开启所有优化?/p>
$ld ... && dsymutil ... && strip
使用案例
git submodule update --init
一下?/p>
gn gen out
ninja -C out
gn gen out --args="target_cpu=\"x86\""
ninja -C out
ȝ