事情的v因是Q想找个?Windows ?Mac 的构建方案。第一考虑自然?CMakeQ毕竟基本上是事实标准了?/p>
但是研究了一?Modern CMakeQ也是?target 为核心的理念。但发现看了好几天文档,也折腑և了可用的东西Q但仍然是没梳理清楚什么理c原理。然?CMake 本n语法很复杂Q再加上?target 一套概念,要给 target 讄各种属性之cȝQ有点强?OOP 的感觉……但其实我们只是需要一?include_dir ?lib_dir 而已Q其他都是Q云~
但如果退回到传统模式Q不?Modern 概念呢,好像可以就Q但W一不去用一个工L最新模式,好像有点不上q的感觉Qpython 2 除外Q;W二QCMake 的两大痛点——语法特立独行、文档晦涩难懂——还是让人有点不爽?/p>
那蟩出来看别的选择呢?目前相对成熟的也只有 Google ?gn+ninja Ҏ(gu)了。gn q套东西?Chromium 里是完全配置好的Q用hq算手Q但要是独立拿出来呢Q就没那么便宜了。关键是它的 toolchain 是要自己定义的?/p>
之前q在公司搞客L的时候,大家׃ Chromium 里面?build、build_overrides {等东西全部拷出来,好家伙,几百 MB 甚至?G。但是公叔R嘛,没h干不干净Q怎么快怎么来。后来又看到 Google 自家?Crashpad 里面也用了这套构建,但工具链被简化了一下,?mini_chromium。这个比 Chromium 里的多了,是可以拿q来直接用的Q缺一些配|可以自己加。但是呢Q像我们q种z癖Q仍然是受不鸟的。所以呢Q我们要q干净净的徏立一套工具链?/p>
首先Q我们明定位。gn ?ninja 都是开发机上需要预装的Q不是Y件提供的。Chromium 的搞法是自己提供Qgn 的文档也说让开发者提供工兗但q套思\跟传l的理念是冲H的。同Ӟ自己安装工具成本是比较低的:
自己下蝲的设|到 PATHQ测?gn --version
以及 ninja --version
Q能q行卛_
希望做到提供一?git repoQ用?clone 到自己项目的 build 目录Q然后用者只要在 .gn 文g里配|?/p>
buildconfig = "//build/BUILDCONFIG.gn"
可以用我们提供的工具链,?PC 三端q行构徏?/p>
使用者的唯一负担是~写自己?BUILD.gn
首先我们?gn 的文档,以及它的例程 simple_build 里的工具N|:
https://gn.googlesource.com/gn/+/HEAD/examples/simple_build/build/toolchain/BUILD.gn
q个是可以直接用的,只不q只?linux 端(当然 mac 也能用)。我们再l合 chrome 里的工具N|,q行一些完善?/p>
首先我们了解 gn 体系需要的最配|是什么?/p>
W一Q它需要在根目录写一?.gn 文gQ在里面定义 buildconfigQ指到另一个文Ӟ一般是
buildconfig = "//build/BUILDCONFIG.gn"
W二、BUILDCONFIG.gn 里面需要设|默认工具链Q也是写一?/p>
set_default_toolchain("//build/toolchain:gcc")
W三、定义工具链Q如上例?//build/toolchain:gcc?/p>
需要在 build/toolchain 下徏?BUILD.gn 文gQ内Ҏ(gu)
toolchain("gcc") {
# ...
}
最后在 toolchain 里定义各U?tool?/p>
q部分文档在q里Qhttps://gn.googlesource.com/gn/+/main/docs/reference.md#func_tool
单复qC下,可被定义的工hQ?/p>
Q其他的先不看了)
我们来看一?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}}"
}
}
可以看到Qcc ?cxx 执行 command 后,生成 .o 文gQ然后这?.o 文g可以作ؓ alink、solink、link ?inputsQ被它们 command l箋使用Q最后输出静态库、动态库以及可执行文件?/p>
其余属性可以查文档了解含义?/p>
主要配置在这里:https://source.chromium.org/chromium/chromium/src/+/main:build/toolchain/gcc_toolchain.gni
也是 gcc 的,?simple_build 里的大同异Q没有特别的?/p>
主要配置在这里:https://source.chromium.org/chromium/chromium/src/+/main:build/toolchain/apple/toolchain.gni
区别有:
基本上是Ҏ(gu)上面分析的要炚w|,最l结果在此:https://github.com/Streamlet/gn_toolchain
新增的一些差异有Q?/p>
增加全局参数 is_debugQ可以在 gn gen out --args="is_debug=true"
传入。默?is_debug ?falseQ开启所有优化?/p>
mac 下生?dSYM 不?python 脚本Q直接是 $ld ... && dsymutil ... && strip
mac 下加了一?templateQapp_bundleQ用来生?xxx.appQ主要配|来自于 create_bundle 文档里的例子
win 下增加了一些配|集
动?静态链?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ؓ了加版本号则必须指定子系l名Uͼ所以分?console_subsystem_xp ?windows_subsystem_xp。又Qxp q里提供了两?subsystem 的配|集Q非 xp 也提供两个?/p>
但是我们没有?_WIN32_WINNT=0x0501、WINVER=0x0501、_USING_V110_SDK71_Q也没有指定必须使用 7.0 版本?SDKQ这些都是非必须的,只要不用?XP 以后d?API 卛_。用者可以在自己?target 里面定义q些宏?/p>
提供一个用案例:https://github.com/Streamlet/gn_toolchain_sample
因ؓ它以 git submodule 形式引用?https://github.com/Streamlet/gn_toolchainQ所?git clone 以后Q需?git submodule update --init
一下?/p>
然后在根目录执行Q(保 gn ?ninja 已经?PATH 中)
gn gen out
ninja -C out
卛_?/p>
Mac 下会额外生成一?objc 目 objc_console_application 以及一?app_bundleQns_application.app?/p>
Win 会额外生成一?Win32 目 win32_application?/p>
Win 下需要先执行一?Visual Studio 带的命o行环境,?VS 2022 Community ?“x64 Native Tools Command Prompt for VS 2022”,cl {工h会可用?/p>
如果要测?XPQ?2位)Q用“x86 Native Tools Command Prompt for VS 2022”进入,CD 到项目目录,执行Q?/p>
gn gen out --args="target_cpu=\"x86\""
ninja -C out
我们只用几十 KB 的大完成了跨端支持Q是很轻量的一个配|。如果?zhn)觉得实用q认可这U方式,Ƣ迎一hl护、完善?/p>
关于文章理的想法,说来话长。我最初是?CSDN 写技术文章,q|页上的~辑器。后来在 CppBlog 写,用上?Windows Live WriteQ一般在 Word 里面写好Q再贴到 WLW 发布。再后来׃太忙了,一直停到现在。其中除了我懒,有两个客观原因,W一是中间好几年不搞 C++Q那么在 CppBlog 上写?C++ 的东西好像有点奇怪;W二是,服务端的东西真的没法每天下班自己玩呀Q每天下班提心吊胆地看短信报警,也没哪个心情和时间再去重新开辟一个和白天工作内容q异的学习场景维持下厅R(佩服自己扑ր口的能力~Q?/p>
前些q_Markdown 兴vQGitHub Pages 兴vQ一众静态博客工具也蓬勃发展。Markdown 真的太适合用来写技术博客了Q唯一不是图片的处理。尽如此,我还是花了很大的_֊把以前所有的文章都{成了 Markdown。然后曾l一度也玩上?GitHub PagesQ用 Huge 生成静态博客。然而,博客的这东西我认Zh(hun)值点和动力还是在于交、碰撞,自己写自qQ跟存本地没啥区别——我?GitHub Pages 几乎没h看……那时候也没写几篇Q大概是 2018 q末?2019 q初的时间?/p>
半年前,我想Cq年来第一个“伪需求”。我?Hugo q种形态操作太|嗦Q先?MarkdownQ再攑ֈ source repo ?post 里,提交一把;再生成静态页面,?public 提交?public repo。如果折腾模版啥的,更复杂。我想?MarkdownQ写完提交一?.mdQ能不能q到呢Q甚臛_脆不提交Q直接同步到服务端。这P得做一套动态系l(相对?Hogo 的静态页面)dqg事,而生成被览的数据的逻辑理论上跟 Hugo 之类的没本质区别。而一般个人博客这U文章量Q根本不用纳入性能上的考量Q因此做成动态是完全可操作的。看了下市面上没有此cȝ工具Q于是就开搞了。我把它叫“NoteIsSite”,GitHub 地址 https://github.com/Streamlet/NoteIsSiteQDemo 地址 https://note-is-site.streamlet.org/Q然后把我所有的文章也用q个工具挂在主页下的一个子分类Q见 https://www.streamlet.org/note/。关于这个,以后再开一文章细说?/p>
到这里ؓ止,写的q程代h(hun)很小了。但是刚才说了,博客q东西,对于我的动力很大一部分来自于评论、碰撞,q是需要发到公共^Cȝ好。最q看C个去q离职的前同事的博客 https://gclxry.com/Q我惊叹于h家一直在坚持写。我x是不是也要捡h了,q是回归 CppBlog 吧。于是问题就来了。最q觉得最好用?Markdown ~辑器是 typoraQ然后它没法发博客;以前?WLW 虽然q能用,但毕竟不Z Markdown。然?typora 不开源,没法l他加一个“发布”功能了事。所以自己做做看Q顺便入一?Electron 的坑Q以及前端的坑?/p>
׃q么大篇q把需求来源说完了。至于ؓ什么?Electron 呢?是Z快点搞定…?/p>
上周学习了下 Electron ?demo 以及打包程Q?a >https://github.com/StreamletStudy/ElectronHelloWorld
然后正式用这?repoQ?a >https://github.com/Streamlet/MarkdownBlog 现在功能׃个:~辑、发布。编辑不是所见即所得的Q左?MarkdownQ右?HTML。发布要每次?API 地址、̎P没做理。整个流E通了Q于是停下来写了q篇文章Q用刚写的工具发布上来?/p>
发现?Electron 的一个坑Q只要在面里调用了 alertQ页面上的焦点就有问题,输入框再也无法输入内容了。目前用 remote.dialog.* 替代。不知道有没有正解?
后面的规?
再后面,先不规划Q做完了再看。当前版?ReleaseQ?a >https://github.com/Streamlet/MarkdownBlog/releases/tag/publish_to_metaweblog_api
2019 q_我回来了?/p>
不知不觉中,我入 PHP 的坑已经 3 q有余,?Go 的坑也大半年了。作Z评论不舒服斯基星人,自然要对 Go 品头一番的?/p>
ȝ一句话QGo 的一些特性确实恰到好处,然而更多的地方却是q_、繁琐、束~,以至于我想不到它是适合哪些场景的?/p>
静态语a里,C、C++ 有着明显的适用领域Q你要想老老实实写E序Q不玩Q何花招,q C 吧,臛_你能掌控一切,实在想玩你还有宏q个大杀器;你要想玩点花招,那就?C++Q代价就是需要自w水qx高,能掌控到多大层次写多大层次Q不懂的不要不懂装懂ȝQM来说q是安全的?/p>
脚本语言里,如果要随便写点什么工Ppython 啥的挺方便的Q写点网l的Q就用世界上最好的语言 PHP 吧。什么?你说 JavaQ实在没办法Q体量太大,公司要你用你q吧。不q就其本质而言Q其?Java 和今天的主角——Go 是同一cȝ。不是说他们语法像,是指应用场景Q不q这个领域拿 PHP 写显然会更爽Q?/p>
嗯——ؓ了表辑և真实的意思,我想用词E微犀利点Q请先做一下心理徏设?/p>
我不怎么?JavaQ就我浅薄的了解而言Q如果你的公司、团队有很多傻|甚至你自׃是,业务上又正好可以?Java 界的一些现成的框架、组Ӟ那么?Java 肯定是没错的啦。它实有一U魔力,让你无论多傻|也绝对写不出错得多么隐蔽、精妙无比的代码Q同时让你无论多牛|也写不出多么_ֽlu、言意赅的代码。Go 也有q种特质Q甚x些地Ҏ(gu)?Java 更有q之而不及。不信请看:
别h家的写法Q?/p>
r = f(p1, p2 != null ? p2 : p3)
$r = f($p1, $p2 ?? $p3)
Go 家的写法Q?/p>
var r someType
if p2 != nil {
r = f(p1, p2)
} else {
r = f(p1, p3)
}
Z么要设计成这PGo 爸爸_你们有些人啊Q会嵌套很多??:
Q导致代码可L太差啦Q于是禁止你们??:
Q这是家法。在q里Q作为熊孩子的代表,我来告诉大家怎样写出?Go 爸爸无语的代码:
foo := 1
bar := 2
var foobar int
if foo > bar { if bar > 1 { foobar = 1 } else if bar < 0 { foobar = 2 } else { foobar = 3 } } else { if foo >= 3 { foobar = 4 } else { foobar = 5 } }
怎么P可读性差不差Q?/p>
看到了吧Q这U傻逼是防不住的Q他愿意??: 嵌套好多层,它同样可能会?if else
嵌套好多层。有素质的h会怎么做?遇到 ?:
嵌套太多立马拆成 if else
。所以结论是Q即使去??:
Q傻D是傻|但是正常的h写代码就会很啰嗦Q支??:
Q傻D是傻|正常人用h爽。要知道一??: 的场景占所??:
场景的比例还是很高的吧。我觉得可以q样QGo 爸爸可以l计一些工业代码库的 ?:
嵌套层数Q作为数据支撑(比如自家 Chrome 里一??:
?95%Q两层占 4.9Q,然后再在语言层面只支持一??:
Q编译参数可选打开两层Q不支持两层以上。这功在千U了?/p>
除了 不支??:
QGo 爸爸q有很多q样的设计,随便丑և个例子:
特别是第三点Q也是这U思\Q因Z们可能会滥用Q所以我不提供。类DU“爸爸思\”,是我今天要喷的最大喷炏V前两点也许是抄 Java 的,不?Go 爸爸?/p>
lgQGo 爸爸通过扼杀一些基本语法或者一些基信息Q来防止傻逼干坏事Q同时让正常人用h很啰嗦,同时q可能防止不了傻逼干坏事。这?Java 通过不提供高U语法来防止傻逼干坏事是师出同门啊Q而且他们正好都能写网l服务程序,你说它们像不像?
然而,Go 爸爸也有_ֈ的时候,它居然发明语法糖了Ӟ比如 if
可以执行一个句句。单p个语法而言Q我的态度是中立偏赞。赞是赞 Go 爸爸实用过心了Q某些时候挺方便Q还能羃?yu)变量作用域Q不q这个d是可有可无的Q毕竟换一行写也不会死Q要变量作用域加个大括号p?/p>
语法方面倒是有个亮点Q那是 switch 的隐?break、显?fallthrough 处理。不多展开了?/p>
除了防傻|Go 爸爸q有一个思\Q就是只许州官放火,不许癑֧点灯。有两个语法点—?/p>
先说泛型吧。不支持泛型其实我挺能理解的Q因Z实??:
复杂多了Q傻逼用不vQ?code>?: 都没有,怎么可能会有泛型呢。然?Go 爸爸有特权呀Q它?map、chan 可都是泛型的哦。但是你要写一个泛型的语法l构的话Q对不v没有?/p>
再说逗号ok断言Q同?Go 爸爸要得P我们要不赗其实我更想要一个这L语法Q当q回值是 xxx, ok 或?xxx, err 的时候,我如果用一个返回值接Q那么就q回W一个,以便铑ּ调用Q同?!ok 或?err != nil 的时?panic?/p>
以上两小点虽然是在喷Q不q还好啦。无所谓的。下面讲几个大的斚w?/p>
我特别赞?Go 对于 package U严格的循环依赖查。然而如果加上其他规则:
实际可操作性就会非常差。要?packageQ就要把依赖关系梳理得特别严|半点不得马虎。这对工一般的E代码来说是个极大的挑战?/p>
我更們于做成函数循环依赖查,或者不限制Q毕竟递归函数也是要支持的嘛)?/p>
q部分,中立偏喷Q偏h因ؓ Go 爸爸用了我的名 internal?/p>
我特别赞?Go 对于 OOP 泛滥成灾的思考与探烦Q以及对于终l这?Java 带来的不正之风的军_。怎么可能万物都是 class 呢。但同时QGo q是有点矫枉q正的,如果我需要利用传l的 OOP 来搞事情Q就非常ȝQ你甚至都无法写Z个框架来。你只能写库让别人用。虽然我也不喜欢框架Q但有的时候是需要框架的?/p>
defer 非常切中痛点Q特别解决一堆错?return 外加资源释放的问题。相比之下C 里只能用 gotoQC++ 本n不支持但可以玩出 LOKI_ON_BLOCK_EXIT 或?BOOST_SCOPE_EXIT。defer 一举解决问题。(要是能再增加命名 defer 以及撤销 defer 的功能就更好了。没错,你也许看出来了,我觉?LOKI_ON_BLOCK_EXIT 是最完美的方案。)
虽然 defer 很好Q但不意味着析构没用武之地了。理想的情况是,析构、多态、defer 都要有…?/p>
q部分我的态度是中立?/p>
l于要点赞了。错误处理是在我看来 go 完胜的地方,恰到好处地处理问题,又防止滥用。也矫正 Java 带来的歪风邪气?/p>
Java 的设计,让h不得不用异常来处理业务。甚?Java 自己q帮我们分好cMQ一U是不是异常的异常,用来处理业务Q另一U是真的异常。一些用?Java 的傻D?C++、PHP、Python 里ؕ拉屎Q到处是 try catch?/p>
Go 爸爸一Co下,万籁俱寂?/p>
最后不得不说说 gorouthineQ毕竟是卖点嘛。我的态度中立偏赞。赞是因是一U太有创意的Ҏ(gu)Q居然想在在语言层面解决多线E、ƈ发问题;不过我还是觉得这更多的是应用层面的问题,做到官方库里会更好,而不是做成语法?/p>
刚开始用 Go 的时候,特别亮眼Q简直处处是亮点Q然后越接触讨厌,一点也不耐看……看得出来,设计者糅合了 C、python、Java 的一些特性,q融入了自己的独特的理解。Go的设计者真的特别特立独行且坚持pQ一些我喜欢的特性因Z们的坚持而存在下来,一些我讨厌的特性也因ؓ他们的坚QGuQ持QZhiQ而不能有所改观。就q样?GoQ想代替 C 作ؓpȝ语言Q是没戏的;惛_|络服务有一番作为,?Java 的䆾额,或许是有Z的,不过最多只能抢 Java 的,q?C# 的都抢不了,C++、PHP 更抢不了?/p>
嗯,除了特定的不得不用的场合Q反正我是不会特意用 Go 的?/p>
2019Q新q快乐!
两年前我从一名光荣的C++E序员专业ؓPHPE序员以后,告别了世界第一IDE Visual StudioQ改用当时觉得特别难用的 PHPStorm。用了这么久以后Q觉得IntelliJpd虽比不上VSQ大概也有世界第二吧Q至比eclipse强太多。除了慢大概也没啥好吐槽的了?/p>
最q又要写Go又要写PHPQ最开始PHPStorm和GoLand一LQ后来想Q用两个渠道包干嘛呢Q还使用他们家的L产品Idea吧。。?/p>
虽然说程序员一般是要用英文版的Q不是Z实用q是Z装逹{但Z更多入门Q我们发起一个开源项目来汉化吧,?https://github.com/Streamlet/ideaLocalizationQ欢q有志之士加入?/p>
我们主要是译 resources.jar。代码框架是q样的,resources\en 是原文g解压后的Qresources\zh-CN是复制了一份resources\enQ我们只要在resources\zh-CN里面地改动卛_?/p>
build.py会把散着的文件们打包成resources.jar。jar里的properties文g里,如果有中文,不能直接是UTF或GBKQ必{成\uXXXX的写法。这个build.py会帮忙{Q因此resources\zh-CN里直接写中文QUTF-8Q就好?/p>
是发v个项目意思意思,估计我是没时间翻译的……^_^
已完成:
本项目诚邀(zhn)的加入Q欢q?zhn)贡献自己的力量?/p>
英文 | 推荐译 | |
---|---|---|
View | 视图 | |
Build | 生成 |
q次是因为傻逼大微Y改了 System32\IME\shared 里的东西Q导致旧pȝ拯来的文g?System32\IME\shared 的东西不兼容了。解x式很暴力Q从以前的版本复?System32\IME\shared q来?/p>
下蝲Q?a >https://www.streamlet.org/software/mspyforever/
Q原发于 GitHub PagesQ?018-10-13 13:36:04Q?/p>