﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-溪流漫话</title><link>http://www.cppblog.com/Streamlet/</link><description>荒废中，求警醒~</description><language>zh-cn</language><lastBuildDate>Mon, 06 Apr 2026 06:31:08 GMT</lastBuildDate><pubDate>Mon, 06 Apr 2026 06:31:08 GMT</pubDate><ttl>60</ttl><item><title>建立一个简单干净的 gn+ninja 工具链</title><link>http://www.cppblog.com/Streamlet/archive/2022/11/06/229483.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Sat, 05 Nov 2022 18:05:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2022/11/06/229483.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/229483.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2022/11/06/229483.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/229483.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/229483.html</trackback:ping><description><![CDATA[
<h2>背景</h2>
<p>事情的起因是，想找个跨 Windows 和 Mac 的构建方案。第一考虑自然是 CMake，毕竟基本上是事实标准了。</p>
<p>但是研究了一下 Modern CMake，也就是以 target 为核心的理念。但发现看了好几天文档，也折腾出了可用的东西，但仍然是没梳理清楚什么理念、原理。然后 CMake 本身语法就很复杂，再加上搞 target 一套概念，要给 target 设置各种属性之类的，有点强行 OOP 的感觉……但其实我们只是需要一个 include_dir 和 lib_dir 而已，其他都是浮云~</p>
<p>但如果退回到传统模式，不用 Modern 概念呢，好像可以将就，但第一不去用一个工具的最新模式，好像有点不上进的感觉（python 2 除外）；第二，CMake 的两大痛点——语法特立独行、文档晦涩难懂——还是让人有点不爽。</p>
<p>那跳出来看别的选择呢？目前相对成熟的也只有 Google 的 gn+ninja 方案了。gn 这套东西在 Chromium 里是完全配置好的，用起来还算顺手，但要是独立拿出来呢，就没那么便宜了。关键是它的 toolchain 是要自己定义的。</p>
<p>之前还在公司搞客户端的时候，大家就从 Chromium 里面把 build、build_overrides 等等东西全部拷出来，好家伙，几百 MB 甚至上 G。但是公司里嘛，没人管干不干净，怎么快怎么来。后来又看到 Google 自家的 Crashpad 里面也用了这套构建，但工具链被简化了一下，叫 mini_chromium。这个比 Chromium 里的小多了，是可以拿过来直接用的，缺少一些配置可以自己加。但是呢，像我们这种洁癖，仍然是受不鸟的。所以呢，我们要干干净净的建立一套工具链。</p>
<h2>构建系统安装</h2>
<p>首先，我们明确定位。gn 和 ninja 都是开发机上需要预装的，不是软件提供的。Chromium 的搞法是自己提供，gn 的文档也说让开发者提供工具。但这套思路跟传统的理念是冲突的。同时，自己安装工具成本是比较低的：</p>
<ul>
<li>linux
<ul>
<li>ninja 在主流包管理系统里已经有了，包名可能是 ninja 或 ninja-build，直接安装就可以</li>
<li>gn 在部分包管理系统有，尝试包名 gn 或 gn-build 等，没有的话可以下载<a href="https://chrome-infra-packages.appspot.com/dl/gn/gn/linux-amd64/+/latest">二进制版本</a>，或者从源代码自行编译</li>
</ul>
</li>
<li>mac
<ul>
<li>ninja 在 brew 里包名叫 ninja，在 MacPorts 里包名叫 ninja-build</li>
<li>gn 在 brew 里没有，可以下载<a href="https://chrome-infra-packages.appspot.com/dl/gn/gn/mac-amd64/+/latest">二进制版本</a>；在 MacPorts 里叫 gn-devel</li>
</ul>
</li>
<li>win
<ul>
<li>ninja 可以在 <a href="https://github.com/ninja-build/ninja/releases">GitHub</a> 下载二进制版本，gn 可以在 gn 官网下载<a href="https://chrome-infra-packages.appspot.com/dl/gn/gn/windows-amd64/+/latest">二进制版本</a></li>
</ul>
</li>
</ul>
<p>自己下载的设置到 PATH，测试 <code>gn --version</code> 以及 <code>ninja --version</code>，能运行即可</p>
<h2>目标</h2>
<p>希望做到提供一个 git repo，使用者 clone 到自己项目的 build 目录，然后使用者只要在 .gn 文件里配置</p>
<pre><code class="language-gn">buildconfig = &quot;//build/BUILDCONFIG.gn&quot;
</code></pre>
<p>就可以使用我们提供的工具链，在 PC 三端进行构建。</p>
<p>使用者的唯一负担就是编写自己的 BUILD.gn</p>
<h2>工具链搭建</h2>
<p>首先我们看 gn 的文档，以及它的例程 simple_build 里的工具链配置：</p>
<p>https://gn.googlesource.com/gn/+/HEAD/examples/simple_build/build/toolchain/BUILD.gn</p>
<p>这个是可以直接用的，只不过只有 linux 端（当然 mac 也能用）。我们再结合 chrome 里的工具链配置，进行一些完善。</p>
<h3>基础概念</h3>
<p>首先我们了解 gn 体系需要的最小配置是什么。</p>
<p>第一，它需要在根目录写一个 .gn 文件，在里面定义 buildconfig，指到另一个文件，一般是</p>
<pre><code class="language-gn">buildconfig = &quot;//build/BUILDCONFIG.gn&quot;
</code></pre>
<p>第二、BUILDCONFIG.gn 里面需要设置默认工具链，也就是写一行</p>
<pre><code class="language-gn">set_default_toolchain(&quot;//build/toolchain:gcc&quot;)
</code></pre>
<p>第三、定义工具链，如上例的 //build/toolchain:gcc。</p>
<p>需要在 build/toolchain 下建立 BUILD.gn 文件，内容是</p>
<pre><code>toolchain(&quot;gcc&quot;) {
	# ...
}
</code></pre>
<p>最后在 toolchain 里定义各种 tool。</p>
<h3>工具链中的工具</h3>
<p>这部分文档在这里：https://gn.googlesource.com/gn/+/main/docs/reference.md#func_tool</p>
<p>简单复述一下，可被定义的工具有：</p>
<ul>
<li>编译工具:<br />
&quot;cc&quot;: C 编译器<br />
&quot;cxx&quot;: C++ 编译器<br />
&quot;cxx_module&quot;: 支持 module 的 C++ 编译器<br />
&quot;objc&quot;: Objective C 编译器<br />
&quot;objcxx&quot;: Objective C++ 编译器<br />
&quot;rc&quot;: Windows 资源脚本编译器<br />
&quot;asm&quot;: 汇编器<br />
&quot;swift&quot;: Swift 编译器</li>
<li>链接工具:<br />
&quot;alink&quot;: 静态库链接器<br />
&quot;solink&quot;: 动态库链接器<br />
&quot;link&quot;: 可执行文件链接器</li>
</ul>
<p>（其他的就先不看了）</p>
<p>我们来看一下 https://gn.googlesource.com/gn/+/HEAD/examples/simple_build/build/toolchain/BUILD.gn 的一些关键配置：</p>
<pre><code class="language-gn">toolchain(&quot;gcc&quot;) {
  tool(&quot;cc&quot;) {
    command = &quot;gcc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}&quot;
    outputs = [ &quot;{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o&quot; ]
    # ...
  }
  tool(&quot;cxx&quot;) {
    command = &quot;g++ -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}&quot;
    outputs = [ &quot;{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o&quot; ]
    # ...
  }
  tool(&quot;alink&quot;) {
    command = &quot;rm -f {{output}} &amp;&amp; ar rcs {{output}} {{inputs}}&quot;
    outputs = [ &quot;{{target_out_dir}}/{{target_output_name}}{{output_extension}}&quot; ]
    # ...
  }
  tool(&quot;solink&quot;) {
    command = &quot;g++ -shared {{ldflags}} -o $sofile $os_specific_option @$rspfile&quot;
    outputs = [ sofile ]
    # ...
  }
  tool(&quot;link&quot;) {
    command = &quot;g++ {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}}&quot;
    outputs = [ outfile ]
    # ...
  }
  tool(&quot;stamp&quot;) {
    command = &quot;touch {{output}}&quot;
  }
  tool(&quot;copy&quot;) {
    command = &quot;cp -af {{source}} {{output}}&quot;
  }
}
</code></pre>
<p>可以看到，cc 和 cxx 执行 command 后，生成 .o 文件，然后这些 .o 文件可以作为 alink、solink、link 的 inputs，被它们 command 继续使用，最后输出静态库、动态库以及可执行文件。</p>
<p>其余属性可以查文档了解含义。</p>
<h3>对比 Chromium 中的配置</h3>
<h4>Linux</h4>
<p>主要配置在这里：https://source.chromium.org/chromium/chromium/src/+/main:build/toolchain/gcc_toolchain.gni</p>
<p>也是 gcc 的，与 simple_build 里的大同小异，没有特别的。</p>
<h4>Mac</h4>
<p>主要配置在这里：https://source.chromium.org/chromium/chromium/src/+/main:build/toolchain/apple/toolchain.gni</p>
<p>区别有：</p>
<ul>
<li>用 clang 系列编译工具，而不是 gcc</li>
<li>alink 不是用 ar，而使用 libtool</li>
<li>solink 的默认扩展名改成了 dylib</li>
<li>用了一个 linker_driver.py 来支持生成 dSYM，在里面调用了 dsymutil 和 strip</li>
</ul>
<h4>Win</h4>
<ul>
<li>编译用 cl，静态库链接用 lib，动态库和可执行文件的链接用 link</li>
<li>lib_switch = &quot;&quot;，lib_dir_switch = &quot;/LIBPATH:&quot;；前两者 lib_switch = &quot;-l&quot;，lib_dir_switch = &quot;-L&quot;</li>
</ul>
<h3>建立我们的工具链</h3>
<p>基本上是根据上面分析的要点配置，最终结果在此：https://github.com/Streamlet/gn_toolchain</p>
<p>新增的一些差异有：</p>
<ul>
<li>
<p>增加全局参数 is_debug，可以在 <code>gn gen out --args=&quot;is_debug=true&quot;</code>传入。默认 is_debug 为 false，开启所有优化。</p>
</li>
<li>
<p>mac 下生成 dSYM 不使用 python 脚本，直接是 <code>$ld ... &amp;&amp; dsymutil ... &amp;&amp; strip</code></p>
</li>
<li>
<p>mac 下加了一个 template：app_bundle，用来生成 xxx.app，主要配置来自于 create_bundle 文档里的例子</p>
</li>
<li>
<p>win 下增加了一些配置集</p>
<ul>
<li>
<p>动态/静态链接 CRT：//build/config/win:console_subsystem、//build/config/win:static_runtime</p>
</li>
<li>
<p>控制台程序、Win32 程序：//build/config/win:console_subsystem、//build/config/win:windows_subsystem</p>
<p>这个其实一般情况下用不着，只要入口函数是 main/WinMain，link 默认就是控制台程序/Win32 程序</p>
</li>
<li>
<p>XP 支持：//build/config/win:console_subsystem_xp、//build/config/win:windows_subsystem_xp</p>
<p>具体实现是链接参数加 /SUBSYSTEM:CONSOLE,5.01 或 /SUBSYSTEM:WINDOWS,5.01。关键是后面的版本号 5.01，为了加版本号则必须指定子系统名称，所以分了 console_subsystem_xp 和 windows_subsystem_xp。又，xp 这里提供了两个 subsystem 的配置集，非 xp 也提供两个。</p>
<p>但是我们没有加 _WIN32_WINNT=0x0501、WINVER=0x0501、_USING_V110_SDK71_，也没有指定必须使用 7.0 版本的 SDK，这些都是非必须的，只要不用到 XP 以后添加的 API 即可。使用者可以在自己的 target 里面定义这些宏。</p>
</li>
</ul>
</li>
</ul>
<h2>使用案例</h2>
<p>提供一个使用案例：https://github.com/Streamlet/gn_toolchain_sample</p>
<p>因为它以 git submodule 形式引用了 https://github.com/Streamlet/gn_toolchain，所以 git clone 以后，需要 <code>git submodule update --init</code>一下。</p>
<p>然后在根目录执行：（确保 gn 和 ninja 已经在 PATH 中）</p>
<pre><code class="language-sh">gn gen out
ninja -C out
</code></pre>
<p>即可。</p>
<p>Mac 下会额外生成一个 objc 项目 objc_console_application 以及一个 app_bundle：ns_application.app。</p>
<p>Win 会额外生成一个 Win32 项目 win32_application。</p>
<p>Win 下需要先执行一下 Visual Studio 带的命令行环境，如 VS 2022 Community 的 “x64 Native Tools Command Prompt for VS 2022”，cl 等工具才会可用。</p>
<p>如果要测试 XP（32位），用“x86 Native Tools Command Prompt for VS 2022”进入，CD 到项目目录，执行：</p>
<pre><code class="language-gn">gn gen out --args=&quot;target_cpu=\&quot;x86\&quot;&quot;
ninja -C out
</code></pre>
<h2>总结</h2>
<p>我们只用几十 KB 的大小完成了跨端支持，是很轻量的一个配置。如果您觉得实用并认可这种方式，欢迎一起来维护、完善。</p>
<img src ="http://www.cppblog.com/Streamlet/aggbug/229483.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2022-11-06 02:05 <a href="http://www.cppblog.com/Streamlet/archive/2022/11/06/229483.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>写一个 Markdown 博客客户端</title><link>http://www.cppblog.com/Streamlet/archive/2020/09/20/217466.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Sun, 20 Sep 2020 08:03:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2020/09/20/217466.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/217466.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2020/09/20/217466.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/217466.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/217466.html</trackback:ping><description><![CDATA[<p>这个“伪需求”是最近才想到的。</p>
<p>关于文章管理的想法，说来话长。我最初是在 CSDN 写技术文章，就用网页上的编辑器。后来在 CppBlog 写，用上了 Windows Live Write，一般在 Word 里面写好，再贴到 WLW 发布。再后来由于太忙了，一直停到现在。其中除了我懒，有两个客观原因，第一是中间好几年不搞 C++，那么在 CppBlog 上写非 C++ 的东西好像有点奇怪；第二是，服务端的东西真的没法每天下班自己玩呀，每天下班提心吊胆地看短信报警，也没哪个心情和时间再去重新开辟一个和白天工作内容迥异的学习场景维持下去。（佩服自己找借口的能力~）</p>
<p>前些年，Markdown 兴起，GitHub Pages 兴起，一众静态博客工具也蓬勃发展。Markdown 真的太适合用来写技术博客了，唯一不足是图片的处理。尽管如此，我还是花了很大的精力把以前所有的文章都转成了 Markdown。然后曾经一度也玩上了 GitHub Pages，用 Huge 生成静态博客。然而，博客的这东西我认为价值点和动力还是在于交流、碰撞，自己写自己看，跟存本地没啥区别——我的 GitHub Pages 几乎没人看……那时候也没写几篇，大概是 2018 年末到 2019 年初的时间。</p>
<p>半年前，我想到了近年来第一个“伪需求”。我嫌 Hugo 这种形态操作太罗嗦：先写 Markdown，再放到 source repo 的 post 里，提交一把；再生成静态页面，把 public 提交到 public repo。如果折腾模版啥的，就更复杂。我就想写 Markdown，写完提交一次 .md，能不能就看到呢？甚至干脆不提交，直接同步到服务端。这样，就得做一套动态系统（相对于 Hogo 的静态页面）去做这件事，而生成被浏览的数据的逻辑理论上跟 Hugo 之类的没本质区别。而一般个人博客这种文章量，根本不用纳入性能上的考量，因此做成动态是完全可操作的。看了下市面上没有此类的工具，于是就开搞了。我把它叫“NoteIsSite”，GitHub 地址 <a href="https://github.com/Streamlet/NoteIsSite">https://github.com/Streamlet/NoteIsSite</a>，Demo 地址 <a href="https://note-is-site.streamlet.org/">https://note-is-site.streamlet.org/</a>，然后把我所有的文章也用这个工具挂在主页下的一个子分类，见 <a href="https://www.streamlet.org/note/">https://www.streamlet.org/note/</a>。关于这个，以后再开一篇文章细说。</p>
<p>到这里为止，写的过程代价很小了。但是刚才说了，博客这东西，对于我的动力很大一部分来自于评论、碰撞，还是需要发到公共平台上去的好。最近看到一个去年离职的前同事的博客 <a href="https://gclxry.com/">https://gclxry.com/</a>，我惊叹于人家一直在坚持写。我想我是不是也要捡起来了，还是回归 CppBlog 吧。于是问题就来了。最近觉得最好用的 Markdown 编辑器是 typora，然后它没法发博客；以前的 WLW 虽然还能用，但毕竟不基于 Markdown。然而 typora 不开源，没法给他加一个“发布”功能了事。所以自己做做看？顺便入一下 Electron 的坑，以及前端的坑。</p>
<p>花了这么大篇幅把需求来源说完了。至于为什么选 Electron 呢？就是为了快点搞定……</p>
<p>上周学习了下 Electron 的 demo 以及打包流程：<a href="https://github.com/StreamletStudy/ElectronHelloWorld">https://github.com/StreamletStudy/ElectronHelloWorld</a></p>
<p>然后正式用这个 repo：<a href="https://github.com/Streamlet/MarkdownBlog">https://github.com/Streamlet/MarkdownBlog</a>
现在功能就两个：编辑、发布。编辑不是所见即所得的，左边 Markdown，右边 HTML。发布要每次填 API 地址、账号，没做管理。整个流程通了，于是停下来写了这篇文章，用刚写的工具发布上来。</p>
<p>发现了 Electron 的一个坑，只要在页面里调用了 alert，页面上的焦点就有问题，输入框再也无法输入内容了。目前用 remote.dialog.* 替代。不知道有没有正解？</p>
<p>后面的规划:</p>
<ol>
<li>搞清楚前端的语言体系，然后选择用原生 JS 还是它的衍生语言，把工程组织进一步完善</li>
<li>搞清楚 UI 复杂度，看要不要选择一个虚拟 DOM 方案</li>
<li>撸功能，账号管理等</li>
<li>撸功能，做成所见即所得</li>
<li>撸功能，支持图片粘贴、上传</li>
</ol>
<p>再后面，先不规划，做完了再看。当前版本 Release：<a href="https://github.com/Streamlet/MarkdownBlog/releases/tag/publish_to_metaweblog_api">https://github.com/Streamlet/MarkdownBlog/releases/tag/publish_to_metaweblog_api</a></p>
<img src ="http://www.cppblog.com/Streamlet/aggbug/217466.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2020-09-20 16:03 <a href="http://www.cppblog.com/Streamlet/archive/2020/09/20/217466.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Go语言的赞和喷</title><link>http://www.cppblog.com/Streamlet/archive/2020/09/20/217465.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Sun, 20 Sep 2020 06:16:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2020/09/20/217465.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/217465.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2020/09/20/217465.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/217465.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/217465.html</trackback:ping><description><![CDATA[<p>（原发于 GitHub Pages，2019-01-01 23:22:43）</p>
<p>2019 年，我回来了。</p>
<p>不知不觉中，我入 PHP 的坑已经 3 年有余，入 Go 的坑也大半年了。作为不评论不舒服斯基星人，自然要对 Go 品头论足一番的。</p>
<p>总的一句话，Go 的一些特性确实恰到好处，然而更多的地方却是平庸、繁琐、束缚，以至于我想不到它是适合哪些场景的。</p>
<p>静态语言里，C、C++ 有着明显的适用领域：你要想老老实实写程序，不玩任何花招，就用 C 吧，至少你能掌控一切，实在想玩你还有宏这个大杀器；你要想玩点花招，那就用 C++，代价就是需要自身水平更高，能掌控到多大层次就写多大层次，不懂的不要不懂装懂去用，总体来说还是安全的。</p>
<p>脚本语言里，如果要随便写点什么工具，python 啥的挺方便的；写点网络的，就用世界上最好的语言 PHP 吧。什么？你说 Java？实在没办法，体量太大，公司要你用你就用吧。不过就其本质而言，其实 Java 和今天的主角——Go 是同一类的。不是说他们语法像，是指应用场景（不过这个领域拿 PHP 写显然会更爽）。</p>
<p>嗯——为了表达出真实的意思，我想用词稍微犀利点，请先做一下心理建设。</p>
<p>我不怎么懂 Java，就我浅薄的了解而言，如果你的公司、团队有很多傻逼，甚至你自己也是，业务上又正好可以用 Java 界的一些现成的框架、组件，那么用 Java 肯定是没错的啦。它确实有一种魔力，让你无论多傻逼，也绝对写不出错得多么隐蔽、精妙无比的代码；同时让你无论多牛逼，也写不出多么精彩绝伦、言简意赅的代码。Go 也有这种特质，甚至有些地方比起 Java 更有过之而不及。不信请看：</p>
<p>别人家的写法：</p>
<pre><code class="language-C++">r = f(p1, p2 != null ? p2 : p3)
</code></pre>
<pre><code class="language-PHP">$r = f($p1, $p2 ?? $p3) 
</code></pre>
<p>Go 家的写法：</p>
<pre><code class="language-GO">var r someType
if p2 != nil {
	r = f(p1, p2)
} else {
	r = f(p1, p3)
}
</code></pre>
<p>为什么要设计成这样？Go 爸爸说：你们有些人啊，会嵌套很多层 <code>?:</code>，导致代码可读性太差啦，于是禁止你们使用 <code>?:</code>，这是家法。在这里，作为熊孩子的代表，我来告诉大家怎样写出让 Go 爸爸无语的代码：</p>
<pre><code class="language-GO">	foo := 1
	bar := 2
	var foobar int
	if foo &gt; bar { if bar &gt; 1 { foobar = 1 } else if bar &lt; 0 { foobar = 2 } else { foobar = 3 } } else { if foo &gt;= 3 { foobar = 4 } else { foobar = 5 } }
</code></pre>
<p>怎么样？可读性差不差？</p>
<p>看到了吧，这种傻逼是防不住的，他愿意把 ?: 嵌套好多层，它同样可能会把 <code>if else</code> 嵌套好多层。有素质的人会怎么做？遇到 <code>?:</code> 嵌套太多立马拆成 <code>if else</code>。所以结论是，即使去掉 <code>?:</code>，傻逼还是傻逼，但是正常的人写代码就会很啰嗦；支持 <code>?:</code>，傻逼还是傻逼，正常人用起来爽。要知道一层 ?: 的场景占所有 <code>?:</code> 场景的比例还是很高的吧。我觉得可以这样，Go 爸爸可以统计一些工业级代码库的 <code>?:</code> 嵌套层数，作为数据支撑（比如自家 Chrome 里一层 <code>?:</code> 占 95%，两层占 4.9），然后再在语言层面只支持一层 <code>?:</code>，编译参数可选打开两层，不支持两层以上。这就功在千秋了。</p>
<p>除了 不支持 <code>?:</code>，Go 爸爸还有很多这样的设计，随便举几个例子：</p>
<ol>
<li>不支持默认参数</li>
<li>不支持运算符重载</li>
<li>不提供 goroutine id（以及 gls、可重入锁）</li>
</ol>
<p>特别是第三点，也是这种思路，因为你们可能会滥用，所以我不提供。类似这种“爸爸思路”，是我今天要喷的最大喷点。前两点也许是抄 Java 的，不怪 Go 爸爸。</p>
<p>综上，Go 爸爸通过扼杀一些基本语法或者一些基础信息，来防止傻逼干坏事，同时让正常人用起来很啰嗦，同时还可能防止不了傻逼干坏事。这跟 Java 通过不提供高级语法来防止傻逼干坏事是师出同门啊，而且他们正好都能写网络服务程序，你说它们像不像？</p>
<p>然而，Go 爸爸也有精分的时候，它居然发明语法糖了耶！比如 <code>if</code> 可以执行一个句句。单就这个语法而言，我的态度是中立偏赞。赞是赞 Go 爸爸确实用过心了，某些时候挺方便，还能缩小变量作用域；不过这个总归是可有可无的，毕竟换一行写也不会死，要变量作用域加个大括号就行。</p>
<p>小语法方面倒是有个亮点，那就是 switch 的隐式 break、显式 fallthrough 处理。不多展开了。</p>
<p>除了防傻逼，Go 爸爸还有一个思路，就是只许州官放火，不许百姓点灯。有两个语法点——</p>
<ol>
<li>泛型</li>
<li>逗号ok断言</li>
</ol>
<p>先说泛型吧。不支持泛型其实我挺能理解的，因为他确实比 <code>?:</code> 复杂多了，傻逼用不起，<code>?:</code> 都没有，怎么可能会有泛型呢。然而 Go 爸爸有特权呀，它的 map、chan 可都是泛型的哦。但是你要写一个泛型的语法结构的话，对不起没有。</p>
<p>再说逗号ok断言，同样 Go 爸爸要得起，我们要不起。其实我更想要一个这样的语法：当返回值是 xxx, ok 或者 xxx, err 的时候，我如果用一个返回值接，那么就返回第一个，以便链式调用，同时 !ok 或者 err != nil 的时候 panic。</p>
<p>以上两小点虽然是在喷，不过还好啦。无所谓的。下面讲几个大的方面。</p>
<h5>代码组织</h5>
<p>我特别赞赏 Go 对于 package 级严格的循环依赖检查。然而如果加上其他规则：</p>
<ul>
<li>一个目录一个 package</li>
<li>不同路径下的同名目录也是不同 package</li>
<li>go 代码无法拆成 .h、.cpp</li>
</ul>
<p>实际可操作性就会非常差。要拆 package，就要把依赖关系梳理得特别严格，半点不得马虎。这对工一般的程代码来说是个极大的挑战。</p>
<p>我更倾向于做成函数级循环依赖检查，或者不限制（毕竟递归函数也是要支持的嘛）。</p>
<p>这部分，中立偏喷，偏喷是因为 Go 爸爸用了我的小名 internal。</p>
<h5>OOP</h5>
<p>我特别赞赏 Go 对于 OOP 泛滥成灾的思考与探索，以及对于终结这阵 Java 带来的不正之风的决心。怎么可能万物都是 class 呢。但同时，Go 还是有点矫枉过正的，如果我需要利用传统的 OOP 来搞事情，就非常麻烦，你甚至都无法写出一个框架来。你只能写库让别人用。虽然我也不喜欢框架，但有的时候是需要框架的。</p>
<p>defer 非常切中痛点，特别解决一堆错误 return 外加资源释放的问题。相比之下C 里只能用 goto，C++ 本身不支持但可以玩出 LOKI_ON_BLOCK_EXIT 或者 BOOST_SCOPE_EXIT。defer 一举解决问题。（要是能再增加命名 defer 以及撤销 defer 的功能就更好了。没错，你也许看出来了，我觉得 LOKI_ON_BLOCK_EXIT 是最完美的方案。）</p>
<p>虽然 defer 很好，但不意味着析构就没用武之地了。理想的情况是，析构、多态、defer 都要有……</p>
<p>这部分我的态度是中立。</p>
<h5>错误处理</h5>
<p>终于要点赞了。错误处理是在我看来 go 完胜的地方，恰到好处地处理问题，又防止滥用。也矫正 Java 带来的歪风邪气。</p>
<p>Java 的设计，让人不得不用异常来处理业务。甚至 Java 自己还帮我们分好类了：一种是不是异常的异常，用来处理业务；另一种是真的异常。一些用惯 Java 的傻逼跑到 C++、PHP、Python 里乱拉屎，到处是 try catch。</p>
<p>Go 爸爸一声令下，万籁俱寂。</p>
<h5>goroutine</h5>
<p>最后不得不说说 gorouthine，毕竟是卖点嘛。我的态度中立偏赞。赞是因为这是一种太有创意的方案，居然想在在语言层面解决多线程、并发问题；不过我还是觉得这更多的是应用层面的问题，做到官方库里会更好，而不是做成语法。</p>
<h1>总结</h1>
<p>刚开始用 Go 的时候，特别亮眼，简直处处是亮点，然后越接触越讨厌，一点也不耐看……看得出来，设计者糅合了 C、python、Java 的一些特性，并融入了自己的独特的理解。Go的设计者真的特别特立独行且坚持己见，一些我喜欢的特性因为他们的坚持而存在下来，一些我讨厌的特性也因为他们的坚（Gu）持（Zhi）而不能有所改观。就这样的 Go，想代替 C 作为系统语言，是没戏的；想在网络服务有一番作为，抢 Java 的份额，或许是有机会的，不过最多只能抢 Java 的，连 C# 的都抢不了，C++、PHP 更抢不了。</p>
<p>嗯，除了特定的不得不用的场合，反正我是不会特意用 Go 的。</p>
<p>2019，新年快乐！</p>
<img src ="http://www.cppblog.com/Streamlet/aggbug/217465.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2020-09-20 14:16 <a href="http://www.cppblog.com/Streamlet/archive/2020/09/20/217465.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我们来汉化IntelliJ IDEA</title><link>http://www.cppblog.com/Streamlet/archive/2020/09/20/217463.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Sun, 20 Sep 2020 06:00:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2020/09/20/217463.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/217463.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2020/09/20/217463.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/217463.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/217463.html</trackback:ping><description><![CDATA[<p>（原发于 GitHub Pages，2018-10-13 13:51:09）</p> <p>两年前我从一名光荣的C++程序员专业为PHP程序员以后，告别了世界第一IDE Visual Studio，改用当时觉得特别难用的 PHPStorm。用了这么久以后，觉得IntelliJ系列虽比不上VS，大概也有世界第二吧，至少比eclipse强太多。除了慢大概也没啥好吐槽的了。</p> <p>最近又要写Go又要写PHP，最开始PHPStorm和GoLand一起用，后来想，用两个渠道包干嘛呢，还使用他们家的主打产品Idea吧。。。</p> <p>虽然说程序员一般是要用英文版的，不管是为了实用还是为了装逼。但为了更多人能入门，我们发起一个开源项目来汉化吧，在 <a href="https://github.com/Streamlet/ideaLocalization">https://github.com/Streamlet/ideaLocalization</a>，欢迎有志之士加入。</p> <p>我们主要就是翻译 resources.jar。代码框架是这样的，resources\en 是原文件解压后的，resources\zh-CN是复制了一份resources\en，我们只要在resources\zh-CN里面就地改动即可。</p> <p>build.py会把散着的文件们打包成resources.jar。jar里的properties文件里，如果有中文，不能直接是UTF或GBK，必须转成\uXXXX的写法。这个build.py会帮忙转，因此resources\zh-CN里直接写中文（UTF-8）就好。</p> <p>就是发起个项目意思意思，估计我是没时间翻译的……^_^</p> <hr>  <h1>当前进度</h1> <p>已完成：</p> <ul> <li>主界面菜单栏翻译 </li></ul> <h1>使用方法</h1> <ol> <li>获取语言包。您可以：  <ul> <li>直接从 release 列表下载 resource_zh_CN.jar  <li>clone 本项目，运行本项目根目录的 build.py 来生成 resource_zh_CN.jar </li></ul> <li>将语言包复制到 idea 安装目录的 <strong>lib</strong> 目录下，复制到 <strong>lib</strong> 目录下，复制到 <strong>lib</strong> 目录下  <li>重启 idea </li></ol> <h2>注意事项</h2> <ul> <li>取决于不同操作系统，您可能需要将系统的界面语言设置为简体中文（zh-CN）才能生效。  <li>本项目目前只针对 idea，对于 jetBrains 的其他产品尚未做适配，理论上可能支持或部分支持，请自行尝试。 </li></ul> <h1>加入我们</h1> <p>本项目诚邀您的加入，欢迎您贡献自己的力量。</p> <ul> <li>您只需原地修改 resources 下的文件即可，可以在空闲的时候修改一个文件、甚至一行  <li>本项目谢绝直接的自动翻译，但不介意您个人使用自动翻译进行某种形式的协助，但最终请您进行人工核对  <li>本项目遵循软件行业通用的翻译规范，同时对标 Visual Studio 的翻译。请自行体会。下面会罗列一些细则。 </li></ul> <h2>分支说明</h2> <ul> <li>dev_build_script: 专门修改构建脚本  <li>dev_readme：专门修改 readme  <li>original_resources_tracker: 英文资源文件  <li>dev_translate：翻译 </li></ul> <h3>合并策略</h3> <ul> <li>dev_build_script 每次修改并测试通过后合入 master  <li>dev_readme 每次修改稳定后合入 master  <li>original_resources_tracker 每次更新资源后打 tag，合入 master  <li>dev_translate 经常性地从 master 合并新的提交  <ul> <li>当 dev_translate 稳定后，从 dev_translate 进行发布  <li>dev_translate 在发布时必须处于对 master 可 Fast-Forward 状态  <li>dev_translate 发布之后 master Fast-Forward 到 dev_translate </li></ul></li></ul> <h2>协作方式</h2> <ul> <li>Fork 版本库，在 dev_translate 上修改，提交 pull request 回来  <li>未来时机成熟的话，成立一个 github 上的 oraganization，届时加入 </li></ul> <h2>翻译规范</h2> <ul> <li>标点：行文中一般使用中文半角，某些形式文案中可能需要用英文半角符号  <ul> <li>需要打开对话框操作的菜单项，使用英文半角的三个点（“...”）表示  <li>菜单项/按钮后的快捷键两侧使用英文半角括号 </li></ul> <li>中英文混排：中文和英文之间需要使用一个半角空格进行分隔  <li>菜单项/按钮的快捷键：放在文案之后，如“文件(&lt;u&gt;F&lt;/u&gt;)” </li></ul> <h3>词汇表</h3> <table style="color: #4b4b4b"> <thead> <tr> <th>英文</th> <th>推荐翻译</th> <th><s>不推荐的翻译</s></th></tr></thead> <tbody> <tr> <td>View</td> <td>视图</td> <td><s>查看</s></td></tr> <tr> <td>Build</td> <td>生成</td> <td><s>构建</s></td></tr></tbody></table><img src ="http://www.cppblog.com/Streamlet/aggbug/217463.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2020-09-20 14:00 <a href="http://www.cppblog.com/Streamlet/archive/2020/09/20/217463.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>微软拼音长句模式恢复工具支持Win10 1803</title><link>http://www.cppblog.com/Streamlet/archive/2020/09/20/217462.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Sun, 20 Sep 2020 05:53:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2020/09/20/217462.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/217462.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2020/09/20/217462.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/217462.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/217462.html</trackback:ping><description><![CDATA[<p>4月份就有人留言旧微软拼音恢复工具不支持Win10 1803了，我自己也遇到了，但因为没时间搞，勉为其难使用了词组模式的微软拼音几个月，终于在八月份抽个空研究了下，解决了。</p> <p>这次是因为傻逼大微软改了 System32\IME\shared 里的东西，导致旧系统拷过来的文件与 System32\IME\shared 的东西不兼容了。解决方式很暴力：从以前的版本复制 System32\IME\shared 过来。</p> <p>下载：<a href="https://www.streamlet.org/software/mspyforever/">https://www.streamlet.org/software/mspyforever/</a></p> <p>（原发于 GitHub Pages，2018-10-13 13:36:04）</p><img src ="http://www.cppblog.com/Streamlet/aggbug/217462.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2020-09-20 13:53 <a href="http://www.cppblog.com/Streamlet/archive/2020/09/20/217462.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>